mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-16 18:13:06 +00:00
Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
079047702f | ||
|
|
85e46c7007 | ||
|
|
f2a0b3f826 | ||
|
|
425b4bab67 | ||
|
|
97f1136f96 | ||
|
|
9cd94f8e39 | ||
|
|
48391f2db5 | ||
|
|
b923e41b2f | ||
|
|
1e0c569f47 | ||
|
|
4e38d1d44c | ||
|
|
21a275a777 | ||
|
|
5ecc05a84f | ||
|
|
c52a63485b | ||
|
|
d4e0da26ac | ||
|
|
4d54d8512b | ||
|
|
a74338e21d | ||
|
|
31d293bdb2 | ||
|
|
d4714e2b01 | ||
|
|
f751370b60 | ||
|
|
49062ae19d | ||
|
|
ecd4fed2ac | ||
|
|
c7e6051b1a | ||
|
|
db0aafa5df |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.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@20d21f43addae05442096a7e935dc2b321361501 # v8.27.0
|
||||
# CACHE
|
||||
- name: Node Modules cache
|
||||
id: node-modules-cache
|
||||
if: ${{ inputs.enable-node-modules-cache == 'true' }}
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
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@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
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 }}
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
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@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
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@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||
|
||||
@@ -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_REPOSITORY_USER }}
|
||||
DOCKER_REPOSITORY_PASSWORD: ${{ secrets.DOCKER_REPOSITORY_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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- id: set-dryrun
|
||||
uses: ./.github/actions/enable-dryrun
|
||||
with:
|
||||
dry-run-flag: ${{ inputs.dry-run-flag }}
|
||||
- name: install NPM
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.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 }}
|
||||
|
||||
@@ -84,10 +84,10 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get branch name
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@20d21f43addae05442096a7e935dc2b321361501 # v8.27.0
|
||||
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@20d21f43addae05442096a7e935dc2b321361501 # v8.27.0
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/get-commit-message@691c1d16c90c88a92d2438a001acdefc0efa7d2a # v8.26.0
|
||||
|
||||
- name: ci:force flag parser
|
||||
shell: bash
|
||||
|
||||
@@ -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 }}
|
||||
@@ -46,7 +51,7 @@ 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
|
||||
@@ -86,6 +91,7 @@ jobs:
|
||||
dry-run-flag: ${{ inputs.dry-run-flag }}
|
||||
- uses: ./.github/actions/download-node-modules-and-artifacts
|
||||
- name: Set libraries versions
|
||||
if: ${{ inputs.npm-tag == 'branch' }}
|
||||
run: |
|
||||
set -u;
|
||||
./scripts/update-version.sh -gnu || exit 1;
|
||||
+29
-203
@@ -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_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"
|
||||
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
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@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
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@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.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@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- 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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- 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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Push Source Files to Crowdin
|
||||
uses: crowdin/github-action@9fd07c1c5b36b15f082d1d860dc399f16f849bd7 # v2.9.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' || '' }}
|
||||
|
||||
@@ -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" ("<") 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" ("<") 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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -56,3 +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.0.1](license-info-8.0.1.md)
|
||||
- [ADF 8.0.2](license-info-8.0.2.md)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
Title: License info, alfresco-ng2-components 8.0.1
|
||||
---
|
||||
|
||||
# License information for alfresco-ng2-components 8.0.1
|
||||
|
||||
This page lists all third party libraries the project depends on.
|
||||
|
||||
## Libraries
|
||||
|
||||
| Name | Version | License |
|
||||
| --- | --- | --- |
|
||||
| [@angular/animations](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/cdk](https://github.com/angular/components) | 19.2.9 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/common](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/compiler](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/core](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/forms](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/material-date-fns-adapter](https://github.com/angular/components) | 19.2.9 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/material](https://github.com/angular/components) | 19.2.9 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/platform-browser-dynamic](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/platform-browser](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/router](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@apollo/client](https://github.com/apollographql/apollo-client) | 3.13.1 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@cspell/eslint-plugin](https://github.com/streetsidesoftware/cspell) | 8.16.1 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@mat-datetimepicker/core](https://github.com/kuhnroyal/mat-datetimepicker) | 15.0.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| @ngx-translate/core | 16.0.4 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@nx/webpack](https://github.com/nrwl/nx) | 20.8.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [angular-oauth2-oidc-jwks](https://github.com/manfredsteyer/angular-oauth2-oidc) | 17.0.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc) | 17.0.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [apollo-angular](https://github.com/kamilkisiela/apollo-angular) | 10.0.3 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [chart.js](https://github.com/chartjs/Chart.js) | 4.4.4 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [cropperjs](https://github.com/fengyuanchen/cropperjs) | 1.6.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [date-fns](https://github.com/date-fns/date-fns) | 2.30.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [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) |
|
||||
| [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/) |
|
||||
| [node-fetch](https://github.com/node-fetch/node-fetch) | 3.3.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [pdfjs-dist](https://github.com/mozilla/pdf.js) | 5.1.91 | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [raphael](https://github.com/DmitryBaranovskiy/raphael) | 2.3.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [rxjs](https://github.com/reactivex/rxjs) | 7.8.2 | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [superagent](https://github.com/ladjs/superagent) | 9.0.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [ts-morph](https://github.com/dsherret/ts-morph) | 26.0.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [tslib](https://github.com/Microsoft/tslib) | 2.8.1 | [0BSD](http://landley.net/toybox/license.html) |
|
||||
| [zone.js](https://github.com/angular/angular) | 0.15.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
Title: License info, alfresco-ng2-components 8.0.2
|
||||
---
|
||||
|
||||
# License information for alfresco-ng2-components 8.0.2
|
||||
|
||||
This page lists all third party libraries the project depends on.
|
||||
|
||||
## Libraries
|
||||
|
||||
| Name | Version | License |
|
||||
| --- | --- | --- |
|
||||
| [@angular/animations](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/cdk](https://github.com/angular/components) | 19.2.9 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/common](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/compiler](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/core](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/forms](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/material-date-fns-adapter](https://github.com/angular/components) | 19.2.9 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/material](https://github.com/angular/components) | 19.2.9 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/platform-browser-dynamic](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/platform-browser](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@angular/router](https://github.com/angular/angular) | 19.2.6 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@apollo/client](https://github.com/apollographql/apollo-client) | 3.13.1 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@cspell/eslint-plugin](https://github.com/streetsidesoftware/cspell) | 8.16.1 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@mat-datetimepicker/core](https://github.com/kuhnroyal/mat-datetimepicker) | 15.0.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| @ngx-translate/core | 16.0.4 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [@nx/webpack](https://github.com/nrwl/nx) | 20.8.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [angular-oauth2-oidc-jwks](https://github.com/manfredsteyer/angular-oauth2-oidc) | 17.0.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc) | 17.0.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [apollo-angular](https://github.com/kamilkisiela/apollo-angular) | 10.0.3 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [chart.js](https://github.com/chartjs/Chart.js) | 4.4.4 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [cropperjs](https://github.com/fengyuanchen/cropperjs) | 1.6.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [date-fns](https://github.com/date-fns/date-fns) | 2.30.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [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.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/) |
|
||||
| [node-fetch](https://github.com/node-fetch/node-fetch) | 3.3.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [pdfjs-dist](https://github.com/mozilla/pdf.js) | 5.1.91 | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [raphael](https://github.com/DmitryBaranovskiy/raphael) | 2.3.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [rxjs](https://github.com/reactivex/rxjs) | 7.8.2 | [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [superagent](https://github.com/ladjs/superagent) | 9.0.2 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [ts-morph](https://github.com/dsherret/ts-morph) | 26.0.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
| [tslib](https://github.com/Microsoft/tslib) | 2.8.1 | [0BSD](http://landley.net/toybox/license.html) |
|
||||
| [zone.js](https://github.com/angular/angular) | 0.15.0 | [MIT](http://www.opensource.org/licenses/MIT) |
|
||||
|
||||
@@ -9,6 +9,8 @@ The first **General Availability** release was v2.0.0.
|
||||
|
||||
## General Availability
|
||||
|
||||
- [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)
|
||||
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
@@ -53,3 +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.0.1](audit-info-8.0.1.md)
|
||||
- [ADF 8.0.2](audit-info-8.0.2.md)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
Title: Audit info, alfresco-ng2-components 8.0.0
|
||||
---
|
||||
|
||||
# Audit information for alfresco-ng2-components 8.0.0
|
||||
|
||||
This page lists the security audit of the dependencies this project depends on.
|
||||
|
||||
## Risks
|
||||
|
||||
- Critical risk: 0
|
||||
- High risk: 0
|
||||
- Moderate risk: 0
|
||||
- Low risk: 0
|
||||
|
||||
Dependencies analyzed:
|
||||
|
||||
## Libraries
|
||||
|
||||
| Severity | Module | Vulnerable versions |
|
||||
| --- | --- | --- |
|
||||
|
||||
|
||||
@@ -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 | "19.0.0-next.0 - 19.2.17" |
|
||||
|high | @angular/common | "<=19.2.17" |
|
||||
|high | @angular/compiler | "19.0.0-next.0 - 19.2.17" |
|
||||
|high | @angular/core | "19.0.0-next.0 - 19.2.17" |
|
||||
|high | @angular/forms | "<=19.2.17" |
|
||||
|high | @angular/platform-browser | "<=19.2.17" |
|
||||
|high | @angular/platform-browser-dynamic | "<=19.2.17" |
|
||||
|high | @angular/router | "<=0.0.0-ROUTERPLACEHOLDER || 2.0.0-rc.0 - 19.2.17" |
|
||||
|high | @isaacs/brace-expansion | "5.0.0" |
|
||||
|high | @nx/devkit | "<=0.0.0-pr-34253-d811c6c || 18.4.0-canary.20240417-801a22b - 22.4.0-canary.20260121-1b12e1f" |
|
||||
|high | @nx/js | "<=0.0.0-pr-34253-d811c6c || 17.0.4 - 17.0.5 || 17.3.0-beta.1 - 22.4.0-canary.20260121-1b12e1f" |
|
||||
|high | @nx/webpack | "<=0.0.0-pr-34082-9d57132 || 18.4.0-canary.20240417-801a22b - 22.4.0-canary.20260121-1b12e1f" |
|
||||
|high | @nx/workspace | "<=0.0.0-pr-34253-d811c6c || 17.0.4 - 17.0.5 || 17.3.0-beta.1 - 22.4.0-canary.20260121-1b12e1f" |
|
||||
|moderate | ajv | "<6.14.0 || >=7.0.0-alpha.0 <8.18.0" |
|
||||
|high | axios | "1.0.0 - 1.13.4" |
|
||||
|high | body-parser | "<=1.20.3 || 2.0.0-beta.1 - 2.0.2" |
|
||||
|low | compression | "1.0.3 - 1.8.0" |
|
||||
|high | express | "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" |
|
||||
|critical | form-data | "4.0.0 - 4.0.3" |
|
||||
|high | glob | "10.2.0 - 10.4.5" |
|
||||
|moderate | js-yaml | "<3.14.2 || >=4.0.0 <4.1.1" |
|
||||
|moderate | lodash | "4.0.0 - 4.17.21" |
|
||||
|moderate | lodash-es | "4.0.0 - 4.17.22" |
|
||||
|high | minimatch | "<=3.1.2 || 5.0.0 - 5.1.6 || 9.0.0 - 9.0.5 || 10.0.0 - 10.2.0" |
|
||||
|high | node-forge | "<=1.3.1" |
|
||||
|high | nx | "<=0.0.0-pr-34253-d811c6c || 17.0.4 - 17.0.5 || 17.3.0-beta.1 - 22.4.0-canary.20260121-1b12e1f" |
|
||||
|low | on-headers | "<1.1.0" |
|
||||
|high | qs | "<=6.14.1" |
|
||||
|low | tmp | "<=0.2.3" |
|
||||
|low | webpack | "5.49.0 - 5.104.0" |
|
||||
|
||||
|
||||
Generated
+19
-13
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"name": "@alfresco/adf-cli",
|
||||
"version": "9.0.0",
|
||||
"version": "8.0.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@alfresco/adf-cli",
|
||||
"version": "9.0.0",
|
||||
"version": "8.0.2",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@alfresco/js-api": ">=9.0.0",
|
||||
"@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.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/js-api/-/js-api-9.0.0.tgz",
|
||||
"integrity": "sha512-tkVc3vCmbyp1cAJOtga/c5kApWmkj7lBmnJk0M+Jx/aek5mUQkXvDKlpPBoE0QR8UHKEKgB6HgwmaOMumYQVAw==",
|
||||
"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",
|
||||
@@ -1142,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",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@alfresco/adf-cli",
|
||||
"description": "Alfresco ADF cli and utils",
|
||||
"version": "9.0.0",
|
||||
"version": "8.0.3",
|
||||
"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.0.0",
|
||||
"@alfresco/js-api": ">=9.0.2",
|
||||
"commander": "^6.2.1",
|
||||
"ejs": "^3.1.9",
|
||||
"license-checker": "^25.0.1",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@alfresco/adf-content-services",
|
||||
"description": "Alfresco ADF content services",
|
||||
"version": "9.0.0",
|
||||
"version": "8.0.3",
|
||||
"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": ">=10.0.0",
|
||||
"@alfresco/js-api": ">=9.0.2",
|
||||
"@ngx-translate/core": ">=16.0.0",
|
||||
"@alfresco/adf-core": ">=9.0.0"
|
||||
"@alfresco/adf-core": ">=8.0.2"
|
||||
},
|
||||
"keywords": [
|
||||
"content-services",
|
||||
|
||||
@@ -156,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
|
||||
|
||||
@@ -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 },
|
||||
|
||||
+2
-2
@@ -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();
|
||||
|
||||
@@ -295,7 +295,7 @@ describe('DropdownSitesComponent', () => {
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
|
||||
+1
-1
@@ -181,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;
|
||||
}
|
||||
|
||||
+2
-2
@@ -646,7 +646,7 @@ describe('DocumentList', () => {
|
||||
title: 'FileAction'
|
||||
});
|
||||
|
||||
spyOn(authenticationService, 'getUsername').and.returnValue('lockOwner');
|
||||
spyOn(authenticationService, 'getEcmUsername').and.returnValue('lockOwner');
|
||||
|
||||
documentList.actions = [documentMenu];
|
||||
|
||||
@@ -677,7 +677,7 @@ describe('DocumentList', () => {
|
||||
title: 'FileAction'
|
||||
});
|
||||
|
||||
spyOn(authenticationService, 'getUsername').and.returnValue('jerryTheKillerCow');
|
||||
spyOn(authenticationService, 'getEcmUsername').and.returnValue('jerryTheKillerCow');
|
||||
|
||||
documentList.actions = [documentMenu];
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
+1
@@ -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"
|
||||
|
||||
-16
@@ -25,14 +25,11 @@ 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 { UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { MatCheckbox } from '@angular/material/checkbox';
|
||||
|
||||
describe('SearchCheckListComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let fixture: ComponentFixture<SearchCheckListComponent>;
|
||||
let component: SearchCheckListComponent;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -41,7 +38,6 @@ describe('SearchCheckListComponent', () => {
|
||||
fixture = TestBed.createComponent(SearchCheckListComponent);
|
||||
component = fixture.componentInstance;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
|
||||
component.context = {
|
||||
queryFragments: {},
|
||||
@@ -142,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 = unitTestingUtils.getAllByDirective(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';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@alfresco/adf-core",
|
||||
"description": "Alfresco ADF core",
|
||||
"version": "9.0.0",
|
||||
"version": "8.0.3",
|
||||
"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": ">=10.0.0",
|
||||
"@alfresco/adf-extensions": ">=9.0.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"
|
||||
|
||||
+8
-14
@@ -15,18 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { InjectionToken, Provider, Type } from '@angular/core';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { AppConfigPipe } from './app-config.pipe';
|
||||
|
||||
export const LANDING_PAGE_TOKEN = new InjectionToken<Type<any>>('LANDING_PAGE_TOKEN');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param componentClass The component class to be registered as the landing page.
|
||||
* @returns A provider that registers the landing page component class.
|
||||
*/
|
||||
export function provideLandingPage(componentClass: Type<any>): Provider {
|
||||
return {
|
||||
provide: LANDING_PAGE_TOKEN,
|
||||
useValue: componentClass
|
||||
};
|
||||
}
|
||||
/** @deprecated This module is deprecated, consider importing AppConfigPipe directly */
|
||||
@NgModule({
|
||||
imports: [AppConfigPipe],
|
||||
exports: [AppConfigPipe]
|
||||
})
|
||||
export class AppConfigModule {}
|
||||
@@ -20,4 +20,5 @@ 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';
|
||||
|
||||
@@ -317,27 +317,14 @@ export class BasicAlfrescoAuthService extends BaseAuthenticationService {
|
||||
return this.redirectUrl && (this.redirectUrl.provider === 'ALL' || provider === 'ALL');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `getUsername()` instead
|
||||
* @returns the username of the authenticated user
|
||||
*/
|
||||
getBpmUsername(): string {
|
||||
return this.processAuth.getUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `getUsername()` instead
|
||||
* @returns the username of the authenticated user
|
||||
*/
|
||||
getEcmUsername(): string {
|
||||
return this.contentAuth.getUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username of the authenticated user.
|
||||
*
|
||||
* @returns the username of the authenticated user
|
||||
*/
|
||||
getUsername(): string {
|
||||
if (this.isBPMProvider()) {
|
||||
return this.processAuth.getUsername();
|
||||
|
||||
@@ -94,7 +94,7 @@ 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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import ee from 'event-emitter';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export interface AuthenticationServiceInterface {
|
||||
|
||||
onError: any;
|
||||
onLogin: any;
|
||||
onLogout: any;
|
||||
@@ -30,26 +31,30 @@ export interface AuthenticationServiceInterface {
|
||||
emit: (type: string, ...args: any[]) => void;
|
||||
|
||||
getToken(): string;
|
||||
|
||||
isLoggedIn(): boolean;
|
||||
|
||||
isOauth(): boolean;
|
||||
|
||||
logout(): any;
|
||||
|
||||
isECMProvider(): boolean;
|
||||
isBPMProvider(): boolean;
|
||||
isALLProvider(): boolean;
|
||||
getUsername(): string;
|
||||
|
||||
getAuthHeaders(requestUrl: string, header: HttpHeaders): HttpHeaders;
|
||||
addTokenToHeader(requestUrl: string, headersArg?: HttpHeaders): Observable<HttpHeaders>;
|
||||
reset(): void;
|
||||
|
||||
/** @deprecated use `isLoggedIn` instead, use `isECMProvider` if you need to know the auth type */
|
||||
isEcmLoggedIn(): boolean;
|
||||
/** @deprecated use `isLoggedIn` instead, use `isBPMProvider` if you need to know the auth type */
|
||||
|
||||
isBpmLoggedIn(): boolean;
|
||||
|
||||
/** @deprecated use `getUsername` instead */
|
||||
isECMProvider(): boolean;
|
||||
|
||||
isBPMProvider(): boolean;
|
||||
|
||||
isALLProvider(): boolean;
|
||||
|
||||
getEcmUsername(): string;
|
||||
/** @deprecated use `getUsername` instead */
|
||||
|
||||
getBpmUsername(): string;
|
||||
|
||||
getAuthHeaders(requestUrl: string, header: HttpHeaders): HttpHeaders;
|
||||
|
||||
addTokenToHeader(requestUrl: string, headersArg?: HttpHeaders): Observable<HttpHeaders>;
|
||||
|
||||
reset(): void;
|
||||
}
|
||||
|
||||
@@ -56,10 +56,6 @@ export class OidcAuthenticationService extends BaseAuthenticationService {
|
||||
map(([authenticated, isDiscoveryDocumentLoaded]) => !authenticated && isDiscoveryDocumentLoaded)
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated use `isLoggedIn` instead
|
||||
* @returns true if the ECM provider is logged in
|
||||
*/
|
||||
isEcmLoggedIn(): boolean {
|
||||
if (this.isECMProvider() || this.isALLProvider()) {
|
||||
return this.isLoggedIn();
|
||||
@@ -67,10 +63,6 @@ export class OidcAuthenticationService extends BaseAuthenticationService {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `isLoggedIn` instead
|
||||
* @returns true if the BPM provider is logged in
|
||||
*/
|
||||
isBpmLoggedIn(): boolean {
|
||||
if (this.isBPMProvider() || this.isALLProvider()) {
|
||||
return this.isLoggedIn();
|
||||
@@ -90,6 +82,16 @@ export class OidcAuthenticationService extends BaseAuthenticationService {
|
||||
return this.oauthService.hasValidIdToken();
|
||||
}
|
||||
|
||||
isImplicitFlow() {
|
||||
const oauth2: OauthConfigModel = Object.assign({}, this.appConfig.get<OauthConfigModel>(AppConfigValues.OAUTHCONFIG, null));
|
||||
return !!oauth2?.implicitFlow;
|
||||
}
|
||||
|
||||
isAuthCodeFlow() {
|
||||
const oauth2: OauthConfigModel = Object.assign({}, this.appConfig.get<OauthConfigModel>(AppConfigValues.OAUTHCONFIG, null));
|
||||
return !!oauth2?.codeFlow;
|
||||
}
|
||||
|
||||
login(username: string, password: string): Observable<{ type: string; ticket: any }> {
|
||||
return this.auth.baseAuthLogin(username, password).pipe(
|
||||
map((response) => {
|
||||
@@ -123,17 +125,12 @@ export class OidcAuthenticationService extends BaseAuthenticationService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username of the authenticated user.
|
||||
*
|
||||
* @returns the logged username
|
||||
*/
|
||||
getUsername() {
|
||||
return this.jwtHelperService.getValueFromLocalToken<string>(JwtHelperService.USER_PREFERRED_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `getUsername` instead
|
||||
* @deprecated
|
||||
* @returns the logged username
|
||||
*/
|
||||
getEcmUsername(): string {
|
||||
@@ -141,7 +138,7 @@ export class OidcAuthenticationService extends BaseAuthenticationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `getUsername` instead
|
||||
* @deprecated
|
||||
* @returns the logged username
|
||||
*/
|
||||
getBpmUsername(): string {
|
||||
@@ -152,6 +149,10 @@ export class OidcAuthenticationService extends BaseAuthenticationService {
|
||||
this.auth.login(redirectUrl);
|
||||
}
|
||||
|
||||
ssoCodeFlowLogin() {
|
||||
this.oauthService.initCodeFlow();
|
||||
}
|
||||
|
||||
isRememberMeSet(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -116,25 +116,17 @@ export class AuthenticationService implements AuthenticationServiceInterface, ee
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `isLoggedIn` instead
|
||||
* @returns true if the ECM provider is logged in
|
||||
*/
|
||||
isEcmLoggedIn(): boolean {
|
||||
if (this.isOauth()) {
|
||||
return this.oidcAuthenticationService.isLoggedIn();
|
||||
return this.oidcAuthenticationService.isEcmLoggedIn();
|
||||
} else {
|
||||
return this.basicAlfrescoAuthService.isEcmLoggedIn();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `isLoggedIn` instead
|
||||
* @returns true if the BPM provider is logged in
|
||||
*/
|
||||
isBpmLoggedIn(): boolean {
|
||||
if (this.isOauth()) {
|
||||
return this.oidcAuthenticationService.isLoggedIn();
|
||||
return this.oidcAuthenticationService.isBpmLoggedIn();
|
||||
} else {
|
||||
return this.basicAlfrescoAuthService.isBpmLoggedIn();
|
||||
}
|
||||
@@ -157,8 +149,6 @@ export class AuthenticationService implements AuthenticationServiceInterface, ee
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username of the authenticated user.
|
||||
*
|
||||
* @returns the username of the authenticated user
|
||||
*/
|
||||
getUsername(): string {
|
||||
@@ -170,19 +160,27 @@ export class AuthenticationService implements AuthenticationServiceInterface, ee
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `getUsername` instead
|
||||
* @deprecated
|
||||
* @returns the logged username
|
||||
*/
|
||||
getEcmUsername(): string {
|
||||
return this.getUsername();
|
||||
if (this.isOauth()) {
|
||||
return this.oidcAuthenticationService.getUsername();
|
||||
} else {
|
||||
return this.basicAlfrescoAuthService.getEcmUsername();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `getUsername` instead
|
||||
* @deprecated
|
||||
* @returns the logged username
|
||||
*/
|
||||
getBpmUsername(): string {
|
||||
return this.getUsername();
|
||||
if (this.isOauth()) {
|
||||
return this.oidcAuthenticationService.getUsername();
|
||||
} else {
|
||||
return this.basicAlfrescoAuthService.getBpmUsername();
|
||||
}
|
||||
}
|
||||
|
||||
getAuthHeaders(requestUrl: string, headers: HttpHeaders): HttpHeaders {
|
||||
|
||||
@@ -40,23 +40,21 @@ export abstract class BaseAuthenticationService implements AuthenticationService
|
||||
}
|
||||
|
||||
abstract getAuthHeaders(requestUrl: string, header: HttpHeaders): HttpHeaders;
|
||||
|
||||
abstract getToken(): string;
|
||||
|
||||
abstract isLoggedIn(): boolean;
|
||||
|
||||
abstract logout(): any;
|
||||
|
||||
/** @deprecated use `isLoggedIn` instead */
|
||||
abstract isEcmLoggedIn(): boolean;
|
||||
|
||||
/** @deprecated use `isLoggedIn` instead */
|
||||
abstract isBpmLoggedIn(): boolean;
|
||||
|
||||
abstract reset(): void;
|
||||
abstract getUsername(): string;
|
||||
|
||||
/** @deprecated use `getUsername` instead */
|
||||
abstract getEcmUsername(): string;
|
||||
|
||||
/** @deprecated use `getUsername` instead */
|
||||
abstract getBpmUsername(): string;
|
||||
|
||||
/**
|
||||
@@ -112,6 +110,11 @@ export abstract class BaseAuthenticationService implements AuthenticationService
|
||||
return provider && provider.toUpperCase() === 'ALL';
|
||||
}
|
||||
|
||||
isOauthConfiguration(): boolean {
|
||||
const authType = this.appConfig.get('authType') as string;
|
||||
return authType === 'OAUTH';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints an error message in the console browser
|
||||
*
|
||||
|
||||
@@ -27,28 +27,12 @@ import { isOutcomeButtonVisible } from './helpers/buttons-visibility';
|
||||
export abstract class FormBaseComponent {
|
||||
protected _form: FormModel;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link FormModel.SAVE_OUTCOME} instead.
|
||||
*/
|
||||
static readonly SAVE_OUTCOME_ID: string = FormModel.SAVE_OUTCOME;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link FormModel.COMPLETE_OUTCOME} instead.
|
||||
*/
|
||||
static readonly COMPLETE_OUTCOME_ID: string = FormModel.COMPLETE_OUTCOME;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link FormModel.START_PROCESS_OUTCOME} instead.
|
||||
*/
|
||||
static readonly START_PROCESS_OUTCOME_ID: string = FormModel.START_PROCESS_OUTCOME;
|
||||
|
||||
static readonly CUSTOM_OUTCOME_ID: string = '$custom';
|
||||
static readonly COMPLETE_BUTTON_COLOR: ThemePalette = 'primary';
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link FormOutcomeModel.COMPLETE_ACTION} instead.
|
||||
*/
|
||||
static readonly COMPLETE_OUTCOME_NAME: string = FormOutcomeModel.COMPLETE_ACTION;
|
||||
static SAVE_OUTCOME_ID: string = '$save';
|
||||
static COMPLETE_OUTCOME_ID: string = '$complete';
|
||||
static START_PROCESS_OUTCOME_ID: string = '$startProcess';
|
||||
static CUSTOM_OUTCOME_ID: string = '$custom';
|
||||
static COMPLETE_BUTTON_COLOR: ThemePalette = 'primary';
|
||||
static COMPLETE_OUTCOME_NAME: string = 'COMPLETE';
|
||||
|
||||
/** Path of the folder where the metadata will be stored. */
|
||||
@Input()
|
||||
@@ -66,7 +50,7 @@ export abstract class FormBaseComponent {
|
||||
@Input()
|
||||
showCompleteButton: boolean = true;
|
||||
|
||||
/** If true then the `Complete` outcome button is shown, but it will be disabled. */
|
||||
/** If true then the `Complete` outcome button is shown but it will be disabled. */
|
||||
@Input()
|
||||
disableCompleteButton: boolean = false;
|
||||
|
||||
@@ -154,7 +138,7 @@ export abstract class FormBaseComponent {
|
||||
}
|
||||
|
||||
getColorForOutcome(outcomeName: string): ThemePalette {
|
||||
return outcomeName === FormOutcomeModel.COMPLETE_ACTION ? FormBaseComponent.COMPLETE_BUTTON_COLOR : null;
|
||||
return outcomeName === FormBaseComponent.COMPLETE_OUTCOME_NAME ? FormBaseComponent.COMPLETE_BUTTON_COLOR : null;
|
||||
}
|
||||
|
||||
isOutcomeButtonEnabled(outcome?: FormOutcomeModel): boolean {
|
||||
@@ -198,20 +182,20 @@ export abstract class FormBaseComponent {
|
||||
}
|
||||
|
||||
if (outcome.isSystem) {
|
||||
if (outcome.id === FormModel.SAVE_OUTCOME) {
|
||||
if (outcome.id === FormBaseComponent.SAVE_OUTCOME_ID) {
|
||||
this.disableSaveButton = true;
|
||||
this.saveTaskForm();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (outcome.id === FormModel.COMPLETE_OUTCOME) {
|
||||
if (outcome.id === FormBaseComponent.COMPLETE_OUTCOME_ID) {
|
||||
this.disableSaveButton = true;
|
||||
this.disableCompleteButton = true;
|
||||
this.completeTaskForm();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (outcome.id === FormModel.START_PROCESS_OUTCOME) {
|
||||
if (outcome.id === FormBaseComponent.START_PROCESS_OUTCOME_ID) {
|
||||
this.completeTaskForm();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
|
||||
<ng-template #render let-fieldToRender="fieldToRender">
|
||||
<div *ngFor="let currentRootElement of fieldToRender">
|
||||
<div *ngIf="currentRootElement.type === 'section'" [id]="'field-' + currentRootElement?.id + '-container'" class="adf-container-widget">
|
||||
<adf-form-section [field]="currentRootElement" />
|
||||
</div>
|
||||
|
||||
<div *ngIf="currentRootElement.type === 'container' || currentRootElement.type === 'group'"
|
||||
[id]="'field-' + currentRootElement?.id + '-container'"
|
||||
class="adf-container-widget"
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
#{ms.$mat-tab-body} {
|
||||
margin-bottom: 8em;
|
||||
|
||||
|
||||
@include flex.layout-bp(lt-md) {
|
||||
margin-bottom: 0;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,22 +66,20 @@
|
||||
display: flex;
|
||||
margin-right: -1%;
|
||||
width: 100%;
|
||||
gap: 8px;
|
||||
|
||||
&-item {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.adf-radio-buttons-widget {
|
||||
padding-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&-single-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
padding-right: 1%;
|
||||
padding-left: 1%;
|
||||
}
|
||||
|
||||
&-item {
|
||||
|
||||
@@ -1,31 +1,10 @@
|
||||
@use '../../../../../src/lib/styles/flex' as flex;
|
||||
|
||||
.adf-grid-list {
|
||||
&-section {
|
||||
&-single-column {
|
||||
display: flex;
|
||||
flex-wrap: inherit;
|
||||
align-items: baseline;
|
||||
flex-direction: column;
|
||||
gap: 1%;
|
||||
|
||||
@include flex.layout-bp(lt-md) {
|
||||
flex: 1 1 100% !important;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.adf-section-widget {
|
||||
@include flex.layout-bp(lt-md) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
@include flex.layout-bp(lt-md) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&-column-view-item {
|
||||
|
||||
@@ -16,11 +16,10 @@
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { UnitTestingUtils, NoopTranslateModule } from '../../../testing';
|
||||
import { UnitTestingUtils } from '../../../testing';
|
||||
import { FormFieldModel, FormModel } from '../widgets';
|
||||
import { FormSectionComponent } from './form-section.component';
|
||||
import { mockSectionWithFields } from '../mock/form-renderer.component.mock';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('FormSectionComponent', () => {
|
||||
let fixture: ComponentFixture<FormSectionComponent>;
|
||||
@@ -29,7 +28,7 @@ describe('FormSectionComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [FormSectionComponent, NoopTranslateModule, NoopAnimationsModule]
|
||||
imports: [FormSectionComponent]
|
||||
});
|
||||
fixture = TestBed.createComponent(FormSectionComponent);
|
||||
testingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
@@ -60,87 +59,4 @@ describe('FormSectionComponent', () => {
|
||||
const sectionFields = testingUtils.getAllByCSS('.adf-grid-list-section-column-view-item adf-form-field');
|
||||
expect(sectionFields.length).toBe(2);
|
||||
});
|
||||
|
||||
describe('getSectionColumnWidth', () => {
|
||||
it('should cap width at 100% when numberOfColumns is not a number', () => {
|
||||
const columnField = { colspan: 2 } as FormFieldModel;
|
||||
|
||||
const width = component.getSectionColumnWidth('invalid' as unknown as number, [columnField]);
|
||||
expect(width).toBe('100');
|
||||
});
|
||||
|
||||
it('should cap width at 100% when numberOfColumns is null', () => {
|
||||
const columnField = { colspan: 3 } as FormFieldModel;
|
||||
|
||||
const width = component.getSectionColumnWidth(null as unknown as number, [columnField]);
|
||||
expect(width).toBe('100');
|
||||
});
|
||||
|
||||
it('should return 100% when numberOfColumns is undefined', () => {
|
||||
const columnField = { colspan: 1 } as FormFieldModel;
|
||||
|
||||
const width = component.getSectionColumnWidth(undefined as unknown as number, [columnField]);
|
||||
expect(width).toBe('100');
|
||||
});
|
||||
|
||||
it('should cap width at 100% when numberOfColumns is 0', () => {
|
||||
const columnField = { colspan: 2 } as FormFieldModel;
|
||||
|
||||
const width = component.getSectionColumnWidth(0, [columnField]);
|
||||
expect(width).toBe('100');
|
||||
});
|
||||
|
||||
it('should cap width at 100% when numberOfColumns is negative', () => {
|
||||
const columnField = { colspan: 3 } as FormFieldModel;
|
||||
|
||||
const width = component.getSectionColumnWidth(-1, [columnField]);
|
||||
expect(width).toBe('100');
|
||||
});
|
||||
|
||||
it('should return 100 when numberOfColumns is falsy and no colspan is defined', () => {
|
||||
const columnField = {} as FormFieldModel;
|
||||
|
||||
const width = component.getSectionColumnWidth(null as unknown as number, [columnField]);
|
||||
expect(width).toBe('100');
|
||||
});
|
||||
|
||||
it('should calculate percentage width when numberOfColumns is a valid number', () => {
|
||||
const numberOfColumns = 4;
|
||||
const columnField = { colspan: 2 } as FormFieldModel;
|
||||
|
||||
const width = component.getSectionColumnWidth(numberOfColumns, [columnField]);
|
||||
expect(width).toBe('50');
|
||||
});
|
||||
|
||||
it('should cap width at 100% when colspan exceeds numberOfColumns', () => {
|
||||
const numberOfColumns = 2;
|
||||
const columnField = { colspan: 5 } as FormFieldModel;
|
||||
|
||||
const width = component.getSectionColumnWidth(numberOfColumns, [columnField]);
|
||||
expect(width).toBe('100');
|
||||
});
|
||||
|
||||
it('should use default colspan of 1 when field has no colspan and numberOfColumns is valid', () => {
|
||||
const numberOfColumns = 5;
|
||||
const columnField = {} as FormFieldModel;
|
||||
|
||||
const width = component.getSectionColumnWidth(numberOfColumns, [columnField]);
|
||||
expect(width).toBe('20');
|
||||
});
|
||||
|
||||
it('should handle empty columnFields array', () => {
|
||||
const numberOfColumns = 3;
|
||||
|
||||
const width = component.getSectionColumnWidth(numberOfColumns, []);
|
||||
expect(parseFloat(width)).toBeCloseTo(33.33);
|
||||
});
|
||||
|
||||
it('should use first field colspan when multiple fields are provided', () => {
|
||||
const numberOfColumns = 2;
|
||||
const columnFields = [{ colspan: 1 } as FormFieldModel, { colspan: 3 } as FormFieldModel];
|
||||
|
||||
const width = component.getSectionColumnWidth(numberOfColumns, columnFields);
|
||||
expect(width).toBe('50');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,10 +43,6 @@ export class FormSectionComponent implements OnInit {
|
||||
const defaultColspan = 1;
|
||||
const fieldColspan = columnFields[firstColumnFieldIndex]?.colspan ?? defaultColspan;
|
||||
|
||||
if (typeof numberOfColumns !== 'number' || !numberOfColumns || numberOfColumns <= 0) {
|
||||
numberOfColumns = 1;
|
||||
}
|
||||
|
||||
return Math.min(100, (100 / numberOfColumns) * fieldColspan) + '';
|
||||
return (100 / numberOfColumns) * fieldColspan + '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,25 @@
|
||||
}
|
||||
|
||||
&-container {
|
||||
display: grid;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
&-amount-widget__input {
|
||||
margin-top: -15px;
|
||||
|
||||
#{ms.$mat-focused} {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#{ms.$mat-form-field-prefix} {
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.adf-input {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ import { FormWidgetModel } from './form-widget.model';
|
||||
import { WidgetVisibilityModel } from '../../../models/widget-visibility.model';
|
||||
|
||||
export class FormOutcomeModel extends FormWidgetModel {
|
||||
static readonly SAVE_ACTION: string = 'SAVE'; // Activiti 'Save' action name
|
||||
static readonly COMPLETE_ACTION: string = 'COMPLETE'; // Activiti 'Complete' action name
|
||||
static readonly START_PROCESS_ACTION: string = 'START PROCESS'; // Activiti 'Start Process' action name
|
||||
static SAVE_ACTION: string = 'SAVE'; // Activiti 'Save' action name
|
||||
static COMPLETE_ACTION: string = 'COMPLETE'; // Activiti 'Complete' action name
|
||||
static START_PROCESS_ACTION: string = 'START PROCESS'; // Activiti 'Start Process' action name
|
||||
|
||||
isSystem: boolean = false;
|
||||
isSelected: boolean = false;
|
||||
|
||||
@@ -708,103 +708,5 @@ describe('FormModel', () => {
|
||||
expect(fields[1].type).toBe(FormFieldTypes.DATE);
|
||||
expect(fields[2].type).toBe(FormFieldTypes.NUMBER);
|
||||
});
|
||||
|
||||
it('should handle sections at root level correctly', () => {
|
||||
const mockFormWithRootSection = {
|
||||
id: 'test-form',
|
||||
name: 'Test Form',
|
||||
fields: [
|
||||
{
|
||||
id: 'root-section',
|
||||
name: 'Root Section',
|
||||
type: 'section',
|
||||
numberOfColumns: 2,
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
id: 'text-in-root-section',
|
||||
name: 'Text in Root Section',
|
||||
type: 'text',
|
||||
required: false,
|
||||
readOnly: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const formWithRootSection = new FormModel(mockFormWithRootSection);
|
||||
|
||||
// Check that the root section is parsed correctly - wrapped in ContainerModel as expected
|
||||
expect(formWithRootSection.fields.length).toBe(1);
|
||||
expect(formWithRootSection.fields[0]).toBeInstanceOf(ContainerModel);
|
||||
expect(formWithRootSection.fields[0].field.type).toBe('section');
|
||||
expect(formWithRootSection.fields[0].field.id).toBe('root-section');
|
||||
|
||||
// Check that getFormFields returns all fields including the section and its children
|
||||
const allFields = formWithRootSection.getFormFields();
|
||||
expect(allFields.length).toBe(2); // section + text field inside
|
||||
expect(allFields[0].type).toBe('section');
|
||||
expect(allFields[1].type).toBe('text');
|
||||
expect(allFields[1].id).toBe('text-in-root-section');
|
||||
});
|
||||
|
||||
it('should process container fields before section fields in getFormFields', () => {
|
||||
const mockFormWithContainerAndSection = {
|
||||
id: 'test-form',
|
||||
name: 'Test Form',
|
||||
fields: [
|
||||
{
|
||||
id: 'container-field',
|
||||
name: 'Container Field',
|
||||
type: 'container',
|
||||
numberOfColumns: 2,
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
id: 'text-in-container',
|
||||
name: 'Text in Container',
|
||||
type: 'text',
|
||||
required: false,
|
||||
readOnly: false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'section-field',
|
||||
name: 'Section Field',
|
||||
type: 'section',
|
||||
numberOfColumns: 1,
|
||||
fields: {
|
||||
1: [
|
||||
{
|
||||
id: 'text-in-section',
|
||||
name: 'Text in Section',
|
||||
type: 'text',
|
||||
required: false,
|
||||
readOnly: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const formWithMixed = new FormModel(mockFormWithContainerAndSection);
|
||||
const allFields = formWithMixed.getFormFields();
|
||||
|
||||
// Check that the following order is correct: container, text-in-container, section, text-in-section
|
||||
expect(allFields.length).toBe(4);
|
||||
expect(allFields[0].type).toBe('container');
|
||||
expect(allFields[0].id).toBe('container-field');
|
||||
expect(allFields[1].type).toBe('text');
|
||||
expect(allFields[1].id).toBe('text-in-container');
|
||||
expect(allFields[2].type).toBe('section');
|
||||
expect(allFields[2].id).toBe('section-field');
|
||||
expect(allFields[3].type).toBe('text');
|
||||
expect(allFields[3].id).toBe('text-in-section');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -62,10 +62,10 @@ export interface FormRepresentationModel {
|
||||
theme?: ThemeModel;
|
||||
}
|
||||
export class FormModel implements ProcessFormModel {
|
||||
static readonly UNSET_TASK_NAME: string = 'Nameless task';
|
||||
static readonly SAVE_OUTCOME: string = '$save';
|
||||
static readonly COMPLETE_OUTCOME: string = '$complete';
|
||||
static readonly START_PROCESS_OUTCOME: string = '$startProcess';
|
||||
static UNSET_TASK_NAME: string = 'Nameless task';
|
||||
static SAVE_OUTCOME: string = '$save';
|
||||
static COMPLETE_OUTCOME: string = '$complete';
|
||||
static START_PROCESS_OUTCOME: string = '$startProcess';
|
||||
|
||||
readonly id: string | number;
|
||||
readonly name: string;
|
||||
@@ -201,7 +201,7 @@ export class FormModel implements ProcessFormModel {
|
||||
this.validateForm();
|
||||
}
|
||||
|
||||
// Activiti supports 4 types of root fields: container|group|dynamic-table|section
|
||||
// Activiti supports 3 types of root fields: container|group|dynamic-table
|
||||
private parseRootFields(json: any): (ContainerModel | FormFieldModel)[] {
|
||||
let fields = [];
|
||||
|
||||
@@ -354,10 +354,10 @@ export class FormModel implements ProcessFormModel {
|
||||
|
||||
private processFields(fields: (ContainerModel | FormFieldModel)[], formFieldModel: FormFieldModel[]): void {
|
||||
fields.forEach((field) => {
|
||||
if (this.isContainerField(field)) {
|
||||
this.handleContainerField(field, formFieldModel);
|
||||
} else if (this.isSectionField(field)) {
|
||||
if (this.isSectionField(field)) {
|
||||
this.handleSectionField(field, formFieldModel);
|
||||
} else if (this.isContainerField(field)) {
|
||||
this.handleContainerField(field, formFieldModel);
|
||||
} else if (this.isFormField(field)) {
|
||||
this.handleSingleField(field, formFieldModel);
|
||||
}
|
||||
@@ -410,28 +410,27 @@ export class FormModel implements ProcessFormModel {
|
||||
}
|
||||
|
||||
protected parseOutcomes() {
|
||||
if (!this.json.fields) return;
|
||||
if (this.json.fields) {
|
||||
const saveOutcome = new FormOutcomeModel(this, {
|
||||
id: FormModel.SAVE_OUTCOME,
|
||||
name: 'SAVE',
|
||||
isSystem: true
|
||||
});
|
||||
const completeOutcome = new FormOutcomeModel(this, {
|
||||
id: FormModel.COMPLETE_OUTCOME,
|
||||
name: 'COMPLETE',
|
||||
isSystem: true
|
||||
});
|
||||
const startProcessOutcome = new FormOutcomeModel(this, {
|
||||
id: FormModel.START_PROCESS_OUTCOME,
|
||||
name: 'START PROCESS',
|
||||
isSystem: true
|
||||
});
|
||||
|
||||
const saveOutcome = new FormOutcomeModel(this, {
|
||||
id: FormModel.SAVE_OUTCOME,
|
||||
name: FormOutcomeModel.SAVE_ACTION,
|
||||
isSystem: true
|
||||
});
|
||||
const customOutcomes = (this.json.outcomes || []).map((obj) => new FormOutcomeModel(this, obj));
|
||||
|
||||
const completeOutcome = new FormOutcomeModel(this, {
|
||||
id: FormModel.COMPLETE_OUTCOME,
|
||||
name: FormOutcomeModel.COMPLETE_ACTION,
|
||||
isSystem: true
|
||||
});
|
||||
|
||||
const startProcessOutcome = new FormOutcomeModel(this, {
|
||||
id: FormModel.START_PROCESS_OUTCOME,
|
||||
name: FormOutcomeModel.START_PROCESS_ACTION,
|
||||
isSystem: true
|
||||
});
|
||||
|
||||
const customOutcomes = (this.json.outcomes ?? ([] as FormModel[])).map((formModel: FormModel) => new FormOutcomeModel(this, formModel));
|
||||
this.outcomes = [saveOutcome].concat(customOutcomes.length > 0 ? customOutcomes : [completeOutcome, startProcessOutcome]);
|
||||
this.outcomes = [saveOutcome].concat(customOutcomes.length > 0 ? customOutcomes : [completeOutcome, startProcessOutcome]);
|
||||
}
|
||||
}
|
||||
|
||||
addValuesNotPresent(valuesToSetIfNotPresent: FormValues) {
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
.adf {
|
||||
&-date-time-widget {
|
||||
&-container {
|
||||
display: grid;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#{ms.$mat-form-field-suffix} {
|
||||
|
||||
@@ -5,6 +5,4 @@
|
||||
color: var(--adf-readonly-text-color, var(--adf-form-label-color, var(--theme-text-color)));
|
||||
line-height: normal;
|
||||
word-break: break-word;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
@@ -74,11 +74,6 @@ export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('blur')
|
||||
onBlur() {
|
||||
this._onTouched();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['inputMask']?.currentValue['mask']) {
|
||||
this.inputMask = changes['inputMask'].currentValue;
|
||||
|
||||
@@ -81,7 +81,7 @@ export class FormService implements FormValidationService {
|
||||
if (!json.fields) {
|
||||
form.outcomes = [
|
||||
new FormOutcomeModel(form, {
|
||||
id: FormModel.SAVE_OUTCOME,
|
||||
id: '$save',
|
||||
name: FormOutcomeModel.SAVE_ACTION,
|
||||
isSystem: true
|
||||
})
|
||||
|
||||
@@ -453,7 +453,7 @@
|
||||
"RESET": "Resetuj",
|
||||
"THUMBNAILS": "Miniatura dokumentu",
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Zamknij panel miniatur",
|
||||
"LOADING": "Wczytywanie dokumentu"
|
||||
"LOADING": "Document is loading"
|
||||
},
|
||||
"PAGE_LABEL": {
|
||||
"SHOWING": "Wyświetlanie",
|
||||
|
||||
@@ -75,10 +75,6 @@ export class UnitTestingUtils {
|
||||
return this.debugElement.query(By.directive(directive));
|
||||
}
|
||||
|
||||
getAllByDirective(directive: Type<any>): DebugElement[] {
|
||||
return this.debugElement.queryAll(By.directive(directive));
|
||||
}
|
||||
|
||||
/** Perform actions */
|
||||
|
||||
clickByCSS(selector: string): void {
|
||||
|
||||
@@ -17,19 +17,34 @@
|
||||
|
||||
export default {
|
||||
GlobalWorkerOptions: {},
|
||||
getDocument() {
|
||||
return {
|
||||
loadingTask: () => ({
|
||||
destroy: () => Promise.resolve()
|
||||
}),
|
||||
promise: new Promise((resolve) => {
|
||||
resolve({
|
||||
numPages: 6,
|
||||
getPage: () => 'fakePage'
|
||||
});
|
||||
})
|
||||
};
|
||||
},
|
||||
getDocument: jasmine.createSpy('getDocument').and.callFake(() => ({
|
||||
loadingTask: () => ({
|
||||
destroy: () => Promise.resolve()
|
||||
}),
|
||||
promise: new Promise((resolve) => {
|
||||
resolve({
|
||||
numPages: 6,
|
||||
getPage: () =>
|
||||
Promise.resolve({
|
||||
getAnnotations: () => [
|
||||
{
|
||||
subtype: 'Text',
|
||||
name: 'NoIcon',
|
||||
id: 'R13',
|
||||
titleObj: {
|
||||
str: 'Annotation title'
|
||||
},
|
||||
contentsObj: {
|
||||
str: 'Annotation contents'
|
||||
},
|
||||
modificationDate: "D:20260202104106Z00'00",
|
||||
popupRef: 'R1'
|
||||
}
|
||||
]
|
||||
})
|
||||
});
|
||||
})
|
||||
})),
|
||||
PasswordResponses: {
|
||||
NEED_PASSWORD: 1,
|
||||
INCORRECT_PASSWORD: 2
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
import { FocusableOption } from '@angular/cdk/a11y';
|
||||
import { AsyncPipe, NgIf } from '@angular/common';
|
||||
import { Component, ElementRef, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, ElementRef, Input, OnInit, ViewEncapsulation, inject } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
|
||||
@@ -29,13 +29,14 @@ import { TranslatePipe } from '@ngx-translate/core';
|
||||
host: { tabindex: '0' }
|
||||
})
|
||||
export class PdfThumbComponent implements OnInit, FocusableOption {
|
||||
private readonly sanitizer = inject(DomSanitizer);
|
||||
private readonly element = inject(ElementRef);
|
||||
|
||||
@Input()
|
||||
page: any = null;
|
||||
page: any;
|
||||
|
||||
image$: Promise<string>;
|
||||
|
||||
constructor(private sanitizer: DomSanitizer, private element: ElementRef) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.image$ = this.page.getPage().then((page) => this.getThumb(page));
|
||||
}
|
||||
|
||||
+8
-6
@@ -2,10 +2,12 @@
|
||||
data-automation-id='adf-thumbnails-content'
|
||||
[style.height.px]="virtualHeight"
|
||||
[style.transform]="'translate(-50%, ' + translateY + 'px)'">
|
||||
<adf-pdf-thumb *ngFor="let page of renderItems; trackBy: trackByFn"
|
||||
class="adf-pdf-thumbnails__thumb"
|
||||
[id]="page.id"
|
||||
[ngClass]="{'adf-pdf-thumbnails__thumb--selected' : isSelected(page.id)}"
|
||||
[page]="page"
|
||||
(click)="goTo(page.id)" />
|
||||
@for (page of renderItems; track page.id) {
|
||||
<adf-pdf-thumb
|
||||
class="adf-pdf-thumbnails__thumb"
|
||||
[id]="page.id"
|
||||
[ngClass]="{'adf-pdf-thumbnails__thumb--selected' : isSelected(page.id)}"
|
||||
[page]="page"
|
||||
(click)="goTo(page.id)" />
|
||||
}
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ describe('PdfThumbListComponent', () => {
|
||||
fixture = TestBed.createComponent(PdfThumbListComponent);
|
||||
testingUtils = new UnitTestingUtils(fixture.debugElement);
|
||||
component = fixture.componentInstance;
|
||||
component.pdfViewer = viewerMock;
|
||||
component.pdfViewer = viewerMock as any;
|
||||
|
||||
// provide scrollable container
|
||||
fixture.nativeElement.style.display = 'block';
|
||||
|
||||
+13
-16
@@ -17,7 +17,7 @@
|
||||
|
||||
import { FocusKeyManager } from '@angular/cdk/a11y';
|
||||
import { DOWN_ARROW, ESCAPE, TAB, UP_ARROW } from '@angular/cdk/keycodes';
|
||||
import { DOCUMENT, NgClass, NgForOf } from '@angular/common';
|
||||
import { DOCUMENT, NgClass } from '@angular/common';
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
Inject,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
@@ -33,7 +32,8 @@ import {
|
||||
QueryList,
|
||||
TemplateRef,
|
||||
ViewChildren,
|
||||
ViewEncapsulation
|
||||
ViewEncapsulation,
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import { delay } from 'rxjs/operators';
|
||||
import { PdfThumbComponent } from '../pdf-viewer-thumb/pdf-viewer-thumb.component';
|
||||
@@ -43,10 +43,13 @@ import { PdfThumbComponent } from '../pdf-viewer-thumb/pdf-viewer-thumb.componen
|
||||
templateUrl: './pdf-viewer-thumbnails.component.html',
|
||||
styleUrls: ['./pdf-viewer-thumbnails.component.scss'],
|
||||
host: { class: 'adf-pdf-thumbnails' },
|
||||
imports: [PdfThumbComponent, NgClass, NgForOf],
|
||||
imports: [PdfThumbComponent, NgClass],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
private readonly element = inject(ElementRef);
|
||||
private readonly document = inject(DOCUMENT);
|
||||
|
||||
@Input({ required: true }) pdfViewer: any;
|
||||
|
||||
@Output()
|
||||
@@ -54,12 +57,12 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
virtualHeight: number = 0;
|
||||
translateY: number = 0;
|
||||
renderItems = [];
|
||||
renderItems: any[] = [];
|
||||
width: number = 91;
|
||||
currentHeight: number = 0;
|
||||
|
||||
private items = [];
|
||||
private margin: number = 15;
|
||||
private items: any[] = [];
|
||||
private readonly margin: number = 15;
|
||||
private itemHeight: number = 114 + this.margin;
|
||||
private previouslyFocusedElement: HTMLElement | null = null;
|
||||
private keyManager: FocusKeyManager<PdfThumbComponent>;
|
||||
@@ -103,12 +106,10 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.calculateItems();
|
||||
}
|
||||
|
||||
constructor(private element: ElementRef, @Inject(DOCUMENT) private document: any) {
|
||||
ngOnInit() {
|
||||
this.calculateItems = this.calculateItems.bind(this);
|
||||
this.onPageChange = this.onPageChange.bind(this);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
/* cspell:disable-next-line */
|
||||
this.pdfViewer.eventBus.on('pagechanging', this.onPageChange);
|
||||
this.element.nativeElement.addEventListener('scroll', this.calculateItems, true);
|
||||
@@ -142,10 +143,6 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
trackByFn(_: number, item: any): number {
|
||||
return item.id;
|
||||
}
|
||||
|
||||
isSelected(pageNumber: number) {
|
||||
return this.pdfViewer.currentPageNumber === pageNumber;
|
||||
}
|
||||
@@ -168,7 +165,7 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
getPages() {
|
||||
getPages(): any[] {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
return this.pdfViewer._pages.map((page) => ({
|
||||
id: page.id,
|
||||
@@ -219,7 +216,7 @@ export class PdfThumbListComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
};
|
||||
}
|
||||
|
||||
private onPageChange(event) {
|
||||
private onPageChange(event: any) {
|
||||
const index = this.renderItems.findIndex((element) => element.id === event.pageNumber);
|
||||
|
||||
if (index < 0) {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { LEFT_ARROW, RIGHT_ARROW } from '@angular/cdk/keycodes';
|
||||
import { Component, SimpleChange, ViewChild } from '@angular/core';
|
||||
import { Component, SimpleChange, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { By } from '@angular/platform-browser';
|
||||
@@ -326,7 +326,7 @@ describe('Test PdfViewer component', () => {
|
||||
() =>
|
||||
({
|
||||
afterClosed: () => of('')
|
||||
} as any)
|
||||
}) as any
|
||||
);
|
||||
|
||||
spyOn(componentUrlTestPasswordComponent.pdfViewerComponent.close, 'emit');
|
||||
@@ -510,6 +510,21 @@ describe('Test PdfViewer - User interaction', () => {
|
||||
expect(component.displayPage).toBe(2);
|
||||
});
|
||||
|
||||
it('should configure PDF.js with the correct wasmUrl', () => {
|
||||
const changes: SimpleChanges = {
|
||||
blobFile: new SimpleChange(null, component.blobFile, true)
|
||||
};
|
||||
|
||||
component.ngOnChanges(changes);
|
||||
|
||||
const getDocumentSpy = pdfjsLibMock.getDocument;
|
||||
|
||||
expect(getDocumentSpy).toHaveBeenCalled();
|
||||
const loadingArgs = getDocumentSpy.calls.mostRecent().args[0];
|
||||
|
||||
expect(loadingArgs.wasmUrl).toBe('./wasm/');
|
||||
});
|
||||
|
||||
describe('Zoom', () => {
|
||||
it('should zoom in increment the scale value', () => {
|
||||
const zoomBefore = component.pdfViewer.currentScaleValue;
|
||||
|
||||
@@ -147,7 +147,8 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
||||
disableAutoFetch: true,
|
||||
disableStream: true,
|
||||
cMapUrl: './cmaps/',
|
||||
cMapPacked: true
|
||||
cMapPacked: true,
|
||||
wasmUrl: './wasm/'
|
||||
};
|
||||
private pdfjsWorkerDestroy$ = new Subject<boolean>();
|
||||
|
||||
|
||||
@@ -1,118 +1,110 @@
|
||||
@if (isLoading) {
|
||||
<div class="adf-viewer-render-main-loader">
|
||||
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
|
||||
<div class="adf-viewer-render-content-container">
|
||||
<div class="adf-viewer-render__loading-screen">
|
||||
<h2 id="loading-spinner-label">{{ 'ADF_VIEWER.LOADING' | translate }}</h2>
|
||||
<div>
|
||||
<mat-spinner aria-labelledby="loading-spinner-label" class="adf-viewer-render__loading-screen__spinner" />
|
||||
</div>
|
||||
<div *ngIf="isLoading" class="adf-viewer-render-main-loader">
|
||||
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
|
||||
<div class="adf-viewer-render-content-container">
|
||||
<div class="adf-viewer-render__loading-screen">
|
||||
<h2 id="loading-spinner-label">{{ 'ADF_VIEWER.LOADING' | translate }}</h2>
|
||||
<div>
|
||||
<mat-spinner aria-labelledby="loading-spinner-label"
|
||||
class="adf-viewer-render__loading-screen__spinner" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (urlFile || blobFile) {
|
||||
<div [style.visibility]="isLoading ? 'hidden' : 'visible'" class="adf-viewer-render-main">
|
||||
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
|
||||
<div class="adf-viewer-render-content-container">
|
||||
@switch (viewerType) {
|
||||
@case ('external') {
|
||||
@if (!!externalViewer) {
|
||||
<adf-preview-extension
|
||||
[id]="externalViewer.component"
|
||||
[url]="urlFile"
|
||||
[extension]="externalViewer.fileExtension"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="externalViewer.component"
|
||||
(contentLoaded)="markAsLoaded()"
|
||||
<div class="adf-viewer-render-content-container" [ngSwitch]="viewerType">
|
||||
<ng-container *ngSwitchCase="'external'">
|
||||
<adf-preview-extension
|
||||
*ngIf="!!externalViewer"
|
||||
[id]="externalViewer.component"
|
||||
[url]="urlFile"
|
||||
[extension]="externalViewer.fileExtension"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="externalViewer.component"
|
||||
(contentLoaded)="markAsLoaded()"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'pdf'">
|
||||
<adf-pdf-viewer
|
||||
[thumbnailsTemplate]="thumbnailsTemplate"
|
||||
[allowThumbnails]="allowThumbnails"
|
||||
[blobFile]="blobFile"
|
||||
[urlFile]="urlFile"
|
||||
[fileName]="internalFileName"
|
||||
[cacheType]="cacheTypeForContent"
|
||||
(pagesLoaded)="markAsLoaded()"
|
||||
(close)="onClose()"
|
||||
(error)="onUnsupportedFile()"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'image'">
|
||||
<adf-img-viewer
|
||||
[urlFile]="urlFile"
|
||||
[readOnly]="readOnly"
|
||||
[fileName]="internalFileName"
|
||||
[allowedEditActions]="allowedEditActions"
|
||||
[blobFile]="blobFile"
|
||||
(error)="onUnsupportedFile()"
|
||||
(submit)="onSubmitFile($event)"
|
||||
(imageLoaded)="markAsLoaded()"
|
||||
(isSaving)="isSaving.emit($event)"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'media'">
|
||||
<adf-media-player
|
||||
id="adf-mdedia-player"
|
||||
[urlFile]="urlFile"
|
||||
[tracks]="tracks"
|
||||
[mimeType]="mimeType"
|
||||
[blobFile]="blobFile"
|
||||
[fileName]="internalFileName"
|
||||
(error)="onUnsupportedFile()"
|
||||
(canPlay)="markAsLoaded()"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'text'">
|
||||
<adf-txt-viewer [urlFile]="urlFile" [blobFile]="blobFile" (contentLoaded)="markAsLoaded()" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'custom'">
|
||||
<ng-container *ngFor="let ext of viewerExtensions">
|
||||
<adf-preview-extension
|
||||
*ngIf="checkExtensions(ext.fileExtension)"
|
||||
[id]="ext.component"
|
||||
[url]="urlFile"
|
||||
[extension]="extension"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="ext.component"
|
||||
(contentLoaded)="markAsLoaded()"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let extensionTemplate of extensionTemplates">
|
||||
<span *ngIf="extensionTemplate.isVisible" class="adf-viewer-render-custom-content">
|
||||
<ng-template
|
||||
[ngTemplateOutlet]="extensionTemplate.template"
|
||||
[ngTemplateOutletContext]="{ urlFile: urlFile, extension: extension, markAsLoaded: markAsLoaded.bind(this) }"
|
||||
/>
|
||||
}
|
||||
}
|
||||
</span>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
@case ('pdf') {
|
||||
<adf-pdf-viewer
|
||||
[thumbnailsTemplate]="thumbnailsTemplate"
|
||||
[allowThumbnails]="allowThumbnails"
|
||||
[blobFile]="blobFile"
|
||||
[urlFile]="urlFile"
|
||||
[fileName]="internalFileName"
|
||||
[cacheType]="cacheTypeForContent"
|
||||
(pagesLoaded)="markAsLoaded()"
|
||||
(close)="onClose()"
|
||||
(error)="onUnsupportedFile()"
|
||||
/>
|
||||
}
|
||||
|
||||
@case ('image') {
|
||||
<adf-img-viewer
|
||||
[urlFile]="urlFile"
|
||||
[readOnly]="readOnly"
|
||||
[fileName]="internalFileName"
|
||||
[allowedEditActions]="allowedEditActions"
|
||||
[blobFile]="blobFile"
|
||||
(error)="onUnsupportedFile()"
|
||||
(submit)="onSubmitFile($event)"
|
||||
(imageLoaded)="markAsLoaded()"
|
||||
(isSaving)="isSaving.emit($event)"
|
||||
/>
|
||||
}
|
||||
|
||||
@case ('media') {
|
||||
<adf-media-player
|
||||
id="adf-mdedia-player"
|
||||
[urlFile]="urlFile"
|
||||
[tracks]="tracks"
|
||||
[mimeType]="mimeType"
|
||||
[blobFile]="blobFile"
|
||||
[fileName]="internalFileName"
|
||||
(error)="onUnsupportedFile()"
|
||||
(canPlay)="markAsLoaded()"
|
||||
/>
|
||||
}
|
||||
|
||||
@case ('text') {
|
||||
<adf-txt-viewer [urlFile]="urlFile" [blobFile]="blobFile" (contentLoaded)="markAsLoaded()" />
|
||||
}
|
||||
|
||||
@case ('custom') {
|
||||
@for (ext of viewerExtensions; track ext.id) {
|
||||
@if (checkExtensions(ext.fileExtension)) {
|
||||
<adf-preview-extension
|
||||
[id]="ext.component"
|
||||
[url]="urlFile"
|
||||
[extension]="extension"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="ext.component"
|
||||
(contentLoaded)="markAsLoaded()"
|
||||
/>
|
||||
}
|
||||
}
|
||||
|
||||
<ng-container *ngFor="let extensionTemplate of extensionTemplates">
|
||||
@if (extensionTemplate.isVisible) {
|
||||
<span class="adf-viewer-render-custom-content">
|
||||
<ng-template
|
||||
[ngTemplateOutlet]="extensionTemplate.template"
|
||||
[ngTemplateOutletContext]="{ urlFile: urlFile, extension: extension, markAsLoaded: markAsLoaded.bind(this) }"
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
@default {
|
||||
<adf-viewer-unknown-format [customError]="customError" />
|
||||
}
|
||||
}
|
||||
<ng-container *ngSwitchDefault>
|
||||
<adf-viewer-unknown-format [customError]="customError" />
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (viewerTemplateExtensions) {
|
||||
<ng-container *ngIf="viewerTemplateExtensions">
|
||||
<ng-template [ngTemplateOutlet]="viewerTemplateExtensions"
|
||||
[ngTemplateOutletContext]="{ urlFile: urlFile, extension: extension, markAsLoaded: markAsLoaded.bind(this) }"
|
||||
[ngTemplateOutletInjector]="injector" />
|
||||
}
|
||||
</ng-container>
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AppExtensionService, ExtensionsModule, ViewerExtensionRef, PreviewExtensionComponent } from '@alfresco/adf-extensions';
|
||||
import { NgForOf, NgTemplateOutlet } from '@angular/common';
|
||||
import { AppExtensionService, ExtensionsModule, ViewerExtensionRef } from '@alfresco/adf-extensions';
|
||||
import { NgForOf, NgIf, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet } from '@angular/common';
|
||||
import { Component, EventEmitter, Injector, Input, OnChanges, OnInit, Output, TemplateRef, ViewEncapsulation } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
@@ -38,6 +38,9 @@ import { UnknownFormatComponent } from '../unknown-format/unknown-format.compone
|
||||
imports: [
|
||||
TranslatePipe,
|
||||
MatProgressSpinnerModule,
|
||||
NgSwitch,
|
||||
NgSwitchCase,
|
||||
NgIf,
|
||||
PdfViewerComponent,
|
||||
ImgViewerComponent,
|
||||
MediaPlayerComponent,
|
||||
@@ -46,7 +49,7 @@ import { UnknownFormatComponent } from '../unknown-format/unknown-format.compone
|
||||
UnknownFormatComponent,
|
||||
ExtensionsModule,
|
||||
NgForOf,
|
||||
PreviewExtensionComponent
|
||||
NgSwitchDefault
|
||||
],
|
||||
providers: [ViewUtilService]
|
||||
})
|
||||
|
||||
@@ -46,20 +46,11 @@
|
||||
[alt]="'ADF_VIEWER.ARIA.MIME_TYPE_ICON' | translate"
|
||||
[src]="mimeTypeIconUrl"
|
||||
data-automation-id="adf-file-thumbnail">
|
||||
@if (displayTitle) {
|
||||
<div class="adf-viewer__title-display-name-container"
|
||||
id="adf-viewer-title-display-name"
|
||||
[title]="displayTitle">
|
||||
<p class="adf-viewer__title-value">{{ displayTitle }}</p>
|
||||
<p class="adf-viewer__display-name-value">{{ displayName }}</p>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="adf-viewer__display-name"
|
||||
id="adf-viewer-display-name"
|
||||
[title]="fileName">
|
||||
<span>{{ displayName }}</span>
|
||||
</div>
|
||||
}
|
||||
<div class="adf-viewer__display-name"
|
||||
id="adf-viewer-display-name"
|
||||
[title]="fileName">
|
||||
<span>{{ displayName }}</span>
|
||||
</div>
|
||||
<button *ngIf="allowNavigate && canNavigateNext"
|
||||
data-automation-id="adf-toolbar-next-file"
|
||||
mat-icon-button
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__title-display-name-container,
|
||||
&__display-name {
|
||||
font-size: var(--theme-subheading-2-font-size);
|
||||
line-height: 1.5;
|
||||
@@ -62,17 +61,6 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__display-name-value,
|
||||
&__title-value {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__display-name-value {
|
||||
font-size: var(--theme-body-1-font-size);
|
||||
}
|
||||
|
||||
&-container {
|
||||
.adf-viewer-layout-content {
|
||||
@extend .adf-full-screen;
|
||||
|
||||
@@ -51,7 +51,6 @@ describe('ViewerComponent', () => {
|
||||
let testingUtils: UnitTestingUtils;
|
||||
|
||||
const getFileName = (): string => testingUtils.getByCSS('#adf-viewer-display-name').nativeElement.textContent;
|
||||
const getTitle = (): string => testingUtils.getByCSS('.adf-viewer__title-value')?.nativeElement?.textContent;
|
||||
const getDividers = (): DebugElement[] => testingUtils.getAllByCSS('.adf-toolbar-divider');
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -141,25 +140,25 @@ describe('ViewerComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Display values Tests', () => {
|
||||
describe('getDisplayTruncatedValue method', () => {
|
||||
describe('File Name Display Tests', () => {
|
||||
describe('displayFileName method', () => {
|
||||
it('should return full filename when total length is 80 characters or less', () => {
|
||||
const fileShortName = 'shortname.txt';
|
||||
component.fileName = fileShortName;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.getDisplayTruncatedValue(fileShortName)).toBe(fileShortName);
|
||||
expect(component.getDisplayFileName()).toBe(fileShortName);
|
||||
expect(getFileName()).toBe(fileShortName);
|
||||
});
|
||||
|
||||
it('should truncate filename when total length exceeds 50 characters', () => {
|
||||
it('should truncate filename when total length exceeds 80 characters', () => {
|
||||
const longName =
|
||||
'verylongfilenamethatexceedsmaximumlengthallowedverylongfilenamethatexceedsmaximumlengthallowed.verylongextensionnamethatistoolongverylongextensionnamethatistoolong';
|
||||
|
||||
component.fileName = longName;
|
||||
fixture.detectChanges();
|
||||
|
||||
const result = component.getDisplayTruncatedValue(longName);
|
||||
const result = component.getDisplayFileName();
|
||||
|
||||
expect(result).toContain('.....');
|
||||
expect(result.length).toBe(50);
|
||||
@@ -169,7 +168,7 @@ describe('ViewerComponent', () => {
|
||||
component.fileName = '';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.getDisplayTruncatedValue('')).toBe('');
|
||||
expect(component.getDisplayFileName()).toBe('');
|
||||
expect(getFileName()).toBe('');
|
||||
});
|
||||
});
|
||||
@@ -199,37 +198,6 @@ describe('ViewerComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('displayTitle', () => {
|
||||
it('should return full title when total length is 50 characters or less', () => {
|
||||
const titleShortName = 'Custom mock title';
|
||||
component.title = titleShortName;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.getDisplayTruncatedValue(titleShortName)).toBe(titleShortName);
|
||||
expect(getTitle()).toBe(titleShortName);
|
||||
});
|
||||
|
||||
it('should truncate title when total length exceeds 50 characters', () => {
|
||||
const longTitle =
|
||||
'verylongTitlethatexceedsmaximumlengthallowedverylongTitlethatexceedsmaximumlengthallowedverylongTitlethatexceedsmaximumlengthallowed';
|
||||
|
||||
component.title = longTitle;
|
||||
fixture.detectChanges();
|
||||
|
||||
const result = component.getDisplayTruncatedValue(longTitle);
|
||||
|
||||
expect(result).toContain('.....');
|
||||
expect(result.length).toBe(50);
|
||||
});
|
||||
|
||||
it('should handle empty title', () => {
|
||||
component.title = undefined;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getTitle()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Viewer Example Component Rendering', () => {
|
||||
it('should use custom toolbar', (done) => {
|
||||
const customFixture = TestBed.createComponent(ViewerWithCustomToolbarComponent);
|
||||
|
||||
@@ -307,27 +307,19 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
||||
private _fileExtension: string;
|
||||
|
||||
public displayName: string;
|
||||
public displayTitle: string;
|
||||
public downloadPromptTimer: number;
|
||||
public downloadPromptReminderTimer: number;
|
||||
public mimeTypeIconUrl: string;
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
/** Override Content title. */
|
||||
@Input()
|
||||
set title(title: string) {
|
||||
this.displayTitle = title ? this.getDisplayTruncatedValue(title) : '';
|
||||
}
|
||||
|
||||
/** Override Content filename. */
|
||||
@Input()
|
||||
set fileName(fileName: string) {
|
||||
this._fileName = fileName;
|
||||
this._fileExtension = this.viewUtilsService.getFileExtension(this.fileName);
|
||||
this._fileNameWithoutExtension = this.fileName?.replace(new RegExp(`${this.fileExtension}$`), '') || '';
|
||||
const value = (this.fileNameWithoutExtension || '') + (this.fileExtension || '');
|
||||
this.displayName = this.getDisplayTruncatedValue(value);
|
||||
this.displayName = this.getDisplayFileName();
|
||||
}
|
||||
|
||||
get fileName(): string {
|
||||
@@ -481,11 +473,12 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
||||
this.clearDownloadPromptTimeouts();
|
||||
}
|
||||
|
||||
getDisplayTruncatedValue(value: string): string {
|
||||
getDisplayFileName(): string {
|
||||
const fullName = (this.fileNameWithoutExtension || '') + (this.fileExtension || '');
|
||||
const maxLength = 50;
|
||||
|
||||
if (value.length <= maxLength) {
|
||||
return value;
|
||||
if (fullName.length <= maxLength) {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
const amountOfTruncateDots = 5;
|
||||
@@ -493,8 +486,8 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
||||
const endLength = 8;
|
||||
const startLength = availableSpace - endLength;
|
||||
|
||||
const start = value.substring(0, startLength);
|
||||
const end = value.substring(value.length - endLength);
|
||||
const start = fullName.substring(0, startLength);
|
||||
const end = fullName.substring(fullName.length - endLength);
|
||||
return start + '.....' + end;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ export * from './lib/toolbar/index';
|
||||
export * from './lib/header/index';
|
||||
export * from './lib/pagination/index';
|
||||
export * from './lib/login/index';
|
||||
export * from './lib/landing-page/index';
|
||||
export * from './lib/language-menu/index';
|
||||
export * from './lib/info-drawer/index';
|
||||
export * from './lib/identity-user-info/index';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@alfresco/eslint-plugin-eslint-angular",
|
||||
"version": "9.0.0",
|
||||
"version": "8.0.3",
|
||||
"description": "Alfresco ADF eslint angular custom rules",
|
||||
"main": "main.js",
|
||||
"author": "Hyland Software, Inc. and its affiliates",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@alfresco/adf-extensions",
|
||||
"description": "Provides extensibility support for ADF applications.",
|
||||
"version": "9.0.0",
|
||||
"version": "8.0.3",
|
||||
"license": "Apache-2.0",
|
||||
"author": "Hyland Software, Inc. and its affiliates",
|
||||
"repository": {
|
||||
@@ -14,7 +14,7 @@
|
||||
"peerDependencies": {
|
||||
"@angular/common": ">=14.1.3",
|
||||
"@angular/core": ">=14.1.3",
|
||||
"@alfresco/js-api": ">=10.0.0"
|
||||
"@alfresco/js-api": ">=9.0.2"
|
||||
},
|
||||
"keywords": [
|
||||
"extensions",
|
||||
|
||||
@@ -15,26 +15,36 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DynamicExtensionComponent } from './components/dynamic-component/dynamic.component';
|
||||
import { DynamicTabComponent } from './components/dynamic-tab/dynamic-tab.component';
|
||||
import { DynamicColumnComponent } from './components/dynamic-column/dynamic-column.component';
|
||||
import { PreviewExtensionComponent } from './components/viewer/preview-extension.component';
|
||||
import { NgModule, ModuleWithProviders, inject, provideAppInitializer } from '@angular/core';
|
||||
import { AppExtensionService } from './services/app-extension.service';
|
||||
import { setupExtensions } from './services/startup-extension-factory';
|
||||
|
||||
/** @deprecated use provideAppExtensions() api instead */
|
||||
@NgModule()
|
||||
export const EXTENSION_DIRECTIVES = [DynamicExtensionComponent, DynamicTabComponent, DynamicColumnComponent, PreviewExtensionComponent] as const;
|
||||
|
||||
/** @deprecated import EXTENSION_DIRECTIVES or standalone components instead */
|
||||
@NgModule({
|
||||
imports: [...EXTENSION_DIRECTIVES],
|
||||
exports: [...EXTENSION_DIRECTIVES]
|
||||
})
|
||||
export class ExtensionsModule {
|
||||
static forRoot(): ModuleWithProviders<ExtensionsModule> {
|
||||
return {
|
||||
ngModule: ExtensionsModule,
|
||||
providers: [
|
||||
provideAppInitializer(() => {
|
||||
const appExtensionService = inject(AppExtensionService);
|
||||
return appExtensionService.load();
|
||||
const initializerFn = setupExtensions(inject(AppExtensionService));
|
||||
return initializerFn();
|
||||
})
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use provideAppExtensions() api instead
|
||||
* @deprecated use `ExtensionsModule` instead, `EXTENSION_DIRECTIVES` or direct standalone components
|
||||
* @returns Module with providers
|
||||
*/
|
||||
static forChild(): ModuleWithProviders<ExtensionsModule> {
|
||||
|
||||
+2
-14
@@ -15,18 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { EnvironmentProviders, inject, provideAppInitializer, Provider } from '@angular/core';
|
||||
import { AppExtensionService } from './services/app-extension.service';
|
||||
import { AppExtensionService } from './app-extension.service';
|
||||
|
||||
/**
|
||||
* Provides all necessary entries for the app extensibility
|
||||
* @returns list of providers
|
||||
*/
|
||||
export function provideAppExtensions(): (Provider | EnvironmentProviders)[] {
|
||||
return [
|
||||
provideAppInitializer(() => {
|
||||
const appExtensionService = inject(AppExtensionService);
|
||||
return appExtensionService.load();
|
||||
})
|
||||
];
|
||||
}
|
||||
export const setupExtensions = (appExtensionService: AppExtensionService) => () => appExtensionService.load();
|
||||
@@ -41,4 +41,3 @@ export * from './lib/store/states/repository.state';
|
||||
|
||||
export * from './lib/components/public-api';
|
||||
export * from './lib/extensions.module';
|
||||
export * from './lib/providers';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@alfresco/adf-insights",
|
||||
"description": "Alfresco ADF insights",
|
||||
"version": "9.0.0",
|
||||
"version": "8.0.3",
|
||||
"author": "Hyland Software, Inc. and its affiliates",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -11,8 +11,8 @@
|
||||
"url": "https://github.com/Alfresco/alfresco-ng2-components/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alfresco/adf-core": ">=9.0.0",
|
||||
"@alfresco/adf-content-services": ">=9.0.0",
|
||||
"@alfresco/adf-core": ">=8.0.2",
|
||||
"@alfresco/adf-content-services": ">=8.0.2",
|
||||
"@ngx-translate/core": ">=14.0.0",
|
||||
"chart.js": "^4.3.0",
|
||||
"ng2-charts": "^4.1.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@alfresco/js-api",
|
||||
"version": "10.0.0",
|
||||
"version": "9.0.3",
|
||||
"license": "Apache-2.0",
|
||||
"description": "JavaScript client library for the Alfresco REST API",
|
||||
"author": "Hyland Software, Inc. and its affiliates",
|
||||
|
||||
@@ -28,6 +28,19 @@
|
||||
},
|
||||
"allowedNonPeerDependencies": [
|
||||
"@apollo/client",
|
||||
"apollo-angular"
|
||||
"apollo-angular",
|
||||
"@editorjs/editorjs",
|
||||
"@editorjs/code",
|
||||
"@editorjs/header",
|
||||
"@editorjs/inline-code",
|
||||
"@editorjs/list",
|
||||
"@editorjs/marker",
|
||||
"@editorjs/paragraph",
|
||||
"@editorjs/underline",
|
||||
"@valano/change-font-size",
|
||||
"editorjs-text-color-plugin",
|
||||
"editorjs-html",
|
||||
"editorjs-paragraph-with-alignment",
|
||||
"editorjs-text-alignment-blocktune"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@alfresco/adf-process-services-cloud",
|
||||
"description": "Alfresco ADF process services cloud",
|
||||
"version": "9.0.0",
|
||||
"version": "8.0.3",
|
||||
"author": "Hyland Software, Inc. and its affiliates",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -10,6 +10,21 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/Alfresco/alfresco-ng2-components/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@editorjs/code": "2.9.0",
|
||||
"@editorjs/editorjs": "^2.28.2",
|
||||
"@editorjs/header": "2.8.1",
|
||||
"@editorjs/inline-code": "1.5.0",
|
||||
"@editorjs/list": "1.9.0",
|
||||
"@editorjs/marker": "1.4.0",
|
||||
"@editorjs/paragraph": "^2.11.6",
|
||||
"@editorjs/underline": "1.1.0",
|
||||
"editorjs-html": "4.0.5",
|
||||
"editorjs-paragraph-with-alignment": "3.0.0",
|
||||
"editorjs-text-alignment-blocktune": "^1.0.3",
|
||||
"editorjs-text-color-plugin": "1.13.1",
|
||||
"@valano/change-font-size": "1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/animations": ">=14.1.3",
|
||||
"@angular/cdk": ">=14.1.2",
|
||||
@@ -21,9 +36,9 @@
|
||||
"@angular/platform-browser": ">=14.1.3",
|
||||
"@angular/platform-browser-dynamic": ">=14.1.3",
|
||||
"@angular/router": ">=14.1.3",
|
||||
"@alfresco/js-api": ">=10.0.0",
|
||||
"@alfresco/adf-core": ">=9.0.0",
|
||||
"@alfresco/adf-content-services": ">=9.0.0",
|
||||
"@alfresco/js-api": ">=9.0.2",
|
||||
"@alfresco/adf-core": ">=8.0.2",
|
||||
"@alfresco/adf-content-services": ">=8.0.2",
|
||||
"@apollo/client": ">=3.7.2",
|
||||
"@ngx-translate/core": ">=14.0.0",
|
||||
"apollo-angular": ">=4.0.1"
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
class="adf-cloud-form-custom-outcome-button"
|
||||
(click)="onOutcomeClicked(outcome)"
|
||||
>
|
||||
{{ getCustomOutcomeButtonText(outcome) || (outcome.name | translate | uppercase) }}
|
||||
{{ outcome.name | translate | uppercase }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</mat-card-actions>
|
||||
|
||||
@@ -1492,54 +1492,6 @@ describe('FormCloudComponent', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Custom outcome button text for default outcomes', () => {
|
||||
beforeEach(() => {
|
||||
formComponent.form = formComponent.parseForm(emptyFormRepresentationJSON);
|
||||
});
|
||||
|
||||
it('should display custom save button text when set', () => {
|
||||
const customText = 'Custom Save Text';
|
||||
formComponent.customSaveButtonText = customText;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const buttonSelector = '#adf-form-save';
|
||||
const outcomeButton = fixture.debugElement.query(By.css(buttonSelector));
|
||||
expect(outcomeButton).toBeTruthy();
|
||||
expect(outcomeButton.nativeElement.textContent.trim()).toBe(customText);
|
||||
});
|
||||
|
||||
it('should display default save button text when not set', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const buttonSelector = '#adf-form-save';
|
||||
const outcomeButton = fixture.debugElement.query(By.css(buttonSelector));
|
||||
expect(outcomeButton).toBeTruthy();
|
||||
expect(outcomeButton.nativeElement.textContent.trim()).toBe('SAVE');
|
||||
});
|
||||
|
||||
it('should display custom complete button text when set', () => {
|
||||
const customText = 'Custom Complete Text';
|
||||
formComponent.customCompleteButtonText = customText;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const buttonSelector = '#adf-form-complete';
|
||||
const outcomeButton = fixture.debugElement.query(By.css(buttonSelector));
|
||||
expect(outcomeButton).toBeTruthy();
|
||||
expect(outcomeButton.nativeElement.textContent.trim()).toBe(customText);
|
||||
});
|
||||
|
||||
it('should display default complete button text when not set', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const buttonSelector = '#adf-form-complete';
|
||||
const outcomeButton = fixture.debugElement.query(By.css(buttonSelector));
|
||||
expect(outcomeButton).toBeTruthy();
|
||||
expect(outcomeButton.nativeElement.textContent.trim()).toBe('COMPLETE');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multilingual Form', () => {
|
||||
|
||||
@@ -121,20 +121,6 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
|
||||
@Input()
|
||||
showCompleteButton = false;
|
||||
|
||||
/**
|
||||
* Custom text for the `Save` button.
|
||||
* If not provided, the default text will be used.
|
||||
*/
|
||||
@Input()
|
||||
customSaveButtonText: string = '';
|
||||
|
||||
/**
|
||||
* Custom text for the `Complete` button.
|
||||
* If not provided, the default text will be used.
|
||||
*/
|
||||
@Input()
|
||||
customCompleteButtonText: string = '';
|
||||
|
||||
/** Emitted when the form is submitted with the `Save` or custom outcomes. */
|
||||
@Output()
|
||||
formSaved = new EventEmitter<FormModel>();
|
||||
@@ -312,15 +298,6 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
|
||||
);
|
||||
}
|
||||
|
||||
getCustomOutcomeButtonText(outcome: FormOutcomeModel): string {
|
||||
if (outcome?.id === FormModel.SAVE_OUTCOME || outcome?.name === FormOutcomeModel.SAVE_ACTION) {
|
||||
return this.customSaveButtonText;
|
||||
} else if (outcome?.id === FormModel.COMPLETE_OUTCOME || outcome?.name === FormOutcomeModel.COMPLETE_ACTION) {
|
||||
return this.customCompleteButtonText;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
isAProcessTask(taskRepresentation: TaskDetailsCloudModel): boolean {
|
||||
return taskRepresentation.processDefinitionId && taskRepresentation.processDefinitionDeploymentId !== 'null';
|
||||
}
|
||||
@@ -453,7 +430,7 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
|
||||
* @returns list of form outcomes
|
||||
*/
|
||||
getFormDefinitionOutcomes(form: FormModel): FormOutcomeModel[] {
|
||||
return [new FormOutcomeModel(form, { id: FormModel.SAVE_OUTCOME, name: FormOutcomeModel.SAVE_ACTION, isSystem: true })];
|
||||
return [new FormOutcomeModel(form, { id: '$save', name: FormOutcomeModel.SAVE_ACTION, isSystem: true })];
|
||||
}
|
||||
|
||||
checkVisibility(field: FormFieldModel) {
|
||||
|
||||
+1
@@ -13,6 +13,7 @@
|
||||
overflow-x: auto;
|
||||
resize: vertical;
|
||||
border-radius: 3px;
|
||||
padding: 10px 12px;
|
||||
outline: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
-15
@@ -998,21 +998,6 @@ describe('DropdownCloudWidgetComponent', () => {
|
||||
expect(widget.dropdownControl.value).toEqual({ id: 'testValue', name: '' });
|
||||
});
|
||||
|
||||
it('should set dropdownControl value when form field value gets changed', () => {
|
||||
widget.field = {
|
||||
value: { id: 'Id_1', name: 'Label 1' },
|
||||
options: [],
|
||||
isVisible: true,
|
||||
markAsValid: () => {}
|
||||
} as FormFieldModel;
|
||||
spyOn(widget.dropdownControl, 'setValue').and.callThrough();
|
||||
|
||||
widget.updateReactiveFormControl();
|
||||
|
||||
expect(widget.dropdownControl.setValue).toHaveBeenCalledWith({ id: 'Id_1', name: 'Label 1' }, { emitEvent: false });
|
||||
expect(widget.dropdownControl.value).toEqual({ id: 'Id_1', name: 'Label 1' });
|
||||
});
|
||||
|
||||
it('should set dropdownControl value without emitting events if is an object', () => {
|
||||
widget.field = {
|
||||
value: { id: 'testValueObj', name: 'testValueObjName' },
|
||||
|
||||
-1
@@ -137,7 +137,6 @@ export class DropdownCloudWidgetComponent extends WidgetComponent implements OnI
|
||||
}
|
||||
|
||||
updateReactiveFormControl(): void {
|
||||
this.setFormControlValue();
|
||||
this.updateFormControlState();
|
||||
this.handleErrors();
|
||||
}
|
||||
|
||||
@@ -29,9 +29,11 @@ import { RadioButtonsCloudWidgetComponent } from './components/widgets/radio-but
|
||||
import { FilePropertiesTableCloudComponent } from './components/widgets/attach-file/file-properties-table/file-properties-table-cloud.component';
|
||||
import { FileViewerWidgetComponent } from './components/widgets/file-viewer/file-viewer.widget';
|
||||
import { DisplayRichTextWidgetComponent } from './components/widgets/display-rich-text/display-rich-text.widget';
|
||||
import { RichTextEditorComponent } from '../rich-text-editor';
|
||||
import { FormSpinnerComponent } from './components/spinner/form-spinner.component';
|
||||
|
||||
export const FORM_CLOUD_DIRECTIVES = [
|
||||
RichTextEditorComponent,
|
||||
FormSpinnerComponent,
|
||||
PropertiesViewerWrapperComponent,
|
||||
PropertiesViewerWidgetComponent,
|
||||
|
||||
@@ -210,7 +210,7 @@ export class FormCloudService extends BaseCloudService implements FormCloudServi
|
||||
*
|
||||
* @param json JSON data to create the form
|
||||
* @param data Values for the form's fields
|
||||
* @param readOnly Toggles whether the form should be read-only
|
||||
* @param readOnly Toggles whether or not the form should be read-only
|
||||
* @returns Form created from the JSON specification
|
||||
*/
|
||||
parseForm(json: any, data?: TaskVariableCloud[], readOnly: boolean = false): FormModel {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<form>
|
||||
<mat-form-field
|
||||
[subscriptSizing]="formFieldSubscriptSizing"
|
||||
[floatLabel]="'auto'"
|
||||
class="adf-people-cloud adf-form-field-input"
|
||||
[class.adf-invalid]="hasError() && isDirty()"
|
||||
>
|
||||
|
||||
@@ -23,6 +23,7 @@ import { ProcessCloudModule } from './process/process-cloud.module';
|
||||
import { FORM_CLOUD_DIRECTIVES } from './form/form-cloud.module';
|
||||
import { TASK_FORM_CLOUD_DIRECTIVES } from './task/task-form/task-form.module';
|
||||
import { PreferenceCloudServiceInterface, TASK_LIST_CLOUD_TOKEN } from './services/public-api';
|
||||
import { RichTextEditorComponent } from './rich-text-editor';
|
||||
import { GroupCloudComponent } from './group/components/group-cloud.component';
|
||||
import { PeopleCloudComponent } from './people/components/people-cloud.component';
|
||||
import { provideCloudFormRenderer, provideCloudPreferences } from './providers';
|
||||
@@ -32,7 +33,8 @@ export const PROCESS_SERVICES_CLOUD_DIRECTIVES = [
|
||||
...APP_LIST_CLOUD_DIRECTIVES,
|
||||
...FORM_CLOUD_DIRECTIVES,
|
||||
...TASK_FORM_CLOUD_DIRECTIVES,
|
||||
PeopleCloudComponent
|
||||
PeopleCloudComponent,
|
||||
RichTextEditorComponent
|
||||
] as const;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
/** Plugin import */
|
||||
import CodeTool from '@editorjs/code';
|
||||
import Header from '@editorjs/header';
|
||||
import Paragraph from '@editorjs/paragraph';
|
||||
import InlineCode from '@editorjs/inline-code';
|
||||
import List from '@editorjs/list';
|
||||
import Marker from '@editorjs/marker';
|
||||
import Underline from '@editorjs/underline';
|
||||
import ChangeFontSize from '@valano/change-font-size';
|
||||
import ColorPlugin from 'editorjs-text-color-plugin';
|
||||
import AlignmentTuneTool from 'editorjs-text-alignment-blocktune';
|
||||
|
||||
export const editorJsConfig = {
|
||||
autofocus: true,
|
||||
logLevel: 'ERROR',
|
||||
tools: {
|
||||
underline: {
|
||||
class: Underline,
|
||||
shortcut: 'CMD+U'
|
||||
},
|
||||
header: {
|
||||
class: Header,
|
||||
inlineToolbar: true,
|
||||
tunes: ['anyTuneName']
|
||||
},
|
||||
paragraph: {
|
||||
class: Paragraph,
|
||||
inlineToolbar: true,
|
||||
tunes: ['anyTuneName']
|
||||
},
|
||||
list: {
|
||||
class: List,
|
||||
inlineToolbar: true,
|
||||
config: {
|
||||
defaultStyle: 'unordered'
|
||||
}
|
||||
},
|
||||
Color: {
|
||||
class: ColorPlugin,
|
||||
config: {
|
||||
customPicker: true,
|
||||
colorCollections: [
|
||||
'#FF1300',
|
||||
'#ffa500',
|
||||
'#9C27B0',
|
||||
'#673AB7',
|
||||
'#3F51B5',
|
||||
'#0070FF',
|
||||
'#03A9F4',
|
||||
'#00BCD4',
|
||||
'#5f9ea0',
|
||||
'#4CAF50',
|
||||
'#8BC34A',
|
||||
'#CDDC39',
|
||||
'#FFF',
|
||||
'#000',
|
||||
'#c0c0c0',
|
||||
'#808080',
|
||||
'#800000'
|
||||
],
|
||||
defaultColor: '#FF1300',
|
||||
type: 'text'
|
||||
}
|
||||
},
|
||||
Marker: {
|
||||
class: Marker,
|
||||
shortcut: 'CMD+M'
|
||||
},
|
||||
'Increase/Decrease font size': {
|
||||
class: ChangeFontSize,
|
||||
config: {
|
||||
cssClass: 'plus20pc',
|
||||
buttonIcon: '<span class="material-icons">format_size</span>'
|
||||
}
|
||||
},
|
||||
inlineCode: {
|
||||
class: InlineCode,
|
||||
shortcut: 'CMD+SHIFT+M'
|
||||
},
|
||||
anyTuneName: {
|
||||
class: AlignmentTuneTool
|
||||
},
|
||||
code: CodeTool
|
||||
}
|
||||
};
|
||||
+2
-1
@@ -15,4 +15,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './provider';
|
||||
export * from './rich-text-editor.component';
|
||||
export * from './rich-text-editor.module';
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="adf-rich-text-editor-container">
|
||||
<div class="editorjs" id="{{dynamicId}}"></div>
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user