Compare commits

..
Author SHA1 Message Date
DominikIwanek b089b855ff Release 8.0.4 2026-09-01 10:40:54 +02:00
DominikIwanek da1a7bc9d7 Release 8.0.3 2026-09-01 09:55:49 +02:00
DominikIwanek d340cf6899 Release 8.0.3 2026-09-01 09:55:48 +02:00
DominikIwanek 522109439f Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:55:48 +02:00
DominikIwanek 58c1784311 Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:55:48 +02:00
DominikIwanek 542bd2c0d4 Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:55:48 +02:00
DominikIwanek dd7dfa760b Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:55:48 +02:00
DominikIwanek f1f0bc7fc9 Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:55:48 +02:00
DominikIwanek 83173680a9 Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:55:48 +02:00
DominikIwanek e617b85faa Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:55:48 +02:00
DominikIwanek 85c414dfb6 Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:55:47 +02:00
DominikIwanek 375502d803 Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:55:47 +02:00
DominikIwanek 8efbce65fc Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:39:21 +02:00
DominikIwanek 1f448f9c07 Release 8.0.3 - Fix PNG signature images in PDF viewer 2026-09-01 09:39:21 +02:00
MichalKinas a74338e21d Release 8.0.2 2026-02-25 11:15:17 +01:00
MichalKinas 31d293bdb2 [MNT-25541] Small unit testing fix 2026-02-25 11:04:01 +01:00
Anton Ramanovich d4714e2b01 [MNT-25541] PDFs containing JP2 images (JPEG 2000) cannot be displayed in ADW viewer (#11618)
* [MNT-25541]: adds wasmUrl to default options

* [MNT-25541]: updates UTs

* [MNT-25541]: naming change
2026-02-25 11:01:44 +01:00
MichalKinas f751370b60 Release from branch workflow fix 2025-08-11 12:55:29 +02:00
MichalKinas 49062ae19d Release 8.0.1 2025-08-11 08:56:26 +02:00
Copilotanderomano ecd4fed2ac Remove unused webdriver-manager dependency to eliminate vulnerable form-data ~2.3.2 (#11060)
* Initial plan

* Remove webdriver-manager to eliminate form-data ~2.3.2 dependency

Co-authored-by: eromano <1030050+eromano@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: eromano <1030050+eromano@users.noreply.github.com>
2025-08-11 08:48:13 +02:00
dependabot[bot] c7e6051b1a build(deps): bump form-data from 3.0.1 to 3.0.4 in /tools/doc (#11043)
Bumps [form-data](https://github.com/form-data/form-data) from 3.0.1 to 3.0.4.
- [Release notes](https://github.com/form-data/form-data/releases)
- [Changelog](https://github.com/form-data/form-data/blob/v3.0.4/CHANGELOG.md)
- [Commits](https://github.com/form-data/form-data/compare/v3.0.1...v3.0.4)

---
updated-dependencies:
- dependency-name: form-data
  dependency-version: 3.0.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-11 08:35:43 +02:00
dependabot[bot] db0aafa5df build(deps): bump form-data from 4.0.0 to 4.0.4 in /lib/cli (#11046)
Bumps [form-data](https://github.com/form-data/form-data) from 4.0.0 to 4.0.4.
- [Release notes](https://github.com/form-data/form-data/releases)
- [Changelog](https://github.com/form-data/form-data/blob/master/CHANGELOG.md)
- [Commits](https://github.com/form-data/form-data/compare/v4.0.0...v4.0.4)

---
updated-dependencies:
- dependency-name: form-data
  dependency-version: 4.0.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-11 08:35:16 +02:00
323 changed files with 7921 additions and 7845 deletions
+1 -8
View File
@@ -28,11 +28,6 @@ module.exports = {
'plugin:@angular-eslint/recommended',
'plugin:@angular-eslint/template/process-inline-templates',
'plugin:jsdoc/recommended-typescript-error'
// Uncomment this once all linting issues are fixed
// Note to developers:
// you can uncomment the full ruleset locally when fixing issues, and then comment
// that will allow splitting the work into smaller chunks
// 'plugin:unicorn/recommended'
],
plugins: [
'eslint-plugin-unicorn',
@@ -157,7 +152,6 @@ module.exports = {
'rxjs/no-subject-value': 'error',
'rxjs/no-unsafe-takeuntil': 'error',
'unicorn/filename-case': 'error',
'unicorn/prefer-optional-catch-binding': 'error',
'@typescript-eslint/no-unused-expressions': [
'error',
{
@@ -200,8 +194,7 @@ module.exports = {
files: ['*.spec.ts'],
plugins: ['@alfresco/eslint-angular'],
rules: {
'@alfresco/eslint-angular/no-angular-material-selectors': 'error',
'@angular-eslint/component-class-suffix': 'off'
'@alfresco/eslint-angular/no-angular-material-selectors': 'error'
}
},
{
+26 -13
View File
@@ -9,18 +9,17 @@ inputs:
runs:
using: "composite"
steps:
- name: Before install
if: ${{ ! env.ACT }}
shell: bash
run: |
pip install --user --quiet awscli
- name: base vars
shell: bash
run: |
if [ -n "${GITHUB_BASE_REF:-}" ]; then
BASE_HASH=$(git merge-base "origin/${GITHUB_BASE_REF}" HEAD 2>/dev/null || git rev-parse HEAD)
else
BASE_HASH=$(git rev-parse HEAD)
fi
{
echo "GIT_HASH=$(git rev-parse HEAD)";
echo "BASE_HASH=$(git merge-base origin/${GITHUB_BASE_REF} HEAD)";
echo "BASE_HASH=${BASE_HASH}";
echo "HEAD_HASH=HEAD";
echo "HEAD_COMMIT_HASH=${GH_COMMIT}";
echo "NX_CALCULATION_FLAGS=--all";
@@ -31,10 +30,22 @@ runs:
- name: affected:* flag parser
shell: bash
if: ${{ contains(github.event.head_commit.message , '[affected:*]') }}
env:
EVENT_NAME: ${{ github.event_name }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
echo "Setting up CI to run with commit flag [affected:*] flag."
echo "BREAK_ACTION=true" >> $GITHUB_ENV
# Get commit message safely from git to avoid script injection
# For PRs, use the PR head SHA; for other events use HEAD
if [ "$EVENT_NAME" == "pull_request" ] && [ -n "$PR_HEAD_SHA" ]; then
COMMIT_MSG=$(git log -1 --format=%B "$PR_HEAD_SHA" 2>/dev/null || echo "")
else
COMMIT_MSG=$(git log -1 --format=%B 2>/dev/null || echo "")
fi
if echo "$COMMIT_MSG" | grep -qF "[affected:*]"; then
echo "Setting up CI to run with commit flag [affected:*] flag."
echo "BREAK_ACTION=true" >> $GITHUB_ENV
fi
- name: PULL_REQUEST event
if: ${{ env.BREAK_ACTION == false && github.event_name == 'pull_request' && !github.event.pull_request.merged }}
@@ -49,13 +60,15 @@ runs:
} >> $GITHUB_ENV
- name: RELEASE on master/develop patch branch
if: ${{ env.BREAK_ACTION == false && github.event.pull_request.merged }}
if: ${{ env.BREAK_ACTION == false && (github.event.pull_request.merged || github.event_name == 'push') }}
shell: bash
env:
REF_NAME: ${{ github.ref_name }}
run: |
if [[ "${{ github.ref_name }}" =~ ^master(-patch.*)?$ ]]; then
if [[ "$REF_NAME" =~ ^master(-patch.*)?$ ]]; then
# into master(-patch*)
echo "Setting up CI flags for Push on master patch"
elif [[ "${{ github.ref_name }}" =~ ^develop-patch.*$ ]]; then
elif [[ "$REF_NAME" =~ ^develop-patch.*$ ]]; then
# into develop-patch*
echo "Setting up CI flags for Push develop patch"
else
+1 -1
View File
@@ -12,7 +12,7 @@ inputs:
runs:
using: 'composite'
steps:
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
name: Create git tag
env:
TAG_NAME: ${{ inputs.tagName }}
@@ -3,17 +3,33 @@ description: "Download build artifacts"
runs:
using: "composite"
steps:
- name: download and extract artifacts from s3
shell: bash
env:
REMOTE_PATH: "alfresco-ng2-components/build-cache/${{ github.run_id }}"
run: |
packages=( dist nxcache node_modules )
for i in "${packages[@]}"; do
time aws s3 cp --no-progress s3://${S3_BUILD_BUCKET_SHORT_NAME}/${REMOTE_PATH}/$i.tar.gz $i.tar.gz
du -h $i.tar.gz
time tar xzf $i.tar.gz
done
- name: Restore dist from cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: dist
key: dist-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
dist-${{ github.run_id }}-
fail-on-cache-miss: true
- name: Restore nxcache from cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: nxcache
key: nxcache-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
nxcache-${{ github.run_id }}-
fail-on-cache-miss: true
- name: Restore node_modules from cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: node_modules
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
node-modules-${{ github.run_id }}-
fail-on-cache-miss: true
- name: show files
shell: bash
run: |
@@ -24,4 +40,4 @@ runs:
echo "====NXCACHE===="
find nxcache -maxdepth 1 -type d
echo "====ADF===="
find node_modules/@alfresco/ -maxdepth 1 -type d
find node_modules/@alfresco/ -maxdepth 1 -type d
+1 -3
View File
@@ -23,6 +23,4 @@ runs:
echo "TAG_NPM not set, aborting"
exit 1
fi
ADF_VERSION=$(npm view @alfresco/adf-core@${TAG_NPM} version)
echo "check bundle on TAG_NPM='${TAG_NPM}' and ADF_VERSION='${ADF_VERSION}'"
./scripts/github/build/npm-check-bundles.sh -v ${ADF_VERSION}
./scripts/github/build/npm-check-bundles.sh
+29 -21
View File
@@ -2,36 +2,44 @@ name: "set npm tag"
description: "se NPM tag"
inputs:
event_name:
description: "override github.event_name"
required: false
default: ${{ github.event_name }}
branch_name:
description: "override GITHUB_REF_NAME"
required: false
default: $GITHUB_REF_NAME
default: ${{ github.ref_name }}
outputs:
npm-tag:
description: "NPM tag"
value: ${{ steps.set-npm-tag.outputs.npm-tag }}
runs:
using: "composite"
steps:
- name: set TAG_NPM
id: set-npm-tag
shell: bash
env:
BRANCH_NAME: ${{ inputs.branch_name }}
run: |
TAG_NPM="alpha"
VERSION_IN_PACKAGE_JSON=$(node -p "require('./package.json')".version)
echo "version in package.json=${VERSION_IN_PACKAGE_JSON}"
if [[ ${{ inputs.branch_name }} =~ ^master(-patch.*)?$ ]]; then
# Pre-release versions
if [[ $VERSION_IN_PACKAGE_JSON =~ ^[0-9]*\.[0-9]*\.[0-9]*-A\.[0-9]*$ ]];
then
TAG_NPM=next
# Stable major versions
else
TAG_NPM=latest
fi
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
TAG_NPM="branch"
else
TAG_NPM="alpha"
VERSION_IN_PACKAGE_JSON=$(node -p "require('./package.json')".version)
echo "version in package.json=${VERSION_IN_PACKAGE_JSON}"
if [[ $BRANCH_NAME =~ ^master(-patch.*)?$ ]]; then
# Pre-release versions
if [[ $VERSION_IN_PACKAGE_JSON =~ ^[0-9]*\.[0-9]*\.[0-9]*-A\.[0-9]*$ ]]; then
TAG_NPM=next
# Stable major versions
else
TAG_NPM=latest
fi
fi
if [[ $BRANCH_NAME =~ ^develop(-patch.*)?$ ]]; then
TAG_NPM=alpha
fi
fi
if [[ ${{ inputs.branch_name }} =~ ^develop(-patch.*)?$ ]]; then
TAG_NPM=alpha
fi
echo "TAG_NPM=${TAG_NPM}" >> $GITHUB_ENV
echo "npm-tag=$TAG_NPM" >> $GITHUB_OUTPUT
echo "Computed tag: $TAG_NPM"
+36 -32
View File
@@ -1,13 +1,12 @@
name: 'Setup'
description: 'Initialize cache, env var load'
inputs:
enable-cache:
description: 'enable caching'
cache-suffix:
description: 'Suffix to make Nx cache key unique per job (e.g. matrix project name)'
required: false
type: boolean
default: 'true'
enable-node-modules-cache:
description: 'enable caching for node modules'
default: 'default'
full-setup:
description: 'Run git-latest-tag, npm-tag, and before-install (requires fetch-depth: 0). Set to false for matrix jobs that only need node/cache.'
required: false
type: boolean
default: 'true'
@@ -16,43 +15,48 @@ inputs:
required: false
type: boolean
default: 'false'
outputs:
npm-tag:
description: 'NPM tag'
value: ${{ steps.set-npm-tag.outputs.npm-tag }}
runs:
using: "composite"
steps:
- name: install NPM
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
- name: Set consistent machine ID for Nx cache
shell: bash
run: echo "nx-github-actions" | sudo tee /etc/machine-id > /dev/null
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: '.nvmrc'
cache-dependency-path: package-lock.json
cache: 'npm'
- name: get latest tag sha
if: ${{ inputs.full-setup == 'true' }}
id: tag-sha
uses: Alfresco/alfresco-build-tools/.github/actions/git-latest-tag@62d25370db3ca229de518fab5b32ec014a061101 # v8.33.1
# CACHE
- name: Node Modules cache
id: node-modules-cache
if: ${{ inputs.enable-node-modules-cache == 'true' }}
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
env:
cache-name: node-modules-cache
uses: Alfresco/alfresco-build-tools/.github/actions/git-latest-tag@98bcfbe06aafffdc0e9a790f352602316f82303b # v18.23.0
- name: load "NPM TAG"
if: ${{ inputs.full-setup == 'true' }}
id: set-npm-tag
uses: ./.github/actions/set-npm-tag
- name: Install dependencies
shell: bash
run: npm ci
- name: Security audit
shell: bash
run: npm audit --audit-level=critical || true
- name: Restore nx cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
node_modules
key: .npm-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
nxcache
.nx
dist
key: ${{ runner.os }}-nxcache-${{ inputs.cache-suffix }}-${{ hashFiles('nx.json') }}-${{ github.sha }}
restore-keys: |
node_modules-${{ runner.os }}-build-${{ env.cache-name }}-
node_modules-${{ runner.os }}-build-
node_modules-${{ runner.os }}-
- name: pip cache
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
if: ${{ inputs.enable-cache == 'true' }}
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-
restore-keys: |
${{ runner.os }}
- name: load "NPM TAG"
uses: ./.github/actions/set-npm-tag
${{ runner.os }}-nxcache-${{ inputs.cache-suffix }}-${{ hashFiles('nx.json') }}-
${{ runner.os }}-nxcache-${{ inputs.cache-suffix }}-
- name: before install script
if: ${{ inputs.full-setup == 'true' }}
uses: ./.github/actions/before-install
with:
act: ${{ inputs.act }}
@@ -4,16 +4,22 @@ description: "Upload build artifacts"
runs:
using: "composite"
steps:
- name: tar and upload artifacts
shell: bash
env:
REMOTE_PATH: "alfresco-ng2-components/build-cache/${{ github.run_id }}"
run: |
packages=( dist nxcache node_modules )
for i in "${packages[@]}"; do
time tar czf $i.tar.gz $i
du -h $i.tar.gz
time aws s3 cp --no-progress $i.tar.gz "s3://${S3_BUILD_BUCKET_SHORT_NAME}/${REMOTE_PATH}/$i.tar.gz"
done
- name: Save dist to cache
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: dist
key: dist-${{ github.run_id }}-${{ github.run_attempt }}
- name: Save nxcache to cache
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: nxcache
key: nxcache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Save node_modules to cache
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: node_modules
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
+4 -4
View File
@@ -22,7 +22,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
@@ -30,7 +30,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5
uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
# 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@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5
uses: github/codeql-action/autobuild@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
# ️ 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@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.29.5
uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
-75
View File
@@ -1,75 +0,0 @@
name: "git-tag"
on:
workflow_call:
inputs:
dry-run-flag:
description: 'enable dry-run on artifact push'
required: false
type: boolean
default: true
push:
branches:
- master
- master-patch-*
env:
BASE_REF: ${{ github.base_ref }}
HEAD_REF: ${{ github.head_ref }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
GITHUB_BRANCH: ${{ github.ref_name }}
GH_BUILD_DIR: ${{ github.workspace }}
GH_COMMIT: ${{ github.sha }}
BUILD_ID: ${{ github.run_id }}
GH_RUN_NUMBER: ${{ github.run_attempt }}
GH_BUILD_NUMBER: ${{ github.run_id }}
JOB_ID: ${{ github.run_id }}
LOG_LEVEL: "ERROR"
S3_BUILD_BUCKET_SHORT_NAME: ${{ secrets.S3_BUILD_BUCKET_SHORT_NAME }}
NODE_OPTIONS: "--max-old-space-size=5120"
DOCKER_REPOSITORY_DOMAIN: ${{ secrets.DOCKER_REPOSITORY_DOMAIN }}
DOCKER_REPOSITORY_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_REPOSITORY_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
DOCKER_REPOSITORY_STORYBOOK: "${{ secrets.DOCKER_REPOSITORY_DOMAIN }}/alfresco/storybook"
NPM_REGISTRY_ADDRESS: ${{ secrets.NPM_REGISTRY_ADDRESS }}
NPM_REGISTRY_TOKEN: ${{ secrets.NPM_REGISTRY_TOKEN }}
BOT_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
REPO_OWNER: "Alfresco"
REPO_NAME: "alfresco-ng2-components"
STORYBOOK_DIR: "./dist/storybook/stories"
BUILT_LIBS_DIR: "./dist/libs"
NODE_MODULES_DIR: "./node_modules"
REDIRECT_URI: /
jobs:
release:
uses: ./.github/workflows/release.yml
secrets: inherit
with:
dry-run-flag: false
setup:
needs: release
timeout-minutes: 20
name: "Release tag"
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: $BOT_GITHUB_TOKEN
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- id: set-dryrun
uses: ./.github/actions/enable-dryrun
with:
dry-run-flag: ${{ inputs.dry-run-flag }}
- name: install NPM
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version-file: '.nvmrc'
- name: "Release tag"
run: |
git fetch --all --quiet
BRANCH=${GITHUB_REF##*/} ./scripts/github/release/git-tag.sh ${{ steps.set-dryrun.outputs.dryrun }}
+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@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ secrets.PAT_WRITE_PKG }}
retries: 3
+3 -3
View File
@@ -1,16 +1,16 @@
name: Pull Translations from Crowdin
on:
schedule:
- cron: "0 7-17 * * 1-5"
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
pull-from-crowdin:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Pull translations from Crowdin
uses: crowdin/github-action@0749939f635900a2521aa6aac7a3766642b2dc71 # v2.11.0
uses: crowdin/github-action@9fd07c1c5b36b15f082d1d860dc399f16f849bd7 # v2.9.0
with:
upload_sources: false
download_translations: true
+12 -12
View File
@@ -46,8 +46,8 @@ env:
S3_BUILD_BUCKET_SHORT_NAME: ${{ secrets.S3_BUILD_BUCKET_SHORT_NAME }}
NODE_OPTIONS: "--max-old-space-size=5120"
DOCKER_REPOSITORY_DOMAIN: ${{ secrets.DOCKER_REPOSITORY_DOMAIN }}
DOCKER_REPOSITORY_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_REPOSITORY_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
DOCKER_REPOSITORY_USER: ${{ secrets.DOCKER_REPOSITORY_USER }}
DOCKER_REPOSITORY_PASSWORD: ${{ secrets.DOCKER_REPOSITORY_PASSWORD }}
DOCKER_REPOSITORY_STORYBOOK: "${{ secrets.DOCKER_REPOSITORY_DOMAIN }}/alfresco/storybook"
REPO_OWNER: "Alfresco"
REPO_NAME: "alfresco-ng2-components"
@@ -61,7 +61,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Ensure SHA pinned actions
uses: zgosalvez/github-actions-ensure-sha-pinned-actions@fc87bb5b5a97953d987372e74478de634726b3e5 # v3.0.25
@@ -79,15 +79,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Get branch name
uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@62d25370db3ca229de518fab5b32ec014a061101 # v8.33.1
uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@691c1d16c90c88a92d2438a001acdefc0efa7d2a # v8.26.0
- name: Save commit message
uses: Alfresco/alfresco-build-tools/.github/actions/get-commit-message@62d25370db3ca229de518fab5b32ec014a061101 # v8.33.1
uses: Alfresco/alfresco-build-tools/.github/actions/get-commit-message@691c1d16c90c88a92d2438a001acdefc0efa7d2a # v8.26.0
- name: ci:force flag parser
shell: bash
@@ -161,7 +161,7 @@ jobs:
needs: [check-if-pr-is-approved, pre-checks]
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0 # Fetch all history for all tags and branches
- uses: ./.github/actions/setup
@@ -196,7 +196,7 @@ jobs:
exclude: "insights,core,extensions,content-services,process-services$,eslint-plugin-eslint-angular,js-api"
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0 # Fetch all history for all tags and branches
- uses: ./.github/actions/setup
@@ -213,7 +213,7 @@ jobs:
needs: [setup]
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0 # Fetch all history for all tags and branches
- uses: ./.github/actions/setup
@@ -228,7 +228,7 @@ jobs:
needs: [setup]
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0 # Fetch all history for all tags and branches
- uses: ./.github/actions/setup
@@ -243,12 +243,12 @@ jobs:
steps:
- id: checkoutRepo
name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 1
- name: PR contains forbidden labels
id: pr-forbidden
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const issueHasLabels = require('./scripts/github/update/check-issue-has-label.js');
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the latest code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Automatic Rebase
@@ -9,6 +9,11 @@ on:
required: false
type: boolean
default: true
npm-tag:
description: 'NPM tag to use for publishing'
required: false
type: string
default: 'branch'
env:
BASE_REF: ${{ github.base_ref }}
@@ -26,8 +31,8 @@ env:
S3_BUILD_BUCKET_SHORT_NAME: ${{ secrets.S3_BUILD_BUCKET_SHORT_NAME }}
NODE_OPTIONS: "--max-old-space-size=5120"
DOCKER_REPOSITORY_DOMAIN: ${{ secrets.DOCKER_REPOSITORY_DOMAIN }}
DOCKER_REPOSITORY_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_REPOSITORY_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
DOCKER_REPOSITORY_USER: ${{ secrets.DOCKER_REPOSITORY_USER }}
DOCKER_REPOSITORY_PASSWORD: ${{ secrets.DOCKER_REPOSITORY_PASSWORD }}
DOCKER_REPOSITORY_STORYBOOK: "${{ secrets.DOCKER_REPOSITORY_DOMAIN }}/alfresco/storybook"
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
REPO_OWNER: "Alfresco"
@@ -46,11 +51,11 @@ jobs:
- name: set TAG_NPM BRANCH
shell: bash
run: |
TAG_NPM="branch"
TAG_NPM=${{ inputs.npm-tag }}
echo "Set TAG with name: ${TAG_NPM}"
echo "TAG_NPM=${TAG_NPM}" >> $GITHUB_ENV
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- uses: ./.github/actions/setup
@@ -66,8 +71,6 @@ jobs:
release-npm:
needs: [setup]
outputs:
release_version: ${{ steps.set-version.outputs.release_version }}
timeout-minutes: 30
runs-on: ubuntu-latest
permissions:
@@ -75,7 +78,7 @@ jobs:
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- uses: ./.github/actions/setup
@@ -88,12 +91,12 @@ jobs:
dry-run-flag: ${{ inputs.dry-run-flag }}
- uses: ./.github/actions/download-node-modules-and-artifacts
- name: Set libraries versions
id: set-version
if: ${{ inputs.npm-tag == 'branch' }}
run: |
set -u;
./scripts/github/build/bumpversion.sh
./scripts/update-version.sh -gnu || exit 1;
- name: Set migrations
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const setMigrations = require('./scripts/github/release/set-migrations.js');
@@ -102,45 +105,30 @@ jobs:
run: |
npx nx run-many --target=build --prod --skip-nx-cache
npx nx run-many --target=build-schematics
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
name: release libraries GH registry
with:
node-version-file: '.nvmrc'
registry-url: 'https://npm.pkg.github.com'
scope: '@alfresco'
- run: npx nx run-many -t npm-publish --tag=$TAG_NPM || exit 1
- run: npx nx run-many --target=npm-publish --tag=branch|| exit 1
env:
NODE_AUTH_TOKEN: ${{ secrets.PAT_WRITE_PKG }}
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
name: release libraries Npm registry
with:
node-version-file: '.nvmrc'
registry-url: 'https://${{ vars.NPM_REGISTRY_ADDRESS }}'
scope: '@alfresco'
- run: npx nx run-many -t npm-publish --tag=$TAG_NPM || exit 1
- run: npx nx run-many --target=npm-publish --tag=branch || exit 1
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_REGISTRY_TOKEN }}
create-git-tag:
runs-on: ubuntu-latest
needs: [setup, release-npm]
name: Create github tag
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 1
- uses: './.github/actions/create-git-tag'
with:
tagName: ${{ needs.release-npm.outputs.release_version }}
npm-check-bundle:
needs: [release-npm]
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: ./.github/actions/npm-check-bundle
+29 -203
View File
@@ -1,237 +1,63 @@
name: "release"
on:
workflow_call:
workflow_dispatch:
inputs:
dry-run-flag:
dry-run:
description: 'enable dry-run on artifact push'
required: false
type: boolean
default: true
pull_request:
types: [closed]
branches:
- develop
- master
- develop-patch*
- master-patch*
default: false
permissions:
id-token: write # Required for OIDC
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
env:
BASE_REF: ${{ github.base_ref }}
HEAD_REF: ${{ github.head_ref }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
GITHUB_BRANCH: ${{ github.ref_name }}
GH_BUILD_DIR: ${{ github.workspace }}
GH_COMMIT: ${{ github.sha }}
BUILD_ID: ${{ github.run_id }}
GH_RUN_NUMBER: ${{ github.run_attempt }}
GH_BUILD_NUMBER: ${{ github.run_id }}
JOB_ID: ${{ github.run_id }}
E2E_ADMIN_EMAIL_IDENTITY: ${{ secrets.E2E_ADMIN_EMAIL_IDENTITY }}
E2E_ADMIN_PASSWORD_IDENTITY: ${{ secrets.E2E_ADMIN_PASSWORD_IDENTITY }}
LOG_LEVEL: "ERROR"
S3_BUILD_BUCKET_SHORT_NAME: ${{ secrets.S3_BUILD_BUCKET_SHORT_NAME }}
NODE_OPTIONS: "--max-old-space-size=5120"
DOCKER_REPOSITORY_DOMAIN: ${{ secrets.DOCKER_REPOSITORY_DOMAIN }}
DOCKER_REPOSITORY_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_REPOSITORY_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
DOCKER_REPOSITORY_STORYBOOK: "${{ secrets.DOCKER_REPOSITORY_DOMAIN }}/alfresco/storybook"
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
REPO_OWNER: "Alfresco"
REPO_NAME: "alfresco-ng2-components"
STORYBOOK_DIR: "./dist/storybook/stories"
BUILT_LIBS_DIR: "./dist/libs"
NODE_MODULES_DIR: "./node_modules"
REDIRECT_URI: /
jobs:
setup:
timeout-minutes: 20
if: github.event.pull_request.merged == true || github.ref_name == 'master' || github.ref_name == 'master-patch-*'
name: "Setup"
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
- uses: ./.github/actions/setup
with:
enable-cache: false
enable-node-modules-cache: false
- name: install
run: |
npm ci
npx nx run js-api:bundle
npx nx run cli:bundle
- uses: ./.github/actions/upload-node-modules-and-artifacts
release-storybook:
needs: [setup]
timeout-minutes: 15
if: github.event.pull_request.merged == true || github.ref_name == 'master' || github.ref_name == 'master-patch-*'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 1
- run: git fetch --all
- id: set-dryrun
uses: ./.github/actions/enable-dryrun
with:
dry-run-flag: ${{ inputs.dry-run-flag }}
- uses: ./.github/actions/setup
with:
enable-cache: false
enable-node-modules-cache: false
act: ${{ inputs.dry-run-flag }}
- uses: ./.github/actions/download-node-modules-and-artifacts
- name: release Storybook docker
run: |
npx nx run stories:build-storybook --configuration ci
. ./scripts/github/release/docker-tag.sh
./scripts/github/release/release-storybook-docker.sh ${{ steps.set-dryrun.outputs.dryrun }}
release-npm:
needs: [setup]
outputs:
release_version: ${{ steps.set-version.outputs.release_version }}
timeout-minutes: 30
if: github.event.pull_request.merged == true || github.ref_name == 'master' || github.ref_name == 'master-patch-*'
timeout-minutes: 45
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- uses: ./.github/actions/setup
with:
enable-cache: false
enable-node-modules-cache: false
- id: set-dryrun
uses: ./.github/actions/enable-dryrun
with:
dry-run-flag: ${{ inputs.dry-run-flag }}
- uses: ./.github/actions/download-node-modules-and-artifacts
- name: Set libraries versions
id: set-version
run: |
set -u;
./scripts/github/build/bumpversion.sh
- name: Set migrations
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const setMigrations = require('./scripts/github/release/set-migrations.js');
setMigrations();
- name: build libraries
run: |
npx nx run-many -t build --prod --skip-nx-cache
npx nx run-many -t build-schematics
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
name: release libraries GH registry
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: '.nvmrc'
registry-url: 'https://npm.pkg.github.com'
scope: '@alfresco'
- run: npx nx run-many -t npm-publish --tag=$TAG_NPM || exit 1
env:
NODE_AUTH_TOKEN: ${{ secrets.PAT_WRITE_PKG }}
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
cache: 'npm'
- name: install
run: npm ci
- name: build libraries
run: |
npm run build:libs
npm run build:schematics
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
name: release libraries Npm registry
with:
node-version-file: '.nvmrc'
registry-url: 'https://${{ vars.NPM_REGISTRY_ADDRESS }}'
scope: '@alfresco'
- run: npx nx run-many -t npm-publish --tag=$TAG_NPM || exit 1
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_REGISTRY_TOKEN }}
create-git-tag:
runs-on: ubuntu-latest
needs: [setup, release-npm]
name: Create github tag
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 1
- uses: './.github/actions/create-git-tag'
with:
tagName: ${{ needs.release-npm.outputs.release_version }}
- name: upgrade npm
run: |
npm install -g npm@11
npm --version
propagate:
needs: [release-npm]
if: ${{ contains(toJson(github.event.pull_request.labels.*.name), 'hxp-upstream') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: HxP upstream invoke
uses: the-actions-org/workflow-dispatch@3133c5d135c7dbe4be4f9793872b6ef331b53bc7 # v4.0.0
with:
repo: Alfresco/hxp-frontend-apps
ref: develop
workflow: upstream-adf.yml
token: ${{ secrets.ALFRESCO_BUILD_GH_TOKEN }}
wait-for-completion: false
inputs: >
{
"tag_version": "alpha"
}
npm-check-bundle:
needs: [release-npm]
timeout-minutes: 15
if: github.event.pull_request.merged == true || github.ref_name == 'master' || github.ref_name == 'master-patch-*'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: ./.github/actions/npm-check-bundle
push-translation-keys-to-crowdin:
name: Push translations keys to Crowdin
if: ${{ github.ref == 'refs/heads/develop' }}
runs-on: ubuntu-latest
needs: [setup]
permissions:
contents: read
packages: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Push Source Files to Crowdin
uses: crowdin/github-action@0749939f635900a2521aa6aac7a3766642b2dc71 # v2.11.0
with:
upload_sources: true
upload_sources_args: --delete-obsolete
env:
CROWDIN_TOKEN: ${{ secrets.CROWDIN_TRANSLATIONS_TOKEN }}
finalize:
if: always()
runs-on: ubuntu-latest
name: Final Results
needs: [release-storybook, release-npm, npm-check-bundle]
steps:
- name: Check job execution status
if: >-
${{
contains(needs.*.result, 'failure')
|| contains(needs.*.result, 'cancelled')
}}
run: exit 1
- run: npx nx run-many -t npm-publish --tag=branch ${{ inputs.dry-run && '--dry-run' || '' }}
@@ -20,7 +20,7 @@ Adds and retrieves comments for nodes in Content Services.
Gets all comments that have been added to a task.
- _id:_ `string` - ID of the target task
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`CommentModel`](../../../lib/core/src/lib/models/comment.model.ts)`[]>` - Details for each comment
- **getUserImage**(userId: `string`): `string`<br/>
Returns the avatar URL for the specified user.
- _userId:_ `string` - ID of the user
- **Returns** `string` - URL of the user's avatar image
- **getUserImage**(avatarId: `string`): `string`<br/>
Gets the URL for the user's profile image.
- _avatarId:_ `string` - ID of the user
- **Returns** `string` - URL for the user's profile image
+31 -32
View File
@@ -60,38 +60,37 @@ See the [Custom layout](#custom-layout) section for full details of all availabl
### Properties
| Name | Type | Default value | Description |
|-----------------------------| ---- | ------------- |-----------------------------------------------------------------------------------------------------------------------------------------|
| allowFullScreen | `boolean` | true | Toggles the 'Full Screen' feature. |
| allowGoBack | `boolean` | true | Allows `back` navigation. |
| closeButtonPosition | `CloseButtonPosition` | `left` | Set close button position right/left. |
| hideInfoButton | `boolean` | false | Toggles Info button. |
| allowLeftSidebar | `boolean` | false | Allow the left the sidebar. |
| allowNavigate | `boolean` | false | Toggles before/next navigation. You can use the arrow buttons to navigate between documents in the collection. |
| allowRightSidebar | `boolean` | false | Allow the right sidebar. |
| blobFile | [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) | | Loads a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) File |
| canNavigateBefore | `boolean` | true | Toggles the "before" ("&lt;") button. Requires `allowNavigate` to be enabled. |
| canNavigateNext | `boolean` | true | Toggles the next (">") button. Requires `allowNavigate` to be enabled. |
| fileName | `string` | | Override Content filename. |
| title | `string` | | Override Content title. |
| mimeType | `string` | | Overload mimeType |
| overlayMode | `boolean` | false | If `true` then show the Viewer as a full page over the current content. Otherwise fit inside the parent div. |
| readOnly | `boolean` | true | Enable when where is possible the editing functionalities |
| allowedEditActions | `{ [key: string]: boolean }` | `{ rotate: true, crop: true }` | Controls which editing actions are enabled when not in read-only mode. Allows granular control over actions like rotation and cropping. |
| showLeftSidebar | `boolean` | false | Toggles left sidebar visibility. Requires `allowLeftSidebar` to be set to `true`. |
| showRightSidebar | `boolean` | false | Toggles right sidebar visibility. Requires `allowRightSidebar` to be set to `true`. |
| showToolbar | `boolean` | true | Hide or show the toolbar |
| showViewer | `boolean` | true | Hide or show the viewer |
| sidebarLeftTemplate | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`<any>` | null | The template for the left sidebar. The template context contains the loaded node data. |
| sidebarLeftTemplateContext | | null | Context object available for binding by the local sidebarLeftTemplate with let declarations. |
| sidebarRightTemplate | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`<any>` | null | The template for the right sidebar. The template context contains the loaded node data. |
| sidebarRightTemplateContext | | null | Context object available for binding by the local sidebarRightTemplate with let declarations. |
| tracks | [`Track`](../../../lib/core/src/lib/viewer/models/viewer.model.ts)`[]` | \[] | media subtitles for the media player |
| urlFile | `string` | "" | If you want to load an external file that does not come from ACS you can use this URL to specify where to load the file from. |
| viewerExtensions | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`<any>` | null | Template containing ViewerExtensionDirective instances providing different viewer extensions based on supported file extension. |
| nodeId | `string` | null | Identifier of a node opened by a viewer. |
| nodeMimeType | `string` | undefined | Original node mime type, should be provided when renditiona mime type is different. |
| customError | `string` | undefined | Custom error message to be displayed in the viewer. |
| Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- |
| allowFullScreen | `boolean` | true | Toggles the 'Full Screen' feature. |
| allowGoBack | `boolean` | true | Allows `back` navigation. |
| closeButtonPosition | `CloseButtonPosition` | `left` | Set close button position right/left. |
| hideInfoButton | `boolean` | false | Toggles Info button. |
| allowLeftSidebar | `boolean` | false | Allow the left the sidebar. |
| allowNavigate | `boolean` | false | Toggles before/next navigation. You can use the arrow buttons to navigate between documents in the collection. |
| allowRightSidebar | `boolean` | false | Allow the right sidebar. |
| blobFile | [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) | | Loads a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) File |
| canNavigateBefore | `boolean` | true | Toggles the "before" ("&lt;") button. Requires `allowNavigate` to be enabled. |
| canNavigateNext | `boolean` | true | Toggles the next (">") button. Requires `allowNavigate` to be enabled. |
| fileName | `string` | | Override Content filename. |
| mimeType | `string` | | Overload mimeType |
| overlayMode | `boolean` | false | If `true` then show the Viewer as a full page over the current content. Otherwise fit inside the parent div. |
| readOnly | `boolean` | true | Enable when where is possible the editing functionalities |
| allowedEditActions | `{ [key: string]: boolean }` | `{ rotate: true, crop: true }` | Controls which editing actions are enabled when not in read-only mode. Allows granular control over actions like rotation and cropping. |
| showLeftSidebar | `boolean` | false | Toggles left sidebar visibility. Requires `allowLeftSidebar` to be set to `true`. |
| showRightSidebar | `boolean` | false | Toggles right sidebar visibility. Requires `allowRightSidebar` to be set to `true`. |
| showToolbar | `boolean` | true | Hide or show the toolbar |
| showViewer | `boolean` | true | Hide or show the viewer |
| sidebarLeftTemplate | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`<any>` | null | The template for the left sidebar. The template context contains the loaded node data. |
| sidebarLeftTemplateContext | | null | Context object available for binding by the local sidebarLeftTemplate with let declarations. |
| sidebarRightTemplate | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`<any>` | null | The template for the right sidebar. The template context contains the loaded node data. |
| sidebarRightTemplateContext | | null | Context object available for binding by the local sidebarRightTemplate with let declarations. |
| tracks | [`Track`](../../../lib/core/src/lib/viewer/models/viewer.model.ts)`[]` | \[] | media subtitles for the media player |
| urlFile | `string` | "" | If you want to load an external file that does not come from ACS you can use this URL to specify where to load the file from. |
| viewerExtensions | [`TemplateRef`](https://angular.io/api/core/TemplateRef)`<any>` | null | Template containing ViewerExtensionDirective instances providing different viewer extensions based on supported file extension. |
| nodeId | `string` | null | Identifier of a node opened by a viewer. |
| nodeMimeType | `string` | undefined | Original node mime type, should be provided when renditiona mime type is different. |
| customError | `string` | undefined | Custom error message to be displayed in the viewer. |
### Events
+71 -25
View File
@@ -2,10 +2,10 @@
Title: Authentication Service
Added: v2.0.0
Status: Active
Last reviewed: 2025-06-12
Last reviewed: 2019-03-19
---
# Authentication Service
# [Authentication Service](../../../lib/core/src/lib/auth/services/authentication.service.ts "Defined in authentication.service.ts")
Provides authentication to ACS and APS.
@@ -13,57 +13,103 @@ Provides authentication to ACS and APS.
### Methods
- **addTokenToHeader**(requestUrl: `string`, headersArg?: `HttpHeaders`): [`Observable`](http://reactivex.io/documentation/observable.html)`<HttpHeaders>`<br/>
- **addTokenToHeader**(headersArg?: `HttpHeaders`): [`Observable`](http://reactivex.io/documentation/observable.html)`<HttpHeaders>`<br/>
Adds the auth token to an HTTP header using the 'bearer' scheme.
- _requestUrl:_ `string` - The URL of the request for which to set authentication headers.
- _headersArg:_ `HttpHeaders` - (Optional) Header that will receive the token
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<HttpHeaders>` - The new header with the token added
- **getBearerExcludedUrls**()<br/>
Gets the set of URLs that the token bearer is excluded from.
- **getBpmLoggedUser**(): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`UserRepresentation`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/UserRepresentation.md)`>`<br/>
Gets information about the user currently logged into APS.
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`UserRepresentation`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/UserRepresentation.md)`>` - User information
- **getBpmUsername**(): `string`<br/>
Gets the BPM username
- **Returns** `string` - The BPM username
- **getEcmUsername**(): `string`<br/>
Gets the ECM username.
- **Returns** `string` - The ECM username
- **getRedirect**(): `string`<br/>
Gets the URL to redirect to after login.
- **Returns** `string` - The redirect URL
- **getTicketBpm**(): `string|null`<br/>
Gets the BPM ticket stored in the Storage.
- **Returns** `string|null` - The ticket or `null` if none was found
- **getTicketEcm**(): `string|null`<br/>
Gets the ECM ticket stored in the Storage.
- **Returns** `string|null` - The ticket or `null` if none was found
- **getTicketEcmBase64**(): `string|null`<br/>
Gets the BPM ticket from the Storage in Base 64 format.
- **Returns** `string|null` - The ticket or `null` if none was found
- **getToken**(): `string`<br/>
Gets the auth token.
- **Returns** `string` - Auth token string
- **getUsername**(): `string`<br/>
Gets the username of the authenticated user.
- **Returns** `string` - Username of the authenticated user
- **getAuthHeaders**(requestUrl: `string`, headers: `HttpHeaders`): `HttpHeaders`<br/>
Gets and sets the necessary authentication headers for a given request URL.
- _requestUrl:_ `string` - The URL of the request for which to obtain authentication headers.
- _headers:_ `HttpHeaders` - The existing HTTP headers to which authentication details might be added.
- **Returns** `HttpHeaders` - The HTTP headers object, potentially updated with authentication tokens.
- **handleError**(error: `any`): [`Observable`](http://reactivex.io/documentation/observable.html)`<any>`<br/>
Prints an error message in the console browser
- _error:_ `any` - Error message
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<any>` - Object representing the error message
- **isALLProvider**(): `boolean`<br/>
Does the provider support both ECM and BPM?
- **Returns** `boolean` - True if both are supported, false otherwise
- **isAuthCodeFlow**(): `boolean`<br/>
- **Returns** `boolean` -
- **isBPMProvider**(): `boolean`<br/>
Does the provider support BPM?
- **Returns** `boolean` - True if supported, false otherwise
- **isBpmLoggedIn**(): `boolean`<br/>
Checks if the user is logged in on a BPM provider.
- **Returns** `boolean` - True if logged in, false otherwise
- **isECMProvider**(): `boolean`<br/>
Does the provider support ECM?
- **Returns** `boolean` - True if supported, false otherwise
- **isEcmLoggedIn**(): `boolean`<br/>
Checks if the user is logged in on an ECM provider.
- **Returns** `boolean` - True if logged in, false otherwise
- **isImplicitFlow**(): `boolean`<br/>
- **Returns** `boolean` -
- **isKerberosEnabled**(): `boolean`<br/>
Does kerberos enabled?
- **Returns** `boolean` - True if enabled, false otherwise
- **isLoggedIn**(): `boolean`<br/>
Checks if the user logged in.
- **Returns** `boolean` - True if logged in, false otherwise
- **isLoggedInWith**(provider: `string`): `boolean`<br/>
- _provider:_ `string` -
- **Returns** `boolean` -
- **isOauth**(): `boolean`<br/>
Does the provider support OAuth?
- **Returns** `boolean` - True if supported, false otherwise
- **login**(username: `string`, password: `string`, rememberMe?: `boolean`): [`Observable`](http://reactivex.io/documentation/observable.html)`<{ type: string; ticket: any }>`<br/>
- **isPublicUrl**(): `boolean`<br/>
- **Returns** `boolean` -
- **isRememberMeSet**(): `boolean`<br/>
Checks whether the "remember me" cookie was set or not.
- **Returns** `boolean` - True if set, false otherwise
- **login**(username: `string`, password: `string`, rememberMe: `boolean` = `false`): [`Observable`](http://reactivex.io/documentation/observable.html)`<Function>`<br/>
Logs the user in.
- _username:_ `string` - Username for the login
- _password:_ `string` - Password for the login
- _rememberMe:_ `boolean` - (Optional) Stores the user's login details if true
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<{ type: string; ticket: any }>` - An Observable that emits an object containing the authentication type (`type`) and the authentication ticket (`ticket`) upon successful login.
- **logout**(): [`Observable`](http://reactivex.io/documentation/observable.html)`<any>`<br/> Logs the user out.
- _rememberMe:_ `boolean` - Stores the user's login details if true
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<Function>` - Object with auth type ("ECM", "BPM" or "ALL") and auth ticket
- **logout**(): [`Observable`](http://reactivex.io/documentation/observable.html)`<any>`<br/>
Logs the user out.
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<any>` - Response event called when logout is complete
- **reset**(): `void`<br/>Resets the authentication state of the service.
- **on**(event: `string`, listener: `Function`): `void`<br/> Adds an event listener for the specified event.
- **off**(event: `string`, listener?: `Function`): `void`<br/> Removes an event listener for the specified event.
- **once**(event: `string`, listener: `Function`): `void`<br/> Adds a one-time event listener for the specified event.
- **emit**(event: `string`, ...args: `any[]`): `void`<br/> Emits an event with optional arguments.
- **onLogin**: [`Subject`](https://reactivex.io/documentation/subject)`<any>`<br/> Emitted when the user logs in successfully.
- **onLogout**: [`Subject`](https://reactivex.io/documentation/subject)`<any>`<br/> Emitted when the user logs out.
- **onTokenReceived**: [`Subject`](https://reactivex.io/documentation/subject)`<any>`<br/> Emitted when an authentication token is received.
- **onError**: [`Observable`](http://reactivex.io/documentation/observable.html)`<any>`<br/> An Observable that emits an error object when an authentication-related error occurs.
- **reset**()<br/>
- **saveRememberMeCookie**(rememberMe: `boolean`)<br/>
Saves the "remember me" cookie as either a long-life cookie or a session cookie.
- _rememberMe:_ `boolean` - Enables a long-life cookie
- **setRedirect**(url?: [`RedirectionModel`](../../../lib/core/src/lib/auth/models/redirection.model.ts))<br/>
Sets the URL to redirect to after login.
- _url:_ [`RedirectionModel`](../../../lib/core/src/lib/auth/models/redirection.model.ts) - (Optional) URL to redirect to
- **ssoImplicitLogin**()<br/>
Logs the user in with SSO
## Details
@@ -65,7 +65,7 @@ class AppComponent {
onLoggedIn() {
this.userPreferences.setStoragePrefix(
this.authService.getUsername()
this.authService.getEcmUsername()
);
}
}
+2 -2
View File
@@ -56,5 +56,5 @@ The pages linked below contain the licenses for all third party dependencies of
- [ADF 7.0.0-alpha.7](license-info-7.0.0-alpha.7.md)
- [ADF 7.0.0](license-info-7.0.0.md)
- [ADF 8.0.0](license-info-8.0.0.md)
- [ADF 8.1.0](license-info-8.1.0.md)
- [ADF 8.1.1](license-info-8.1.1.md)
- [ADF 8.0.1](license-info-8.0.1.md)
- [ADF 8.0.2](license-info-8.0.2.md)
@@ -1,8 +1,8 @@
---
Title: License info, alfresco-ng2-components 8.1.1
Title: License info, alfresco-ng2-components 8.0.1
---
# License information for alfresco-ng2-components 8.1.1
# License information for alfresco-ng2-components 8.0.1
This page lists all third party libraries the project depends on.
@@ -35,7 +35,6 @@ This page lists all third party libraries the project depends on.
| [dotenv-expand](https://github.com/motdotla/dotenv-expand) | 11.0.7 | [BSD-2-Clause](http://www.opensource.org/licenses/BSD-2-Clause) |
| dotenv-expand | 5.1.0 | [BSD-2-Clause](http://www.opensource.org/licenses/BSD-2-Clause) |
| [event-emitter](https://github.com/medikoo/event-emitter) | 0.3.5 | [MIT](http://www.opensource.org/licenses/MIT) |
| [graphql-ws](https://github.com/enisdenjo/graphql-ws) | 6.0.6 | [MIT](http://www.opensource.org/licenses/MIT) |
| [material-icons](https://github.com/marella/material-icons) | 1.13.14 | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) |
| [minimatch-browser](https://github.com/isaacs/minimatch) | 1.0.0 | [ISC](https://www.isc.org/downloads/software-support-policy/isc-license/) |
| [ng2-charts](https://github.com/valor-software/ng2-charts) | 4.1.1 | [ISC](https://www.isc.org/downloads/software-support-policy/isc-license/) |
@@ -1,8 +1,8 @@
---
Title: License info, alfresco-ng2-components 8.1.0
Title: License info, alfresco-ng2-components 8.0.2
---
# License information for alfresco-ng2-components 8.1.0
# License information for alfresco-ng2-components 8.0.2
This page lists all third party libraries the project depends on.
@@ -35,7 +35,7 @@ This page lists all third party libraries the project depends on.
| [dotenv-expand](https://github.com/motdotla/dotenv-expand) | 11.0.7 | [BSD-2-Clause](http://www.opensource.org/licenses/BSD-2-Clause) |
| dotenv-expand | 5.1.0 | [BSD-2-Clause](http://www.opensource.org/licenses/BSD-2-Clause) |
| [event-emitter](https://github.com/medikoo/event-emitter) | 0.3.5 | [MIT](http://www.opensource.org/licenses/MIT) |
| [graphql-ws](https://github.com/enisdenjo/graphql-ws) | 6.0.6 | [MIT](http://www.opensource.org/licenses/MIT) |
| [graphql-ws](https://github.com/enisdenjo/graphql-ws) | 6.0.5 | [MIT](http://www.opensource.org/licenses/MIT) |
| [material-icons](https://github.com/marella/material-icons) | 1.13.14 | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) |
| [minimatch-browser](https://github.com/isaacs/minimatch) | 1.0.0 | [ISC](https://www.isc.org/downloads/software-support-policy/isc-license/) |
| [ng2-charts](https://github.com/valor-software/ng2-charts) | 4.1.1 | [ISC](https://www.isc.org/downloads/software-support-policy/isc-license/) |
@@ -60,12 +60,10 @@ export class YourService extends ScreenRenderingService {
| appName | `string` | "" | App id to fetch corresponding form and values. |
| canClaimTask | `boolean` | | Boolean informing if a task can be claimed. |
| canUnclaimTask | `boolean` | | Boolean informing if a task can be unclaimed. |
| isNextTaskCheckboxChecked | `boolean` | false | Whether the `Open next task` checkbox is checked by default or not. |
| processInstanceId | `string` | | Process Instance Id to fetch corresponding data. |
| rootProcessInstanceId | `string` | | Root Process Instance Id to fetch corresponding data. |
| readOnly | `boolean` | false | Toggle readonly state of the task. |
| showCancelButton | `boolean` | true | Toggle rendering of the `Cancel` button. |
| showNextTaskCheckbox | `boolean` | false | Toggle rendering of the `Open next task` checkbox (controlled internally by parent component). |
| screenId | `string` | | Screen id to create dynamic component |
| taskId | `string` | | Task id to fetch corresponding form and values. |
| taskName | `string` | | Name of the task. |
+2 -2
View File
@@ -9,8 +9,8 @@ The first **General Availability** release was v2.0.0.
## General Availability
- [8.1.1](RelNote-8.1.1.md)
- [8.1.0](RelNote-8.1.0.md)
- [8.0.2](RelNote-8.0.2.md)
- [8.0.1](RelNote-8.0.1.md)
- [8.0.0](RelNote-8.0.0.md)
- [7.0.0](RelNote-7.0.0.md)
- [7.0.0-alpha.7](RelNote-7.0.0-alpha.7.md)
+8
View File
@@ -0,0 +1,8 @@
---
Title: Changelog for alfresco-ng2-components v8.0.1
---
# Changelog
[4c4dd195a45cdb8cd0218a68972b7a77242359ed](https://github.com/Alfresco/alfresco-ng2-components/commit/4c4dd195a45cdb8cd0218a68972b7a77242359ed)Remove unused webdriver-manager dependency to eliminate vulnerable form-data ~2.3.2 (#11060)
[5e6e2b59495662c103b527e4cae5b019f5136f91](https://github.com/Alfresco/alfresco-ng2-components/commit/5e6e2b59495662c103b527e4cae5b019f5136f91) Bumps [form-data](https://github.com/form-data/form-data) from 3.0.1 to 3.0.4.
[31bff2806b0db10d260855c61034db7d4b48d6e5](https://github.com/Alfresco/alfresco-ng2-components/commit/31bff2806b0db10d260855c61034db7d4b48d6e5) Bumps [form-data](https://github.com/form-data/form-data) from 4.0.0 to 4.0.4.
+6
View File
@@ -0,0 +1,6 @@
---
Title: Changelog for alfresco-ng2-components v8.0.2
---
# Changelog
- [283b996063](git@github.com:Alfresco/alfresco-ng2-components/commit/283b996063) [MNT-25541] PDFs containing JP2 images (JPEG 2000) cannot be displayed in ADW viewer (#11618)
-48
View File
@@ -1,48 +0,0 @@
---
Title: Changelog for alfresco-ng2-components v8.1.0
---
# Changelog
- [2e20c3da45](https://github.com/Alfresco/alfresco-ng2-components/commit/2e20c3da45) [ACS-9978] DynamicChipListComponent not rendered as expected (#11132)
- [bf8c68e05f](https://github.com/Alfresco/alfresco-ng2-components/commit/bf8c68e05f) [ACS-9978] DynamicChipListComponent not rendered as expected (#11128)
- [f81348997b](https://github.com/Alfresco/alfresco-ng2-components/commit/f81348997b) [ACS-10010] [ACA] Label position problem in some perform actions like &#39;send-email&#39; (#11117)
- [cbc204519e](https://github.com/Alfresco/alfresco-ng2-components/commit/cbc204519e) [ACS-9986]: removes unneccesary styles (#11105)
- [9b6688ce10](https://github.com/Alfresco/alfresco-ng2-components/commit/9b6688ce10) CSX-73 Date and Select Satori (#11056)
- [9deaab4c11](https://github.com/Alfresco/alfresco-ng2-components/commit/9deaab4c11) AAE-37006 Fix floating label overlapping in dateitem component (#11118)
- [81e307c81e](https://github.com/Alfresco/alfresco-ng2-components/commit/81e307c81e) AAE-32587 new custom screen registration api (#11120)
- [0e4fced94e](https://github.com/Alfresco/alfresco-ng2-components/commit/0e4fced94e) AAE-37073 Fix error message location and field not highlighting red for card-view-textitem component (#11115)
- [b16e326ac3](https://github.com/Alfresco/alfresco-ng2-components/commit/b16e326ac3) AAE-36664 additional linting rules, cleanup (#11084)
- [794bc92b4a](https://github.com/Alfresco/alfresco-ng2-components/commit/794bc92b4a) AAE-37293 core auth provider api (#11104)
- [5213621023](https://github.com/Alfresco/alfresco-ng2-components/commit/5213621023) AAE-37287 provideExtensions provider api for Angular standalone (#11103)
- [67b1d67668](https://github.com/Alfresco/alfresco-ng2-components/commit/67b1d67668) AAE-37067 Extend QueryParams interface (#11102)
- [1fe4dd6fc9](https://github.com/Alfresco/alfresco-ng2-components/commit/1fe4dd6fc9) AAE-36822 Removes showNextTaskCheckbox input for the feature flag (#11066)
- [9a0b75caa1](https://github.com/Alfresco/alfresco-ng2-components/commit/9a0b75caa1) [ADF-5582] Fix avatar rendering logic in adf-node-comments (#10995)
- [8ef0aee768](https://github.com/Alfresco/alfresco-ng2-components/commit/8ef0aee768) AAE-36869 Handles error messages with wrong JSON format (#11078)
- [3eead3917e](https://github.com/Alfresco/alfresco-ng2-components/commit/3eead3917e) AAE-36582 Fix forms misalignment in form renderer (#11062)
- [c8f0860514](https://github.com/Alfresco/alfresco-ng2-components/commit/c8f0860514) AAE-35934 Cleanup dependencies (#11089)
- [b67d0a7886](https://github.com/Alfresco/alfresco-ng2-components/commit/b67d0a7886) [AAE-36538] Removed flex-direction:column for form section column large screens (#11090)
- [613de66244](https://github.com/Alfresco/alfresco-ng2-components/commit/613de66244) [MNT-25110] Unwanted duplicated Horizontal scrollbar (#11079)
- [8978e24c79](https://github.com/Alfresco/alfresco-ng2-components/commit/8978e24c79) [AAE-36983] Updated translation keys in search-text-input.component.html (#11083)
- [bf7f7ebf9f](https://github.com/Alfresco/alfresco-ng2-components/commit/bf7f7ebf9f) AAE-36536 fix for root section and mobile form input layout (#11081)
- [d5c2e7c585](https://github.com/Alfresco/alfresco-ng2-components/commit/d5c2e7c585) AAE-36664 Cleanup deprecated AppConfigModule (#11016)
- [4c4dd195a4](https://github.com/Alfresco/alfresco-ng2-components/commit/4c4dd195a4) Remove unused webdriver-manager dependency to eliminate vulnerable form-data ~2.3.2 (#11060)
- [a29d846f4a](https://github.com/Alfresco/alfresco-ng2-components/commit/a29d846f4a) AAE-35310 fixing alignment for checkboxes in sections (#11039)
- [7fbcfe7d6a](https://github.com/Alfresco/alfresco-ng2-components/commit/7fbcfe7d6a) AAE-36536 Allow form sections to be at the root level of form (#11070)
- [0706c9f6de](https://github.com/Alfresco/alfresco-ng2-components/commit/0706c9f6de) AAE-36388 Form Field alignment issues for one liner forms (#11054)
- [dcd15debf0](https://github.com/Alfresco/alfresco-ng2-components/commit/dcd15debf0) AAE-25571 Add title to file name (#11027)
- [fbacd5c51e](https://github.com/Alfresco/alfresco-ng2-components/commit/fbacd5c51e) Update form-section.component.scss (#11064)
- [19b69e024a](https://github.com/Alfresco/alfresco-ng2-components/commit/19b69e024a) AAE-33082 Fixing dropdown widget update value based on form rule (#11068)
- [71df219f94](https://github.com/Alfresco/alfresco-ng2-components/commit/71df219f94) AAE-36023 Making develop sync with ng18 backup branch (#11061)
- [49c0f44435](https://github.com/Alfresco/alfresco-ng2-components/commit/49c0f44435) Removed esm2022 check as is not supported anymore since Ng18 (#11058)
- [9a3ababb9c](https://github.com/Alfresco/alfresco-ng2-components/commit/9a3ababb9c) AAE-36716 fixing text-form-field blur mechanism in control Value Accessor (#11045)
- [d7ec3a1b77](https://github.com/Alfresco/alfresco-ng2-components/commit/d7ec3a1b77) AAE-35981 Form button customization (#11047)
- [06a9ddc068](https://github.com/Alfresco/alfresco-ng2-components/commit/06a9ddc068) AAE-36023 Some form fields are not properly aligned and cropped out ng19 (#11050)
- [0f9e4759ad](https://github.com/Alfresco/alfresco-ng2-components/commit/0f9e4759ad) AAE-0000 Added fix for stylus ban (#11051)
- [0b90affea4](https://github.com/Alfresco/alfresco-ng2-components/commit/0b90affea4) ACS-8770 Update the Auth Service api docs and deprecations (#9947)
- [45834e20f9](https://github.com/Alfresco/alfresco-ng2-components/commit/45834e20f9) AAE-36388 fixing form-field cut issue on preview (#11025)
- [f15014f295](https://github.com/Alfresco/alfresco-ng2-components/commit/f15014f295) [ACS-9880] Create ADF upgrade guide from 7.0.0 to 8.0.0 (#11029)
- [b28479b92b](https://github.com/Alfresco/alfresco-ng2-components/commit/b28479b92b) [AAE-32978] Move ADF &#34;RichTextEditorComponent&#34; to HxP monorepo (#10967)
- [89380f2905](https://github.com/Alfresco/alfresco-ng2-components/commit/89380f2905) [ACS-7266] checkboxes in sorting boxes are put on the right side of the text instead of the left side (#11009)
- [e5fcfde2ec](https://github.com/Alfresco/alfresco-ng2-components/commit/e5fcfde2ec) Post release version bump (#11021)
- [2e10d2c5c7](https://github.com/Alfresco/alfresco-ng2-components/commit/2e10d2c5c7) AAE-36718 Expose a landing page provider for the landing-page-token (#11020)
-7
View File
@@ -1,7 +0,0 @@
---
Title: Changelog for alfresco-ng2-components v8.1.1
---
# Changelog
- [0576aac985](https://github.com/Alfresco/alfresco-ng2-components/commit/0576aac985) Revert &#34;CSX-73 Date and Select Satori (#11056)&#34; (#11144)
-164
View File
@@ -1,164 +0,0 @@
---
Title: Upgrading from ADF v7.0 to v8.0
---
# Upgrading from ADF v7.0 to v8.0
This guide provides instructions for upgrading your v7.0.0 ADF projects to v8.0.0.
## Before you begin
Always perform upgrades on a "clean" project state. Back up your changes or create a full project backup before proceeding.
```shell
# Recommended clean up
nx reset && rm -rf .angular .nx dist node_modules nxcache tmp
```
## Libraries
Update your dependencies to the versions introduced in the 8.0.0 release:
```json
{
"dependencies": {
"@alfresco/adf-core": "8.0.0",
"@alfresco/adf-content-services": "8.0.0",
"@alfresco/adf-process-services-cloud": "8.0.0",
"@alfresco/adf-insights": "8.0.0",
"@alfresco/adf-extensions": "8.0.0",
"@alfresco/adf-cli": "8.0.0",
"@alfresco/eslint-plugin-eslint-angular": "8.0.0",
"@alfresco/adf-testing": "8.0.0",
"@alfresco/js-api": "9.0.0"
}
}
```
Currently used Node version: 22.14.0.
### Breaking changes
Major version updates have been applied to the following core libraries:
- Angular: 19.2.6
- Angular Material: 19.2.9
- Typescript: 5.8.2
> Details on Angular update can be found in *Update Guide* from Angular documentation.
### Added libraries
```json
{
"dependencies": {
"node-fetch": "^3.3.2"
},
"devDependencies": {
"resize-observer-polyfill": "^1.5.1",
"webdriver-manager": "12.1.9"
}
}
```
### Deleted libraries
```json
{
"devDependencies": {
"mini-css-extract-plugin": "X.X.X",
"css-loader": "X.X.X"
}
}
```
Reinstall your dependencies and perform an initial build:
```shell
npm i
npm run build
```
Review your applications as some styles and classes of Angular Material components might have changed.
## Deprecations
The following table lists deprecated features and modules that will be removed in upcoming releases. Consider replacing them as soon as you update ADF to minimize future technical debt.
| Name | Notes |
|-------------------------------|-----------------------------------------------------------------------------------------------|
| Custom Theme | Refer to [Custom Theme documentation](../../lib/core/custom-theme/README.md) |
| ShellModule | Refer to [Shell documentation](../../lib/core/shell/README.md) |
| FormBaseModule | Use standalone components instead. |
| CoreTestingModule | Use standalone components instead. |
| ProcessServicesCloudModule | Refer to [ProcessServicesCloudModule replacement](#processservicescloudmodule-replacement) |
### ProcessServicesCloudModule replacement
To replace this module, import the standalone components directly or use the following provider API to replicate its behavior:
```typescript
providers: [
provideTranslations('adf-process-services-cloud', 'assets/adf-process-services-cloud'),
provideCloudPreferences(),
provideCloudFormRenderer(),
{ provide: TASK_LIST_CLOUD_TOKEN, useClass: TaskListCloudService }
]
```
## New features and APIs
You can start using the new features and APIs introduced in the 8.0.0 release.
### XMLHttpRequest.withCredentials
Support for disabling the `withCredentials` property in `app.config.json` for identity providers that disallow credentials has been introduced. You can configure it as shown below:
```json
{
"auth": {
"withCredentials": false
}
}
```
### provideShell
The new provideShell API for providing the main application layout can replace the `withRoutes(routes: Routes | AppShellRoutesConfig)` method, as shown below.
```typescript
import { provideShell } from '@alfresco/adf-core/shell';
provideShell(
{
routes: [],
appService: AppService,
authGuard: AuthGuard,
navBar: {
minWidth: 0,
maxWidth: 100
}
}
)
```
### provideI18N
The new `provideI18N` API for providing translation can replace `provideTranslations('app', 'assets')` method, as shown below.
```typescript
import { provideI18N } from '@alfresco/adf-core';
provideI18N(
{
defaultLanguage: "en", // optional, defaults to "en"
assets: [['en', '/assets/i18n/en.json'], ['fr', '/assets/i18n/fr.json']]
}
)
```
## Final steps
After updating your code, thoroughly test your application to ensure everything works as expected.
If you encounter any issues during the upgrade process, refer to the Angular update guide or seek assistance from the ADF community.
+8 -18
View File
@@ -19,24 +19,14 @@
4. Apply and commit your fix to **develop-patch-VERSION** branch.
5. Increment the version in the package.json with the following command where `-v` refers to the ADF version and `-vj` to the new js-api version.
The js-api must have a major version that is one higher than the other packages. For example, if adf-core is at version `4.11.1`, then js-api should be at version `5.11.1`
```bash
./scripts/update-version.sh -v X.X.X -vj X.X.X
# e.g. ./scripts/update-version.sh -v 4.1.11 -vj 5.1.11
```
6. The `"@alfresco/js-api"` dependency in the `lib/cli/package.json` has to remain unchanged
7. Run [release.sh](../../scripts/release.sh) script with proper patch version:
5. Run [release.sh](../../scripts/release.sh) script with proper patch version:
```bash
scripts/release.sh -v VERSION
# e.g. scripts/release.sh -v 4.11.1
```
8. Push your changes and run all tests:
6. Push your changes and run all tests:
```bash
git push -u origin develop-patch-VERSION
@@ -49,28 +39,28 @@ The js-api must have a major version that is one higher than the other packages.
git push
```
9. Verify if tests are green and if everything looks fine, you can proceed further.
7. Verify if tests are green and if everything looks fine, you can proceed further.
10. Create new branch from **master** and call it **master-patch-VERSION** (e.g. master-patch-4.11.1):
8. Create new branch from **master** and call it **master-patch-VERSION** (e.g. master-patch-4.11.1):
```bash
git checkout master
git checkout -b master-patch-VERSION
```
11. Merge **develop-patch-VERSION** into **master-patch-VERSION**:
9. Merge **develop-patch-VERSION** into **master-patch-VERSION**:
```bash
git checkout master-patch-VERSION
git merge develop-patch-VERSION
```
12. Push **master-patch-VERSION** branch:
10. Push **master-patch-VERSION** branch:
```bash
git push -u origin master-patch-VERSION
```
13. Verify if build is green and check if proper [tag](https://github.com/Alfresco/alfresco-ng2-components/tags) was created.
11. Verify if build is green and check if proper [tag](https://github.com/Alfresco/alfresco-ng2-components/tags) was created.
14. After all is done, you can **cherry-pick** your fix to develop.
12. After all is done, you can **cherry-pick** your fix to develop.
+2 -2
View File
@@ -53,5 +53,5 @@ The pages linked below contain the audit for all third party dependencies of ADF
- [ADF 7.0.0-alpha.7](audit-info-7.0.0-alpha.7.md)
- [ADF 7.0.0](audit-info-7.0.0.md)
- [ADF 8.0.0](audit-info-8.0.0.md)
- [ADF 8.1.0](audit-info-8.1.0.md)
- [ADF 8.1.1](audit-info-8.1.1.md)
- [ADF 8.0.1](audit-info-8.0.1.md)
- [ADF 8.0.2](audit-info-8.0.2.md)
@@ -1,8 +1,8 @@
---
Title: Audit info, alfresco-ng2-components 8.1.0
Title: Audit info, alfresco-ng2-components 8.0.0
---
# Audit information for alfresco-ng2-components 8.1.0
# Audit information for alfresco-ng2-components 8.0.0
This page lists the security audit of the dependencies this project depends on.
+53
View File
@@ -0,0 +1,53 @@
---
Title: Audit info, alfresco-ng2-components 8.0.2
---
# Audit information for alfresco-ng2-components 8.0.2
This page lists the security audit of the dependencies this project depends on.
## Risks
- Critical risk: 1
- High risk: 21
- Moderate risk: 4
- Low risk: 4
Dependencies analyzed:
## Libraries
| Severity | Module | Vulnerable versions |
| --- | --- | --- |
|high | @angular/animations | &#34;19.0.0-next.0 - 19.2.17&#34; |
|high | @angular/common | &#34;&lt;=19.2.17&#34; |
|high | @angular/compiler | &#34;19.0.0-next.0 - 19.2.17&#34; |
|high | @angular/core | &#34;19.0.0-next.0 - 19.2.17&#34; |
|high | @angular/forms | &#34;&lt;=19.2.17&#34; |
|high | @angular/platform-browser | &#34;&lt;=19.2.17&#34; |
|high | @angular/platform-browser-dynamic | &#34;&lt;=19.2.17&#34; |
|high | @angular/router | &#34;&lt;=0.0.0-ROUTERPLACEHOLDER || 2.0.0-rc.0 - 19.2.17&#34; |
|high | @isaacs/brace-expansion | &#34;5.0.0&#34; |
|high | @nx/devkit | &#34;&lt;=0.0.0-pr-34253-d811c6c || 18.4.0-canary.20240417-801a22b - 22.4.0-canary.20260121-1b12e1f&#34; |
|high | @nx/js | &#34;&lt;=0.0.0-pr-34253-d811c6c || 17.0.4 - 17.0.5 || 17.3.0-beta.1 - 22.4.0-canary.20260121-1b12e1f&#34; |
|high | @nx/webpack | &#34;&lt;=0.0.0-pr-34082-9d57132 || 18.4.0-canary.20240417-801a22b - 22.4.0-canary.20260121-1b12e1f&#34; |
|high | @nx/workspace | &#34;&lt;=0.0.0-pr-34253-d811c6c || 17.0.4 - 17.0.5 || 17.3.0-beta.1 - 22.4.0-canary.20260121-1b12e1f&#34; |
|moderate | ajv | &#34;&lt;6.14.0 || &gt;=7.0.0-alpha.0 &lt;8.18.0&#34; |
|high | axios | &#34;1.0.0 - 1.13.4&#34; |
|high | body-parser | &#34;&lt;=1.20.3 || 2.0.0-beta.1 - 2.0.2&#34; |
|low | compression | &#34;1.0.3 - 1.8.0&#34; |
|high | express | &#34;2.5.8 - 2.5.11 || 3.2.1 - 3.2.3 || 4.0.0-rc1 - 4.21.2 || 5.0.0-alpha.1 - 5.0.1&#34; |
|critical | form-data | &#34;4.0.0 - 4.0.3&#34; |
|high | glob | &#34;10.2.0 - 10.4.5&#34; |
|moderate | js-yaml | &#34;&lt;3.14.2 || &gt;=4.0.0 &lt;4.1.1&#34; |
|moderate | lodash | &#34;4.0.0 - 4.17.21&#34; |
|moderate | lodash-es | &#34;4.0.0 - 4.17.22&#34; |
|high | minimatch | &#34;&lt;=3.1.2 || 5.0.0 - 5.1.6 || 9.0.0 - 9.0.5 || 10.0.0 - 10.2.0&#34; |
|high | node-forge | &#34;&lt;=1.3.1&#34; |
|high | nx | &#34;&lt;=0.0.0-pr-34253-d811c6c || 17.0.4 - 17.0.5 || 17.3.0-beta.1 - 22.4.0-canary.20260121-1b12e1f&#34; |
|low | on-headers | &#34;&lt;1.1.0&#34; |
|high | qs | &#34;&lt;=6.14.1&#34; |
|low | tmp | &#34;&lt;=0.2.3&#34; |
|low | webpack | &#34;5.49.0 - 5.104.0&#34; |
-23
View File
@@ -1,23 +0,0 @@
---
Title: Audit info, alfresco-ng2-components 8.1.1
---
# Audit information for alfresco-ng2-components 8.1.1
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 |
| --- | --- | --- |
+25 -21
View File
@@ -1,20 +1,20 @@
{
"name": "@alfresco/adf-cli",
"version": "8.3.0",
"version": "8.0.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@alfresco/adf-cli",
"version": "8.3.0",
"version": "8.0.2",
"license": "Apache-2.0",
"dependencies": {
"@alfresco/js-api": ">=9.1.1",
"@alfresco/js-api": ">=8.0.0-alpha.7",
"commander": "^6.2.1",
"ejs": "^3.1.9",
"license-checker": "^25.0.1",
"node-fetch": "^2.7.0",
"rxjs": "7.8.2",
"rxjs": "^6.6.6",
"shelljs": "^0.8.3",
"spdx-license-list": "^5.0.0"
},
@@ -30,10 +30,9 @@
}
},
"node_modules/@alfresco/js-api": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-9.1.1.tgz",
"integrity": "sha512-G45OueaXjy0LxUv0RuQb6xfiEf/ecVX2K5qgfMdKlDcmXSv2k8lL/m+wUqeVw1NC+EeoSg6hMyOH60Y3qLvTuQ==",
"license": "Apache-2.0",
"version": "8.0.0-alpha.7-12984503308",
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-8.0.0-alpha.7-12984503308.tgz",
"integrity": "sha512-ua8YgR6BHO751wKclLCQeJEByLJbLl5xmfQqEDJyRlnMvDCk+v7a5e2ibF58meQkmstR+CkIXi5ZlW9YhBKtZg==",
"dependencies": {
"event-emitter": "^0.3.5",
"superagent": "^9.0.1",
@@ -144,10 +143,9 @@
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"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==",
"license": "MIT",
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -478,10 +476,9 @@
}
},
"node_modules/filelist/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==",
"license": "MIT",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dependencies": {
"balanced-match": "^1.0.0"
}
@@ -1144,14 +1141,21 @@
}
},
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"license": "Apache-2.0",
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^1.9.0"
},
"engines": {
"npm": ">=2.0.0"
}
},
"node_modules/rxjs/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@alfresco/adf-cli",
"description": "Alfresco ADF cli and utils",
"version": "8.3.0",
"version": "8.0.4",
"author": "Hyland Software, Inc. and its affiliates",
"bin": {
"adf-cli": "bin/adf-cli",
@@ -20,7 +20,7 @@
"dist": "rm -rf ../../dist/libs/cli && npm run build && cp -R ./bin ../../dist/libs/cli && cp -R ./resources ../../dist/libs/cli && cp -R ./templates ../../dist/libs/cli && cp ./package.json ../../dist/libs/cli"
},
"dependencies": {
"@alfresco/js-api": ">=9.1.1",
"@alfresco/js-api": ">=9.0.2",
"commander": "^6.2.1",
"ejs": "^3.1.9",
"license-checker": "^25.0.1",
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@alfresco/adf-content-services",
"description": "Alfresco ADF content services",
"version": "8.3.0",
"version": "8.0.4",
"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.1.1",
"@alfresco/js-api": ">=9.0.2",
"@ngx-translate/core": ">=16.0.0",
"@alfresco/adf-core": ">=8.2.0"
"@alfresco/adf-core": ">=8.0.2"
},
"keywords": [
"content-services",
@@ -20,6 +20,7 @@ import { ContentService } from './content.service';
import { AppConfigService, AuthenticationService, RedirectAuthService, StorageService } from '@alfresco/adf-core';
import { Node, PermissionsInfo } from '@alfresco/js-api';
import { EMPTY, of } from 'rxjs';
import { HttpClientTestingModule } from '@angular/common/http/testing';
describe('ContentService', () => {
let contentService: ContentService;
@@ -28,6 +29,7 @@ describe('ContentService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ContentService, AuthenticationService, { provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } }]
});
authService = TestBed.inject(AuthenticationService);
@@ -154,7 +156,7 @@ describe('ContentService', () => {
});
it('should take current logged user id if userId undefined ', () => {
spyOn(authService, 'getUsername').and.returnValue('user1');
spyOn(authService, 'getEcmUsername').and.returnValue('user1');
const permissionNode = new Node({
permissions: {
inherited: [
@@ -84,7 +84,7 @@ export class ContentService {
*/
hasPermissions(node: Node, permission: PermissionsEnum | string, userId?: string): boolean {
let hasPermissions = false;
userId = userId ?? this.authService.getUsername();
userId = userId ?? this.authService.getEcmUsername();
const permissions = [...(node.permissions?.locallySet || []), ...(node.permissions?.inherited || [])].filter(
(currentPermission) => currentPermission.authorityId === userId
@@ -38,14 +38,11 @@ export class DiscoveryApiService {
*/
ecmProductInfo$ = new Subject<RepositoryInfo>();
constructor(
private readonly authenticationService: AuthenticationService,
private readonly alfrescoApiService: AlfrescoApiService
) {
constructor(private authenticationService: AuthenticationService, private alfrescoApiService: AlfrescoApiService) {
this.authenticationService.onLogin.subscribe(() => {
this.alfrescoApiService.alfrescoApiInitialized
.pipe(
filter(() => this.authenticationService.isLoggedIn()),
filter(() => this.authenticationService.isEcmLoggedIn()),
take(1),
switchMap(() => this.getEcmProductInfo())
)
@@ -21,7 +21,7 @@ import { PeopleContentQueryRequestModel, PeopleContentService } from './people-c
import { TestBed } from '@angular/core/testing';
import { PersonPaging } from '@alfresco/js-api';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { EMPTY, firstValueFrom, of } from 'rxjs';
import { EMPTY, of } from 'rxjs';
import { AlfrescoApiService } from '../../services';
import { AlfrescoApiServiceMock } from '../../mock';
@@ -83,14 +83,14 @@ describe('PeopleContentService', () => {
it('should be able to fetch person details based on id', async () => {
spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(Promise.resolve({ entry: fakeEcmUser } as any));
const person = await firstValueFrom(peopleContentService.getPerson('fake-id'));
const person = await peopleContentService.getPerson('fake-id').toPromise();
expect(person.id).toEqual('fake-id');
expect(person.email).toEqual('fakeEcm@ecmUser.com');
});
it('should be able to list people', async () => {
spyOn(peopleContentService.peopleApi, 'listPeople').and.returnValue(Promise.resolve(fakeEcmUserList));
const response = await firstValueFrom(peopleContentService.listPeople());
const response = await peopleContentService.listPeople().toPromise();
const people = response.entries;
const pagination = response.pagination;
@@ -112,7 +112,7 @@ describe('PeopleContentService', () => {
};
const expectedValue = { skipCount: 10, maxItems: 20, orderBy: ['firstName ASC'] } as any;
await firstValueFrom(peopleContentService.listPeople(requestQueryParams));
await peopleContentService.listPeople(requestQueryParams).toPromise();
expect(listPeopleSpy).toHaveBeenCalledWith(expectedValue);
});
@@ -122,14 +122,14 @@ describe('PeopleContentService', () => {
const requestQueryParams: PeopleContentQueryRequestModel = { skipCount: 10, maxItems: 20, sorting: undefined };
const expectedValue = { skipCount: 10, maxItems: 20 };
await firstValueFrom(peopleContentService.listPeople(requestQueryParams));
await peopleContentService.listPeople(requestQueryParams).toPromise();
expect(listPeopleSpy).toHaveBeenCalledWith(expectedValue);
});
it('should be able to create new person', async () => {
spyOn(peopleContentService.peopleApi, 'createPerson').and.returnValue(Promise.resolve({ entry: fakeEcmUser } as any));
const newUser = await firstValueFrom(peopleContentService.createPerson(createNewPersonMock));
const newUser = await peopleContentService.createPerson(createNewPersonMock).toPromise();
expect(newUser.id).toEqual('fake-id');
expect(newUser.email).toEqual('fakeEcm@ecmUser.com');
});
@@ -150,12 +150,12 @@ describe('PeopleContentService', () => {
Promise.resolve({ entry: fakeEcmAdminUser } as any)
);
const user = await firstValueFrom(peopleContentService.getCurrentUserInfo());
const user = await peopleContentService.getCurrentUserInfo().toPromise();
expect(user.id).toEqual('fake-id');
expect(peopleContentService.isCurrentUserAdmin()).toBe(true);
expect(getCurrentPersonSpy.calls.count()).toEqual(1);
await firstValueFrom(peopleContentService.getCurrentUserInfo());
await peopleContentService.getCurrentUserInfo().toPromise();
expect(peopleContentService.isCurrentUserAdmin()).toBe(true);
expect(getCurrentPersonSpy.calls.count()).toEqual(1);
@@ -165,13 +165,13 @@ describe('PeopleContentService', () => {
const getCurrentPersonSpy = spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(
Promise.resolve({ entry: fakeEcmAdminUser } as any)
);
await firstValueFrom(peopleContentService.getCurrentUserInfo());
await peopleContentService.getCurrentUserInfo().toPromise();
getCurrentPersonSpy.and.returnValue(Promise.resolve({ entry: fakeEcmUser2 } as any));
await firstValueFrom(peopleContentService.getPerson('fake-id'));
await peopleContentService.getPerson('fake-id').toPromise();
expect(getCurrentPersonSpy.calls.count()).toEqual(2);
const currentUser = await firstValueFrom(peopleContentService.getCurrentUserInfo());
const currentUser = await peopleContentService.getCurrentUserInfo().toPromise();
expect(peopleContentService.isCurrentUserAdmin()).toBe(true);
expect(currentUser.id).toEqual(fakeEcmAdminUser.id);
expect(currentUser.id).not.toEqual(fakeEcmUser2.id);
@@ -73,11 +73,7 @@ export class RenditionService {
return this._versionsApi;
}
constructor(
private readonly apiService: AlfrescoApiService,
private readonly translateService: TranslationService,
private readonly viewUtilsService: ViewUtilService
) {}
constructor(private apiService: AlfrescoApiService, private translateService: TranslationService, private viewUtilsService: ViewUtilService) {}
getRenditionUrl(nodeId: string, type: string, renditionExists: boolean): string {
return renditionExists && type !== RenditionService.ContentGroup.IMAGE
@@ -171,7 +167,7 @@ export class RenditionService {
}
try {
return versionId ? await this.waitNodeRendition(nodeId, renditionId, versionId) : await this.waitNodeRendition(nodeId, renditionId);
} catch {
} catch (e) {
return null;
}
} catch {
@@ -17,12 +17,13 @@
import { EventEmitter } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { AppConfigService, AppConfigServiceMock } from '@alfresco/adf-core';
import { AppConfigModule, AppConfigService, AppConfigServiceMock } from '@alfresco/adf-core';
import { UploadService } from './upload.service';
import { RepositoryInfo } from '@alfresco/js-api';
import { BehaviorSubject } from 'rxjs';
import { DiscoveryApiService } from '../../common/services/discovery-api.service';
import { FileModel, FileUploadStatus } from '../../common/models/file.model';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { AlfrescoApiService } from '../../services';
import { AlfrescoApiServiceMock } from '../../mock';
@@ -37,7 +38,7 @@ describe('UploadService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [],
imports: [AppConfigModule, HttpClientTestingModule],
providers: [
UploadService,
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
@@ -198,7 +198,7 @@
</mat-expansion-panel>
<ng-container *ngIf="groupedProperties$ | async; else loading; let groupedProperties">
<div *ngFor="let group of groupedProperties; let first = first" class="adf-content-metadata-ai">
<div *ngFor="let group of groupedProperties; let first = first" class="adf-metadata-grouped-properties-container">
<mat-expansion-panel
[attr.data-automation-id]="'adf-metadata-group-' + group.title"
[expanded]="multi ? !displayDefaultProperties && first || group.expanded : !displayDefaultProperties && first || currentPanel.panelTitle === group.title && currentPanel.expanded"
@@ -209,7 +209,37 @@
<mat-expansion-panel-header
class="adf-metadata-properties-header"
[class.adf-metadata-properties-header-expanded]="currentPanel.panelTitle === group.title && currentPanel.expanded">
<adf-content-metadata-header [title]="group.title" [expanded]="currentPanel.panelTitle === group.title && currentPanel.expanded" />
<adf-content-metadata-header [title]="group.title" [expanded]="currentPanel.panelTitle === group.title && currentPanel.expanded">
<button
*ngIf="group.editable && !this.readOnly && !isPanelEditing(group.title)"
mat-icon-button
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.aria-label]="'CORE.METADATA.ACCESSIBILITY.EDIT' | translate"
data-automation-id="meta-data-card-toggle-edit"
class="adf-edit-icon-buttons"
(click)="toggleGroupEditing(group.title, $event)">
<mat-icon>mode_edit</mat-icon>
</button>
<div class="adf-metadata-action-buttons" *ngIf="group.editable && isPanelEditing(group.title)">
<button
mat-icon-button
[attr.title]="'CORE.METADATA.ACTIONS.CANCEL' | translate"
(click)="cancelGroupEditing(group.title, $event)"
data-automation-id="reset-metadata"
class="adf-metadata-action-buttons-clear">
<mat-icon>clear</mat-icon>
</button>
<button
mat-icon-button
[attr.title]="'CORE.METADATA.ACTIONS.SAVE' | translate"
(click)="saveChanges($event)"
color="primary"
data-automation-id="save-metadata"
[disabled]="!hasMetadataChanged || invalidProperties.size > 0">
<mat-icon>check</mat-icon>
</button>
</div>
</adf-content-metadata-header>
</mat-expansion-panel-header>
<div *ngIf="!showGroup(group) && group.editable && editedPanelTitle !== group.title" class="adf-metadata-no-item-added">
{{ 'METADATA.BASIC.NO_ITEMS_MESSAGE' | translate : { groupTitle: group.title | translate } }}
@@ -217,7 +247,7 @@
<adf-card-view
(keydown)="keyDown($event)"
[properties]="group.properties"
[editable]="false"
[editable]="!readOnly && group.editable && isPanelEditing(group.title)"
[displayEmpty]="displayEmpty"
[copyToClipboardAction]="copyToClipboardAction"
[useChipsForMultiValueProperty]="useChipsForMultiValueProperty"
@@ -227,7 +257,6 @@
</div>
</ng-container>
<ng-template #loading>
<mat-progress-bar mode="indeterminate" [attr.aria-label]="'DATA_LOADING' | translate" />
</ng-template>
@@ -32,7 +32,7 @@ import { MatChipHarness } from '@angular/material/chips/testing';
import { MatDialogModule } from '@angular/material/dialog';
import { MatExpansionPanel } from '@angular/material/expansion';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { EMPTY, firstValueFrom, of, throwError } from 'rxjs';
import { EMPTY, of, throwError } from 'rxjs';
import { CategoriesManagementComponent, CategoriesManagementMode } from '../../../category';
import { TagsCreatorComponent, TagsCreatorMode } from '../../../tag';
import { ContentTestingModule } from '../../../testing/content.testing.module';
@@ -1144,7 +1144,7 @@ describe('ContentMetadataComponent', () => {
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
fixture.detectChanges();
await firstValueFrom(component.groupedProperties$);
await component.groupedProperties$.toPromise();
fixture.detectChanges();
const verProp = queryDom('Versionable');
@@ -1164,7 +1164,7 @@ describe('ContentMetadataComponent', () => {
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
fixture.detectChanges();
await firstValueFrom(component.groupedProperties$);
await component.groupedProperties$.toPromise();
fixture.detectChanges();
const verProps = fixture.debugElement.queryAll(By.css('[data-automation-id="adf-metadata-group-Versionable"]'));
@@ -1184,7 +1184,7 @@ describe('ContentMetadataComponent', () => {
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
fixture.detectChanges();
await firstValueFrom(component.groupedProperties$);
await component.groupedProperties$.toPromise();
fixture.detectChanges();
const verProp = queryDom('Versionable');
@@ -1205,7 +1205,7 @@ describe('ContentMetadataComponent', () => {
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
fixture.detectChanges();
await firstValueFrom(component.groupedProperties$);
await component.groupedProperties$.toPromise();
fixture.detectChanges();
const verProp = queryDom('Versionable');
@@ -1225,7 +1225,7 @@ describe('ContentMetadataComponent', () => {
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
fixture.detectChanges();
await firstValueFrom(component.groupedProperties$);
await component.groupedProperties$.toPromise();
fixture.detectChanges();
const verProp = queryDom('Versionable');
@@ -1249,7 +1249,7 @@ describe('ContentMetadataComponent', () => {
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
fixture.detectChanges();
await firstValueFrom(component.groupedProperties$);
await component.groupedProperties$.toPromise();
fixture.detectChanges();
const exifProp = queryDom('Exif');
@@ -1283,7 +1283,7 @@ describe('ContentMetadataComponent', () => {
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
fixture.detectChanges();
await firstValueFrom(component.groupedProperties$);
await component.groupedProperties$.toPromise();
fixture.detectChanges();
const exifProps = fixture.debugElement.queryAll(By.css('[data-automation-id="adf-metadata-group-Exif"]'));
@@ -18,7 +18,7 @@
import { AppConfigService } from '@alfresco/adf-core';
import { ClassesApi, Node } from '@alfresco/js-api';
import { TestBed } from '@angular/core/testing';
import { firstValueFrom, of } from 'rxjs';
import { of } from 'rxjs';
import { ContentTestingModule } from '../../testing/content.testing.module';
import { OrganisedPropertyGroup } from '../interfaces/content-metadata.interfaces';
import { PropertyGroup } from '../interfaces/property-group.interface';
@@ -253,7 +253,7 @@ describe('ContentMetaDataService', () => {
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(exifResponse));
const groupedProperties = await firstValueFrom(service.getGroupedProperties(fakeNode));
const groupedProperties = await service.getGroupedProperties(fakeNode).toPromise();
expect(groupedProperties.length).toEqual(1);
expect(groupedProperties[0].title).toEqual('Exif');
@@ -267,7 +267,7 @@ describe('ContentMetaDataService', () => {
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(exifResponse));
const groupedProperties = await firstValueFrom(service.getGroupedProperties(fakeNode));
const groupedProperties = await service.getGroupedProperties(fakeNode).toPromise();
expect(groupedProperties.length).toEqual(1);
expect(groupedProperties[0].title).toEqual('Exif');
@@ -284,7 +284,7 @@ describe('ContentMetaDataService', () => {
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
const groupedProperties = await firstValueFrom(service.getGroupedProperties(fakeContentNode));
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
expect(groupedProperties.length).toEqual(1);
expect(groupedProperties[0].title).toEqual('Versionable');
@@ -301,7 +301,7 @@ describe('ContentMetaDataService', () => {
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
const groupedProperties = await firstValueFrom(service.getGroupedProperties(fakeContentNode));
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
expect(groupedProperties.length).toEqual(2);
expect(groupedProperties[0].title).toEqual('Versionable');
@@ -319,7 +319,7 @@ describe('ContentMetaDataService', () => {
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
const groupedProperties = await firstValueFrom(service.getGroupedProperties(fakeContentNode));
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
expect(groupedProperties.length).toEqual(0);
expect(classesApi.getClass).toHaveBeenCalledTimes(1 + fakeContentNode.aspectNames.length);
@@ -335,7 +335,7 @@ describe('ContentMetaDataService', () => {
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
const groupedProperties = await firstValueFrom(service.getGroupedProperties(fakeContentNode));
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
expect(groupedProperties.length).toEqual(1);
expect(groupedProperties[0].title).toEqual('Versionable');
@@ -351,7 +351,7 @@ describe('ContentMetaDataService', () => {
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(verResponse));
const groupedProperties = await firstValueFrom(service.getGroupedProperties(fakeContentNode));
const groupedProperties = await service.getGroupedProperties(fakeContentNode).toPromise();
expect(groupedProperties.length).toEqual(0);
expect(classesApi.getClass).toHaveBeenCalledTimes(1 + fakeContentNode.aspectNames.length);
@@ -367,7 +367,7 @@ describe('ContentMetaDataService', () => {
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(exifResponse));
const groupedProperties = await firstValueFrom(service.getGroupedProperties(fakeNode));
const groupedProperties = await service.getGroupedProperties(fakeNode).toPromise();
expect(groupedProperties.length).toEqual(1);
expect(groupedProperties[0].title).toEqual('Exif');
@@ -387,7 +387,7 @@ describe('ContentMetaDataService', () => {
spyOn(classesApi, 'getClass').and.returnValue(Promise.resolve(exifResponse));
const groupedProperties = await firstValueFrom(service.getGroupedProperties(fakeNode));
const groupedProperties = await service.getGroupedProperties(fakeNode).toPromise();
expect(groupedProperties.length).toEqual(2);
expect(groupedProperties[0].title).toEqual('Exif');
@@ -54,7 +54,7 @@ const customSiteList = {
describe('DropdownSitesComponent', () => {
let loader: HarnessLoader;
let component: DropdownSitesComponent;
let component: any;
let fixture: ComponentFixture<DropdownSitesComponent>;
let element: HTMLElement;
let siteService: SitesService;
@@ -167,7 +167,7 @@ describe('DropdownSitesComponent', () => {
});
it('should load custom sites when the "siteList" input property is given a value', async () => {
component.siteList = customSiteList as any;
component.siteList = customSiteList;
fixture.detectChanges();
await fixture.whenStable();
@@ -246,7 +246,7 @@ describe('DropdownSitesComponent', () => {
fixture.whenStable().then(() => {
expect(component.selected).toBeUndefined();
expect(component.isLoading).toBeFalsy();
expect(component.loading).toBeFalsy();
done();
});
});
@@ -274,7 +274,7 @@ describe('DropdownSitesComponent', () => {
});
it('should show only sites which logged user is member of when member relation is set', async () => {
spyOn(authService, 'getUsername').and.returnValue('test');
spyOn(authService, 'getEcmUsername').and.returnValue('test');
fixture.detectChanges();
await fixture.whenStable();
@@ -290,12 +290,12 @@ describe('DropdownSitesComponent', () => {
describe('No relations', () => {
beforeEach(() => {
component.relations = '';
component.relations = [];
authService = TestBed.inject(AuthenticationService);
});
it('should show all the sites if no relation is set', async () => {
spyOn(authService, 'getUsername').and.returnValue('test');
spyOn(authService, 'getEcmUsername').and.returnValue('test');
fixture.detectChanges();
await fixture.whenStable();
@@ -89,10 +89,6 @@ export class DropdownSitesComponent implements OnInit {
selected: SiteEntry = null;
MY_FILES_VALUE = '-my-';
get isLoading(): boolean {
return this.loading;
}
constructor(
private authService: AuthenticationService,
private sitesService: SitesService,
@@ -185,7 +181,7 @@ export class DropdownSitesComponent implements OnInit {
}
private filteredResultsByMember(sites: SitePaging): SitePaging {
const loggedUserName = this.authService.getUsername();
const loggedUserName = this.authService.getEcmUsername();
sites.list.entries = sites.list.entries.filter((site) => this.isCurrentUserMember(site, loggedUserName));
return sites;
}
@@ -36,6 +36,7 @@ class AlfrescoApiMock {
isOauthConfiguration = () => true;
isLoggedIn = () => true;
isEcmConfiguration = () => true;
isEcmLoggedIn = () => true;
}
export class ContentApiMock {
@@ -161,7 +161,7 @@ export class FolderDialogComponent implements OnInit {
if (statusCode === 409) {
errorMessage = 'CORE.MESSAGES.ERRORS.EXISTENT_FOLDER';
}
} catch {
} catch (err) {
/* Do nothing, keep the original message */
}
@@ -20,7 +20,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NodeDeleteDirective } from './node-delete.directive';
import { RedirectAuthService } from '@alfresco/adf-core';
import { EMPTY, of, Subscription } from 'rxjs';
import { EMPTY, of } from 'rxjs';
import { CheckAllowableOperationDirective } from './check-allowable-operation.directive';
@Component({
@@ -73,10 +73,10 @@ describe('NodeDeleteDirective', () => {
let elementWithPermanentDelete: DebugElement;
let component: TestComponent;
let componentWithPermanentDelete: TestDeletePermanentComponent;
let deleteNodeSpy: jasmine.Spy;
let disposableDelete: Subscription;
let deleteNodePermanentSpy: jasmine.Spy;
let purgeDeletedNodePermanentSpy: jasmine.Spy;
let deleteNodeSpy: any;
let disposableDelete: any;
let deleteNodePermanentSpy: any;
let purgeDeletedNodePermanentSpy: any;
beforeEach(() => {
TestBed.configureTestingModule({
@@ -50,7 +50,7 @@ describe('NodeDownloadDirective', () => {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
},
isLoggedIn: jasmine.createSpy('isLoggedIn'),
isEcmLoggedIn: jasmine.createSpy('isEcmLoggedIn'),
reply: jasmine.createSpy('reply')
};
@@ -38,7 +38,7 @@ describe('NodeRestoreDirective', () => {
let component: TestComponent;
let trashcanApi: TrashcanApi;
let directiveInstance: NodeRestoreDirective;
let restoreNodeSpy: jasmine.Spy;
let restoreNodeSpy: any;
let translationService: TranslationService;
beforeEach(() => {
@@ -131,7 +131,7 @@ describe('NodeRestoreDirective', () => {
it('should notify on multiple fails', (done) => {
const error = { message: '{ "error": {} }' };
directiveInstance.restore.subscribe((event) => {
directiveInstance.restore.subscribe((event: any) => {
expect(event.message).toEqual('CORE.RESTORE_NODE.PARTIAL_PLURAL');
done();
});
@@ -193,7 +193,7 @@ describe('NodeRestoreDirective', () => {
restoreNodeSpy.and.returnValue(Promise.reject(error));
directiveInstance.restore.subscribe((event) => {
directiveInstance.restore.subscribe((event: any) => {
expect(event.message).toEqual('CORE.RESTORE_NODE.LOCATION_MISSING');
done();
});
@@ -205,7 +205,7 @@ describe('NodeRestoreDirective', () => {
});
it('should notify success when restore multiple nodes', (done) => {
directiveInstance.restore.subscribe((event) => {
directiveInstance.restore.subscribe((event: any) => {
expect(event.message).toEqual('CORE.RESTORE_NODE.PLURAL');
done();
@@ -52,6 +52,7 @@ import {
} from '../../mock';
import { ContentTestingModule } from '../../testing/content.testing.module';
import { domSanitizerMock } from '../../testing/dom-sanitizer-mock';
import { matIconRegistryMock } from '../../testing/mat-icon-registry-mock';
import { ImageResolver } from '../data/image-resolver.model';
import { RowFilter } from '../data/row-filter.model';
import { ShareDataRow } from '../data/share-data-row.model';
@@ -63,16 +64,11 @@ import { FileAutoDownloadComponent } from './file-auto-download/file-auto-downlo
import { DocumentListComponent } from './document-list.component';
import { CustomResourcesService, DocumentListService } from '../public-api';
import { CommonModule } from '@angular/common';
import { MatIconRegistry } from '@angular/material/icon';
const mockDialog = {
open: jasmine.createSpy('open')
};
export const matIconRegistryMock = {
addSvgIconInNamespace: () => {}
} as any as MatIconRegistry;
describe('DocumentList', () => {
let loader: HarnessLoader;
let documentList: DocumentListComponent;
@@ -650,7 +646,7 @@ describe('DocumentList', () => {
title: 'FileAction'
});
spyOn(authenticationService, 'getUsername').and.returnValue('lockOwner');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('lockOwner');
documentList.actions = [documentMenu];
@@ -681,7 +677,7 @@ describe('DocumentList', () => {
title: 'FileAction'
});
spyOn(authenticationService, 'getUsername').and.returnValue('jerryTheKillerCow');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('jerryTheKillerCow');
documentList.actions = [documentMenu];
@@ -430,7 +430,7 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
dataTable: DataTableComponent;
actions: ContentActionModel[] = [];
contextActionHandler = new Subject();
contextActionHandler: Subject<any> = new Subject();
data: ShareDataTableAdapter;
noPermission: boolean = false;
selection = new Array<NodeEntry>();
@@ -1051,7 +1051,7 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
if (JSON.parse(err.message).error.statusCode === 403) {
this.noPermission = true;
}
} catch {
} catch (error) {
/* empty */
}
}
@@ -57,3 +57,17 @@ export enum ContentActionTarget {
}
export type ContentActionHandler = (obj: any, target?: any, permission?: string) => any;
export class DocumentActionModel extends ContentActionModel {
constructor(json?: any) {
super(json);
this.target = 'document';
}
}
export class FolderActionModel extends ContentActionModel {
constructor(json?: any) {
super(json);
this.target = 'folder';
}
}
@@ -95,7 +95,7 @@ describe('FolderActionsService', () => {
it('should delete the folder node if there is the delete permission', () => {
spyOn(documentListService, 'deleteNode').and.callFake(
() =>
new Observable((observer) => {
new Observable<any>((observer) => {
observer.next(undefined);
observer.complete();
})
@@ -156,7 +156,7 @@ describe('FolderActionsService', () => {
it('should delete the folder node if there is the delete and others permission ', () => {
spyOn(documentListService, 'deleteNode').and.callFake(
() =>
new Observable((observer) => {
new Observable<any>((observer) => {
observer.next(undefined);
observer.complete();
})
@@ -174,7 +174,7 @@ describe('FolderActionsService', () => {
it('should support deletion only folder node', () => {
spyOn(documentListService, 'deleteNode').and.callFake(
() =>
new Observable((observer) => {
new Observable<any>((observer) => {
observer.next(undefined);
observer.complete();
})
@@ -195,7 +195,7 @@ describe('FolderActionsService', () => {
it('should require node id to delete', () => {
spyOn(documentListService, 'deleteNode').and.callFake(
() =>
new Observable((observer) => {
new Observable<any>((observer) => {
observer.next(undefined);
observer.complete();
})
@@ -211,7 +211,7 @@ describe('FolderActionsService', () => {
it('should reload target upon node deletion', async () => {
spyOn(documentListService, 'deleteNode').and.callFake(
() =>
new Observable((observer) => {
new Observable<any>((observer) => {
observer.next(undefined);
observer.complete();
})
@@ -137,22 +137,22 @@ describe('LockService', () => {
} as Node;
it('should return false when the user is the lock owner', () => {
spyOn(authenticationService, 'getUsername').and.returnValue('lock-owner-user');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('lock-owner-user');
expect(service.isLocked(nodeOwnerAllowedLock)).toBeFalsy();
});
it('should return true when the user is not the lock owner', () => {
spyOn(authenticationService, 'getUsername').and.returnValue('banana-user');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('banana-user');
expect(service.isLocked(nodeOwnerAllowedLock)).toBeTruthy();
});
it('should return false when the user is not the lock owner but the lock is expired', () => {
spyOn(authenticationService, 'getUsername').and.returnValue('banana-user');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('banana-user');
expect(service.isLocked(nodeOwnerAllowedLockWithExpiredDate)).toBeFalsy();
});
it('should return true when is not the lock owner and the expiration date is valid', () => {
spyOn(authenticationService, 'getUsername').and.returnValue('banana-user');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('banana-user');
expect(service.isLocked(nodeOwnerAllowedLockWithActiveExpiration)).toBeTruthy();
});
});
@@ -32,7 +32,7 @@ export class LockService {
if (this.isReadOnlyLock(node)) {
isLocked = !this.isLockExpired(node);
} else if (this.isLockOwnerAllowed(node)) {
isLocked = this.authService.getUsername() !== node.properties['cm:lockOwner'].id;
isLocked = this.authService.getEcmUsername() !== node.properties['cm:lockOwner'].id;
if (this.isLockExpired(node)) {
isLocked = false;
}
+2 -2
View File
@@ -184,8 +184,8 @@
"DUPLICATED_CATEGORY": "Kategoria została już dodana",
"CREATE_CATEGORIES": "Błąd podczas tworzenia kategorii",
"EXISTING_CATEGORIES": "Niektóre kategorie już istnieją",
"SPECIAL_CHARACTERS": "Nazwa kategorii nie może zawierać niedozwolonych znaków",
"ENDS_WITH_DOT": "Nazwa kategorii nie może kończyć się kropką"
"SPECIAL_CHARACTERS": "Category name cannot contain prohibited characters",
"ENDS_WITH_DOT": "Category name cannot end with a dot"
},
"CATEGORIES_SEARCH_PLACEHOLDER": "Kategorie wyszukiwania"
},
@@ -18,7 +18,7 @@
import { Component, EventEmitter, Output } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { BehaviorSubject, firstValueFrom, of, Subject } from 'rxjs';
import { BehaviorSubject, of, Subject } from 'rxjs';
import { mockFile, mockNewVersionUploaderData, mockNode } from '../mock';
import { ContentTestingModule } from '../testing/content.testing.module';
import {
@@ -114,7 +114,7 @@ describe('NewVersionUploaderService', () => {
});
it('should open dialog with default configuration', fakeAsync(() => {
firstValueFrom(service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData));
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData).toPromise();
tick();
expect(spyOnDialogOpen).toHaveBeenCalledWith(NewVersionUploaderDialogComponent, expectedConfig);
}));
@@ -124,7 +124,7 @@ describe('NewVersionUploaderService', () => {
panelClass: 'adf-custom-class',
width: '500px'
};
firstValueFrom(service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData, mockDialogConfiguration));
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData, mockDialogConfiguration).toPromise();
tick();
expectedConfig.panelClass = 'adf-custom-class';
expectedConfig.width = '500px';
@@ -135,7 +135,7 @@ describe('NewVersionUploaderService', () => {
const mockDialogConfiguration: MatDialogConfig = {
height: '600px'
};
firstValueFrom(service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData, mockDialogConfiguration));
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData, mockDialogConfiguration).toPromise();
tick();
expectedConfig.height = '600px';
expect(spyOnDialogOpen).toHaveBeenCalledWith(NewVersionUploaderDialogComponent, expectedConfig);
@@ -143,7 +143,7 @@ describe('NewVersionUploaderService', () => {
it('should not override dialog configuration, if dialog configuration is empty', fakeAsync(() => {
const mockDialogConfiguration: MatDialogConfig = {};
firstValueFrom(service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData, mockDialogConfiguration));
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogData, mockDialogConfiguration).toPromise();
tick();
expect(spyOnDialogOpen).toHaveBeenCalledWith(NewVersionUploaderDialogComponent, expectedConfig);
}));
@@ -156,7 +156,7 @@ describe('NewVersionUploaderService', () => {
showComments: true,
allowDownload: true
};
firstValueFrom(service.openUploadNewVersionDialog(mockNewVersionUploaderDialogDataWithVersionsOnly));
service.openUploadNewVersionDialog(mockNewVersionUploaderDialogDataWithVersionsOnly).toPromise();
tick();
expectedConfig.data.showVersionsOnly = true;
expectedConfig.panelClass = ['adf-new-version-uploader-dialog', 'adf-new-version-uploader-dialog-list'];
@@ -38,6 +38,7 @@ describe('NodeCommentsService', () => {
]
});
service = TestBed.inject(NodeCommentsService);
jasmine.Ajax.install();
});
@@ -80,17 +81,5 @@ describe('NodeCommentsService', () => {
responseText: JSON.stringify(fakeContentComments)
});
});
it('should return avatar image URL for given userId', () => {
const userId = 'fake-user-id';
const expectedUrl = 'https://fake-avatar-url.com/avatar.png';
spyOn(service.peopleApi, 'getAvatarImageUrl').and.returnValue(expectedUrl);
const result = service.getUserImage(userId);
expect(service.peopleApi.getAvatarImageUrl).toHaveBeenCalledWith(userId);
expect(result).toBe(expectedUrl);
});
});
});
@@ -16,10 +16,11 @@
*/
import { CommentModel, CommentsService, User } from '@alfresco/adf-core';
import { CommentEntry, CommentsApi, Comment, PeopleApi } from '@alfresco/js-api';
import { CommentEntry, CommentsApi, Comment } from '@alfresco/js-api';
import { Injectable } from '@angular/core';
import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators';
import { ContentService } from '../../common/services/content.service';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
@Injectable({
@@ -32,13 +33,7 @@ export class NodeCommentsService implements CommentsService {
return this._commentsApi;
}
private _peopleApi: PeopleApi;
get peopleApi(): PeopleApi {
this._peopleApi = this._peopleApi ?? new PeopleApi(this.apiService.getInstance());
return this._peopleApi;
}
constructor(private readonly apiService: AlfrescoApiService) {}
constructor(private apiService: AlfrescoApiService, private contentService: ContentService) {}
/**
* Gets all comments that have been added to a task.
@@ -86,13 +81,7 @@ export class NodeCommentsService implements CommentsService {
});
}
/**
* Gets the avatar image URL for a given user ID.
*
* @param userId ID of the user
* @returns The URL of the user's avatar image
*/
getUserImage(userId: string): string {
return this.peopleApi.getAvatarImageUrl(userId);
getUserImage(avatarId: string): string {
return this.contentService.getContentUrl(avatarId);
}
}
@@ -2,6 +2,7 @@
<mat-checkbox
*ngFor="let option of options"
[checked]="option.checked"
labelPosition="before"
(keydown.enter)="option.checked = !option.checked"
[attr.data-automation-id]="'checkbox-' + (option.name)"
[attr.aria-label]="option.name | translate"
@@ -25,8 +25,6 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { MatButtonHarness } from '@angular/material/button/testing';
import { ReplaySubject } from 'rxjs';
import { MatCheckbox } from '@angular/material/checkbox';
import { By } from '@angular/platform-browser';
describe('SearchCheckListComponent', () => {
let loader: HarnessLoader;
@@ -140,18 +138,6 @@ describe('SearchCheckListComponent', () => {
expect(component.context.filterRawParams[component.id]).toBeUndefined();
});
it('should have set labelPosition to after for checkboxes', () => {
component.options = new SearchFilterList<SearchListOption>([
{ name: 'Folder', value: `TYPE:'cm:folder'`, checked: true },
{ name: 'Document', value: `TYPE:'cm:content'`, checked: true }
]);
fixture.detectChanges();
const checkboxes = fixture.debugElement.queryAll(By.directive(MatCheckbox));
expect(checkboxes.length).toBe(2);
expect(checkboxes.every((checkbox) => checkbox.componentInstance.labelPosition === 'after')).toBeTrue();
});
describe('Pagination', () => {
it('should show 5 items when pageSize not defined', async () => {
component.id = 'checklist';
@@ -69,7 +69,7 @@ describe('SearchControlComponent', () => {
searchService = TestBed.inject(SearchService);
authService = TestBed.inject(AuthenticationService);
userPreferencesService = TestBed.inject(UserPreferencesService);
spyOn(authService, 'isLoggedIn').and.returnValue(true);
spyOn(authService, 'isEcmLoggedIn').and.returnValue(true);
component = fixture.componentInstance;
element = fixture.nativeElement;
@@ -109,16 +109,13 @@ export class SearchControlComponent {
noSearchResultTemplate: TemplateRef<any> = null;
searchTerm: string = '';
constructor(
public authService: AuthenticationService,
private readonly thumbnailService: ThumbnailService
) {}
constructor(public authService: AuthenticationService, private thumbnailService: ThumbnailService) {}
isNoSearchTemplatePresent(): boolean {
return !!this.emptySearchTemplate;
}
isLoggedIn(): boolean {
return this.authService.isLoggedIn();
return this.authService.isEcmLoggedIn();
}
inputChange(value: string) {
@@ -21,7 +21,6 @@ import { fakeAuthorityClearanceApiResponse } from './mock/security-authorities.m
import { fakeGroupsApiResponse, createNewSecurityGroupMock } from './mock/security-groups.mock';
import { fakeMarksApiResponse, createNewSecurityMarkMock } from './mock/security-marks.mock';
import { SecurityGroupBody, SecurityMarkBody, SecurityMarkEntry } from '@alfresco/js-api';
import { firstValueFrom } from 'rxjs';
describe('SecurityControlsService', () => {
let service: SecurityControlsService;
@@ -79,7 +78,7 @@ describe('SecurityControlsService', () => {
}
})
);
const response = await firstValueFrom(service.createSecurityGroup(createNewSecurityGroupMock));
const response = await service.createSecurityGroup(createNewSecurityGroupMock).toPromise();
securityGroupId = response.entry.id;
expect(response.entry.groupName).toEqual('TestGroup');
@@ -177,7 +176,7 @@ describe('SecurityControlsService', () => {
it('should delete a security group', async () => {
spyOn(service.groupsApi, 'deleteSecurityGroup').and.returnValue(Promise.resolve());
await firstValueFrom(service.deleteSecurityGroup(securityGroupId));
await service.deleteSecurityGroup(securityGroupId).toPromise();
expect(service.groupsApi.deleteSecurityGroup).toHaveBeenCalled();
});
@@ -186,7 +185,7 @@ describe('SecurityControlsService', () => {
Promise.resolve(fakeAuthorityClearanceApiResponse)
);
const clearancePromise = service.getClearancesForAuthority('test-id', 0, 10);
const clearance = await firstValueFrom(clearancePromise);
const clearance = await clearancePromise.toPromise();
expect(getClearancesForAuthoritySpy).toHaveBeenCalledWith('test-id', {
skipCount: 0,
@@ -211,15 +210,15 @@ describe('SecurityControlsService', () => {
}
})
);
const response = (await firstValueFrom(
service.updateClearancesForAuthority('test-id', [
const response = (await service
.updateClearancesForAuthority('test-id', [
{
groupId: 'test-group-id',
op: 'test-op',
id: 'test-id'
}
])
)) as SecurityMarkEntry;
.toPromise()) as SecurityMarkEntry;
expect(response.entry.id).toEqual('test-id');
expect(response.entry.groupId).toEqual('test-groupId');
@@ -19,7 +19,7 @@ import { AppConfigService, UserPreferencesService } from '@alfresco/adf-core';
import { TagService } from './tag.service';
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { ContentTestingModule } from '../../testing/content.testing.module';
import { firstValueFrom, throwError } from 'rxjs';
import { throwError } from 'rxjs';
import { Pagination, Tag, TagBody, TagEntry, TagPaging, TagPagingList } from '@alfresco/js-api';
describe('TagService', () => {
@@ -75,7 +75,7 @@ describe('TagService', () => {
let lastValue: any;
service.refresh.subscribe((res) => (lastValue = res));
await firstValueFrom(service.addTag('fake-node-id', 'fake-tag'));
await service.addTag('fake-node-id', 'fake-tag').toPromise();
expect(lastValue).toBe(tagEntry);
});
@@ -83,7 +83,7 @@ describe('TagService', () => {
let lastValue = false;
service.refresh.subscribe(() => (lastValue = true));
await firstValueFrom(service.deleteTag('fake-tag-id'));
await service.deleteTag('fake-tag-id').toPromise();
expect(lastValue).toBeTrue();
});
@@ -110,7 +110,7 @@ describe('TagService', () => {
spyOn(service.refresh, 'emit');
spyOn(service.tagsApi, 'createTags').and.returnValue(Promise.resolve(tag));
await firstValueFrom(service.createTags([]));
await service.createTags([]).toPromise();
expect(service.refresh.emit).toHaveBeenCalledWith(tag);
});
});
@@ -248,7 +248,7 @@ describe('TagService', () => {
it('should emit refresh when tag updated successfully', async () => {
spyOn(service.refresh, 'emit');
spyOn(service.tagsApi, 'updateTag').and.returnValue(Promise.resolve(updatedTag));
await firstValueFrom(service.updateTag(tag.entry.id, tagBody));
await service.updateTag(tag.entry.id, tagBody).toPromise();
expect(service.refresh.emit).toHaveBeenCalledWith(updatedTag);
});
});
@@ -43,7 +43,7 @@ describe('TagActionsComponent', () => {
}
};
let component: TagActionsComponent;
let component: any;
let fixture: ComponentFixture<TagActionsComponent>;
let element: HTMLElement;
let tagService: TagService;
@@ -90,7 +90,7 @@ describe('TagActionsComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const deleteButton = element.querySelector<HTMLButtonElement>('#tag_delete_test1');
const deleteButton: any = element.querySelector('#tag_delete_test1');
deleteButton.click();
expect(tagService.removeTag).toHaveBeenCalledWith('fake-node-id', '0ee933fa-57fc-4587-8a77-b787e814f1d2');
});
@@ -102,7 +102,7 @@ describe('TagActionsComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const addButton = element.querySelector<HTMLButtonElement>('#add-tag');
const addButton: any = element.querySelector('#add-tag');
expect(addButton.disabled).toEqual(true);
});
@@ -110,7 +110,7 @@ describe('TagActionsComponent', () => {
component.nodeId = 'fake-node-id';
component.newTagName = 'test1';
component.error.subscribe((res) => {
await component.error.subscribe((res) => {
expect(res).toEqual('TAG.MESSAGES.EXIST');
});
@@ -118,7 +118,7 @@ describe('TagActionsComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const addButton = element.querySelector<HTMLButtonElement>('#add-tag');
const addButton: any = element.querySelector('#add-tag');
addButton.click();
});
@@ -130,7 +130,7 @@ describe('TagActionsComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
const addButton = element.querySelector<HTMLButtonElement>('#add-tag');
const addButton: any = element.querySelector('#add-tag');
expect(addButton.disabled).toEqual(false);
});
});
@@ -15,26 +15,8 @@
* limitations under the License.
*/
import { DataColumn } from '@alfresco/adf-core';
import { MatIconRegistry } from '@angular/material/icon';
export const getDataColumnMock = <T = unknown>(column: Partial<DataColumn<T>> = {}): DataColumn<T> => ({
id: 'columnId',
key: 'key',
type: 'text',
format: 'format',
sortable: false,
title: 'title',
srTitle: 'srTitle',
cssClass: 'cssClass',
template: undefined,
copyContent: false,
editable: false,
focus: false,
sortingKey: 'sortingKey',
header: undefined,
draggable: false,
resizable: true,
isHidden: false,
customData: undefined,
...column
});
export const matIconRegistryMock = {
addSvgIconInNamespace: () => {}
} as any as MatIconRegistry;
@@ -790,7 +790,7 @@ describe('AlfrescoViewerComponent', () => {
});
it('should Click on close button hide the viewer', (done) => {
const closeButton = element.querySelector<HTMLButtonElement>('.adf-viewer-close-button');
const closeButton: any = element.querySelector('.adf-viewer-close-button');
closeButton.click();
fixture.detectChanges();
@@ -300,7 +300,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
try {
const sharedLinkEntry = await this.sharedLinksApi.getSharedLink(this.sharedLinkId);
await this.setUpSharedLinkFile(sharedLinkEntry);
} catch {
} catch (error) {
this.invalidSharedLink.next(undefined);
this.mimeType = 'invalid-link';
this.urlFileContent = 'invalid-file';
@@ -317,7 +317,7 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
await this.setUpNodeFile(this.nodeEntry.entry);
this.cdr.detectChanges();
}
} catch {
} catch (error) {
this.urlFileContent = 'invalid-node';
}
}
@@ -392,14 +392,14 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit {
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'pdf');
return { url: urlFileContent, mimeType: 'application/pdf' };
}
} catch {
} catch (error) {
try {
const rendition: RenditionEntry = await this.sharedLinksApi.getSharedLinkRendition(sharedId, 'imgpreview');
if (rendition.entry.status.toString() === 'CREATED') {
const urlFileContent = this.contentApi.getSharedLinkRenditionUrl(sharedId, 'imgpreview');
return { url: urlFileContent, mimeType: 'image/png' };
}
} catch {
} catch (renditionError) {
return null;
}
}
@@ -21,7 +21,6 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/
import { TestBed } from '@angular/core/testing';
import { AdfHttpClient } from './adf-http-client.service';
import { AlfrescoApiResponseError } from './alfresco-api/alfresco-api.response-error';
import EventEmitter from 'eventemitter3';
const securityOptions: SecurityOptions = {
authentications: {},
@@ -31,9 +30,16 @@ const securityOptions: SecurityOptions = {
withCredentials: false
};
const emitter = {
emit: () => {},
off: () => {},
on: () => {},
once: () => {}
};
const emitters: Emitters = {
eventEmitter: new EventEmitter(),
apiClientEmitter: new EventEmitter()
eventEmitter: emitter,
apiClientEmitter: emitter
};
const mockResponse = {
@@ -118,10 +124,10 @@ describe('AdfHttpClient', () => {
httpMethod: 'POST'
};
const eventSpy = spyOn(emitters.eventEmitter, 'emit').and.callThrough();
const spy = spyOn(emitter, 'emit').and.callThrough();
angularHttpClient.request('http://example.com', options, securityOptions, emitters).catch(() => {
expect(eventSpy).toHaveBeenCalledWith('unauthorized');
expect(spy).toHaveBeenCalledWith('unauthorized');
done();
});
+35 -52
View File
@@ -19,7 +19,7 @@ import { SHOULD_ADD_AUTH_TOKEN } from '@alfresco/adf-core/auth';
import { Emitters as JsApiEmitters, HttpClient as JsApiHttpClient } from '@alfresco/js-api';
import { HttpClient, HttpContext, HttpErrorResponse, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { lastValueFrom, Observable, of, Subject, throwError } from 'rxjs';
import { Observable, of, Subject, throwError } from 'rxjs';
import { catchError, map, takeUntil } from 'rxjs/operators';
import {
convertObjectToFormData,
@@ -34,25 +34,24 @@ import { AlfrescoApiParamEncoder } from './alfresco-api/alfresco-api.param-encod
import { AlfrescoApiResponseError } from './alfresco-api/alfresco-api.response-error';
import { Constructor } from './types';
import { RequestOptions, SecurityOptions } from './interfaces';
import { EventEmitter } from 'eventemitter3';
type EventEmitterInstance = InstanceType<typeof EventEmitter>;
type EventEmitterEvents = 'progress' | 'success' | 'error' | 'forbidden' | 'abort' | 'unauthorized' | string;
import ee, { Emitter } from 'event-emitter';
export interface Emitters {
readonly eventEmitter: EventEmitterInstance;
readonly apiClientEmitter: EventEmitterInstance;
readonly eventEmitter: Emitter;
readonly apiClientEmitter: Emitter;
}
@Injectable({
providedIn: 'root'
})
export class AdfHttpClient implements JsApiHttpClient {
private eventEmitter = new EventEmitter();
export class AdfHttpClient implements ee.Emitter, JsApiHttpClient {
on: ee.EmitterMethod;
off: ee.EmitterMethod;
once: ee.EmitterMethod;
_disableCsrf: boolean;
emit: (type: string, ...args: any[]) => void;
get disableCsrf(): boolean {
return this._disableCsrf;
}
@@ -69,27 +68,7 @@ export class AdfHttpClient implements JsApiHttpClient {
};
constructor(private httpClient: HttpClient) {
// No need for ee(this) anymore - we use composition instead of inheritance
}
// EventEmitter delegation methods
on(event: EventEmitterEvents, fn: (...args: any[]) => void, context?: any): this {
this.eventEmitter.on(event, fn, context);
return this;
}
off(event: EventEmitterEvents, fn?: (...args: any[]) => void, context?: any): this {
this.eventEmitter.off(event, fn, context);
return this;
}
once(event: EventEmitterEvents, fn: (...args: any[]) => void, context?: any): this {
this.eventEmitter.once(event, fn, context);
return this;
}
emit(event: EventEmitterEvents, ...args: any[]): boolean {
return this.eventEmitter.emit(event, ...args);
ee(this);
}
setDefaultSecurityOption(options: any) {
@@ -157,19 +136,24 @@ export class AdfHttpClient implements JsApiHttpClient {
private addPromiseListeners<T = any>(promise: Promise<T>, eventEmitter: any) {
const eventPromise = Object.assign(promise, {
on<K extends string | symbol>(event: K, fn: (...args: any[]) => void, context?: any) {
eventEmitter.on(event, fn, context);
on() {
// eslint-disable-next-line prefer-spread, prefer-rest-params
eventEmitter.on.apply(eventEmitter, arguments);
return this;
},
once<K extends string | symbol>(event: K, fn: (...args: any[]) => void, context?: any) {
eventEmitter.once(event, fn, context);
once() {
// eslint-disable-next-line prefer-spread, prefer-rest-params
eventEmitter.once.apply(eventEmitter, arguments);
return this;
},
emit<K extends string | symbol>(event: K, ...args: any[]): boolean {
return eventEmitter.emit(event, ...args);
emit() {
// eslint-disable-next-line prefer-spread, prefer-rest-params
eventEmitter.emit.apply(eventEmitter, arguments);
return this;
},
off<K extends string | symbol>(event: K, fn?: (...args: any[]) => void, context?: any) {
eventEmitter.off(event, fn, context);
off() {
// eslint-disable-next-line prefer-spread, prefer-rest-params
eventEmitter.off.apply(eventEmitter, arguments);
return this;
}
});
@@ -178,17 +162,16 @@ export class AdfHttpClient implements JsApiHttpClient {
}
private getEventEmitters(): Emitters {
const apiClientEmitter: EventEmitterInstance = new EventEmitter();
// Bind this instance's methods to the apiClientEmitter for backward compatibility
apiClientEmitter.on = this.on.bind(this);
apiClientEmitter.off = this.off.bind(this);
apiClientEmitter.once = this.once.bind(this);
apiClientEmitter.emit = this.emit.bind(this);
const apiClientEmitter = {
on: this.on.bind(this),
off: this.off.bind(this),
once: this.once.bind(this),
emit: this.emit.bind(this)
};
return {
apiClientEmitter,
eventEmitter: new EventEmitter()
eventEmitter: ee({})
};
}
@@ -196,8 +179,8 @@ export class AdfHttpClient implements JsApiHttpClient {
const abort$ = new Subject<void>();
const { eventEmitter, apiClientEmitter } = emitters;
const promise = lastValueFrom(
request$.pipe(
const promise = request$
.pipe(
map((res) => {
if (isHttpUploadProgressEvent(res)) {
const percent = Math.round((res.loaded / res.total) * 100);
@@ -243,7 +226,7 @@ export class AdfHttpClient implements JsApiHttpClient {
}),
takeUntil(abort$)
)
);
.toPromise();
(promise as any).abort = function () {
eventEmitter.emit('abort');
@@ -330,7 +313,7 @@ export class AdfHttpClient implements JsApiHttpClient {
try {
document.cookie = 'CSRF-TOKEN=' + token + ';path=/';
} catch {
} catch (err) {
/* continue regardless of error */
}
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { isConstructor, getQueryParamsWithCustomEncoder, removeNilValues, convertObjectToFormData } from './alfresco-api.utils';
import { isConstructor, getQueryParamsWithCustomEncoder, removeNilValues } from './alfresco-api.utils';
describe('AlfrescoApiUtils', () => {
describe('isConstructor', () => {
@@ -93,30 +93,4 @@ describe('AlfrescoApiUtils', () => {
expect(actual?.getAll('key2')).toEqual(['value2', 'value3']);
});
});
describe('convertObjectToFormData', () => {
it('should create correct FormData entries for string values', () => {
const testParams: Record<string, string> = { name: 'file name', description: 'file description' };
const result = convertObjectToFormData(testParams);
expect(result.get('name')).toBe('file name');
expect(result.get('description')).toBe('file description');
});
it('should handle Blob files correctly', () => {
const testFile = new File(['content'], 'test.txt', { type: 'text/plain' });
const testParams: Record<string, Blob> = { file: testFile };
const result = convertObjectToFormData(testParams);
expect(result.get('file')).toEqual(testFile);
});
it('should create multiple entries with same key for arrays', () => {
const testParams: Record<string, Array<string>> = { categories: ['category1', 'category2', 'category3'] };
const result = convertObjectToFormData(testParams);
const values = result.getAll('categories');
expect(values).toEqual(['category1', 'category2', 'category3']);
});
});
});
@@ -85,7 +85,7 @@ export const removeNilValues = (obj: Record<string | number, unknown>) => {
}, {});
};
export const convertObjectToFormData = (formParams: Record<string | number, string | Blob | Array<string | Blob>>): FormData => {
export const convertObjectToFormData = (formParams: Record<string | number, string | Blob>): FormData => {
const formData = new FormData();
for (const key in formParams) {
@@ -93,8 +93,6 @@ export const convertObjectToFormData = (formParams: Record<string | number, stri
const value = formParams[key];
if (value instanceof File) {
formData.append(key, value, value.name);
} else if (Array.isArray(value)) {
value.forEach((item) => formData.append(key, item));
} else {
formData.append(key, value);
}
@@ -58,7 +58,7 @@ describe('FlagsComponent', () => {
});
it('should update inputValue$ when onInputChange is called', (done) => {
component.onInputChange('test');
(component as any).onInputChange('test');
component.inputValue$.subscribe((value) => {
expect(value).toBe('test');
done();
@@ -67,12 +67,12 @@ describe('FlagsComponent', () => {
it('should clear inputValue when onClearInput is called', () => {
component.inputValue = 'test';
component.onClearInput();
(component as any).onClearInput();
expect(component.inputValue).toBe('');
});
it('should filter flags when when onClearInput is called', (done) => {
component.onInputChange('feature1');
(component as any).onInputChange('feature1');
component.flags$.subscribe((flags) => {
expect(flags).toEqual([{ fictive: false, flag: 'feature1', value: true }]);
done();
@@ -123,11 +123,11 @@ export class FlagsComponent {
this.featuresService.enable(value);
}
onInputChange(text: string) {
protected onInputChange(text: string) {
this.inputValue$.next(text);
}
onClearInput() {
protected onClearInput() {
this.inputValue = '';
this.inputValue$.next('');
}
+2 -1
View File
@@ -26,7 +26,8 @@ module.exports = function (config) {
included: false,
served: true,
watched: false
}
},
{ pattern: 'node_modules/resize-observer-polyfill/dist/ResizeObserver.global.js', included: true, watched: false }
],
frameworks: ['jasmine-ajax', 'jasmine', '@angular-devkit/build-angular'],
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@alfresco/adf-core",
"description": "Alfresco ADF core",
"version": "8.3.0",
"version": "8.0.4",
"author": "Hyland Software, Inc. and its affiliates",
"repository": {
"type": "git",
@@ -38,8 +38,8 @@
"@angular/router": ">=16.0.0",
"@mat-datetimepicker/core": ">=12.0.1",
"@ngx-translate/core": ">=16.0.0",
"@alfresco/js-api": ">=9.1.1",
"@alfresco/adf-extensions": ">=8.2.0",
"@alfresco/js-api": ">=9.0.2",
"@alfresco/adf-extensions": ">=8.0.2",
"minimatch": ">=10.0.0",
"pdfjs-dist": ">=3.3.122",
"ts-morph": ">=20.0.0"
@@ -18,7 +18,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AboutServerSettingsComponent } from './about-server-settings.component';
import { AppConfigService } from '../../app-config/app-config.service';
import { provideAppConfigTesting } from '@alfresco/adf-core';
import { AppConfigServiceMock } from '../../common';
const aboutGithubDetails = {
url: 'https://github.com/componany/repository/commits/',
@@ -36,7 +36,7 @@ describe('AboutServerSettingsComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [provideAppConfigTesting()]
providers: [{ provide: AppConfigService, useClass: AppConfigServiceMock }]
});
fixture = TestBed.createComponent(AboutServerSettingsComponent);
component = fixture.componentInstance;
@@ -0,0 +1,26 @@
/*!
* @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 { NgModule } from '@angular/core';
import { AppConfigPipe } from './app-config.pipe';
/** @deprecated This module is deprecated, consider importing AppConfigPipe directly */
@NgModule({
imports: [AppConfigPipe],
exports: [AppConfigPipe]
})
export class AppConfigModule {}
@@ -0,0 +1,37 @@
/*!
* @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 { Injectable } from '@angular/core';
import { StorageService } from '../common/services/storage.service';
import { AppConfigService, AppConfigValues } from './app-config.service';
@Injectable()
export class DebugAppConfigService extends AppConfigService {
constructor(private storage: StorageService) {
super();
}
get<T>(key: string, defaultValue?: T): T {
if (key === AppConfigValues.OAUTHCONFIG) {
return JSON.parse(this.storage.getItem(key)) || super.get<T>(key, defaultValue);
} else if (key === AppConfigValues.APPLICATION) {
return undefined;
} else {
return (this.storage.getItem(key) as any) || super.get<T>(key, defaultValue);
}
}
}
@@ -16,7 +16,9 @@
*/
export * from './app-config.service';
export * from './debug-app-config.service';
export * from './app-config.pipe';
export * from './app-config-storage-prefix.factory';
export * from './app-config.module';
export * from './provide-app-config';
@@ -127,6 +127,22 @@ describe('BasicAlfrescoAuthService', () => {
});
});
it('isBpmLoggedIn should return value from processAuth', () => {
spyOn(processAuth, 'isLoggedIn').and.returnValue(true);
const result = basicAlfrescoAuthService.isBpmLoggedIn();
expect(result).toBeTrue();
expect(processAuth.isLoggedIn).toHaveBeenCalled();
});
it('isEcmLoggedIn should return value from contentAuth', () => {
spyOn(contentAuth, 'isLoggedIn').and.returnValue(true);
const result = basicAlfrescoAuthService.isEcmLoggedIn();
expect(result).toBeTrue();
expect(contentAuth.isLoggedIn).toHaveBeenCalled();
});
describe('isLoggedIn', () => {
let contentAuthSpy: jasmine.Spy;
let processAuthSpy: jasmine.Spy;
@@ -43,12 +43,7 @@ export class BasicAlfrescoAuthService extends BaseAuthenticationService {
type: 'basic'
};
constructor(
appConfig: AppConfigService,
cookie: CookieService,
private readonly contentAuth: ContentAuth,
private readonly processAuth: ProcessAuth
) {
constructor(appConfig: AppConfigService, cookie: CookieService, private contentAuth: ContentAuth, private processAuth: ProcessAuth) {
super(appConfig, cookie);
this.appConfig.onLoad.subscribe(() => {
@@ -219,6 +214,30 @@ export class BasicAlfrescoAuthService extends BaseAuthenticationService {
}
}
/**
* @deprecated
* @returns content auth token
*/
getTicketEcm(): string {
return this.contentAuth.getToken();
}
/**
* @deprecated
* @returns process auth token
*/
getTicketBpm(): string {
return this.processAuth.getToken();
}
isBpmLoggedIn(): boolean {
return this.processAuth.isLoggedIn();
}
isEcmLoggedIn(): boolean {
return this.contentAuth.isLoggedIn();
}
isLoggedIn(): boolean {
const authWithCredentials = this.isKerberosEnabled();
@@ -298,11 +317,14 @@ export class BasicAlfrescoAuthService extends BaseAuthenticationService {
return this.redirectUrl && (this.redirectUrl.provider === 'ALL' || provider === 'ALL');
}
/**
* Gets the username of the authenticated user.
*
* @returns the username of the authenticated user
*/
getBpmUsername(): string {
return this.processAuth.getUsername();
}
getEcmUsername(): string {
return this.contentAuth.getUsername();
}
getUsername(): string {
if (this.isBPMProvider()) {
return this.processAuth.getUsername();
@@ -71,7 +71,7 @@ describe('AuthGuardService BPM', () => {
});
it('should redirect url if the alfresco js api is NOT logged in and isOAuth with silentLogin', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isBpmLoggedIn').and.returnValue(false);
spyOn(authService, 'isOauth').and.returnValue(true);
spyOn(oidcAuthenticationService, 'isPublicUrl').and.returnValue(false);
spyOn(oidcAuthenticationService, 'ssoLogin').and.stub();
@@ -94,14 +94,14 @@ describe('AuthGuardService BPM', () => {
});
it('if the alfresco js api is logged in should canActivate be true', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(true);
spyOn(authService, 'isBpmLoggedIn').and.returnValue(true);
authGuard = TestBed.runInInjectionContext(() => AuthGuardBpm(route, state)) as Promise<boolean>;
expect(await authGuard).toBeTruthy();
});
it('if the alfresco js api is configured with withCredentials true should canActivate be true', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(true);
spyOn(authService, 'isBpmLoggedIn').and.returnValue(true);
appConfigService.config.auth.withCredentials = true;
authGuard = TestBed.runInInjectionContext(() => AuthGuardBpm(route, state)) as Promise<boolean>;
@@ -110,7 +110,7 @@ describe('AuthGuardService BPM', () => {
});
it('if the alfresco js api is NOT logged in should canActivate be false', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isBpmLoggedIn').and.returnValue(false);
authGuard = TestBed.runInInjectionContext(() => AuthGuardBpm(route, state)) as Promise<boolean>;
@@ -119,7 +119,7 @@ describe('AuthGuardService BPM', () => {
it('if the alfresco js api is NOT logged in should trigger a redirect event', async () => {
appConfigService.config.loginRoute = 'login';
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isBpmLoggedIn').and.returnValue(false);
authGuard = TestBed.runInInjectionContext(() => AuthGuardBpm(route, state)) as Promise<boolean>;
@@ -128,7 +128,7 @@ describe('AuthGuardService BPM', () => {
});
it('should redirect url if the alfresco js api is NOT logged in and isOAuthWithoutSilentLogin', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isBpmLoggedIn').and.returnValue(false);
spyOn(authService, 'isOauth').and.returnValue(true);
appConfigService.config.oauth2.silentLogin = false;
@@ -139,7 +139,7 @@ describe('AuthGuardService BPM', () => {
});
it('should redirect url if NOT logged in and isOAuth but no silentLogin configured', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isBpmLoggedIn').and.returnValue(false);
spyOn(authService, 'isOauth').and.returnValue(true);
appConfigService.config.oauth2.silentLogin = undefined;
@@ -28,7 +28,7 @@ export const AuthGuardBpm: CanActivateFn = async (_: ActivatedRouteSnapshot, sta
return authGuardBaseService.redirectSSOSuccessURL();
}
if (authenticationService.isLoggedIn() || authGuardBaseService.withCredentials) {
if (authenticationService.isBpmLoggedIn() || authGuardBaseService.withCredentials) {
return true;
}
@@ -71,7 +71,7 @@ describe('AuthGuardService ECM', () => {
});
it('if the alfresco js api is logged in should canActivate be true', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(true);
spyOn(authService, 'isEcmLoggedIn').and.returnValue(true);
authGuard = TestBed.runInInjectionContext(() => AuthGuardEcm(route, state)) as Promise<boolean>;
@@ -79,7 +79,7 @@ describe('AuthGuardService ECM', () => {
});
it('if the alfresco js api is configured with withCredentials true should canActivate be true', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(true);
spyOn(authService, 'isBpmLoggedIn').and.returnValue(true);
appConfigService.config.auth.withCredentials = true;
authGuard = TestBed.runInInjectionContext(() => AuthGuardEcm(route, state)) as Promise<boolean>;
@@ -88,7 +88,7 @@ describe('AuthGuardService ECM', () => {
});
it('if the alfresco js api is NOT logged in should canActivate be false', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isEcmLoggedIn').and.returnValue(false);
authGuard = TestBed.runInInjectionContext(() => AuthGuardEcm(route, state)) as Promise<boolean>;
@@ -97,7 +97,7 @@ describe('AuthGuardService ECM', () => {
it('if the alfresco js api is NOT logged in should trigger a redirect event', async () => {
appConfigService.config.loginRoute = 'login';
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isEcmLoggedIn').and.returnValue(false);
authGuard = TestBed.runInInjectionContext(() => AuthGuardEcm(route, state)) as Promise<boolean>;
@@ -106,7 +106,7 @@ describe('AuthGuardService ECM', () => {
});
it('should redirect url if the alfresco js api is NOT logged in and isOAuthWithoutSilentLogin', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isEcmLoggedIn').and.returnValue(false);
spyOn(authService, 'isOauth').and.returnValue(true);
appConfigService.config.oauth2.silentLogin = false;
@@ -117,7 +117,7 @@ describe('AuthGuardService ECM', () => {
});
it('should redirect url if the alfresco js api is NOT logged in and isOAuth with silentLogin', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isEcmLoggedIn').and.returnValue(false);
spyOn(authService, 'isOauth').and.returnValue(true);
spyOn(oidcAuthenticationService, 'isPublicUrl').and.returnValue(false);
spyOn(oidcAuthenticationService, 'ssoLogin').and.stub();
@@ -139,7 +139,7 @@ describe('AuthGuardService ECM', () => {
});
it('should not redirect url if NOT logged in and isOAuth but no silentLogin configured', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(false);
spyOn(authService, 'isEcmLoggedIn').and.returnValue(false);
spyOn(authService, 'isOauth').and.returnValue(true);
appConfigService.config.oauth2.silentLogin = undefined;
@@ -28,7 +28,7 @@ export const AuthGuardEcm: CanActivateFn = async (_: ActivatedRouteSnapshot, sta
return authGuardBaseService.redirectSSOSuccessURL();
}
if (authenticationService.isLoggedIn() || authGuardBaseService.withCredentials) {
if (authenticationService.isEcmLoggedIn() || authGuardBaseService.withCredentials) {
return true;
}
@@ -26,7 +26,8 @@ import { BasicAlfrescoAuthService } from '../basic-auth/basic-alfresco-auth.serv
import { RedirectAuthService } from '../oidc/redirect-auth.service';
import { EMPTY, of } from 'rxjs';
import { MatDialogModule } from '@angular/material/dialog';
import { provideCoreAuthTesting } from '../../testing/';
import { RouterTestingModule } from '@angular/router/testing';
import { NoopAuthModule } from '../../testing';
describe('AuthGuardService', () => {
let state: RouterStateSnapshot;
@@ -41,9 +42,9 @@ describe('AuthGuardService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [MatDialogModule],
imports: [MatDialogModule, RouterTestingModule, NoopAuthModule],
providers: [
provideCoreAuthTesting(),
AppConfigService,
{ provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of(), init: () => {} } },
{
provide: OidcAuthenticationService,
@@ -89,7 +90,7 @@ describe('AuthGuardService', () => {
});
it('if the alfresco js api is configured with withCredentials true should canActivate be true', async () => {
spyOn(authService, 'isLoggedIn').and.returnValue(true);
spyOn(authService, 'isBpmLoggedIn').and.returnValue(true);
appConfigService.config.auth.withCredentials = true;
authGuard = TestBed.runInInjectionContext(() => AuthGuard(route, state)) as Promise<boolean>;
@@ -16,32 +16,45 @@
*/
import { HttpHeaders } from '@angular/common/http';
import { EventEmitter } from 'eventemitter3';
import ee from 'event-emitter';
import { Observable } from 'rxjs';
type EventEmitterInstance = InstanceType<typeof EventEmitter>;
export interface AuthenticationServiceInterface {
onError: any;
onLogin: any;
onLogout: any;
on: EventEmitterInstance['on'];
off: EventEmitterInstance['off'];
once: EventEmitterInstance['once'];
emit: EventEmitterInstance['emit'];
on: ee.EmitterMethod;
off: ee.EmitterMethod;
once: ee.EmitterMethod;
emit: (type: string, ...args: any[]) => void;
getToken(): string;
isLoggedIn(): boolean;
isOauth(): boolean;
logout(): any;
isEcmLoggedIn(): boolean;
isBpmLoggedIn(): boolean;
isECMProvider(): boolean;
isBPMProvider(): boolean;
isALLProvider(): boolean;
getUsername(): string;
getEcmUsername(): string;
getBpmUsername(): string;
getAuthHeaders(requestUrl: string, header: HttpHeaders): HttpHeaders;
addTokenToHeader(requestUrl: string, headersArg?: HttpHeaders): Observable<HttpHeaders>;
reset(): void;
}
@@ -76,6 +76,20 @@ export const clientRoles: IdentityRoleModel[] = [
export const mockJoinGroupRequest: IdentityJoinGroupRequestModel = { userId: 'mock-hser-id', groupId: 'mock-group-id', realm: 'mock-realm-name' };
export const mockGroup1 = {
id: 'mock-group-id-1',
name: 'Mock Group 1',
path: '/mock',
subGroups: []
} as IdentityGroupModel;
export const mockGroup2 = {
id: 'mock-group-id-2',
name: 'Mock Group 2',
path: '',
subGroups: []
} as IdentityGroupModel;
export const mockGroups = [
{ id: 'mock-group-id-1', name: 'Mock Group 1', path: '/mock', subGroups: [] } as IdentityGroupModel,
{ id: 'mock-group-id-2', name: 'Mock Group 2', path: '', subGroups: [] } as IdentityGroupModel
@@ -0,0 +1,142 @@
/*!
* @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 { Injectable } from '@angular/core';
import { mockIdentityGroups, mockIdentityGroupsCount, mockIdentityRoles } from './identity-group.mock';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { IdentityGroupServiceInterface } from '../interfaces/identity-group.interface';
import {
IdentityGroupModel,
IdentityGroupQueryResponse,
IdentityGroupQueryCloudRequestModel,
IdentityGroupSearchParam,
IdentityGroupCountModel
} from '../models/identity-group.model';
import { IdentityRoleModel } from '../models/identity-role.model';
Injectable({ providedIn: 'root' });
export class IdentityGroupServiceMock implements IdentityGroupServiceInterface {
getGroups(): Observable<IdentityGroupModel[]> {
return of(mockIdentityGroups);
}
getAvailableRoles(_groupId: string): Observable<IdentityRoleModel[]> {
return of(mockIdentityRoles);
}
getAssignedRoles(_groupId: string): Observable<IdentityRoleModel[]> {
return of(mockIdentityRoles);
}
assignRoles(_groupId: string, _roles: IdentityRoleModel[]): Observable<any> {
return of();
}
removeRoles(_groupId: string, _roles: IdentityRoleModel[]): Observable<any> {
return of();
}
getEffectiveRoles(_groupId: string): Observable<IdentityRoleModel[]> {
return of(mockIdentityRoles);
}
queryGroups(_requestQuery: IdentityGroupQueryCloudRequestModel): Observable<IdentityGroupQueryResponse> {
return of();
}
getTotalGroupsCount(): Observable<IdentityGroupCountModel> {
return of(mockIdentityGroupsCount);
}
createGroup(_newGroup: IdentityGroupModel): Observable<any> {
return of();
}
updateGroup(_groupId: string, _updatedGroup: IdentityGroupModel): Observable<any> {
return of();
}
deleteGroup(_groupId: string): Observable<any> {
return of();
}
findGroupsByName(searchParams: IdentityGroupSearchParam): Observable<IdentityGroupModel[]> {
if (searchParams.name === '') {
return of([]);
}
return of(mockIdentityGroups.filter((group) => group.name.toUpperCase().includes(searchParams.name.toUpperCase())));
}
getGroupRoles(_groupId: string): Observable<IdentityRoleModel[]> {
return of(mockIdentityRoles);
}
checkGroupHasRole(groupId: string, roleNames: string[]): Observable<boolean> {
return this.getGroupRoles(groupId).pipe(
map((groupRoles) => {
let hasRole = false;
if (groupRoles?.length > 0) {
roleNames.forEach((roleName: string) => {
const role = groupRoles.find(({ name }) => roleName === name);
if (role) {
hasRole = true;
return;
}
});
}
return hasRole;
})
);
}
getClientIdByApplicationName(_applicationName: string): Observable<string> {
return of('fake-client-id');
}
getClientRoles(groupId: string, _clientId: string): Observable<IdentityRoleModel[]> {
if (['mock-group-id-1', 'mock-group-id-2'].includes(groupId)) {
return of([{ id: 'mock-role-id', name: 'MOCK-ADMIN-ROLE' }]);
}
return of([{ id: 'mock-role-id', name: 'MOCK-USER-ROLE' }]);
}
checkGroupHasClientApp(groupId: string, clientId: string): Observable<boolean> {
return this.getClientRoles(groupId, clientId).pipe(map((response) => response && response.length > 0));
}
checkGroupHasAnyClientAppRole(groupId: string, clientId: string, roleNames: string[]): Observable<boolean> {
return this.getClientRoles(groupId, clientId).pipe(
map((clientRoles: any[]) => {
let hasRole = false;
if (clientRoles.length > 0) {
roleNames.forEach((roleName) => {
const role = clientRoles.find(({ name }) => name === roleName);
if (role) {
hasRole = true;
return;
}
});
}
return hasRole;
})
);
}
}
@@ -27,7 +27,7 @@ import {
IdentityJoinGroupRequestModel
} from '../interfaces/identity-user.service.interface';
import { mockIdentityGroups } from './identity-group.mock';
import { firstValueFrom, Observable, of } from 'rxjs';
import { Observable, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { mockAssignedRoles, mockAvailableRoles, mockEffectiveRoles, mockIdentityUser1, mockIdentityUsers } from './identity-user.mock';
@@ -127,7 +127,7 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
async getUsersByRolesWithCurrentUser(roleNames: string[]): Promise<IdentityUserModel[]> {
const filteredUsers: IdentityUserModel[] = [];
if (roleNames && roleNames.length > 0) {
const users = await firstValueFrom(this.getUsers());
const users = await this.getUsers().toPromise();
for (let i = 0; i < users.length; i++) {
const hasAnyRole = await this.userHasAnyRole(users[i].id, roleNames);
@@ -144,7 +144,7 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
const filteredUsers: IdentityUserModel[] = [];
if (roleNames && roleNames.length > 0) {
const currentUser = this.getCurrentUserInfo();
let users = await firstValueFrom(this.getUsers());
let users = await this.getUsers().toPromise();
users = users.filter(({ username }) => username !== currentUser.username);
@@ -160,7 +160,7 @@ export class IdentityUserServiceMock implements IdentityUserServiceInterface {
}
private async userHasAnyRole(userId: string, roleNames: string[]): Promise<boolean> {
const userRoles = await firstValueFrom(this.getUserRoles(userId));
const userRoles = await this.getUserRoles(userId).toPromise();
const hasAnyRole = roleNames.some((roleName) => {
const filteredRoles = userRoles.filter((userRole) => userRole.name.toLocaleLowerCase() === roleName.toLocaleLowerCase());
@@ -0,0 +1,133 @@
/*!
* @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 { mockGroups, mockIdentityGroups, roleMappingMock } from './identity-group.mock';
import { mockAssignedRoles, mockAvailableRoles, mockEffectiveRoles, mockIdentityUsers } from './identity-user.mock';
export const queryUsersMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockIdentityUsers)
}
};
export const createUserMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const updateUserMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const deleteUserMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const getInvolvedGroupsMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockGroups)
}
};
export const joinGroupMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const leaveGroupMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const getAvailableRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockAvailableRoles)
}
};
export const getAssignedRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockAssignedRoles)
}
};
export const getEffectiveRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockEffectiveRoles)
}
};
export const assignRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const removeRolesMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const roleMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(roleMappingMock)
}
};
export const noRoleMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve([])
}
};
export const groupsMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve(mockIdentityGroups)
}
};
export const createGroupMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const updateGroupMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const deleteGroupMappingApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve()
}
};
export const applicationDetailsMockApi: any = {
oauth2Auth: {
callCustomApi: () => Promise.resolve([{ id: 'mock-app-id', name: 'mock-app-name' }])
}
};
@@ -17,7 +17,7 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { EMPTY } from 'rxjs';
import { AppConfigService } from '../../app-config/app-config.service';
import { AUTH_MODULE_CONFIG } from './auth-config';
import { AuthConfigService } from './auth-config.service';
@@ -102,7 +102,7 @@ describe('AuthConfigService', () => {
spyOn<any>(service, 'getLocationOrigin').and.returnValue('http://localhost:3000');
appConfigService = TestBed.inject(AppConfigService);
appConfigService.onLoad = of(true);
appConfigService.onLoad = EMPTY;
});
describe('load auth config using hash', () => {
@@ -21,7 +21,6 @@ import { take } from 'rxjs/operators';
import { AppConfigService } from '../../app-config/app-config.service';
import { AUTH_MODULE_CONFIG, AuthModuleConfig } from './auth-config';
import { OauthConfigModel } from '../models/oauth-config.model';
import { firstValueFrom } from 'rxjs';
/**
* Create auth configuration factory
@@ -37,10 +36,7 @@ export function authConfigFactory(authConfigService: AuthConfigService): Promise
providedIn: 'root'
})
export class AuthConfigService {
constructor(
private appConfigService: AppConfigService,
@Inject(AUTH_MODULE_CONFIG) private readonly authModuleConfig: AuthModuleConfig
) {}
constructor(private appConfigService: AppConfigService, @Inject(AUTH_MODULE_CONFIG) private readonly authModuleConfig: AuthModuleConfig) {}
private _authConfig!: AuthConfig;
get authConfig(): AuthConfig {
@@ -48,7 +44,7 @@ export class AuthConfigService {
}
loadConfig(): Promise<AuthConfig> {
return firstValueFrom(this.appConfigService.onLoad.pipe(take(1))).then(this.loadAppConfig.bind(this));
return this.appConfigService.onLoad.pipe(take(1)).toPromise().then(this.loadAppConfig.bind(this));
}
loadAppConfig(): AuthConfig {

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