mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-16 18:13:06 +00:00
Compare commits
237
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
449433219a | ||
|
|
268067b63b | ||
|
|
a51af0866e | ||
|
|
00d0ffc945 | ||
|
|
96e109d6f3 | ||
|
|
3280107fe0 | ||
|
|
d62f241098 | ||
|
|
4592a8ae21 | ||
|
|
99c574bad6 | ||
|
|
f435b63e42 | ||
|
|
1ab385a3c9 | ||
|
|
33cf47342d | ||
|
|
4cbe97c12c | ||
|
|
e717189430 | ||
|
|
e4e5d4a908 | ||
|
|
9e5c3d71d0 | ||
|
|
4a5154b0c8 | ||
|
|
57b7a79bc2 | ||
|
|
c46496f2fc | ||
|
|
12ae30ce06 | ||
|
|
72522c0f72 | ||
|
|
3d01611249 | ||
|
|
b06098c500 | ||
|
|
2579d58d25 | ||
|
|
9a7e037522 | ||
|
|
83f8b3cff5 | ||
|
|
3f232e75bc | ||
|
|
4123a89814 | ||
|
|
8ebbfa819e | ||
|
|
9587995ac3 | ||
|
|
0c099eafb0 | ||
|
|
4f32198afd | ||
|
|
f0c60b422d | ||
|
|
b8df098e35 | ||
|
|
c0ab354698 | ||
|
|
c9473d93c0 | ||
|
|
6c8b874704 | ||
|
|
c316c6b594 | ||
|
|
c941c81984 | ||
|
|
b234ca6c42 | ||
|
|
b6ae479cd0 | ||
|
|
03e6320bd2 | ||
|
|
e1f463aa8a | ||
|
|
ac3b21454f | ||
|
|
9a49e4ff5c | ||
|
|
565af341dd | ||
|
|
ba814fd6ec | ||
|
|
3f2c767d43 | ||
|
|
a1ee4e0d48 | ||
|
|
40a0a67583 | ||
|
|
85ec35cdf9 | ||
|
|
9f21d602fc | ||
|
|
2827d44768 | ||
|
|
1b905fe312 | ||
|
|
1f7722ca89 | ||
|
|
62dff48260 | ||
|
|
660b14a780 | ||
|
|
9d5f6e692c | ||
|
|
3496363b8e | ||
|
|
d25038dc59 | ||
|
|
c348ea32c0 | ||
|
|
0505b1d5c3 | ||
|
|
0a19be090e | ||
|
|
b69c3ae1ae | ||
|
|
ce907417b7 | ||
|
|
4c7765e3fa | ||
|
|
407a64996e | ||
|
|
c0a102f87f | ||
|
|
066ef30516 | ||
|
|
01cea60490 | ||
|
|
f438c6ce69 | ||
|
|
09ef05038c | ||
|
|
c7bd56f244 | ||
|
|
b86e41515e | ||
|
|
0b35118dee | ||
|
|
fe2b3d85dd | ||
|
|
b0dc85422c | ||
|
|
23f0392c12 | ||
|
|
997303e6a7 | ||
|
|
45d1818f04 | ||
|
|
2f50af623d | ||
|
|
9c56712328 | ||
|
|
448e667c52 | ||
|
|
18e602aa85 | ||
|
|
53ef0cfc00 | ||
|
|
4cd8648a05 | ||
|
|
7f57b3936b | ||
|
|
5a30baad99 | ||
|
|
5050c3d974 | ||
|
|
d8b36606e2 | ||
|
|
37f8fe47ac | ||
|
|
af0d1e4ead | ||
|
|
699f45e486 | ||
|
|
416f04d6bd | ||
|
|
5123e80bd9 | ||
|
|
283a0ab18a | ||
|
|
bab668033e | ||
|
|
1a50dad132 | ||
|
|
d0f9c3d5a4 | ||
|
|
2808988171 | ||
|
|
bd7f393db9 | ||
|
|
d2d6696c05 | ||
|
|
7546aa91a3 | ||
|
|
74d67c39a0 | ||
|
|
20c20f2749 | ||
|
|
2c3020c7fc | ||
|
|
100d348f5e | ||
|
|
b498d5744c | ||
|
|
80eef35e1d | ||
|
|
49a3f1e104 | ||
|
|
0beaa18452 | ||
|
|
76fd461741 | ||
|
|
78697ee62a | ||
|
|
43c5bc17fb | ||
|
|
cda20e0386 | ||
|
|
8f5099e822 | ||
|
|
5dd709ed58 | ||
|
|
9d353bf271 | ||
|
|
633702860f | ||
|
|
bf5b3af285 | ||
|
|
caeaa74704 | ||
|
|
7bf0939a49 | ||
|
|
ec04358796 | ||
|
|
49a28b357c | ||
|
|
dd9e58ddaa | ||
|
|
c723e19b6d | ||
|
|
bb6f9b1f3d | ||
|
|
7bb219e4dd | ||
|
|
9ec31dd543 | ||
|
|
70038bea26 | ||
|
|
a445569139 | ||
|
|
5ad3dca38d | ||
|
|
fd3802f2dc | ||
|
|
a8eee9fe3a | ||
|
|
0a7fa14d0f | ||
|
|
4dde6d2a45 | ||
|
|
78661f11c5 | ||
|
|
faf9d3faac | ||
|
|
75d9845754 | ||
|
|
5c8eb21ab3 | ||
|
|
7d76d789b2 | ||
|
|
a71cc84f11 | ||
|
|
cdcfab0240 | ||
|
|
5a20501577 | ||
|
|
34acdd20cf | ||
|
|
f39b9167b8 | ||
|
|
aa2a357fb2 | ||
|
|
e52b63eaf9 | ||
|
|
f9899883dc | ||
|
|
46b2d0380b | ||
|
|
274ddb3098 | ||
|
|
f602070f1e | ||
|
|
d206d28f1c | ||
|
|
80e9e51cfa | ||
|
|
345e1e69ad | ||
|
|
a2b026ed7e | ||
|
|
e40fd2250e | ||
|
|
cfdd3f9c50 | ||
|
|
1314f0751f | ||
|
|
f4882e99be | ||
|
|
b5d2de583d | ||
|
|
70f90c65a5 | ||
|
|
e6ef0de7a8 | ||
|
|
8559d27a04 | ||
|
|
c9b2939588 | ||
|
|
b69776012f | ||
|
|
27c62f2632 | ||
|
|
b8fa940dc9 | ||
|
|
637b67da59 | ||
|
|
cefc666a09 | ||
|
|
f339647f40 | ||
|
|
a7fa68056d | ||
|
|
8280aa2f6d | ||
|
|
5553aaaefe | ||
|
|
15814380a5 | ||
|
|
4044fafc39 | ||
|
|
ece50ac32c | ||
|
|
1d163c6749 | ||
|
|
1fbd869902 | ||
|
|
165d0fc521 | ||
|
|
64d9f3a6d4 | ||
|
|
454236873e | ||
|
|
16202197f7 | ||
|
|
dbdcc3175b | ||
|
|
b1cb7060d1 | ||
|
|
fc55aa0a44 | ||
|
|
b8c115a725 | ||
|
|
9e106b006c | ||
|
|
8309d2dc55 | ||
|
|
a21908a782 | ||
|
|
e3430ae36e | ||
|
|
7bf7610cf5 | ||
|
|
57ec1ab835 | ||
|
|
1860fefd42 | ||
|
|
e5eb90f93b | ||
|
|
c9464581e8 | ||
|
|
53abaaf246 | ||
|
|
9fe4006a0d | ||
|
|
62fb51e910 | ||
|
|
b7783d2259 | ||
|
|
410490158f | ||
|
|
57bf066164 | ||
|
|
9cdacf3ebf | ||
|
|
8821980913 | ||
|
|
a73b100fae | ||
|
|
2649cdea2d | ||
|
|
3a543d8a0a | ||
|
|
3fc59b2358 | ||
|
|
d7487e30bd | ||
|
|
b6d292df2b | ||
|
|
992f4779fc | ||
|
|
337b82e988 | ||
|
|
0faa2e1a56 | ||
|
|
d6262eafc6 | ||
|
|
bba9a0afe2 | ||
|
|
d3ad66d25b | ||
|
|
b49513e9c2 | ||
|
|
aa2de3bde6 | ||
|
|
d1d06a68bc | ||
|
|
a394222c54 | ||
|
|
0a6da1ba13 | ||
|
|
7853121080 | ||
|
|
d3ac5362ba | ||
|
|
ddb8adc0e4 | ||
|
|
85005c9c1c | ||
|
|
67b4486b44 | ||
|
|
a4f4f5eb47 | ||
|
|
02009108e9 | ||
|
|
e7c5e5371b | ||
|
|
5a032945bc | ||
|
|
407c6c1829 | ||
|
|
e3fc03c58d | ||
|
|
510a813ed2 | ||
|
|
7864f1a8e0 | ||
|
|
c09edd71ff | ||
|
|
64826c3a99 | ||
|
|
423c646bac |
@@ -1,14 +0,0 @@
|
||||
.angular
|
||||
nxcache
|
||||
node_modules
|
||||
dist
|
||||
coverage
|
||||
.github
|
||||
.vscode
|
||||
scripts
|
||||
/angular.json
|
||||
docs/**/*.md
|
||||
lib/js-api/docs/**/*.md
|
||||
.storybook
|
||||
webpack.config.js
|
||||
lib/core/src/lib/icon
|
||||
-249
@@ -1,249 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
|
||||
ignorePatterns: ['projects/**/*', '**/node_modules/**/*', 'lib/cli/node_modules/**/*', '**/node_modules', '**/assets', '**/scripts', '**/docs'],
|
||||
|
||||
plugins: ['@nx'],
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts'],
|
||||
parserOptions: {
|
||||
project: ['tsconfig.json'],
|
||||
createDefaultProgram: true
|
||||
},
|
||||
extends: [
|
||||
'plugin:@nx/typescript',
|
||||
'plugin:@nx/angular',
|
||||
'plugin:@cspell/recommended',
|
||||
'plugin:@angular-eslint/recommended',
|
||||
'plugin:@angular-eslint/template/process-inline-templates',
|
||||
'plugin:jsdoc/recommended-typescript-error'
|
||||
// Uncomment this once all linting issues are fixed
|
||||
// Note to developers:
|
||||
// you can uncomment the full ruleset locally when fixing issues, and then comment
|
||||
// that will allow splitting the work into smaller chunks
|
||||
// 'plugin:unicorn/recommended'
|
||||
],
|
||||
plugins: [
|
||||
'eslint-plugin-unicorn',
|
||||
'eslint-plugin-rxjs',
|
||||
'prettier',
|
||||
'ban',
|
||||
'license-header',
|
||||
'@cspell',
|
||||
'eslint-plugin-import',
|
||||
'@angular-eslint/eslint-plugin',
|
||||
'@typescript-eslint',
|
||||
'jsdoc'
|
||||
],
|
||||
rules: {
|
||||
// Uncomment this to enable prettier checks as part of the ESLint
|
||||
// 'prettier/prettier': 'error',
|
||||
'ban/ban': [
|
||||
'error',
|
||||
{ name: 'eval', message: 'Calls to eval is not allowed.' },
|
||||
{ name: 'fdescribe', message: 'Calls to fdescribe is not allowed' },
|
||||
{ name: 'fit', message: 'Calls to fit is not allowed' },
|
||||
{ name: 'xit', message: 'Calls to xit is not allowed' },
|
||||
{ name: 'xdescribe', message: 'Calls to xdescribe is not allowed' },
|
||||
{ name: ['test', 'only'], message: 'Calls to test.only is not allowed' },
|
||||
{ name: ['describe', 'only'], message: 'Calls to describe.only is not allowed' }
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: ['adf', 'app'],
|
||||
style: 'kebab-case'
|
||||
}
|
||||
],
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: ['element', 'attribute'],
|
||||
prefix: ['adf', 'app'],
|
||||
style: 'kebab-case'
|
||||
}
|
||||
],
|
||||
'@angular-eslint/no-host-metadata-property': 'off',
|
||||
'@angular-eslint/no-input-prefix': 'error',
|
||||
'@angular-eslint/prefer-inject': 'error',
|
||||
'@typescript-eslint/consistent-type-definitions': 'error',
|
||||
'@typescript-eslint/dot-notation': 'off',
|
||||
'@typescript-eslint/explicit-member-accessibility': [
|
||||
'off',
|
||||
{
|
||||
accessibility: 'explicit'
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/await-thenable': 'error',
|
||||
'@typescript-eslint/prefer-optional-chain': 'warn',
|
||||
'@typescript-eslint/prefer-readonly': 'error',
|
||||
'@typescript-eslint/no-inferrable-types': 'off',
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'error',
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: [
|
||||
'classProperty',
|
||||
'objectLiteralProperty',
|
||||
'typeProperty',
|
||||
'classMethod',
|
||||
'objectLiteralMethod',
|
||||
'typeMethod',
|
||||
'accessor',
|
||||
'enumMember'
|
||||
],
|
||||
format: null,
|
||||
modifiers: ['requiresQuotes']
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/member-ordering': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'prefer-arrow/prefer-arrow-functions': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'prefer-promise-reject-errors': 'error',
|
||||
'brace-style': 'off',
|
||||
'comma-dangle': 'error',
|
||||
'default-case': 'error',
|
||||
'import/order': 'off',
|
||||
'max-len': [
|
||||
'error',
|
||||
{
|
||||
code: 240
|
||||
}
|
||||
],
|
||||
'no-bitwise': 'off',
|
||||
'no-console': [
|
||||
'error',
|
||||
{
|
||||
allow: [
|
||||
'warn',
|
||||
'dir',
|
||||
'timeLog',
|
||||
'assert',
|
||||
'clear',
|
||||
'count',
|
||||
'countReset',
|
||||
'group',
|
||||
'groupEnd',
|
||||
'table',
|
||||
'dirxml',
|
||||
'error',
|
||||
'groupCollapsed',
|
||||
'Console',
|
||||
'profile',
|
||||
'profileEnd',
|
||||
'timeStamp',
|
||||
'context'
|
||||
]
|
||||
}
|
||||
],
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-multiple-empty-lines': 'error',
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-redeclare': ['off', { ignoreDeclarationMerge: true }],
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_'
|
||||
}
|
||||
],
|
||||
'no-return-await': 'error',
|
||||
'rxjs/no-create': 'error',
|
||||
'rxjs/no-subject-unsubscribe': 'error',
|
||||
'rxjs/no-subject-value': 'error',
|
||||
'rxjs/no-unsafe-takeuntil': 'error',
|
||||
'unicorn/filename-case': 'error',
|
||||
'unicorn/prefer-optional-catch-binding': 'error',
|
||||
'@typescript-eslint/no-unused-expressions': [
|
||||
'error',
|
||||
{
|
||||
allowShortCircuit: true,
|
||||
allowTernary: true
|
||||
}
|
||||
],
|
||||
'license-header/header': [
|
||||
'error',
|
||||
[
|
||||
'/*!',
|
||||
' * @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.',
|
||||
' */'
|
||||
]
|
||||
],
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: "Identifier[name='CUSTOM_ELEMENTS_SCHEMA']",
|
||||
message: 'The use of CUSTOM_ELEMENTS_SCHEMA is not allowed. Consider alternatives for proper schema handling.'
|
||||
},
|
||||
{
|
||||
selector: "Identifier[name='NO_ERRORS_SCHEMA']",
|
||||
message: 'The use of NO_ERRORS_SCHEMA is not allowed. Consider alternatives for proper schema handling.'
|
||||
},
|
||||
{
|
||||
selector: 'TSEnumDeclaration',
|
||||
message: 'Enums are not allowed. Use string literal types (e.g., type Foo = "a" | "b") or const objects instead.'
|
||||
},
|
||||
{
|
||||
selector: ':matches(Literal[value=/ng-reflect-/], TemplateElement[value.cooked=/ng-reflect-/])',
|
||||
message: '*ng-reflect-* attributes should not be used. Consider alternatives for proper selectors.'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['*.html'],
|
||||
extends: ['plugin:@angular-eslint/template/recommended', 'plugin:@angular-eslint/template/accessibility'],
|
||||
parser: '@angular-eslint/template-parser',
|
||||
rules: {
|
||||
'@angular-eslint/template/prefer-self-closing-tags': 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['*.spec.ts'],
|
||||
plugins: ['@alfresco/eslint-angular'],
|
||||
rules: {
|
||||
'@alfresco/eslint-angular/no-angular-material-selectors': 'error',
|
||||
'@angular-eslint/component-class-suffix': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['*.ts'],
|
||||
extends: ['plugin:@angular-eslint/template/process-inline-templates'],
|
||||
excludedFiles: ['*.spec.ts']
|
||||
},
|
||||
{
|
||||
files: ['*.json'],
|
||||
parser: 'jsonc-eslint-parser',
|
||||
rules: {
|
||||
'comma-dangle': ['error', 'never']
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.stories.ts'],
|
||||
rules: {
|
||||
'@cspell/spellchecker': 'off'
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
extends: ['plugin:storybook/recommended']
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": ["./.eslintrc.js"]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
.github/workflows/*.lock.yml linguist-generated=true merge=ours
|
||||
+3
-3
@@ -4,15 +4,15 @@
|
||||
# the repo. Unless a later match takes precedence,
|
||||
# these users will be requested for
|
||||
# review when someone opens a pull request.
|
||||
* @eromano @popovicsandras @DenysVuika
|
||||
* @eromano
|
||||
|
||||
# Order is important; the last matching pattern takes the most
|
||||
# precedence. When someone opens a pull request that only
|
||||
# modifies JS files, only @js-owner and not the global
|
||||
# owner(s) will be requested for a review.
|
||||
/e2e/ @eromano @cristinaj
|
||||
/e2e/ @eromano
|
||||
|
||||
# The `docs/*` pattern will match files like
|
||||
# `docs/getting-started.md` but not further nested files like
|
||||
# `docs/build-app/troubleshooting.md`.
|
||||
/docs/ @m-hulbert @eromano
|
||||
/docs/ @eromano
|
||||
|
||||
@@ -12,9 +12,14 @@ runs:
|
||||
- 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";
|
||||
@@ -25,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 }}
|
||||
@@ -43,7 +60,7 @@ 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 }}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -4,7 +4,7 @@ runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Restore dist from cache
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: dist
|
||||
key: dist-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@@ -13,7 +13,7 @@ runs:
|
||||
fail-on-cache-miss: true
|
||||
|
||||
- name: Restore nxcache from cache
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: nxcache
|
||||
key: nxcache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@@ -22,7 +22,7 @@ runs:
|
||||
fail-on-cache-miss: true
|
||||
|
||||
- name: Restore node_modules from cache
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: node_modules
|
||||
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
|
||||
@@ -23,8 +23,8 @@ runs:
|
||||
env:
|
||||
DRY_RUN_FLAG: ${{ inputs.dry-run-flag }}
|
||||
run: |
|
||||
if [[ '$DRY_RUN_FLAG' == 'true' ]]; then
|
||||
echo "dryrun=--dryrun" >> $GITHUB_OUTPUT;
|
||||
if [[ "$DRY_RUN_FLAG" == 'true' ]]; then
|
||||
echo "dryrun=--dry-run" >> $GITHUB_OUTPUT;
|
||||
echo "enabling dryrun"
|
||||
else
|
||||
echo "dryrun=" >> $GITHUB_OUTPUT;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
name: 'Save Nx Cache'
|
||||
description: 'Save Nx cache and dist outputs only when the job succeeds'
|
||||
inputs:
|
||||
cache-suffix:
|
||||
description: 'Must match the cache-suffix used in the setup action'
|
||||
required: true
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Save nx cache
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: |
|
||||
nxcache
|
||||
.nx
|
||||
dist
|
||||
key: ${{ runner.os }}-nxcache-${{ inputs.cache-suffix }}-${{ hashFiles('nx.json') }}-${{ github.sha }}
|
||||
@@ -1,8 +1,12 @@
|
||||
name: 'Setup'
|
||||
description: 'Initialize cache, env var load'
|
||||
inputs:
|
||||
enable-node-modules-cache:
|
||||
description: 'enable caching for node modules'
|
||||
cache-suffix:
|
||||
description: 'Suffix to make Nx cache key unique per job (e.g. matrix project name)'
|
||||
required: false
|
||||
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'
|
||||
@@ -18,33 +22,43 @@ outputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: install NPM
|
||||
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.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 pnpm
|
||||
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache-dependency-path: package-lock.json
|
||||
cache: 'pnpm'
|
||||
- name: get latest tag sha
|
||||
if: ${{ inputs.full-setup == 'true' }}
|
||||
id: tag-sha
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/git-latest-tag@c00625b5f30db226fb0634299effc4cd15fdd7bb # v17.2.0
|
||||
# CACHE
|
||||
- name: Node Modules cache
|
||||
id: node-modules-cache
|
||||
if: ${{ inputs.enable-node-modules-cache == 'true' }}
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
env:
|
||||
cache-name: node-modules-cache
|
||||
with:
|
||||
path: |
|
||||
node_modules
|
||||
key: .npm-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
.npm-${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
.npm-${{ runner.os }}-build-
|
||||
.npm-${{ runner.os }}-
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/git-latest-tag@44f603af32dc79129056a9e4246ab62f35987a2b # v18.21.1
|
||||
- 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: pnpm install --frozen-lockfile
|
||||
- name: Security audit
|
||||
shell: bash
|
||||
run: pnpm audit --audit-level=critical
|
||||
- name: Restore nx cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: |
|
||||
nxcache
|
||||
.nx
|
||||
dist
|
||||
key: ${{ runner.os }}-nxcache-${{ inputs.cache-suffix }}-${{ hashFiles('nx.json') }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ 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 }}
|
||||
|
||||
@@ -5,19 +5,19 @@ runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Save dist to cache
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
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@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
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@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: node_modules
|
||||
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"entries": {
|
||||
"github/gh-aw-actions/setup@v0.85.4": {
|
||||
"repo": "github/gh-aw-actions/setup",
|
||||
"version": "v0.85.4",
|
||||
"sha": "2709137ea6c5b0e19aa621454dc643ea8dc526b1"
|
||||
}
|
||||
},
|
||||
"containers": {
|
||||
"ghcr.io/github/gh-aw-firewall/agent:0.27.44": {
|
||||
"image": "ghcr.io/github/gh-aw-firewall/agent:0.27.44",
|
||||
"digest": "sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4",
|
||||
"pinned_image": "ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"
|
||||
},
|
||||
"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44": {
|
||||
"image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44",
|
||||
"digest": "sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7",
|
||||
"pinned_image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"
|
||||
},
|
||||
"ghcr.io/github/gh-aw-firewall/squid:0.27.44": {
|
||||
"image": "ghcr.io/github/gh-aw-firewall/squid:0.27.44",
|
||||
"digest": "sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627",
|
||||
"pinned_image": "ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"
|
||||
},
|
||||
"ghcr.io/github/gh-aw-mcpg:v0.4.8": {
|
||||
"image": "ghcr.io/github/gh-aw-mcpg:v0.4.8",
|
||||
"digest": "sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8",
|
||||
"pinned_image": "ghcr.io/github/gh-aw-mcpg:v0.4.8@sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8"
|
||||
},
|
||||
"ghcr.io/github/gh-aw-node": {
|
||||
"image": "ghcr.io/github/gh-aw-node",
|
||||
"digest": "sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196",
|
||||
"pinned_image": "ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"
|
||||
},
|
||||
"ghcr.io/github/github-mcp-server:v1.8.0": {
|
||||
"image": "ghcr.io/github/github-mcp-server:v1.8.0",
|
||||
"digest": "sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520",
|
||||
"pinned_image": "ghcr.io/github/github-mcp-server:v1.8.0@sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520"
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
-33
@@ -6,6 +6,8 @@ updates:
|
||||
interval: "weekly"
|
||||
day: "sunday"
|
||||
time: "07:00"
|
||||
cooldown:
|
||||
default-days: 3
|
||||
open-pull-requests-limit: 5
|
||||
target-branch: develop
|
||||
groups:
|
||||
@@ -21,44 +23,38 @@ updates:
|
||||
nrwl:
|
||||
patterns:
|
||||
- "@nrwl/*"
|
||||
typescript-eslint:
|
||||
patterns:
|
||||
- "@typescript-eslint/*"
|
||||
ignore:
|
||||
- dependency-name: "pdfjs-dist"
|
||||
- dependency-name: "@types/*"
|
||||
- dependency-name: "typescript"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/before-install"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/download-node-modules-and-artifacts"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/enable-dryrun"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/get-latest-tag-sha"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/npm-check-bundle"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/set-npm-tag"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/setup"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/upload-node-modules-and-artifacts"
|
||||
directories:
|
||||
- "/"
|
||||
- "/.github/actions/before-install"
|
||||
- "/.github/actions/create-git-tag"
|
||||
- "/.github/actions/download-node-modules-and-artifacts"
|
||||
- "/.github/actions/enable-dryrun"
|
||||
- "/.github/actions/get-latest-tag-sha"
|
||||
- "/.github/actions/npm-check-bundle"
|
||||
- "/.github/actions/save-nx-cache"
|
||||
- "/.github/actions/set-npm-tag"
|
||||
- "/.github/actions/setup"
|
||||
- "/.github/actions/upload-node-modules-and-artifacts"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
cooldown:
|
||||
default-days: 3
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
ignore:
|
||||
# Managed by gh aw add. Version-locked to the gh-aw compiler; do not bump.
|
||||
- dependency-name: "github/gh-aw-actions"
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
name: "Build Lib Workflow"
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
base_ref:
|
||||
description: 'Base branch for affected calculation'
|
||||
required: false
|
||||
type: string
|
||||
default: 'develop'
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=5120"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "Build affected libs"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup environment
|
||||
id: setup-env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
cache-suffix: build
|
||||
full-setup: 'false'
|
||||
- name: Build affected libs
|
||||
env:
|
||||
BASE_REF: ${{ inputs.base_ref }}
|
||||
run: pnpm nx affected --target=build --base=origin/$BASE_REF --head=HEAD --configuration=production --exclude=stories
|
||||
- name: Save nx cache
|
||||
if: ${{ success() }}
|
||||
uses: ./.github/actions/save-nx-cache
|
||||
with:
|
||||
cache-suffix: build
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3.29.5
|
||||
uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v3.29.5
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
with:
|
||||
languages: javascript
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3.29.5
|
||||
uses: github/codeql-action/autobuild@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v3.29.5
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -53,4 +53,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v3.29.5
|
||||
uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v3.29.5
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
name: "Sends notification when A/N BDU label is attached to PR"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled]
|
||||
branches: [develop]
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
issues: read # timeline API is served via the issues endpoint
|
||||
|
||||
jobs:
|
||||
notify-bdu:
|
||||
name: Notify Teams when A/N BDU label is added
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
if: >-
|
||||
github.event.label.name == 'A/N BDU' &&
|
||||
github.event.pull_request.state == 'open'
|
||||
steps:
|
||||
- name: Was the label added after PR creation?
|
||||
id: check
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const prCreatedAt = new Date(context.payload.pull_request.created_at).getTime();
|
||||
const events = await github.paginate(github.rest.issues.listEventsForTimeline, {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number,
|
||||
per_page: 100
|
||||
});
|
||||
const labeled = events.filter(e => e.event === 'labeled' && e.label?.name === 'A/N BDU');
|
||||
if (labeled.length === 0) {
|
||||
core.setOutput('notify', 'false');
|
||||
return;
|
||||
}
|
||||
const labeledAt = new Date(labeled[labeled.length - 1].created_at).getTime();
|
||||
// labels applied within 30s of opening are treated as "added at creation"
|
||||
core.setOutput('notify', (labeledAt - prCreatedAt) > 30000 ? 'true' : 'false');
|
||||
|
||||
- name: Send Teams notification
|
||||
if: steps.check.outputs.notify == 'true'
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/send-teams-notification@1d671f8f10336861c89c67be57c6648d98876103 # v18.19.0
|
||||
with:
|
||||
webhook-url: ${{ secrets.TEAMS_NOTIFICATION_ADF_BDU_WEBHOOK }}
|
||||
skip_checkout: true
|
||||
status: success
|
||||
title: "A/N BDU PR: ${{ github.event.pull_request.title }}"
|
||||
message: |
|
||||
A pull request has been marked with the **A/N BDU** label.
|
||||
|
||||
- **Repository:** ${{ github.repository }}
|
||||
- **PR:** [#${{ github.event.pull_request.number }} ${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})
|
||||
- **Author:** ${{ github.event.pull_request.user.login }}
|
||||
@@ -8,13 +8,22 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.registry_package.package_type == 'npm' && github.event.registry_package.name == 'adf-core'
|
||||
steps:
|
||||
- name: Generate app token
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
client-id: ${{ vars.GH_APP_ENGINEERING_CONTRIB_CLIENT_ID }}
|
||||
private-key: ${{ secrets.GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repositories: alfresco-apps
|
||||
permission-contents: write
|
||||
- name: Dispatch event to monorepo
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
env:
|
||||
PACKAGE_NAME: ${{ github.event.registry_package.name }}
|
||||
PACKAGE_VERSION: ${{ github.event.registry_package.package_version.name }}
|
||||
with:
|
||||
github-token: ${{ secrets.PAT_WRITE_PKG }}
|
||||
github-token: ${{ steps.app-token.outputs.token }}
|
||||
retries: 3
|
||||
script: |
|
||||
const payload = {
|
||||
|
||||
@@ -5,21 +5,31 @@ on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
secrets:
|
||||
BOT_GITHUB_TOKEN:
|
||||
GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY:
|
||||
required: true
|
||||
CROWDIN_TRANSLATIONS_TOKEN:
|
||||
required: true
|
||||
HXPS_GIT_COMMIT_SIGNING_PRIVATE_KEY:
|
||||
required: true
|
||||
jobs:
|
||||
pull-from-crowdin:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate app token
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
client-id: ${{ vars.GH_APP_ENGINEERING_CONTRIB_CLIENT_ID }}
|
||||
private-key: ${{ secrets.GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY }}
|
||||
permission-contents: write
|
||||
permission-pull-requests: write
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
ref: develop
|
||||
token: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
- name: Pull translations from Crowdin
|
||||
uses: crowdin/github-action@7ca9c452bfe9197d3bb7fa83a4d7e2b0c9ae835d # v2.16.0
|
||||
uses: crowdin/github-action@c7af9bc98b01694653031fef2a0dc6c7888ce9bc # v2.17.0
|
||||
with:
|
||||
skip_ref_checkout: true
|
||||
upload_sources: false
|
||||
@@ -28,6 +38,9 @@ jobs:
|
||||
localization_branch_name: automated-translations-update
|
||||
pull_request_title: "GH auto: Automated Update of Translations from Crowdin"
|
||||
pull_request_base_branch_name: develop
|
||||
github_user_name: ${{ vars.HXPS_GIT_USERNAME }}
|
||||
github_user_email: ${{ vars.HXPS_GIT_EMAIL }}
|
||||
gpg_private_key: ${{ secrets.HXPS_GIT_COMMIT_SIGNING_PRIVATE_KEY }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
CROWDIN_TOKEN: ${{ secrets.CROWDIN_TRANSLATIONS_TOKEN }}
|
||||
|
||||
+216
-173
@@ -31,249 +31,295 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref }}
|
||||
HEAD_REF: ${{ github.head_ref }}
|
||||
GH_COMMIT: ${{ github.sha }}
|
||||
GH_BUILD_NUMBER: ${{ github.run_id }}
|
||||
LOG_LEVEL: "ERROR"
|
||||
NODE_OPTIONS: "--max-old-space-size=5120"
|
||||
|
||||
jobs:
|
||||
pre-checks:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
code-changed: ${{ steps.path-filter.outputs.code-changed }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Ensure SHA pinned actions
|
||||
uses: hyland/github-actions-ensure-sha-pinned-actions@7d494b6b53e71f75194d74b4dd890a2266d060b5 # v2.0.0
|
||||
uses: hyland/github-actions-ensure-sha-pinned-actions@7957efb76aba0eec7580a9c0392d3e5bec381359 # v2.0.1
|
||||
|
||||
- name: Check package-lock.json version
|
||||
- name: Check pnpm-lock.yaml version
|
||||
run: |
|
||||
if [[ $(jq '.lockfileVersion == 3' package-lock.json) == "true" ]] ; then
|
||||
echo "package-lock.json has a correct version"
|
||||
if [[ -f "pnpm-lock.yaml" ]]; then
|
||||
LOCKFILE_VERSION=$(grep "^lockfileVersion:" pnpm-lock.yaml | cut -d"'" -f2)
|
||||
if [[ "$LOCKFILE_VERSION" == "9.0" ]]; then
|
||||
echo "pnpm-lock.yaml has correct version: $LOCKFILE_VERSION"
|
||||
else
|
||||
echo "pnpm-lock.yaml must be version 9.0, found: $LOCKFILE_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "package-lock must be version 3"
|
||||
echo "pnpm-lock.yaml is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Detect code changes
|
||||
id: path-filter
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" != "pull_request" ]; then
|
||||
echo "Not a PR event — assuming code changed"
|
||||
echo "code-changed=true" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
FILES=$(gh api /repos/$GITHUB_REPOSITORY/pulls/${{ github.event.pull_request.number }}/files --paginate --jq '.[].filename')
|
||||
|
||||
CODE_CHANGED="false"
|
||||
while IFS= read -r file; do
|
||||
case "$file" in
|
||||
*.md|docs/*|.github/*.md|.github/CODEOWNERS|.github/dependabot.yml|LICENSE*|NOTICE*|.editorconfig|.gitattributes)
|
||||
;;
|
||||
*)
|
||||
CODE_CHANGED="true"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done <<< "$FILES"
|
||||
|
||||
echo "code-changed=$CODE_CHANGED" >> $GITHUB_OUTPUT
|
||||
echo "Code changed: $CODE_CHANGED"
|
||||
|
||||
check-if-pr-is-approved:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Get branch name
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@c00625b5f30db226fb0634299effc4cd15fdd7bb # v17.2.0
|
||||
|
||||
- name: Save commit message
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/get-commit-message@c00625b5f30db226fb0634299effc4cd15fdd7bb # v17.2.0
|
||||
with:
|
||||
header-only: true
|
||||
|
||||
- name: ci:force flag parser
|
||||
shell: bash
|
||||
- name: Check if PR approval can be skipped
|
||||
id: skip-check
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
ACTOR: ${{ github.actor }}
|
||||
DEVEL_FLAG: ${{ inputs.devel }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
if [ "$EVENT_NAME" == "schedule" ] || [ "$ACTOR" == "dependabot[bot]" ]; then
|
||||
echo -e "\033[32mci:force check can be skipped\033[0m"
|
||||
skip_check="true"
|
||||
elif [[ "$COMMIT_MESSAGE" == *"[ci:force]"* ]]; then
|
||||
echo -e "\033[32m[ci:force] flag detected. No need for approval.\033[0m"
|
||||
skip_check="true"
|
||||
skip="false"
|
||||
|
||||
# Get commit message safely from git to avoid script injection
|
||||
if [ "$EVENT_NAME" == "pull_request" ] && [ -n "$PR_HEAD_SHA" ]; then
|
||||
COMMIT_MESSAGE=$(git log -1 --format=%B "$PR_HEAD_SHA" 2>/dev/null || echo "")
|
||||
else
|
||||
COMMIT_MESSAGE=$(git log -1 --format=%B 2>/dev/null || echo "")
|
||||
fi
|
||||
|
||||
if [ "$EVENT_NAME" == "schedule" ] || [ "$EVENT_NAME" == "workflow_dispatch" ]; then
|
||||
echo -e "\033[32mSchedule/dispatch event — skipping approval check\033[0m"
|
||||
skip="true"
|
||||
elif [ "$ACTOR" == "dependabot[bot]" ] || [ "$ACTOR" == "alfresco-build" ]; then
|
||||
echo -e "\033[32mCommit by $ACTOR — skipping approval check\033[0m"
|
||||
skip="true"
|
||||
elif echo "$PR_TITLE" | grep -qF "[ci:force]"; then
|
||||
echo -e "\033[32m[ci:force] flag detected in PR title — skipping approval check\033[0m"
|
||||
skip="true"
|
||||
elif echo "$COMMIT_MESSAGE" | grep -qF "[ci:force]"; then
|
||||
echo -e "\033[32m[ci:force] flag detected in commit message — skipping approval check\033[0m"
|
||||
skip="true"
|
||||
elif [[ "$DEVEL_FLAG" == "true" ]]; then
|
||||
echo -e "\033[32mDevel flag — skipping approval check\033[0m"
|
||||
skip="true"
|
||||
fi
|
||||
|
||||
echo "skip=$skip" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get PR number
|
||||
if: ${{ github.event_name != 'schedule' && github.event_name != 'workflow_dispatch' }}
|
||||
uses: kamatama41/get-pr-number-action@ff143e03abaa79d346ca5407d49d335b5def979e # v1.0.1
|
||||
id: action
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: show pr number
|
||||
shell: bash
|
||||
if: ${{ steps.skip-check.outputs.skip != 'true' }}
|
||||
id: pr-number
|
||||
env:
|
||||
PR_NUMBER: ${{ steps.action.outputs.number }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
PR_NUMBER="${{ github.event.pull_request.number }}"
|
||||
if [ -z "$PR_NUMBER" ]; then
|
||||
PR_NUMBER=$(gh pr view --json number --jq '.number' 2>/dev/null || echo "")
|
||||
fi
|
||||
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
|
||||
echo "PR: $PR_NUMBER"
|
||||
|
||||
- name: check if pr is approved
|
||||
- name: Check if PR is approved
|
||||
if: ${{ steps.skip-check.outputs.skip != 'true' && steps.pr-number.outputs.pr_number != '' }}
|
||||
env:
|
||||
DEVEL_FLAG: ${{ inputs.devel }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
skip_check: "false"
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
ACTOR: ${{ github.actor }}
|
||||
PR_NUMBER: ${{ steps.action.outputs.number }}
|
||||
PR_NUMBER: ${{ steps.pr-number.outputs.pr_number }}
|
||||
run: |
|
||||
if [ "$EVENT_NAME" == "schedule" ] || [ "$ACTOR" == "dependabot[bot]" ]; then
|
||||
echo -e "\033[32mci:force check can be skipped\033[0m"
|
||||
skip_check="true"
|
||||
elif [[ "$COMMIT_MESSAGE" == *"[ci:force]"* ]]; then
|
||||
echo -e "\033[32m[ci:force] flag detected. No need for approval.\033[0m"
|
||||
skip_check="true"
|
||||
fi
|
||||
|
||||
if [ "$ACTOR" == "dependabot[bot]" ] || [ "$ACTOR" == "alfresco-build" ]; then
|
||||
echo -e "\033[32mCommit by $ACTOR. No need for approval.\033[0m"
|
||||
skip_check="true"
|
||||
fi
|
||||
if [ "$EVENT_NAME" == "schedule" ] || [ "$EVENT_NAME" == "workflow_dispatch" ]; then
|
||||
echo -e "\033[32mSchedule event\033[0m"
|
||||
skip_check="true"
|
||||
fi
|
||||
|
||||
if [[ "$DEVEL_FLAG" == "true" ]]; then
|
||||
echo -e "\033[32mDevel flag\033[0m"
|
||||
skip_check="true"
|
||||
fi
|
||||
|
||||
if [ "$skip_check" == "false" ]; then
|
||||
echo "Checking PR approval"
|
||||
prNumber=$PR_NUMBER
|
||||
echo "PR: $prNumber"
|
||||
checkApproval=$(gh api /repos/$GITHUB_REPOSITORY/pulls/$prNumber/reviews | jq '.[] | select(.state == "APPROVED") | .user.login')
|
||||
if [[ $checkApproval ]]; then
|
||||
echo -e "\033[32mPR approved\033[0m"
|
||||
else
|
||||
echo -e "\033[31mPR NOT approved\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
echo "Checking approval for PR: $PR_NUMBER"
|
||||
checkApproval=$(gh api /repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews | jq '.[] | select(.state == "APPROVED") | .user.login')
|
||||
if [[ $checkApproval ]]; then
|
||||
echo -e "\033[32mPR approved\033[0m"
|
||||
else
|
||||
echo -e "\033[31mPR NOT approved\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
setup:
|
||||
# long timeout required when cache has to be recreated
|
||||
timeout-minutes: 30
|
||||
name: "Setup"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check-if-pr-is-approved, pre-checks]
|
||||
if: ${{ needs.pre-checks.outputs.code-changed == 'true' }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for all tags and branches
|
||||
- uses: ./.github/actions/setup
|
||||
- name: install
|
||||
run: |
|
||||
npm ci
|
||||
npm run bundle:js-api
|
||||
npm run bundle:cli
|
||||
- uses: ./.github/actions/upload-node-modules-and-artifacts
|
||||
|
||||
unit-tests:
|
||||
timeout-minutes: 30
|
||||
name: "Unit tests: ${{ matrix.unit-tests.name }}"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [setup]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# max-parallel: 4
|
||||
matrix:
|
||||
unit-tests:
|
||||
- name: js-api
|
||||
exclude: "core,insights,content-services,process-services,process-services-cloud,eslint-plugin-eslint-angular"
|
||||
- name: content-services
|
||||
exclude: "insights,core,extensions,process-services,process-services-cloud,eslint-plugin-eslint-angular,js-api"
|
||||
- name: core
|
||||
exclude: "insights,content-services,process-services,process-services-cloud,eslint-plugin-eslint-angular,js-api"
|
||||
- name: insights
|
||||
exclude: "core,extensions,content-services,process-services-cloud,process-services,eslint-plugin-eslint-angular,js-api"
|
||||
- name: process-services
|
||||
exclude: "core,extensions,content-services,process-services-cloud,insights,eslint-plugin-eslint-angular,js-api"
|
||||
- name: process-services-cloud
|
||||
exclude: "insights,core,extensions,content-services,process-services$,eslint-plugin-eslint-angular,js-api"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
fetch-depth: 0
|
||||
- name: Setup environment
|
||||
id: setup-env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for all tags and branches
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/download-node-modules-and-artifacts
|
||||
- name: Run unit tests
|
||||
env:
|
||||
EXCLUDE_PATTERN: ${{ matrix.unit-tests.exclude }}
|
||||
cache-suffix: setup
|
||||
- name: Bundle
|
||||
run: |
|
||||
/usr/bin/xvfb-run --auto-servernum npm run test:affected -- $NX_CALCULATION_FLAGS --exclude=$EXCLUDE_PATTERN
|
||||
pnpm bundle:js-api
|
||||
pnpm bundle:cli
|
||||
- name: Save nx cache
|
||||
if: ${{ success() }}
|
||||
uses: ./.github/actions/save-nx-cache
|
||||
with:
|
||||
cache-suffix: setup
|
||||
|
||||
lint:
|
||||
# long timeout required when cache has to be recreated
|
||||
timeout-minutes: 30
|
||||
name: "Lint"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [setup]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for all tags and branches
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/download-node-modules-and-artifacts
|
||||
- run: npm run lint:affected -- $NX_CALCULATION_FLAGS
|
||||
fetch-depth: 0
|
||||
- name: Setup environment
|
||||
id: setup-env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
cache-suffix: lint
|
||||
full-setup: 'false'
|
||||
- name: Run lint
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref || 'develop' }}
|
||||
run: pnpm nx affected --target=lint --base=origin/$BASE_REF --head=HEAD
|
||||
- name: Save nx cache
|
||||
if: ${{ success() }}
|
||||
uses: ./.github/actions/save-nx-cache
|
||||
with:
|
||||
cache-suffix: lint
|
||||
|
||||
build-libs:
|
||||
# long timeout required when cache has to be recreated
|
||||
timeout-minutes: 30
|
||||
name: "Build libs"
|
||||
runs-on: ubuntu-latest
|
||||
trigger-build:
|
||||
name: "Build Libs"
|
||||
needs: [setup]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for all tags and branches
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/download-node-modules-and-artifacts
|
||||
- run: NX_REJECT_UNKNOWN_LOCAL_CACHE=0 npm run build:affected -- $NX_CALCULATION_FLAGS --prod
|
||||
- uses: ./.github/actions/upload-node-modules-and-artifacts
|
||||
uses: ./.github/workflows/build-lib-workflow.yml
|
||||
with:
|
||||
base_ref: ${{ github.base_ref || 'develop' }}
|
||||
|
||||
build-storybook:
|
||||
timeout-minutes: 30
|
||||
name: "Build storybook"
|
||||
runs-on: ubuntu-latest
|
||||
name: "Build Storybook"
|
||||
needs: [setup]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for all tags and branches
|
||||
- uses: ./.github/actions/setup
|
||||
- uses: ./.github/actions/download-node-modules-and-artifacts
|
||||
- run: npm run build-storybook
|
||||
- uses: ./.github/actions/upload-node-modules-and-artifacts
|
||||
fetch-depth: 0
|
||||
- name: Setup environment
|
||||
id: setup-env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
cache-suffix: storybook
|
||||
full-setup: 'false'
|
||||
- name: Build Storybook
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref || 'develop' }}
|
||||
run: |
|
||||
pnpm nx affected --target=build-storybook --base=origin/$BASE_REF --head=HEAD --configuration=ci
|
||||
- name: Save nx cache
|
||||
if: ${{ success() }}
|
||||
uses: ./.github/actions/save-nx-cache
|
||||
with:
|
||||
cache-suffix: storybook
|
||||
|
||||
trigger-unit-tests:
|
||||
name: "Unit Tests"
|
||||
needs: [setup]
|
||||
uses: ./.github/workflows/unit-test-workflow.yml
|
||||
with:
|
||||
base_ref: ${{ github.base_ref || 'develop' }}
|
||||
|
||||
PR-size-check:
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR size
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
script: |
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.issue.number,
|
||||
});
|
||||
|
||||
const additions = pr.additions;
|
||||
const deletions = pr.deletions;
|
||||
const totalChanges = additions + deletions;
|
||||
const changedFiles = pr.changed_files;
|
||||
|
||||
let size = 'S';
|
||||
if (totalChanges > 1000 || changedFiles > 30) size = 'XL';
|
||||
else if (totalChanges > 500 || changedFiles > 20) size = 'L';
|
||||
else if (totalChanges > 200 || changedFiles > 10) size = 'M';
|
||||
|
||||
core.summary
|
||||
.addHeading('PR Size: ' + size, 3)
|
||||
.addTable([
|
||||
[{data: 'Metric', header: true}, {data: 'Count', header: true}],
|
||||
['Files changed', String(changedFiles)],
|
||||
['Additions', '+' + String(additions)],
|
||||
['Deletions', '-' + String(deletions)],
|
||||
['Total changes', String(totalChanges)],
|
||||
]);
|
||||
|
||||
if (size === 'XL') {
|
||||
core.summary.addRaw('⚠️ This PR is very large. Consider splitting it into smaller PRs for easier review.');
|
||||
}
|
||||
|
||||
await core.summary.write();
|
||||
|
||||
if (size === 'XL') {
|
||||
core.warning('This PR has ' + totalChanges + ' changes across ' + changedFiles + ' files. Consider splitting it for easier review.');
|
||||
}
|
||||
|
||||
PR-forbidden-labels:
|
||||
if: ${{ inputs.cron-run == '' || inputs.cron-run == 'false' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: checkoutRepo
|
||||
name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: PR contains forbidden labels
|
||||
id: pr-forbidden
|
||||
- name: Check for forbidden labels
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
script: |
|
||||
const issueHasLabels = require('./scripts/github/update/check-issue-has-label.js');
|
||||
const checkLabels = ['next version ➡️', 'do not merge🙅🏻♂️'];
|
||||
const { data: issue } = await github.rest.issues.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
});
|
||||
const labels = issue.labels?.map(item => item.name) || [];
|
||||
const forbidden = ['next version ➡️', 'do not merge🙅🏻♂️'];
|
||||
|
||||
const hasLabel = await issueHasLabels({github, context, checkLabels})
|
||||
|
||||
if(hasLabel) {
|
||||
if (forbidden.some(l => labels.includes(l))) {
|
||||
core.setFailed('The PR contains a forbidden label! You are not allowed to merge until the label is there.');
|
||||
}
|
||||
- name: Check value after
|
||||
env:
|
||||
STEP_RESULT: ${{ toJson(steps.pr-forbidden.*.result) }}
|
||||
HAS_FAILURE: ${{ contains(toJson(steps.pr-forbidden.*.result), 'failure') }}
|
||||
run: |
|
||||
echo "Step result: $STEP_RESULT"
|
||||
echo "Has failure: $HAS_FAILURE"
|
||||
|
||||
finalize:
|
||||
if: ${{ always() }}
|
||||
@@ -284,16 +330,13 @@ jobs:
|
||||
check-if-pr-is-approved,
|
||||
pre-checks,
|
||||
setup,
|
||||
unit-tests,
|
||||
trigger-unit-tests,
|
||||
lint,
|
||||
build-libs,
|
||||
trigger-build,
|
||||
build-storybook,
|
||||
PR-forbidden-labels,
|
||||
]
|
||||
steps:
|
||||
- name: Check job execution status
|
||||
if: >-
|
||||
${{
|
||||
contains(needs.*.result, 'failure')
|
||||
|| contains(needs.*.result, 'cancelled')
|
||||
}}
|
||||
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
|
||||
run: exit 1
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the latest code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Automatic Rebase
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
name: "release"
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
dry-run-flag:
|
||||
description: 'enable dry-run on artifact push'
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry-run-flag:
|
||||
@@ -15,13 +8,10 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
pull_request:
|
||||
types: [closed]
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- develop-patch*
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- master-patch-*
|
||||
|
||||
@@ -34,8 +24,6 @@ concurrency:
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref }}
|
||||
HEAD_REF: ${{ github.head_ref }}
|
||||
GH_COMMIT: ${{ github.sha }}
|
||||
GH_BUILD_NUMBER: ${{ github.run_id }}
|
||||
LOG_LEVEL: "ERROR"
|
||||
@@ -44,22 +32,23 @@ env:
|
||||
jobs:
|
||||
setup:
|
||||
timeout-minutes: 20
|
||||
if: github.event.pull_request.merged == true || github.ref_name == 'master' || github.ref_name == 'master-patch-*' || github.event_name == 'workflow_dispatch'
|
||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
name: "Setup"
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/setup
|
||||
with:
|
||||
enable-node-modules-cache: false
|
||||
- name: install
|
||||
run: |
|
||||
npm ci
|
||||
npm run bundle:js-api
|
||||
npm run bundle:cli
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm bundle:js-api
|
||||
pnpm bundle:cli
|
||||
- uses: ./.github/actions/upload-node-modules-and-artifacts
|
||||
|
||||
release-npm:
|
||||
@@ -67,21 +56,20 @@ jobs:
|
||||
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-*' || github.event_name == 'workflow_dispatch'
|
||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write # Required for OIDC
|
||||
contents: read
|
||||
packages: write
|
||||
actions: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- id: setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
enable-node-modules-cache: false
|
||||
- id: set-dryrun
|
||||
uses: ./.github/actions/enable-dryrun
|
||||
with:
|
||||
@@ -100,24 +88,24 @@ jobs:
|
||||
setMigrations();
|
||||
- name: build libraries
|
||||
run: |
|
||||
npm run build:libs
|
||||
npm run build:schematics
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
pnpm build:libs
|
||||
pnpm build:schematics
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
name: release libraries GH registry
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
registry-url: 'https://npm.pkg.github.com'
|
||||
scope: '@alfresco'
|
||||
- run: npm run publish -- --tag=${{ steps.setup.outputs.npm-tag }}
|
||||
- run: pnpm run publish --tag ${{ steps.setup.outputs.npm-tag }} --provenance=false ${{ steps.set-dryrun.outputs.dryrun }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
|
||||
- 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: npm run publish -- --tag=${{ steps.setup.outputs.npm-tag }}
|
||||
- run: pnpm run publish --tag ${{ steps.setup.outputs.npm-tag }} ${{ steps.set-dryrun.outputs.dryrun }}
|
||||
|
||||
create-git-tag:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -128,41 +116,21 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- uses: './.github/actions/create-git-tag'
|
||||
with:
|
||||
tagName: ${{ needs.release-npm.outputs.release_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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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-*' || github.event_name == 'workflow_dispatch'
|
||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: ./.github/actions/npm-check-bundle
|
||||
|
||||
push-translation-keys-to-crowdin:
|
||||
@@ -176,10 +144,10 @@ jobs:
|
||||
actions: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Push Source Files to Crowdin
|
||||
uses: crowdin/github-action@7ca9c452bfe9197d3bb7fa83a4d7e2b0c9ae835d # v2.16.0
|
||||
uses: crowdin/github-action@c7af9bc98b01694653031fef2a0dc6c7888ce9bc # v2.17.0
|
||||
with:
|
||||
upload_sources: true
|
||||
upload_sources_args: --delete-obsolete
|
||||
@@ -191,8 +159,9 @@ jobs:
|
||||
name: Run Crowdin pull pipeline for up-to-date sync
|
||||
uses: ./.github/workflows/pull-from-crowdin.yml
|
||||
secrets:
|
||||
BOT_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||
GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY: ${{ secrets.GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY }}
|
||||
CROWDIN_TRANSLATIONS_TOKEN: ${{ secrets.CROWDIN_TRANSLATIONS_TOKEN }}
|
||||
HXPS_GIT_COMMIT_SIGNING_PRIVATE_KEY: ${{ secrets.HXPS_GIT_COMMIT_SIGNING_PRIVATE_KEY }}
|
||||
|
||||
finalize:
|
||||
if: always()
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
name: Stale PR Cleanup
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
stale-pr-cleanup:
|
||||
uses: Alfresco/alfresco-build-tools/.github/workflows/stale-pr-cleanup.yml@44f603af32dc79129056a9e4246ab62f35987a2b # v18.21.1
|
||||
@@ -0,0 +1,31 @@
|
||||
name: Supply Chain Review - PR Instructions
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
paths:
|
||||
- "package.json"
|
||||
- "pnpm-lock.yaml"
|
||||
- "**/package.json"
|
||||
- "pom.xml"
|
||||
- "**/pom.xml"
|
||||
|
||||
jobs:
|
||||
instructions:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: Alfresco/alfresco-build-tools/.github/actions/github-upsert-comment@44f603af32dc79129056a9e4246ab62f35987a2b # v18.21.1
|
||||
with:
|
||||
comment-identifier: supply-chain-review-instructions
|
||||
comment-body: |
|
||||
## 🔒 Supply Chain Security
|
||||
|
||||
This PR modifies dependencies. To run a security analysis, comment:
|
||||
|
||||
```
|
||||
/supply-chain-review
|
||||
```
|
||||
|
||||
The analysis will check for vulnerabilities, typosquatting, maintainer takeovers, and other supply chain risks.
|
||||
+1796
File diff suppressed because one or more lines are too long
@@ -0,0 +1,362 @@
|
||||
---
|
||||
on:
|
||||
slash_command:
|
||||
name: supply-chain-review
|
||||
reaction: rocket
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
engine:
|
||||
id: copilot
|
||||
model: gpt-5-mini
|
||||
|
||||
tools:
|
||||
github:
|
||||
toolsets: [context, pull_requests, repos]
|
||||
|
||||
network:
|
||||
allowed:
|
||||
- defaults
|
||||
- node
|
||||
- java
|
||||
- api.osv.dev
|
||||
- api.scorecard.dev
|
||||
- search.maven.org
|
||||
|
||||
safe-outputs:
|
||||
add-comment:
|
||||
hide-older-comments: true
|
||||
add-labels:
|
||||
allowed: [security:low, security:medium, security:high]
|
||||
remove-labels:
|
||||
allowed: [security:low, security:medium, security:high]
|
||||
submit-pull-request-review:
|
||||
|
||||
source: Alfresco/alfresco-build-tools/.github/workflows/supply-chain-review.md@7bc0fc6f4f11df6c065b57d4a6aa90d7ea362b2f
|
||||
---
|
||||
|
||||
# Supply Chain Review
|
||||
|
||||
You are a supply chain security analyst reviewing a pull request for dependency changes.
|
||||
Your goal is to identify any dependency additions or upgrades and produce a thorough risk assessment for each change, covering known vulnerabilities, typosquatting, maintainer takeover, install script abuse, version anomalies, source code changes, and project health.
|
||||
|
||||
You are the primary and only analysis engine. There is no secondary check. Be thorough but calibrated: false positives erode trust, but missed threats have severe consequences.
|
||||
|
||||
## Step 1 — Identify Dependency Changes
|
||||
|
||||
Read the **full** pull request diff — every commit in the PR, not just the latest one — and find all modified dependency files (`package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`/`pnpm-lock.yml`, `pnpm-workspace.yaml`/`pnpm-workspace.yml`, `npm-shrinkwrap.json`, `pom.xml`, `build.gradle`, etc.).
|
||||
|
||||
**CRITICAL**: always use the GitHub MCP Server `pull_requests` toolset (e.g. `get_diff` / `get_files`) to fetch the diff — this always reflects every commit in the PR, regardless of local git history, against the correct base branch. Do NOT rely on local git commands or assumptions about the PR's commit history.
|
||||
|
||||
For each changed dependency extract:
|
||||
|
||||
- Package name (including scope/groupId if applicable)
|
||||
- Ecosystem (`npm` or `maven`)
|
||||
- Old version (or mark as `NEW DEPENDENCY` if newly added)
|
||||
- New version
|
||||
|
||||
If no dependency files were changed, post a brief PR comment stating that no dependency changes were detected and no review is needed, then stop.
|
||||
|
||||
## Step 1b — Filter Internal Dependencies
|
||||
|
||||
Before collecting external data, identify and exclude internal/private dependencies that cannot be resolved by public APIs.
|
||||
|
||||
**Internal dependency namespaces (skip these):**
|
||||
|
||||
- **Maven**: Any dependency with a `groupId` starting with `com.hyland.`, `org.alfresco.`, or `org.activiti.`
|
||||
- **npm**: Any package under the `@hyland/`, `@hylandsoftware/`, or `@alfresco/` scopes
|
||||
|
||||
For each internal dependency found:
|
||||
|
||||
1. Remove it from the analysis pipeline — do NOT query OSV.dev, OpenSSF Scorecard, or registry APIs for these packages (they will fail or return irrelevant data).
|
||||
2. Record the package name (with `@` replaced by `(at)` for GitHub comment compatibility), ecosystem, old version, and new version in a separate "Internal Dependencies (Skipped)" list.
|
||||
3. Continue with Step 2 only for the remaining external/public dependencies.
|
||||
|
||||
If ALL changed dependencies are internal, skip Steps 2-4 and proceed directly to Step 5, posting a report that lists the internal dependencies and notes that no external supply chain analysis was performed.
|
||||
|
||||
## Step 2 — Collect Data for Each Dependency
|
||||
|
||||
For every changed dependency, gather the following data. Fetch all data sources in parallel where possible. If any request fails or returns no data, note it and continue — missing data alone is not proof of malice, but factor it into your confidence level.
|
||||
|
||||
### 2a. Known Vulnerabilities (OSV.dev)
|
||||
|
||||
Query the OSV.dev API for vulnerabilities affecting the **new** version:
|
||||
|
||||
- **npm**: `POST https://api.osv.dev/v1/query` with body `{"package":{"name":"<package-name>","ecosystem":"npm"},"version":"<new-version>"}`
|
||||
- **Maven**: `POST https://api.osv.dev/v1/query` with body `{"package":{"name":"<groupId>:<artifactId>","ecosystem":"Maven"},"version":"<new-version>"}`
|
||||
|
||||
Record all returned vulnerability IDs, severity ratings, and summaries. CRITICAL and HIGH severity CVEs in the new version are the most urgent signal.
|
||||
|
||||
### 2b. OpenSSF Scorecard
|
||||
|
||||
Fetch the project health score. First determine the source repository from the package metadata (see 2c), then query:
|
||||
|
||||
`GET https://api.scorecard.dev/projects/github.com/{owner}/{repo}`
|
||||
|
||||
Record the overall score (0-10) and individual check results. Pay special attention to: Maintained, Code-Review, Vulnerabilities, Branch-Protection, Signed-Releases. A score below 3 is very concerning; below 5 warrants caution. If the package has no linked source repository, the scorecard will be unavailable — this is itself a risk signal.
|
||||
|
||||
### 2c. Package Metadata (Registry)
|
||||
|
||||
**For npm packages**, fetch:
|
||||
|
||||
`GET https://registry.npmjs.org/<package-name>`
|
||||
|
||||
From the full registry document, extract for BOTH the old and new versions:
|
||||
|
||||
- `versions[<version>]._npmUser` — the publisher
|
||||
- `versions[<version>].maintainers` — the maintainer list
|
||||
- `versions[<version>].scripts` — lifecycle scripts (`preinstall`, `install`, `postinstall`)
|
||||
- `versions[<version>].dependencies` — runtime dependencies
|
||||
- `time[<version>]` — publish timestamp
|
||||
- `repository` — source repository URL
|
||||
|
||||
Also extract the `time` object to build a version history (last 10 versions with publish dates).
|
||||
|
||||
**For Maven packages**, fetch:
|
||||
|
||||
`GET https://central.sonatype.com/api/v1/search?q=g:<groupId>+AND+a:<artifactId>&sort=published&limit=10`
|
||||
|
||||
For POM details (build plugins, dependencies): `GET https://repo1.maven.org/maven2/<groupId-as-path>/<artifactId>/<version>/<artifactId>-<version>.pom`
|
||||
|
||||
### 2d. Source Code Diff and Release Notes
|
||||
|
||||
Use the PR diff itself to review the actual file changes for dependency manifest files. Additionally, if a source repository is identified (from 2c), fetch release notes and compare tags:
|
||||
|
||||
- Release notes: `GET https://api.github.com/repos/{owner}/{repo}/releases/tags/v<new-version>` (try with and without the `v` prefix)
|
||||
- For a code-level diff between old and new versions: `GET https://api.github.com/repos/{owner}/{repo}/compare/v<old-version>...v<new-version>` (try with and without the `v` prefix)
|
||||
|
||||
## Step 3 — Analyze Against Threat Taxonomy
|
||||
|
||||
Evaluate each dependency against ALL of the following threat categories. Not every category applies to every package — use judgment.
|
||||
|
||||
### 3a. Known Vulnerabilities
|
||||
|
||||
Assess the severity and exploitability of any CVEs or advisories returned from OSV.dev. CRITICAL and HIGH severity vulnerabilities in the new version are the most urgent signal. Also check whether the upgrade itself fixes known vulnerabilities in the old version (a positive signal).
|
||||
|
||||
### 3b. Typosquatting / Name Confusion
|
||||
|
||||
Determine if the package name could be a typosquatting attempt targeting a well-known package. Consider:
|
||||
|
||||
- Levenshtein distance to popular packages (e.g., `lodas` vs `lodash`)
|
||||
- Dash/underscore/separator swaps (e.g., `my_package` vs `my-package`)
|
||||
- Suffix variants (e.g., `express-js`, `express.js`)
|
||||
- Scope squatting for npm (e.g., `@attacker/lodash` vs `lodash`)
|
||||
- GroupId squatting for Maven (e.g., `org.apach.commons` vs `org.apache.commons`)
|
||||
|
||||
Use your knowledge of the ecosystem to identify plausible targets. Reason from your training data about popular packages.
|
||||
|
||||
### 3c. Maintainer Takeover
|
||||
|
||||
Compare the publisher and maintainer metadata between the old and new versions. Red flags:
|
||||
|
||||
- Publisher changed between versions (different `_npmUser`)
|
||||
- Old maintainers removed and replaced
|
||||
- New publisher has no prior history with the package
|
||||
- Classic pattern: publisher change + maintainer removal (like the event-stream incident)
|
||||
|
||||
### 3d. Install Script Abuse
|
||||
|
||||
**For npm**: Analyze lifecycle scripts (`preinstall`, `install`, `postinstall`) from the registry metadata. Red flags:
|
||||
|
||||
- Scripts that download and execute remote code (`curl`, `wget`, `http://`)
|
||||
- `eval()`, `Function()`, `child_process` usage
|
||||
- Environment variable access (`process.env`) for credential theft
|
||||
- Base64/hex decoding of payloads
|
||||
- Access to sensitive paths (`~/.ssh`, `~/.aws`, `~/.npmrc`, `/etc/passwd`)
|
||||
- Network calls (`dns.lookup`, `net.connect`) for exfiltration
|
||||
- Scripts that are NEW in this version (not present in the old version) are especially suspicious
|
||||
|
||||
**For Maven**: Look for dangerous build plugins in POM changes:
|
||||
|
||||
- `exec-maven-plugin`, `maven-antrun-plugin` with `<exec>`
|
||||
- `<extensions>true</extensions>` on untrusted plugins
|
||||
- Download plugins, Groovy/script plugins
|
||||
|
||||
### 3e. Version Anomalies
|
||||
|
||||
Analyze the version change pattern and history from the registry metadata:
|
||||
|
||||
- Major version jumps (skipping 1+ major versions)
|
||||
- Version downgrade (new version < old version)
|
||||
- Stable to prerelease transition
|
||||
- Very recent publish (less than 48 hours old) — could indicate a rush to distribute malicious code
|
||||
- Rapid successive publishes (many versions in a short window)
|
||||
- Long dormancy then sudden publish (more than 1 year gap) — may indicate account takeover
|
||||
|
||||
### 3f. Source Code Changes
|
||||
|
||||
If source diffs are available (from the GitHub compare API or the PR diff itself), analyze for:
|
||||
|
||||
- Obfuscated code (minified without source maps, hex/unicode escapes, string concatenation to hide function names)
|
||||
- Data exfiltration (network calls sending `process.env`, API keys, tokens to external endpoints)
|
||||
- Filesystem access outside the package directory
|
||||
- Dynamic code execution (`eval()`, `Function()`, `vm.runInNewContext`, `WebAssembly.instantiate`)
|
||||
- Encoded payloads (Base64/hex decoded and executed at runtime)
|
||||
- Inconsistency between release notes and actual changes (changelog says "bug fix" but diff adds network calls)
|
||||
- Cryptocurrency mining patterns
|
||||
- Suspicious new transitive dependencies
|
||||
|
||||
### 3g. Project Health
|
||||
|
||||
Interpret the OpenSSF Scorecard data:
|
||||
|
||||
- Overall score below 3/10 is very concerning
|
||||
- Score below 5/10 warrants caution
|
||||
- Pay attention to specific failing checks: Maintained, Code-Review, Vulnerabilities, Branch-Protection, Signed-Releases
|
||||
- Missing scorecard data (no source repo linked) is itself a risk signal
|
||||
|
||||
### 3h. Missing Source Repository
|
||||
|
||||
A package with no linked source repository prevents code audit and is a risk signal, especially combined with other concerns.
|
||||
|
||||
### 3i. Tag Poisoning / Build Provenance
|
||||
|
||||
Evaluate whether the published artifact can be traced back to a verified source commit. This category covers attacks where a legitimate-looking version tag is manipulated to distribute malicious code.
|
||||
|
||||
#### Tag-to-Registry Provenance Mismatch
|
||||
|
||||
Check whether the git tag for the new version corresponds to the published artifact:
|
||||
|
||||
- Compare the tag commit date with the registry publish timestamp. A discrepancy of more than a few hours (allowing for CI/CD pipeline time) is suspicious.
|
||||
- If the source diff between the tag and the previous tag includes changes not documented in release notes, flag as suspicious.
|
||||
|
||||
#### Mutable/Moved Tags
|
||||
|
||||
Check if the tag appears to have been recreated:
|
||||
|
||||
- Use `GET https://api.github.com/repos/{owner}/{repo}/git/refs/tags/{tag}` to get the tag reference.
|
||||
- For annotated tags, use `GET https://api.github.com/repos/{owner}/{repo}/git/tags/{sha}` to check the tag object and its `tagger.date`.
|
||||
- If the tag creation date is significantly newer than the commit it points to (e.g., more than 7 days), this may indicate the tag was deleted and recreated pointing to a different commit.
|
||||
|
||||
#### Unsigned Tags
|
||||
|
||||
Determine tag type and signing status:
|
||||
|
||||
- **Annotated + signed tags** (GPG or SSH signature present) — strongest integrity signal.
|
||||
- **Annotated but unsigned tags** — moderate integrity; the tag is immutable but unverified.
|
||||
- **Lightweight tags** — weakest integrity; easily moved without trace. Flag as a risk signal for high-profile or security-critical packages.
|
||||
|
||||
For the tag object, check the `verification` field in the GitHub API response for signature status.
|
||||
|
||||
#### Build Provenance / Attestation
|
||||
|
||||
Check for SLSA provenance attestations or Sigstore signatures:
|
||||
|
||||
**For npm packages**: Query `GET https://registry.npmjs.org/-/npm/v1/attestations/<package-name>@<new-version>`. If attestations are present, verify:
|
||||
|
||||
- The `predicateType` matches a known SLSA provenance type
|
||||
- The `subject` digest matches the published package tarball
|
||||
- The build was performed by a trusted CI system (e.g., GitHub Actions)
|
||||
|
||||
**For Maven packages**: Check if Sigstore `.sigstore` bundle files exist alongside the artifact at:
|
||||
`GET https://repo1.maven.org/maven2/<groupId-as-path>/<artifactId>/<version>/<artifactId>-<version>.jar.sigstore`
|
||||
|
||||
The absence of provenance attestations on a high-profile package (>1000 weekly downloads for npm, or widely used in the ecosystem) is a moderate risk signal. Packages that previously published with provenance but stopped doing so are especially suspicious.
|
||||
|
||||
#### Tag Mimicry on Forks
|
||||
|
||||
Verify that the source repository URL in registry metadata points to the canonical repository:
|
||||
|
||||
- Cross-reference the `repository` field from package metadata (Step 2c) with the GitHub API response.
|
||||
- If the repository URL points to a fork rather than the original project, flag as HIGH risk — this may indicate a hijacked tag on a lookalike fork.
|
||||
- Check that the repository owner matches known maintainers of the package.
|
||||
|
||||
## Step 4 — Score and Classify Risk
|
||||
|
||||
Assign a risk score (0-100) to each dependency using these guidelines:
|
||||
|
||||
| Priority | Signal | Typical Impact |
|
||||
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
|
||||
| Highest | Known CRITICAL/HIGH CVEs in new version, confirmed typosquatting, malicious code in diff, build provenance mismatch (tag points to different code than published artifact), tag mimicry on fork | 60+ points |
|
||||
| High | Maintainer takeover pattern (publisher changed + old maintainers removed), dangerous install scripts, known compromised package, moved/recreated tag with different commit, provenance attestations removed from package that previously had them | 20-40 points |
|
||||
| Medium | Low OpenSSF Scorecard (< 3), publisher changed (without full takeover), new install scripts, very recent publish (< 48h), obfuscated code in diff, unsigned lightweight tags on security-critical packages, absence of provenance on high-profile packages | 10-20 points |
|
||||
| Lower | Scorecard 3-5, version anomalies, missing source repository, long dormancy, rapid publishes, tag date slightly newer than commit (within 7 days), annotated but unsigned tags | 5-10 points |
|
||||
|
||||
These are guidelines, not rigid formulas. Use judgment to combine signals — multiple medium signals can compound into a high-risk assessment.
|
||||
|
||||
**Risk level thresholds**: 0-20 = LOW, 21-50 = MEDIUM, 51-80 = HIGH, 81-100 = CRITICAL.
|
||||
|
||||
If no suspicious patterns are found, assign a score of 0-10 and risk level LOW. Most legitimate upgrades should score LOW.
|
||||
|
||||
## Step 5 — Post Findings as PR Comment
|
||||
|
||||
Post a structured report in the following format.
|
||||
|
||||
**CRITICAL: Sanitize all `@` symbols before posting**
|
||||
|
||||
GitHub enforces a maximum of 10 mentions per comment. Package names containing `@` (like `@hyland/core`, `@alfresco/js-api`) are interpreted as user/team mentions and trigger this limit, causing comment post failures.
|
||||
|
||||
**Before generating the comment text**:
|
||||
|
||||
1. Replace **every** `@` symbol in package names with `(at)` — e.g., `@hyland/core` → `(at)hyland/core`
|
||||
2. Apply this transformation to ALL occurrences: table cells, headings, inline code blocks, findings sections, reason columns
|
||||
3. This applies to both external and internal dependencies
|
||||
4. Do NOT skip this step — even if only a few packages are affected, GitHub counts all `@` symbols
|
||||
|
||||
```txt
|
||||
## Supply Chain Security Review
|
||||
|
||||
| Package | Ecosystem | Old Version | New Version | Risk Score | Risk Level |
|
||||
|---------|-----------|-------------|-------------|------------|------------|
|
||||
| example | npm | 1.0.0 | 2.0.0 | 5 | LOW |
|
||||
|
||||
### Internal Dependencies (Skipped)
|
||||
|
||||
| Package | Ecosystem | Old Version | New Version | Reason |
|
||||
|-------------------|-----------|-------------|-------------|---------------------------------|
|
||||
| (at)hyland/core | npm | 3.1.0 | 3.2.0 | Internal ((at)hyland/* scope) |
|
||||
|
||||
_These dependencies are internal packages not available on public registries. External API checks were skipped._
|
||||
|
||||
### Findings
|
||||
|
||||
#### `<package-name-sanitized>` (<old-version> -> <new-version>) — <RISK_LEVEL>
|
||||
|
||||
**Risk Score**: <score>/100
|
||||
|
||||
<If findings exist, list each one:>
|
||||
|
||||
**<Category>** (<severity>) — <title>
|
||||
<detailed explanation with specific evidence>
|
||||
|
||||
<If no findings:>
|
||||
No suspicious patterns detected. Routine upgrade.
|
||||
|
||||
---
|
||||
|
||||
### Data Collection Notes
|
||||
|
||||
<List any APIs that were unavailable or returned errors, so reviewers know what was and wasn't checked.>
|
||||
|
||||
---
|
||||
|
||||
### Overall Risk: <highest risk level across all dependencies>
|
||||
|
||||
**Recommendation**: <approve|review|block>
|
||||
- **approve**: LOW risk, routine upgrade, no concerns found
|
||||
- **review**: MEDIUM risk, a human should examine specific findings before merging
|
||||
- **block**: HIGH/CRITICAL risk, should not be merged without security team review
|
||||
```
|
||||
|
||||
## Step 6 — Apply Label and Review Status
|
||||
|
||||
- First, remove any `security:low`, `security:medium`, or `security:high` labels already present on the PR from a previous review — this PR may have been reviewed before (e.g., after a new commit), and stale risk labels must not remain alongside the new one.
|
||||
- Then apply a label to the PR based on the highest risk level found:
|
||||
- `security:low` for LOW risk
|
||||
- `security:medium` for MEDIUM risk
|
||||
- `security:high` for HIGH or CRITICAL risk
|
||||
- If the highest risk level is HIGH or CRITICAL, submit a pull request review requesting changes, with a summary of the critical findings.
|
||||
- If the risk is MEDIUM, submit a pull request review as a comment, noting that human review is recommended.
|
||||
- If the risk is LOW, do not submit a review — the PR comment is sufficient.
|
||||
|
||||
## Important Guidelines
|
||||
|
||||
- **Never approve or merge the PR** — all actions are advisory or blocking only. A human always makes the merge decision.
|
||||
- Be specific in findings — cite exact data (vulnerability ID, maintainer name, script content, file path, API response) rather than vague warnings.
|
||||
- For Maven packages, adapt npm-specific checks appropriately (e.g., install scripts become build plugin analysis, maintainer metadata may be limited).
|
||||
- When a package is a NEW dependency (no old version), pay extra attention to project health, name legitimacy, and install scripts since there is no historical baseline to compare against.
|
||||
- If data collection fails for all external APIs, still analyze the PR diff directly and provide the best assessment you can with available information, noting the limitations clearly.
|
||||
- For tag poisoning checks, not all packages will have provenance attestations — this is still an emerging practice. Weight the absence of attestations proportionally to the package's profile and criticality. Do not flag low-download utility packages for missing provenance.
|
||||
- When checking tag dates, allow for reasonable CI/CD pipeline delays (up to a few hours between tag push and publish). Only flag significant discrepancies (days or weeks).
|
||||
@@ -0,0 +1,81 @@
|
||||
name: "Unit Tests Workflow"
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
base_ref:
|
||||
description: 'Base branch for affected calculation'
|
||||
required: false
|
||||
type: string
|
||||
default: 'develop'
|
||||
|
||||
jobs:
|
||||
generate-affected-matrix:
|
||||
name: "Generate affected matrix"
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
unitMatrix: ${{ steps.set-matrix.outputs.unitMatrix }}
|
||||
hasProjects: ${{ steps.set-matrix.outputs.hasProjects }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup environment
|
||||
id: setup-env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
cache-suffix: test-matrix
|
||||
- name: Generate affected projects matrix
|
||||
id: set-matrix
|
||||
env:
|
||||
BASE_REF: ${{ inputs.base_ref }}
|
||||
run: |
|
||||
echo "Base ref is $BASE_REF"
|
||||
AFFECTED_UNIT=$(pnpm nx show projects --affected --target=test --base=origin/$BASE_REF --head=HEAD --select=projects --plain --exclude=cli,stories,eslint-angular)
|
||||
echo "Affected projects for UNIT: $AFFECTED_UNIT"
|
||||
|
||||
if [ -z "$AFFECTED_UNIT" ]; then
|
||||
echo "No affected projects found"
|
||||
echo "hasProjects=false" >> $GITHUB_OUTPUT
|
||||
echo "unitMatrix=[]" >> $GITHUB_OUTPUT
|
||||
else
|
||||
UNIT_MATRIX_JSON=$(echo "$AFFECTED_UNIT" | xargs -n1 | jq -R -s -c 'split("\n") | map(select(length > 0)) | map({ "project": . })')
|
||||
echo "Matrix UNIT: $UNIT_MATRIX_JSON"
|
||||
echo "hasProjects=true" >> $GITHUB_OUTPUT
|
||||
echo "unitMatrix=$UNIT_MATRIX_JSON" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Save nx cache
|
||||
if: ${{ success() }}
|
||||
uses: ./.github/actions/save-nx-cache
|
||||
with:
|
||||
cache-suffix: test-matrix
|
||||
|
||||
unit-tests:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
needs: generate-affected-matrix
|
||||
if: ${{ needs.generate-affected-matrix.outputs.hasProjects == 'true' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include: ${{ fromJson(needs.generate-affected-matrix.outputs.unitMatrix) }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Setup environment
|
||||
id: setup-env
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
cache-suffix: test-${{ matrix.project }}
|
||||
full-setup: 'false'
|
||||
- name: Run unit tests for ${{ matrix.project }}
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=5120"
|
||||
run: |
|
||||
xvfb-run --auto-servernum pnpm nx run ${{ matrix.project }}:test
|
||||
- name: Save nx cache
|
||||
if: ${{ success() }}
|
||||
uses: ./.github/actions/save-nx-cache
|
||||
with:
|
||||
cache-suffix: test-${{ matrix.project }}
|
||||
+1
-1
@@ -8,7 +8,6 @@ bundles
|
||||
dist
|
||||
tmp
|
||||
temp
|
||||
*.npmrc
|
||||
.history
|
||||
.ng_pkg_build/
|
||||
coverage/
|
||||
@@ -24,3 +23,4 @@ nxcache
|
||||
.husky
|
||||
.cursor/rules/nx-rules.mdc
|
||||
.github/instructions/nx.instructions.md
|
||||
lib/eslint-angular/dist/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
export NODE_OPTIONS=--max_old_space_size=8192
|
||||
|
||||
lint-staged
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"*.{ts,js}": ["prettier --write", "eslint"],
|
||||
"*.{ts,js}": ["prettier --write", "eslint --flag v10_config_lookup_from_file"],
|
||||
"*.{css,scss}": ["prettier --write", "stylelint --fix"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Fail on high severity vulnerabilities during audit
|
||||
audit-level=high
|
||||
|
||||
# Use exact versions to prevent unexpected updates
|
||||
save-exact=true
|
||||
@@ -1,6 +1,12 @@
|
||||
{
|
||||
"extends": ["stylelint-config-standard-scss"],
|
||||
"rules": {
|
||||
"custom-property-pattern": [
|
||||
"^(mat-sys|mdc)",
|
||||
{
|
||||
"message": "Use only Angular Material system variables (--mat-sys-*, --mdc-*)"
|
||||
}
|
||||
],
|
||||
"color-function-notation": "legacy",
|
||||
"alpha-value-notation": "number",
|
||||
"color-no-invalid-hex": true,
|
||||
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"meterian.meterian-heidi"
|
||||
]
|
||||
}
|
||||
@@ -21,6 +21,29 @@ for full details on what you may need to install before using ADF.
|
||||
- [Node Version Manager](docs/tutorials/nvm.md)
|
||||
- [CORS guide](ALFRESCOCORS.md)
|
||||
|
||||
## Installation
|
||||
|
||||
This project uses **pnpm** for package management with built-in supply chain attack protection.
|
||||
|
||||
```bash
|
||||
pnpm install # install all packages
|
||||
pnpm run add <package> # add a new package (with security check)
|
||||
```
|
||||
|
||||
### Supply Chain Security
|
||||
|
||||
**Layer 1: pnpm script blocking**
|
||||
- All lifecycle scripts (postinstall, etc.) are blocked by default
|
||||
- Only trusted packages in `pnpm-workspace.yaml` can run scripts
|
||||
- Protects during `pnpm install` and `pnpm add`
|
||||
|
||||
**Layer 2: Security database check**
|
||||
- `pnpm run add` checks packages against OSV and GitHub Advisory databases BEFORE installing
|
||||
- Pre-commit hook blocks commits containing known malicious packages
|
||||
|
||||
**Layer 3: npm blocked**
|
||||
- Running `npm install` will fail - enforces pnpm usage
|
||||
|
||||
## Components
|
||||
|
||||
You can find the sources for all ADF components in the [`lib`](/lib) folder.
|
||||
|
||||
+9
-2
@@ -351,7 +351,6 @@ for more information about installing and using the source code.
|
||||
|
||||
| Name | Description | Source link |
|
||||
| ---- | ----------- | ----------- |
|
||||
| [Agent Service](content-services/services/agent.service.md) | Manages agents in Content Services. | [Source](../lib/content-services/src/lib/agent/services/agent.service.ts) |
|
||||
| [Audit Service](content-services/services/audit.service.md) | Manages Audit apps and entries. | [Source](../lib/content-services/src/lib/audit/audit.service.ts) |
|
||||
| [Card View Content Update Service](content-services/services/card-view-content-update.service.md) | Manages Card View properties in the content services environment. Implements BaseCardViewContentUpdate. | [Source](../lib/content-services/src/lib/common/services/card-view-content-update.service.ts) | |
|
||||
| [Category tree datasource service](content-services/services/category-tree-datasource.service.md) | Datasource service for category tree. | [Source](../lib/content-services/src/lib/category/services/category-tree-datasource.service.ts) |
|
||||
@@ -367,7 +366,6 @@ for more information about installing and using the source code.
|
||||
| [Node Comments Service](content-services/services/node-comments.service.md) | Adds and retrieves comments for nodes in Content Services. | [Source](../lib/content-services/src/lib/node-comments/services/node-comments.service.ts) |
|
||||
| [Node permission dialog service](content-services/services/node-permission-dialog.service.md) | Displays dialogs to let the user set node permissions. | [Source](../lib/content-services/src/lib/permission-manager/services/node-permission-dialog.service.ts) |
|
||||
| [Node Permission service](content-services/services/node-permission.service.md) | Manages role permissions for content nodes. | [Source](../lib/content-services/src/lib/permission-manager/services/node-permission.service.ts) |
|
||||
| [Search Ai Service](content-services/services/search-ai.service.md) | Manages search AI in Content Services. | [Source](../lib/content-services/src/lib/search-ai/services/search-ai.service.ts) |
|
||||
| [Search filter service](content-services/services/search-filter.service.md) | Registers widgets for use with the Search Filter component. | [Source](../lib/content-services/src/lib/search/services/search-filter.service.ts) |
|
||||
| [Search Query Builder service](content-services/services/search-query-builder.service.md) | Stores information from all the custom search and faceted search widgets, compiles and runs the final search query. | [Source](../lib/content-services/src/lib/search/services/search-query-builder.service.ts) |
|
||||
| [Security Controls service](content-services/services/security-controls.service.md) | Manages security groups & marks in Content Services. | [Source](../lib/content-services/src/lib/security/services/security-controls-groups-marks-security.service.ts) |
|
||||
@@ -567,3 +565,12 @@ Contains all custom rules used by ESLint.
|
||||
<!--eslint-angular end-->
|
||||
|
||||
[(Back to Contents)](#contents)
|
||||
|
||||
## Notes
|
||||
|
||||
### Knowledge Discovery removal (v9.0.0)
|
||||
|
||||
The Knowledge Discovery components, services, and APIs have been removed as of version 9.0.0.
|
||||
The integrated Knowledge Discovery features have been replaced with a section in the side navigation panel containing a link to the standalone Knowledge Discovery UI application in higher level apps such as ACA and ADW.
|
||||
|
||||
If you were using those features, please consider cleaning Local Storage in your browser as *aiReferences* entry may remain.
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# CI Commands and Labels
|
||||
|
||||
Reference for flags and labels that control CI behavior on pull requests.
|
||||
|
||||
## PR Title Flags
|
||||
|
||||
Include these flags anywhere in the **PR title** to modify CI behavior.
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `[ci:force]` | Skips the PR approval check, allowing the full pipeline to run without an approved review. Useful for testing CI changes on draft PRs. |
|
||||
|
||||
Example: `[AAE-12345] Fix pagination component [ci:force]`
|
||||
|
||||
## Commit Message Flags
|
||||
|
||||
Include these flags in a **commit message** to modify CI behavior.
|
||||
|
||||
| Flag | Effect |
|
||||
|------|--------|
|
||||
| `[ci:force]` | Skips the PR approval check (same as PR title flag). |
|
||||
| `[affected:*]` | Forces all Nx targets to run against all projects, ignoring the affected calculation. Equivalent to `--all`. |
|
||||
|
||||
## PR Labels
|
||||
|
||||
Labels applied to the PR that affect CI behavior.
|
||||
|
||||
| Label | Effect |
|
||||
|-------|--------|
|
||||
| `do not merge` | Blocks the PR from passing the finalize check. CI will fail until the label is removed. |
|
||||
| `next version` | Same as above - blocks the PR from merging. Used to hold PRs for the next release cycle. |
|
||||
|
||||
## Automatic Skip Conditions
|
||||
|
||||
The approval check is automatically skipped for:
|
||||
|
||||
- **Scheduled runs** (`schedule` event)
|
||||
- **Workflow dispatch** (`workflow_dispatch` event)
|
||||
- **Dependabot PRs** (actor is `dependabot[bot]`)
|
||||
- **Build bot PRs** (actor is `alfresco-build`)
|
||||
- **Devel flag** (when `devel: true` is passed via `workflow_call`)
|
||||
|
||||
## Path-Based Filtering
|
||||
|
||||
PRs that only modify non-code files skip the build, test, and lint jobs entirely. Files considered non-code:
|
||||
|
||||
- Markdown files (`*.md`)
|
||||
- Documentation (`docs/`)
|
||||
- `LICENSE`, `NOTICE`
|
||||
- `.editorconfig`, `.gitattributes`
|
||||
- `.github/CODEOWNERS`, `.github/dependabot.yml`
|
||||
|
||||
## PR Size Check
|
||||
|
||||
Every PR gets an automatic size classification displayed in the job summary:
|
||||
|
||||
| Size | Criteria |
|
||||
|------|----------|
|
||||
| **S** | < 200 total changes and < 10 files |
|
||||
| **M** | 200-500 total changes or 10-20 files |
|
||||
| **L** | 500-1000 total changes or 20-30 files |
|
||||
| **XL** | > 1000 total changes or > 30 files (warning annotation added) |
|
||||
@@ -417,7 +417,8 @@ Once you have enabled this feature you will be able to double click on your meta
|
||||
"exif:exif": [ "exif:pixelXDimension", "exif:pixelYDimension"]
|
||||
}
|
||||
},
|
||||
"copy-to-clipboard-action": true
|
||||
"copy-to-clipboard-action": true,
|
||||
"display-copy-to-clipboard-icon": true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -46,9 +46,9 @@ Implements a [search widget](../../../lib/content-services/src/lib/search/models
|
||||
| field | string | Field to apply the query fragment to. Required value |
|
||||
| pattern | string | Regular expression pattern to restrict the format of the input text |
|
||||
| placeholder | string | Text displayed in the widget when the input string is empty |
|
||||
| searchSuffix | string | Text to append always in the search of a string |
|
||||
| searchPrefix | string | Text to prepend always in the search of a string |
|
||||
| allowUpdateOnChange | `boolean` | Enable/Disable the update fire event when text has been changed. By default is true. |
|
||||
| searchSuffix | string | Text to append in the search of a string. Only applied when wildcard matching is enabled (the `search-wildcards-enabled` app config flag, default `true`). |
|
||||
| searchPrefix | string | Text to prepend in the search of a string. Only applied when wildcard matching is enabled (the `search-wildcards-enabled` app config flag, default `true`). |
|
||||
| allowUpdateOnChange | `boolean` | Enable/Disable firing the search update when the text changes. Defaults to `false`; when disabled the search runs only when the user submits the value. |
|
||||
| hideDefaultAction | boolean | Show/hide the widget actions. By default is false. |
|
||||
|
||||
## Details
|
||||
|
||||
@@ -13,7 +13,6 @@ Update the current node by adding/removing the inherited permissions.
|
||||
|
||||
```html
|
||||
<button mat-raised-button
|
||||
color="primary"
|
||||
adf-inherit-permission [nodeId]="nodeId"
|
||||
(updated)="onUpdatedPermissions($node)">PERMISSION</button>
|
||||
```
|
||||
|
||||
@@ -115,8 +115,8 @@ that will be used when performing the actual query.
|
||||
Every query fragment is stored and retrieved using its widget `id`.
|
||||
It is your responsibility to format the query correctly.
|
||||
|
||||
Once your change to the query is finished, update the context and call the `update` method
|
||||
to inform other components about the change:
|
||||
Once your change to the query is finished, update the context and call the `execute` method
|
||||
to rebuild and run the query so the results reflect your change:
|
||||
|
||||
```ts
|
||||
@Component({...})
|
||||
@@ -126,12 +126,15 @@ export class MyComponent implements SearchWidget, OnInit {
|
||||
|
||||
onUIChanged() {
|
||||
this.context.queryFragments[this.id] = `some query`;
|
||||
this.context.update();
|
||||
void this.context.execute();
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** Earlier versions called `this.context.update()` here. The `update()` method and the
|
||||
> `updated` stream have been removed; call `this.context.execute()` directly instead.
|
||||
|
||||
When executed, your fragment will be injected into the resulting query based on the category order in the application configuration file.
|
||||
|
||||
```text
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
---
|
||||
Title: Agent service
|
||||
Added: v7.0.0-alpha.3
|
||||
Status: Active
|
||||
Last reviewed: 2024-07-12
|
||||
---
|
||||
|
||||
# [Agent service](../../../lib/content-services/src/lib/agent/services/agent.service.ts "Defined in agent.service.ts")
|
||||
|
||||
Manages agents in Content Services.<br/>
|
||||
|
||||
<b>In order to use this service, you need to have the HX Insights Connector (additional ACS module) installed.</b>
|
||||
|
||||
## Class members
|
||||
|
||||
### Methods
|
||||
|
||||
- **getAgents**(): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AgentPaging`](../../../lib/js-api/src/api/content-rest-api/docs/AgentsApi.md#agentpaging)`>`<br/>
|
||||
Gets all agents.
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AgentPaging`](../../../lib/js-api/src/api/content-rest-api/docs/AgentsApi.md#agentpaging)`>` - AgentPaging object containing the agents.
|
||||
|
||||
## Details
|
||||
|
||||
See the
|
||||
[Agents API](../../../lib/js-api/src/api/content-rest-api/docs/AgentsApi.md) for more information about the types returned by [Agent
|
||||
service](agent.service.md) methods and for the implementation of the REST API the service is
|
||||
based on.
|
||||
@@ -23,11 +23,12 @@ Manages Document List information that is specific to a user.
|
||||
- _node:_ `any` - Node object
|
||||
- _nodeId:_ `string` - ID of the node object
|
||||
- **Returns** `string` - ID value
|
||||
- **getRecentFiles**(personId: `string`, pagination: [`PaginationModel`](../../../lib/core/src/lib/models/pagination.model.ts), filters?: `string[]`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`NodePaging`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/content-rest-api/docs/NodePaging.md)`>`<br/>
|
||||
- **getRecentFiles**(personId: `string`, pagination: [`PaginationModel`](../../../lib/core/src/lib/models/pagination.model.ts), filters?: `string[]`, includeFields: `string[]` = `[]`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`NodePaging`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/content-rest-api/docs/NodePaging.md)`>`<br/>
|
||||
Gets files recently accessed by a user.
|
||||
- _personId:_ `string` - ID of the user
|
||||
- _pagination:_ [`PaginationModel`](../../../lib/core/src/lib/models/pagination.model.ts) - Specifies how to paginate the results
|
||||
- _filters:_ `string[]` - (Optional) Specifies additional filters to apply (joined with **AND**)
|
||||
- _includeFields:_ `string[]` - List of data field names to include in the results
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`NodePaging`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/content-rest-api/docs/NodePaging.md)`>` - List of nodes for the recently used files
|
||||
- **hasCorrespondingNodeIds**(nodeId: `string`): `boolean`<br/>
|
||||
Does the well-known alias have a corresponding node ID?
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Title: Document List service
|
||||
Added: v2.0.0
|
||||
Status: Active
|
||||
Last reviewed: 2019-01-16
|
||||
Last reviewed: 2026-06-16
|
||||
---
|
||||
|
||||
# Document List Service
|
||||
@@ -21,10 +21,11 @@ import { DocumentListService } from '@alfresco/adf-core';
|
||||
|
||||
### Events
|
||||
|
||||
| Name | Description |
|
||||
|-------------------|-------------------------------------------------|
|
||||
| `reload$` | Emits when the document list should be reloaded |
|
||||
| `resetSelection$` | Emits when the selection should be reset |
|
||||
| Name | Description |
|
||||
|-------------------|----------------------------------------------------------------------------------------------|
|
||||
| `reload$` | Emits when the document list should be reloaded. |
|
||||
| `resetSelection$` | Emits when the selection should be reset. |
|
||||
| `reloadSilently$` | Emits when the document list should be reloaded **without** resetting the current selection. |
|
||||
|
||||
### Methods
|
||||
|
||||
@@ -32,6 +33,8 @@ import { DocumentListService } from '@alfresco/adf-core';
|
||||
Reloads the document list.
|
||||
- **resetSelection**(): `void`<br/>
|
||||
Resets the selection.
|
||||
- **reloadSilently**(): `void`<br/>
|
||||
Reloads the document list **without** resetting the current selection.
|
||||
- **copyNode**(nodeId: `string`, targetParentId: `string`): `Observable<NodeEntry>`<br/>
|
||||
Copy a node to destination node
|
||||
- _nodeId:_ `string` - The id of the node to be copied
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
---
|
||||
Title: Search Ai service
|
||||
Added: v7.0.0-alpha.3
|
||||
Status: Active
|
||||
Last reviewed: 2024-07-12
|
||||
---
|
||||
|
||||
# [Search Ai service](../../../lib/content-services/src/lib/search-ai/services/search-ai.service.ts "Defined in search-ai.service.ts")
|
||||
|
||||
Manages search AI in Content Services.
|
||||
|
||||
<b>In order to use this service, you need to have the HX Insights Connector (additional ACS module) installed.</b>
|
||||
|
||||
## Class members
|
||||
|
||||
### Methods
|
||||
|
||||
- **updateSearchAiInputState**(state: `SearchAiInputState`): `void`<br/>
|
||||
Update the state of the search AI input.
|
||||
- _state:_ `SearchAiInputState` - The new state of the search AI input.
|
||||
- **ask**(question: [`QuestionRequest`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#questionrequest)): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`QuestionModel`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#questionmodel)`>`<br/>
|
||||
Ask a question to the AI.
|
||||
- _question:_ [`QuestionRequest`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#questionrequest) - The question to ask.
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`QuestionModel`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#questionmodel)`>` - QuestionModel object containing information about questions.
|
||||
- **getAnswer**(questionId: `string`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AiAnswerEntry`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#aianswerentry)`>`<br/>
|
||||
Get an answer to specific question.
|
||||
- _questionId:_ `string` - The ID of the question to get an answer for.
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`AiAnswerEntry`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#aianswerentry)`>` - AiAnswerEntry object containing the answer.
|
||||
- **getConfig**(): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`KnowledgeRetrievalConfigEntry`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#knowledgeretrievalconfigentry)`>`<br/>
|
||||
Get the knowledge retrieval configuration.
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`KnowledgeRetrievalConfigEntry`](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md#knowledgeretrievalconfigentry)`>` - KnowledgeRetrievalConfigEntry object containing the configuration.
|
||||
- **checkSearchAvailability**(selectedNodesState: `SelectionState`, maxSelectedNodes: `number`): `string`<br/>
|
||||
Check if using of search is possible (if all conditions are met).
|
||||
- _selectedNodesState:_ `SelectionState` - information about selected nodes.
|
||||
- _maxSelectedNodes:_ `number` - max number of selected nodes. Default 100.
|
||||
- **Returns** `string` - string with error if any condition is not met, empty string otherwise.
|
||||
|
||||
## Details
|
||||
|
||||
See the
|
||||
[Search Ai API](../../../lib/js-api/src/api/content-rest-api/docs/SearchAiApi.md) for more information about the types returned by [Search Ai
|
||||
service](search-ai.service.md) methods and for the implementation of the REST API the service is
|
||||
based on.
|
||||
@@ -2,7 +2,7 @@
|
||||
Title: Search Query Builder service
|
||||
Added: v2.3.0
|
||||
Status: Active
|
||||
Last reviewed: 2019-03-19
|
||||
Last reviewed: 2026-06-29
|
||||
---
|
||||
|
||||
# [Search Query Builder service](../../../lib/content-services/src/lib/search/services/search-query-builder.service.ts "Defined in search-query-builder.service.ts")
|
||||
@@ -11,6 +11,17 @@ Stores information from all the custom search and faceted search widgets, compil
|
||||
|
||||
## Class members
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Description |
|
||||
| ----------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| userQuery | `string` | The raw query string typed by the user. Setting it stores the value, records it in `filterRawParams` and recomputes `parsedQuery` according to the current `searchMode`. |
|
||||
| parsedQuery | `string` (read-only) | The query derived from `userQuery`. In `regular` mode the user terms are expanded against the configured fields (see `app:fields`) and optionally wildcarded; in `formula` mode it is identical to `userQuery`. |
|
||||
| searchMode | `'regular' \| 'formula'` | Controls how `userQuery` is turned into `parsedQuery`. `regular` (default) parses the user input into a field query; `formula` uses the user input verbatim as an AFTS expression. |
|
||||
| selectedConfigurationId | `string` | Id of the currently active search configuration. Setting it also records the value in `filterRawParams`. |
|
||||
| encodedQuery | `string` (read-only) | The Base64-encoded `filterRawParams`, produced by `encodeQuery()` and written to the `q` route query parameter. |
|
||||
| wildcardsEnabled | `boolean` (read-only) | Reads the `search-wildcards-enabled` app config flag (default `true`). When enabled, query terms are suffixed with `*` so partial matches are returned. |
|
||||
|
||||
### Methods
|
||||
|
||||
- **addFilterQuery**(query: `string`)<br/>
|
||||
@@ -25,9 +36,10 @@ Stores information from all the custom search and faceted search widgets, compil
|
||||
- **Returns** `SearchRequest` - The finished query
|
||||
- **encodeQuery**()<br/>
|
||||
Encodes query shards stored in `filterRawParams` property.
|
||||
- **execute**(queryBody?: `SearchRequest`)<br/>
|
||||
Builds and executes the current query.
|
||||
- _queryBody:_ `SearchRequest` - (Optional)
|
||||
- **execute**(updateQueryParams: `boolean` = `true`, queryBody?: `SearchRequest`)<br/>
|
||||
Builds and executes the current query, then emits the result on the `executed` stream.
|
||||
- _updateQueryParams:_ `boolean` - (Optional) When `true` (default) the encoded query is written to the `q` route query parameter. Pass `false` to execute without updating the URL.
|
||||
- _queryBody:_ `SearchRequest` - (Optional) Pre-built query to execute instead of building one from the current state.
|
||||
- **getDefaultConfiguration**(): [`SearchConfiguration`](../../../lib/content-services/src/lib/search/models/search-configuration.interface.ts)`|undefined`<br/>
|
||||
|
||||
- **Returns** [`SearchConfiguration`](../../../lib/content-services/src/lib/search/models/search-configuration.interface.ts)`|undefined` -
|
||||
@@ -70,6 +82,11 @@ Stores information from all the custom search and faceted search widgets, compil
|
||||
|
||||
- **Returns** `boolean` -
|
||||
|
||||
- **isOperator**(input: `string`): `boolean`<br/>
|
||||
Checks whether the supplied string is a logical `AND` or `OR` operator. Used when parsing a multi-word user query in `regular` search mode.
|
||||
- _input:_ `string` - String to check
|
||||
- **Returns** `boolean` - `true` if the trimmed string is `AND` or `OR`, otherwise `false`
|
||||
|
||||
- **loadConfiguration**(): [`SearchConfiguration`](../../../lib/content-services/src/lib/search/models/search-configuration.interface.ts)<br/>
|
||||
|
||||
- **Returns** [`SearchConfiguration`](../../../lib/content-services/src/lib/search/models/search-configuration.interface.ts) -
|
||||
@@ -86,7 +103,10 @@ Stores information from all the custom search and faceted search widgets, compil
|
||||
Removes an existing bucket from a field.
|
||||
- _field:_ [`FacetField`](../../../lib/content-services/src/lib/search/models/facet-field.interface.ts) - The target field
|
||||
- _bucket:_ [`FacetFieldBucket`](../../../lib/content-services/src/lib/search/models/facet-field-bucket.interface.ts) - Bucket to remove
|
||||
- **resetToDefaults**()<br/>
|
||||
- **resetToDefaults**(withNavigate: `boolean` = `false`, resetUserQuery: `boolean` = `true`)<br/>
|
||||
Resets the query builder back to the default search configuration.
|
||||
- _withNavigate:_ `boolean` - (Optional) When `true`, clears the `q` route query parameter while resetting. Defaults to `false`.
|
||||
- _resetUserQuery:_ `boolean` - (Optional) When `true` (default), the `userQuery` and its parsed form are cleared. Pass `false` to keep the current user query while resetting the rest of the options.
|
||||
|
||||
- **search**(queryBody: `SearchRequest`): [`Observable`](http://reactivex.io/documentation/observable.html)`<`[`ResultSetPaging`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/search-rest-api/docs/ResultSetPaging.md)`>`<br/>
|
||||
|
||||
@@ -97,14 +117,13 @@ Stores information from all the custom search and faceted search widgets, compil
|
||||
|
||||
- _scope:_ `RequestScope` -
|
||||
|
||||
- **update**(queryBody?: `SearchRequest`)<br/>
|
||||
Builds the current query and triggers the `updated` event.
|
||||
- _queryBody:_ `SearchRequest` - (Optional)
|
||||
- **updateSearchQueryParams**() <br/>
|
||||
Encodes the query and navigates to existing search route adding encoded query as a search param.
|
||||
- **updateSelectedConfiguration**(index: `number`)<br/>
|
||||
|
||||
- _index:_ `number` -
|
||||
- **updateSelectedConfiguration**(id: `string`, resetFilters: `boolean` = `true`, shouldExecute: `boolean` = `true`)<br/>
|
||||
Switches the active search configuration to the one matching the supplied id (only relevant when multiple configurations are provided).
|
||||
- _id:_ `string` - Id of the configuration to select
|
||||
- _resetFilters:_ `boolean` - (Optional) When `true` (default), the current search options are reset before applying the new configuration. Pass `false` to keep them.
|
||||
- _shouldExecute:_ `boolean` - (Optional) When `true` (default), the query is executed immediately after switching configuration.
|
||||
|
||||
## Details
|
||||
|
||||
@@ -127,10 +146,6 @@ You can use custom widgets to populate and edit the following parts of the resul
|
||||
```ts
|
||||
constructor(queryBuilder: SearchQueryBuilderService) {
|
||||
|
||||
queryBuilder.updated.subscribe(query => {
|
||||
this.queryBuilder.execute();
|
||||
});
|
||||
|
||||
queryBuilder.executed.subscribe(data => {
|
||||
this.onDataLoaded(data);
|
||||
});
|
||||
@@ -138,6 +153,29 @@ constructor(queryBuilder: SearchQueryBuilderService) {
|
||||
}
|
||||
```
|
||||
|
||||
To run a search, build the query state (for example by setting `userQuery` or by letting a
|
||||
search widget update `queryFragments`) and then call `execute()`. The result is delivered
|
||||
through the `executed` stream.
|
||||
|
||||
```ts
|
||||
this.queryBuilder.userQuery = 'invoice';
|
||||
void this.queryBuilder.execute();
|
||||
```
|
||||
|
||||
> **Note:** Earlier versions exposed an `updated` stream and an `update()` method that built the
|
||||
> query and emitted it so that a subscriber could call `execute()`. Both have been removed; build
|
||||
> the query state and call `execute()` directly instead.
|
||||
|
||||
### Search modes
|
||||
|
||||
The builder supports two search modes, selected through the `searchMode` property:
|
||||
|
||||
- **regular** (default) - the text in `userQuery` is treated as user input and parsed into a
|
||||
field query. The query is split into terms, each term is matched against the fields listed in
|
||||
the `app:fields` search configuration entry (falling back to `cm:name`), and a `*` wildcard is
|
||||
appended when wildcards are enabled. Bare `AND`/`OR` words are preserved as operators.
|
||||
- **formula** - the text in `userQuery` is used verbatim as an [AFTS](https://docs.alfresco.com/content-services/latest/develop/search-api/) expression, allowing callers that already build their own query syntax to bypass parsing.
|
||||
|
||||
> **Note:** From ADF 3.0.0, the query contains the `"facetFormat": "V2"` parameter so that all the responses have the same structure whether they come from search queries containing facetFields, facetQueries, grouped facetQueries or facetIntervals.
|
||||
|
||||
## Runtime Configuration
|
||||
|
||||
@@ -109,6 +109,7 @@ Defining properties from Typescript:
|
||||
| Name | Type | Default value | Description |
|
||||
| ---- | ---- | ------------- | ----------- |
|
||||
| copyToClipboardAction | `boolean` | true | Toggles whether or not to enable copy to clipboard action. |
|
||||
| displayCopyToClipboardIcon | `boolean` | true | Toggles whether or not to show copy to clipboard icon. |
|
||||
| displayClearAction | `boolean` | true | Toggles whether or not to display clear action. |
|
||||
| displayEmpty | `boolean` | true | Toggles whether or not to show empty items in non-editable mode. |
|
||||
| displayNoneOption | `boolean` | true | Toggles whether or not to display none option. |
|
||||
@@ -193,6 +194,7 @@ const textItemProperty = new CardViewTextItemModel(options);
|
||||
| clickable | boolean | false | Toggles whether the property responds to clicks |
|
||||
| clickableCallBack | function | null | Function to execute when click the element |
|
||||
| copyToClipboardAction | `boolean` | true | Toggles whether or not to enable copy to clipboard action. |
|
||||
| displayCopyToClipboardIcon | `boolean` | true | Toggles whether or not to show copy to clipboard icon. |
|
||||
| useChipsForMultiValueProperty | `boolean` | true | Toggles whether or not to enable chips for multivalued properties. |
|
||||
| multiValueSeparator | `string` | ',' | String separator between multi-value property items. |
|
||||
| icon | string | | The material icon to show beside the item if it is clickable |
|
||||
@@ -249,6 +251,7 @@ const dateItemProperty = new CardViewDateItemModel(options);
|
||||
| label\* | string | | Item label |
|
||||
| value\* | any | | The original data value for the item |
|
||||
| copyToClipboardAction | `boolean` | true | Toggles whether or not to enable copy to clipboard action. |
|
||||
| displayCopyToClipboardIcon | `boolean` | true | Toggles whether or not to show copy to clipboard icon. |
|
||||
| key\* | string | | Identifying key (important when editing the item) |
|
||||
| default | any | | The default value to display if the value is empty |
|
||||
| displayValue\* | any | | The value to display |
|
||||
|
||||
@@ -351,7 +351,6 @@ while the data for the table is loading:
|
||||
<!--Add your custom loading template here-->
|
||||
<mat-progress-spinner
|
||||
class="adf-document-list-loading-margin"
|
||||
[color]="'primary'"
|
||||
[mode]="'indeterminate'">
|
||||
</mat-progress-spinner>
|
||||
</ng-template>
|
||||
|
||||
@@ -16,7 +16,6 @@ Reusable header for Alfresco applications.
|
||||
title="title"
|
||||
logo="logo.svg"
|
||||
[redirectUrl]="'/home'"
|
||||
color="primary"
|
||||
(clicked)=toggleMenu($event)>
|
||||
</adf-layout-header>
|
||||
```
|
||||
@@ -38,7 +37,7 @@ body of the element:
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| ---- | ---- | ------------- | ----------- |
|
||||
| color | [`ThemePalette`](https://github.com/angular/components/blob/master/src/material/core/common-behaviors/color.ts) | | Background color for the header. It can be any hex color code or one of the Material theme colors: 'primary', 'accent' or 'warn'. |
|
||||
| backgroundColor | [`string`] | Background color for the header. It can be any hex color code or CSS variable. |
|
||||
| expandedSidenav | `boolean` | true | expandedSidenav: Toggles the expanded state of the component. |
|
||||
| logo | `string` | | Path to an image file for the application logo. |
|
||||
| position | `string` | "start" | The side of the page that the drawer is attached to (can be 'start' or 'end') |
|
||||
@@ -58,5 +57,5 @@ body of the element:
|
||||
## Details
|
||||
|
||||
This component displays a customizable header that can be reused. Use the input properties to
|
||||
configure the left side (title, button) and the primary color of the header. The right part of the
|
||||
configure the left side (title, button) and the background color of the header. The right part of the
|
||||
header can contain other components which are transcluded in the header component.
|
||||
|
||||
@@ -27,6 +27,21 @@ The main purpose of the [Notification history component](../../core/components/n
|
||||
| maxNotifications | `number` | 5 | Maximum number of notifications to display. The rest will remain hidden until load more is clicked |
|
||||
| menuPositionX | [`MenuPositionX`](https://github.com/angular/components/blob/master/src/material/menu/menu-positions.ts) | "after" | Custom choice for opening the menu at the bottom. Can be `before` or `after`. |
|
||||
| menuPositionY | [`MenuPositionY`](https://github.com/angular/components/blob/master/src/material/menu/menu-positions.ts) | "below" | Custom choice for opening the menu at the bottom. Can be `above` or `below`. |
|
||||
| badgeSize | [`MatBadgeSize`](https://v19.material.angular.dev/components/badge/api#MatBadgeSize) | `small` | Badge size. Can be `small`, `medium` or `large`. |
|
||||
|
||||
### App config
|
||||
|
||||
You can set a default badge size in `app.config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"notification": {
|
||||
"badgeSize": "medium"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `notification.badgeSize` value is applied on init when the `badgeSize` input is not set explicitly on the component.
|
||||
|
||||
## See also
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ Simple container for headers, titles, actions and breadcrumbs.
|
||||
- [Properties](#properties)
|
||||
- [Details](#details)
|
||||
- [Dropdown menu](#dropdown-menu)
|
||||
- [Custom color](#custom-color)
|
||||
- [See also](#see-also)
|
||||
|
||||
## Basic Usage
|
||||
@@ -74,7 +73,6 @@ pushed to the right by a spacer:
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| ---- | ---- | ------------- | ----------- |
|
||||
| color | [`ThemePalette`](https://github.com/angular/components/blob/master/src/material/core/common-behaviors/color.ts) | | Toolbar color. Can be changed to empty value (default), `primary`, `accent` or `warn`. |
|
||||
| title | `string` | "" | Toolbar title. |
|
||||
|
||||
## Details
|
||||
@@ -116,21 +114,6 @@ when you click the menu button:
|
||||
|
||||

|
||||
|
||||
### Custom color
|
||||
|
||||
Besides the default color you can use 'primary', 'accent', or 'warn' values:
|
||||
|
||||
You might also want to change colors to follow your application's color
|
||||
[theme](../../user-guide/theming.md):
|
||||
|
||||
For example:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## See also
|
||||
|
||||
- [Toolbar Divider component](toolbar-divider.component.md)
|
||||
|
||||
@@ -50,6 +50,7 @@ Contains the value and metadata for a field of a [`Form`](../../../lib/process-s
|
||||
| numberOfColumns | number | 1 | Number of columns defined by a container field |
|
||||
| fields | [`FormFieldModel`](../../core/models/form-field.model.md)\[] | \[] | Fields contained within a container field |
|
||||
| columns | [`ContainerColumnModel`](../../../lib/core/src/lib/form/components/widgets/core/container-column.model.ts)\[] | \[] | Column definitions for a container field |
|
||||
| rows | [`ContainerRowModel`](../../../lib/core/src/lib/form/components/widgets/core/container-row.model.ts)\[] | \[] | Row definitions for a repeatable section field |
|
||||
| emptyOption | [`FormFieldOption`](../../../lib/core/src/lib/form/components/widgets/core/form-field-option.ts) | | Dropdown menu item to use when no option is chosen |
|
||||
| validationSummary | string | | Error/information message added during field validation (see [`FormFieldValidator`](../../../lib/core/src/lib/form/components/widgets/core/form-field-validator.ts) interface) |
|
||||
|
||||
@@ -95,6 +96,17 @@ The [REST Call Task 101](https://community.alfresco.com/community/bpm/blog/2016/
|
||||
tutorial on the [APS community site](https://community.alfresco.com/community/bpm)
|
||||
contains full details about how the REST calls work, along with a worked example.
|
||||
|
||||
### Repeatable sections
|
||||
|
||||
Repeatable section fields (`type: 'repeatable-section'`) support an `initialNumberOfRows` parameter in `params`.
|
||||
Setting `initialNumberOfRows` to `0` is valid: the section starts with no runtime rows and users add rows via the **Add row** action.
|
||||
|
||||
When no rows exist, `columns` holds a design-time column template (used by form editors and form-rules).
|
||||
Template fields are bound to the form for rendering but are marked as templates and do not write to `form.values`.
|
||||
No row data is written to `form.values` until the user adds a row or saved values are loaded from the server.
|
||||
|
||||
If saved values are present on the field (`value` array), row count is derived from `value.length` (subject to `maxNumberOfRows`), regardless of `initialNumberOfRows`.
|
||||
|
||||
## See also
|
||||
|
||||
- [Extensibility](../../user-guide/extensibility.md)
|
||||
|
||||
@@ -66,12 +66,19 @@ Manipulates content related to a Process Instance or Task Instance in APS.
|
||||
- _taskId:_ `string` - ID of the target task
|
||||
- _opts:_ `any` - (Optional) Options supported by JS-API
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)`<any>` - Metadata for the content
|
||||
- **getProcessesAndTasksOnContent**(sourceId: `string`, source: `string`, size?: `number`, page?: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)<[`ResultListDataRepresentationRelatedProcessTask`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/ResultListDataRepresentation%C2%ABRelatedContentRepresentation%C2%BB.md)><br/>
|
||||
- **getProcessesAndTasksOnContent**(sourceId: `string`, source: `string`, size?: `number`, page?: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)<[`ResultListDataRepresentationRelatedProcessTask`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/ResultListDataRepresentationRelatedProcessTask.md)><br/>
|
||||
Lists processes and tasks on workflow started with provided document
|
||||
- _sourceId:_ `string` - id of the document that workflow or task has been started with
|
||||
- _source:_ `string` - source of the document that workflow or task has been started with
|
||||
- _size:_ `number` - size of the entries to get
|
||||
- _page:_ `number` - page number
|
||||
- **getProcessesAndTasksOnContentBatch**(sourceIds: `string[]`, source: `string`, size?: `number`, page?: `number`): [`Observable`](http://reactivex.io/documentation/observable.html)<[`ResultListDataRepresentationRelatedProcessTask`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/ResultListDataRepresentationRelatedProcessTask.md)><br/>
|
||||
Batch variant of getProcessesAndTasksOnContent. Accepts multiple source document ids in one request (up to 500) and returns the related processes and tasks for all of them.
|
||||
- _sourceIds:_ `string[]` - ids of the documents to query process participation for (up to 500)
|
||||
- _source:_ `string` - source of the documents that workflows or tasks have been started with
|
||||
- _size:_ `number` - (Optional) size of the entries to get
|
||||
- _page:_ `number` - (Optional) page number
|
||||
- **Returns** [`Observable`](http://reactivex.io/documentation/observable.html)<[`ResultListDataRepresentationRelatedProcessTask`](https://github.com/Alfresco/alfresco-js-api/blob/develop/src/api/activiti-rest-api/docs/ResultListDataRepresentationRelatedProcessTask.md)>
|
||||
- **handleError**(error: `any`): [`Observable`](http://reactivex.io/documentation/observable.html)`<any>`<br/>
|
||||
Reports an error message.
|
||||
- _error:_ `any` - Data object with optional `message` and `status` fields for the error
|
||||
@@ -95,7 +102,7 @@ Let's say we have an upload button as follows:
|
||||
|
||||
```html
|
||||
<div>
|
||||
<button mat-button color="accent" mat-mini-fab (click)="fileInput.click()">
|
||||
<button mat-button mat-mini-fab (click)="fileInput.click()">
|
||||
<mat-icon>attachment</mat-icon>
|
||||
</button>
|
||||
<input hidden type="file" #fileInput (change)="onUploadFile($event)"/>
|
||||
@@ -422,6 +429,21 @@ this.contentService.getProcessesAndTasksOnContent(sourceId, source).subscribe(
|
||||
});
|
||||
```
|
||||
|
||||
#### getProcessesAndTasksOnContentBatch(sourceIds: string[], source: string, size?: number, page?: number): Observable`<ResultListDataRepresentationRelatedProcessTask>`
|
||||
|
||||
Batch variant of `getProcessesAndTasksOnContent`. Accepts multiple source document ids in one request (up to 500) and returns the related processes and tasks for all of them.
|
||||
|
||||
```ts
|
||||
const sourceIds = ['sourceId1', 'sourceId2'];
|
||||
const source = 'source';
|
||||
this.contentService.getProcessesAndTasksOnContentBatch(sourceIds, source).subscribe(
|
||||
res => {
|
||||
console.log('Response: ', res);
|
||||
}, error => {
|
||||
console.log('Error: ', error);
|
||||
});
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
## Importing
|
||||
|
||||
@@ -62,3 +62,5 @@ The pages linked below contain the licenses for all third party dependencies of
|
||||
- [ADF 8.2.1](license-info-8.2.1.md)
|
||||
- [ADF 8.3.1](license-info-8.3.1.md)
|
||||
- [ADF 8.4.1](license-info-8.4.1.md)
|
||||
- [ADF 8.5.0](license-info-8.5.0.md)
|
||||
- [ADF 9.0.0](license-info-9.0.0.md)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
Title: License info, alfresco-ng2-components 8.4.0
|
||||
Title: License info, alfresco-ng2-components 8.4.1
|
||||
---
|
||||
|
||||
# License information for alfresco-ng2-components 8.4.0
|
||||
# License information for alfresco-ng2-components 8.4.1
|
||||
|
||||
This page lists all third party libraries the project depends on.
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
---
|
||||
Title: License info, alfresco-ng2-components 8.5.0
|
||||
---
|
||||
|
||||
# License information for alfresco-ng2-components 8.5.0
|
||||
|
||||
This page lists all third party libraries the project depends on.
|
||||
|
||||
## Libraries
|
||||
|
||||
| Name | Version | License |
|
||||
| --- | --- | --- |
|
||||
| [@angular/animations](https://github.com/angular/angular.git) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/cdk](https://github.com/angular/components.git) | 19.2.19 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/common](https://github.com/angular/angular.git) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/compiler](https://github.com/angular/angular.git) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/core](https://github.com/angular/angular.git) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/forms](https://github.com/angular/angular.git) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/material](https://github.com/angular/components.git) | 19.2.19 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/material-date-fns-adapter](https://github.com/angular/components.git) | 19.2.19 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/platform-browser](https://github.com/angular/angular.git) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/platform-browser-dynamic](https://github.com/angular/angular.git) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/router](git+https://github.com/angular/angular.git) | 19.2.20 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@apollo/client](git+https://github.com/apollographql/apollo-client.git) | 3.13.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@babel/runtime](https://github.com/babel/babel.git) | 7.26.10 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@cspell/eslint-plugin](https://github.com/streetsidesoftware/cspell.git) | 10.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@graphql-typed-document-node/core](git@github.com:dotansimha/graphql-typed-document-node.git) | 3.2.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@mat-datetimepicker/core](https://github.com/kuhnroyal/mat-datetimepicker.git) | 15.0.2 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@napi-rs/canvas](git+https://github.com/Brooooooklyn/canvas.git) | 0.1.100 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@napi-rs/canvas-darwin-arm64](git+https://github.com/Brooooooklyn/canvas.git) | 0.1.100 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@ngx-translate/core](https://github.com/ngx-translate/core) | 17.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@wry/caches](git+https://github.com/benjamn/wryware.git) | 1.0.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@wry/context](git+https://github.com/benjamn/wryware.git) | 0.7.4 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@wry/equality](git+https://github.com/benjamn/wryware.git) | 0.5.7 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@wry/trie](git+https://github.com/benjamn/wryware.git) | 0.5.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc) | 19.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [apollo-angular](https://github.com/kamilkisiela/apollo-angular) | 10.0.3 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [balanced-match](git://github.com/juliangruber/balanced-match.git) | 1.0.2 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [brace-expansion](git://github.com/juliangruber/brace-expansion.git) | 1.1.15 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [brace-expansion](git://github.com/juliangruber/brace-expansion.git) | 2.1.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [concat-map](git://github.com/substack/node-concat-map.git) | 0.0.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [cropperjs](git+https://github.com/fengyuanchen/cropperjs.git) | 1.6.2 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [date-fns](https://github.com/date-fns/date-fns) | 2.30.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| dotenv-expand | 5.1.0 | [BSD-2-Clause](https://opensource.org/licenses/BSD-2-Clause) |
|
||||
| editorjs-html | 4.0.5 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [eve-raphael](https://github.com/tomasAlabes/eve.git) | 0.5.0 | UNKNOWN |
|
||||
| [eventemitter3](git://github.com/primus/eventemitter3.git) | 5.0.4 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [fetch-blob](https://github.com/node-fetch/fetch-blob.git) | 3.2.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [formdata-polyfill](git+https://jimmywarting@github.com/jimmywarting/FormData.git) | 4.0.10 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [graphql-tag](git+https://github.com/apollographql/graphql-tag.git) | 2.12.6 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [graphql-ws](git+https://github.com/enisdenjo/graphql-ws.git) | 6.0.8 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [hoist-non-react-statics](git://github.com/mridgway/hoist-non-react-statics.git) | 3.3.2 | [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) |
|
||||
| [js-tokens](lydell/js-tokens) | 4.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [lodash-es](lodash/lodash) | 4.18.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [loose-envify](git://github.com/zertosh/loose-envify.git) | 1.4.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [material-icons](git+https://github.com/marella/material-icons.git) | 1.13.14 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [minimatch](git://github.com/isaacs/minimatch.git) | 5.1.9 | [ISC](https://www.isc.org/licenses/) |
|
||||
| [minimatch-browser](git://github.com/isaacs/minimatch.git) | 1.0.0 | [ISC](https://www.isc.org/licenses/) |
|
||||
| [ng2-charts](git+https://github.com/valor-software/ng2-charts.git) | 4.1.1 | [ISC](https://www.isc.org/licenses/) |
|
||||
| [node-domexception](git+https://github.com/jimmywarting/node-domexception.git) | 1.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [node-fetch](https://github.com/node-fetch/node-fetch.git) | 3.3.2 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [object-assign](sindresorhus/object-assign) | 4.1.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [optimism](git+https://github.com/benjamn/optimism.git) | 0.18.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [pdfjs-dist](git+https://github.com/mozilla/pdf.js.git) | 5.1.91 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [prop-types](facebook/prop-types) | 15.8.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [raphael](git://github.com/DmitryBaranovskiy/raphael.git) | 2.3.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [react-is](https://github.com/facebook/react.git) | 16.13.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [regenerator-runtime](https://github.com/facebook/regenerator/tree/main/packages/runtime) | 0.14.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [rehackt](git+https://github.com/phryneas/rehackt.git) | 0.1.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [rxjs](https://github.com/reactivex/rxjs.git) | 7.8.2 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [symbol-observable](blesh/symbol-observable) | 4.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [ts-invariant](git+https://github.com/apollographql/invariant-packages.git) | 0.10.3 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [tslib](https://github.com/Microsoft/tslib.git) | 2.8.1 | [0BSD](http://landley.net/toybox/license.html) |
|
||||
| [uuid](https://github.com/uuidjs/uuid.git) | 14.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [web-streams-polyfill](git+https://github.com/MattiasBuelens/web-streams-polyfill.git) | 3.3.3 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [zen-observable](zenparsing/zen-observable) | 0.8.15 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [zen-observable-ts](git+https://github.com/apollographql/zen-observable-ts.git) | 1.2.5 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [zone.js](git://github.com/angular/angular.git) | 0.15.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
Title: License info, alfresco-ng2-components 9.0.0
|
||||
---
|
||||
|
||||
# License information for alfresco-ng2-components 9.0.0
|
||||
|
||||
This page lists all third party libraries the project depends on.
|
||||
|
||||
## Libraries
|
||||
|
||||
| Name | Version | License |
|
||||
| --- | --- | --- |
|
||||
| [@angular-eslint/bundled-angular-compiler](https://github.com/angular-eslint/angular-eslint.git) | 20.7.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular-eslint/utils](https://github.com/angular-eslint/angular-eslint.git) | 20.7.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/animations](https://github.com/angular/angular.git) | 20.3.25 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/cdk](https://github.com/angular/components.git) | 20.2.14 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/common](https://github.com/angular/angular.git) | 20.3.25 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/compiler](https://github.com/angular/angular.git) | 20.3.25 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/core](https://github.com/angular/angular.git) | 20.3.25 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/forms](https://github.com/angular/angular.git) | 20.3.25 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/material](https://github.com/angular/components.git) | 20.2.14 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/material-date-fns-adapter](https://github.com/angular/components.git) | 20.2.14 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/platform-browser](https://github.com/angular/angular.git) | 20.3.25 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/platform-browser-dynamic](https://github.com/angular/angular.git) | 20.3.25 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@angular/router](git+https://github.com/angular/angular.git) | 20.3.25 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@apollo/client](git+https://github.com/apollographql/apollo-client.git) | 3.13.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@babel/runtime](https://github.com/babel/babel.git) | 7.26.10 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@cspell/eslint-plugin](https://github.com/streetsidesoftware/cspell.git) | 10.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@graphql-typed-document-node/core](git@github.com:dotansimha/graphql-typed-document-node.git) | 3.2.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@mat-datetimepicker/core](https://github.com/kuhnroyal/mat-datetimepicker.git) | 16.0.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@napi-rs/canvas](git+https://github.com/Brooooooklyn/canvas.git) | 0.1.100 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@napi-rs/canvas-darwin-arm64](git+https://github.com/Brooooooklyn/canvas.git) | 0.1.100 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@ngx-translate/core](https://github.com/ngx-translate/core) | 17.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@wry/caches](git+https://github.com/benjamn/wryware.git) | 1.0.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@wry/context](git+https://github.com/benjamn/wryware.git) | 0.7.4 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@wry/equality](git+https://github.com/benjamn/wryware.git) | 0.5.7 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [@wry/trie](git+https://github.com/benjamn/wryware.git) | 0.5.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc) | 19.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [apollo-angular](https://github.com/kamilkisiela/apollo-angular) | 11.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [balanced-match](git://github.com/juliangruber/balanced-match.git) | 1.0.2 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [brace-expansion](git://github.com/juliangruber/brace-expansion.git) | 1.1.15 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [brace-expansion](git://github.com/juliangruber/brace-expansion.git) | 2.1.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [concat-map](git://github.com/substack/node-concat-map.git) | 0.0.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [cropperjs](git+https://github.com/fengyuanchen/cropperjs.git) | 1.6.2 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [date-fns](https://github.com/date-fns/date-fns) | 2.30.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| dotenv-expand | 5.1.0 | [BSD-2-Clause](https://opensource.org/licenses/BSD-2-Clause) |
|
||||
| editorjs-html | 4.0.5 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [eve-raphael](https://github.com/tomasAlabes/eve.git) | 0.5.0 | UNKNOWN |
|
||||
| [eventemitter3](git://github.com/primus/eventemitter3.git) | 5.0.4 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [fetch-blob](https://github.com/node-fetch/fetch-blob.git) | 3.2.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [formdata-polyfill](git+https://jimmywarting@github.com/jimmywarting/FormData.git) | 4.0.10 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [graphql-tag](git+https://github.com/apollographql/graphql-tag.git) | 2.12.7 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [graphql-ws](git+https://github.com/enisdenjo/graphql-ws.git) | 6.0.8 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [hoist-non-react-statics](git://github.com/mridgway/hoist-non-react-statics.git) | 3.3.2 | [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) |
|
||||
| [js-tokens](lydell/js-tokens) | 4.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [lodash-es](lodash/lodash) | 4.18.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [loose-envify](git://github.com/zertosh/loose-envify.git) | 1.4.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [material-icons](git+https://github.com/marella/material-icons.git) | 1.13.14 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [minimatch](git://github.com/isaacs/minimatch.git) | 5.1.9 | [ISC](https://www.isc.org/licenses/) |
|
||||
| [minimatch-browser](git://github.com/isaacs/minimatch.git) | 1.0.0 | [ISC](https://www.isc.org/licenses/) |
|
||||
| [ng2-charts](git+https://github.com/valor-software/ng2-charts.git) | 4.1.1 | [ISC](https://www.isc.org/licenses/) |
|
||||
| [node-domexception](git+https://github.com/jimmywarting/node-domexception.git) | 1.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [node-fetch](https://github.com/node-fetch/node-fetch.git) | 3.3.2 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [object-assign](sindresorhus/object-assign) | 4.1.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [optimism](git+https://github.com/benjamn/optimism.git) | 0.18.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [pdfjs-dist](git+https://github.com/mozilla/pdf.js.git) | 5.1.91 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [prop-types](facebook/prop-types) | 15.8.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [raphael](git://github.com/DmitryBaranovskiy/raphael.git) | 2.3.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [react-is](https://github.com/facebook/react.git) | 16.13.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [regenerator-runtime](https://github.com/facebook/regenerator/tree/main/packages/runtime) | 0.14.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [rehackt](git+https://github.com/phryneas/rehackt.git) | 0.1.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [rxjs](https://github.com/reactivex/rxjs.git) | 7.8.2 | [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) |
|
||||
| [symbol-observable](blesh/symbol-observable) | 4.0.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [ts-invariant](git+https://github.com/apollographql/invariant-packages.git) | 0.10.3 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [tslib](https://github.com/Microsoft/tslib.git) | 2.8.1 | [0BSD](http://landley.net/toybox/license.html) |
|
||||
| [uuid](https://github.com/uuidjs/uuid.git) | 14.0.1 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [web-streams-polyfill](git+https://github.com/MattiasBuelens/web-streams-polyfill.git) | 3.3.3 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [zen-observable](zenparsing/zen-observable) | 0.8.15 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [zen-observable-ts](git+https://github.com/apollographql/zen-observable-ts.git) | 1.2.5 | [MIT](https://opensource.org/license/mit/) |
|
||||
| [zone.js](git://github.com/angular/angular.git) | 0.15.0 | [MIT](https://opensource.org/license/mit/) |
|
||||
|
||||
@@ -89,7 +89,7 @@ The template defined inside `empty-form` will be shown when no form definition i
|
||||
| path | `string` | | Path of the folder where the metadata will be stored. |
|
||||
| processInstanceId | `string` | | ProcessInstanceId id to fetch corresponding form and values. |
|
||||
| readOnly | `boolean` | false | Toggle readonly state of the form. Forces all form widgets to render as readonly if enabled. |
|
||||
| showCompleteButton | `boolean` | true | Toggle rendering of the `Complete` outcome button. |
|
||||
| showCompleteButton | `boolean` | false | Toggle rendering of the `Complete` outcome button. |
|
||||
| showRefreshButton | `boolean` | true | Toggle rendering of the `Refresh` button. |
|
||||
| showSaveButton | `boolean` | true | Toggle rendering of the `Save` outcome button. |
|
||||
| showTitle | `boolean` | true | Toggle rendering of the form title. |
|
||||
|
||||
@@ -9,6 +9,8 @@ The first **General Availability** release was v2.0.0.
|
||||
|
||||
## General Availability
|
||||
|
||||
- [9.0.0](RelNote-9.0.0.md)
|
||||
- [8.5.0](RelNote-8.5.0.md)
|
||||
- [8.4.1](RelNote-8.4.1.md)
|
||||
- [8.3.1](RelNote-8.3.1.md)
|
||||
- [8.2.1](RelNote-8.2.1.md)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
Title: Changelog for alfresco-ng2-components v8.4.0
|
||||
Title: Changelog for alfresco-ng2-components v8.4.1
|
||||
---
|
||||
|
||||
# Changelog
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
Title: Changelog for alfresco-ng2-components v8.5.0
|
||||
---
|
||||
|
||||
# Changelog
|
||||
|
||||
- [ec04358796](https://github.com/Alfresco/alfresco-ng2-components/commit/ec04358796) AAE-46943 Rename git signing secret/vars to HXPS_GIT_* (#11978)
|
||||
- [49a28b357c](https://github.com/Alfresco/alfresco-ng2-components/commit/49a28b357c) AAE-46943 Sign Crowdin translation PR commits with GPG (#11974)
|
||||
- [dd9e58ddaa](https://github.com/Alfresco/alfresco-ng2-components/commit/dd9e58ddaa) [ACS-11927] init acs aps scripts update terraform (#11976)
|
||||
- [c723e19b6d](https://github.com/Alfresco/alfresco-ng2-components/commit/c723e19b6d) AAE-46971 Update Supply Chain Review GH AW to latest (#11972)
|
||||
- [bb6f9b1f3d](https://github.com/Alfresco/alfresco-ng2-components/commit/bb6f9b1f3d) AAE-46434 Fix disabled stying for people widgets (#11967)
|
||||
- [7bb219e4dd](https://github.com/Alfresco/alfresco-ng2-components/commit/7bb219e4dd) AAE-46654 Fix - return empty string when no value is provided in card… (#11969)
|
||||
- [70038bea26](https://github.com/Alfresco/alfresco-ng2-components/commit/70038bea26) AAE-46246 Format typed values in form display widgets v2 (#11952)
|
||||
- [5ad3dca38d](https://github.com/Alfresco/alfresco-ng2-components/commit/5ad3dca38d) AAE-46684 fix release workflow eslint publish fix provenance (#11963)
|
||||
- [fd3802f2dc](https://github.com/Alfresco/alfresco-ng2-components/commit/fd3802f2dc) AAE-46684 fix release workflow eslint publish fix (#11962)
|
||||
- [a8eee9fe3a](https://github.com/Alfresco/alfresco-ng2-components/commit/a8eee9fe3a) Improvements/aae 46684 fix release workflow fixed command (#11961)
|
||||
- [0a7fa14d0f](https://github.com/Alfresco/alfresco-ng2-components/commit/0a7fa14d0f) Improvements/aae 46684 fix release workflow ignore (#11960)
|
||||
- [4dde6d2a45](https://github.com/Alfresco/alfresco-ng2-components/commit/4dde6d2a45) [AAE-46514] - Fix release workflow (#11959)
|
||||
- [78661f11c5](https://github.com/Alfresco/alfresco-ng2-components/commit/78661f11c5) [AAE-46514] - Migration to PNPM (#11926)
|
||||
- [faf9d3faac](https://github.com/Alfresco/alfresco-ng2-components/commit/faf9d3faac) AAE-46388 Update Supply Chain Review GH AW to latest (#11957)
|
||||
- [5c8eb21ab3](https://github.com/Alfresco/alfresco-ng2-components/commit/5c8eb21ab3) AAE-46387 Standardize DependaBot config schedule/grouping (#11953)
|
||||
- [7d76d789b2](https://github.com/Alfresco/alfresco-ng2-components/commit/7d76d789b2) AAE-41418 Add process instance id input to task header cloud component (#11897)
|
||||
- [a71cc84f11](https://github.com/Alfresco/alfresco-ng2-components/commit/a71cc84f11) AAE-46507 Next Task Endpoint (#11943)
|
||||
- [34acdd20cf](https://github.com/Alfresco/alfresco-ng2-components/commit/34acdd20cf) Revert "AAE-46246 Format typed values in form display widgets (#11935)" (#11951)
|
||||
- [f39b9167b8](https://github.com/Alfresco/alfresco-ng2-components/commit/f39b9167b8) AAE-46246 Format typed values in form display widgets (#11935)
|
||||
- [aa2a357fb2](https://github.com/Alfresco/alfresco-ng2-components/commit/aa2a357fb2) AAE-46434 Fix read-only field styling on forms (#11928)
|
||||
- [f9899883dc](https://github.com/Alfresco/alfresco-ng2-components/commit/f9899883dc) Revert AAE-46242 crowdin locale mapping changes (#11949)
|
||||
- [46b2d0380b](https://github.com/Alfresco/alfresco-ng2-components/commit/46b2d0380b) AAE-45774 Shorten invalid date error message (#11920)
|
||||
- [274ddb3098](https://github.com/Alfresco/alfresco-ng2-components/commit/274ddb3098) AAE-46386 Set DependaBot cooldown for all ecosystems as 3d (#11947)
|
||||
- [f602070f1e](https://github.com/Alfresco/alfresco-ng2-components/commit/f602070f1e) AAE-46388 Fix DependaBot config to ignore gh-aw-actions (#11946)
|
||||
- [d206d28f1c](https://github.com/Alfresco/alfresco-ng2-components/commit/d206d28f1c) [AAE-32905] Fix commit messages commands aren't working (#11922)
|
||||
- [80e9e51cfa](https://github.com/Alfresco/alfresco-ng2-components/commit/80e9e51cfa) AAE-46242 - Looks like we need to override the mapping as crowding config is not set to this format (#11939)
|
||||
- [345e1e69ad](https://github.com/Alfresco/alfresco-ng2-components/commit/345e1e69ad) AAE-46242 - should use the variable osx_locale to match the format xx-YY (#11936)
|
||||
- [a2b026ed7e](https://github.com/Alfresco/alfresco-ng2-components/commit/a2b026ed7e) [AAE-46242] - Changed the name convention for translation files to ISO standard naming (#11924)
|
||||
- [e40fd2250e](https://github.com/Alfresco/alfresco-ng2-components/commit/e40fd2250e) AAE-46388 Add Supply Chain Review agentic workflow (#11927)
|
||||
- [cfdd3f9c50](https://github.com/Alfresco/alfresco-ng2-components/commit/cfdd3f9c50) MD3 migration fixes (#11919)
|
||||
- [1314f0751f](https://github.com/Alfresco/alfresco-ng2-components/commit/1314f0751f) AAE-46476 Fix sorting functionality of task list retrieval from runtime bundle (#11921)
|
||||
- [f4882e99be](https://github.com/Alfresco/alfresco-ng2-components/commit/f4882e99be) Revert "New Crowdin translations by GitHub Action (#11796)" (#11923)
|
||||
- [b5d2de583d](https://github.com/Alfresco/alfresco-ng2-components/commit/b5d2de583d) build(deps): update 3rd party dependencies (#11916)
|
||||
- [70f90c65a5](https://github.com/Alfresco/alfresco-ng2-components/commit/70f90c65a5) AAE-46392 Fix card view select item crash on numeric initial value (#11917)
|
||||
- [f339647f40](https://github.com/Alfresco/alfresco-ng2-components/commit/f339647f40) refactor: migrate license checks off license-checker (#11905)
|
||||
- [a7fa68056d](https://github.com/Alfresco/alfresco-ng2-components/commit/a7fa68056d) chore: remove unused @nx/node dependency (#11895)
|
||||
- [8280aa2f6d](https://github.com/Alfresco/alfresco-ng2-components/commit/8280aa2f6d) chore: update NX packages to version 22.7.2 and related dependencies (#11904)
|
||||
- [5553aaaefe](https://github.com/Alfresco/alfresco-ng2-components/commit/5553aaaefe) [MNT-25522] Add support for fileLink icon (#11903)
|
||||
- [15814380a5](https://github.com/Alfresco/alfresco-ng2-components/commit/15814380a5) [ci:force] AAE-46219 [TEST] Revert cli build/installDeps changes from #11880 and #11899 (#11901)
|
||||
- [4044fafc39](https://github.com/Alfresco/alfresco-ng2-components/commit/4044fafc39) AAE-46219 Skip prod deps in cli:installDeps to unblock release (#11899)
|
||||
- [ece50ac32c](https://github.com/Alfresco/alfresco-ng2-components/commit/ece50ac32c) [MNT-25149] Card view select item multivalued property support (#11891)
|
||||
- [1d163c6749](https://github.com/Alfresco/alfresco-ng2-components/commit/1d163c6749) Revert "AAE-44065 Change date picker to match other styles (#11868)" (#11896)
|
||||
- [1fbd869902](https://github.com/Alfresco/alfresco-ng2-components/commit/1fbd869902) chore: remove unused eslint-plugin-prefer-arrow (#11894)
|
||||
- [165d0fc521](https://github.com/Alfresco/alfresco-ng2-components/commit/165d0fc521) chore: remove unused moment dependency (#11893)
|
||||
- [64d9f3a6d4](https://github.com/Alfresco/alfresco-ng2-components/commit/64d9f3a6d4) AAE-45774 Show error for date fields if invalid format (#11886)
|
||||
- [9e106b006c](https://github.com/Alfresco/alfresco-ng2-components/commit/9e106b006c) AAE-43881 Fix for form rules not applying when new [data] comes in (#11879)
|
||||
- [8309d2dc55](https://github.com/Alfresco/alfresco-ng2-components/commit/8309d2dc55) AAE-44065 Change date picker to match other styles (#11868)
|
||||
- [e3430ae36e](https://github.com/Alfresco/alfresco-ng2-components/commit/e3430ae36e) AAE-45695 Group @typescript-eslint/* packages in dependabot (#11880)
|
||||
- [1860fefd42](https://github.com/Alfresco/alfresco-ng2-components/commit/1860fefd42) [MNT-25647] Handle facets label wrapped in quotes (#11866)
|
||||
- [9fe4006a0d](https://github.com/Alfresco/alfresco-ng2-components/commit/9fe4006a0d) AAE-45391 Lazy loading and improvements for pdfJS (#11869)
|
||||
- [62fb51e910](https://github.com/Alfresco/alfresco-ng2-components/commit/62fb51e910) Update CODEOWNERS
|
||||
- [b7783d2259](https://github.com/Alfresco/alfresco-ng2-components/commit/b7783d2259) AAE-39830 Removing Material components color property (#11865)
|
||||
- [410490158f](https://github.com/Alfresco/alfresco-ng2-components/commit/410490158f) AAE-30881 Remove jsrassign (#11863)
|
||||
- [57bf066164](https://github.com/Alfresco/alfresco-ng2-components/commit/57bf066164) AAE-30882 Remove superagent for fetch (#11856)
|
||||
- [9cdacf3ebf](https://github.com/Alfresco/alfresco-ng2-components/commit/9cdacf3ebf) AAE-45312 Removing propagate job from release workflow (#11864)
|
||||
- [8821980913](https://github.com/Alfresco/alfresco-ng2-components/commit/8821980913) AAE-38566 Remove globals mixin (#11798)
|
||||
- [a73b100fae](https://github.com/Alfresco/alfresco-ng2-components/commit/a73b100fae) AAE-45003 Extend task cloud services (#11850)
|
||||
- [2649cdea2d](https://github.com/Alfresco/alfresco-ng2-components/commit/2649cdea2d) AAE-44003 Allow manual input for date field (#11830)
|
||||
- [3a543d8a0a](https://github.com/Alfresco/alfresco-ng2-components/commit/3a543d8a0a) AAE-32905 Rework pr pipeline (#11853)
|
||||
- [3fc59b2358](https://github.com/Alfresco/alfresco-ng2-components/commit/3fc59b2358) AAE-45216 Removing custom theme from core (#11862)
|
||||
- [337b82e988](https://github.com/Alfresco/alfresco-ng2-components/commit/337b82e988) AAE-45215 Removing unused breadcrumb theme (#11861)
|
||||
- [0faa2e1a56](https://github.com/Alfresco/alfresco-ng2-components/commit/0faa2e1a56) [AAE-0000] - fixed run for process-service-cloud (#11855)
|
||||
- [d6262eafc6](https://github.com/Alfresco/alfresco-ng2-components/commit/d6262eafc6) [ACS-11628] small for for init-acs-env.ts (#11860)
|
||||
- [d3ad66d25b](https://github.com/Alfresco/alfresco-ng2-components/commit/d3ad66d25b) AAE-44435 Fix incorrect Start process button on user task forms (#11837)
|
||||
- [aa2de3bde6](https://github.com/Alfresco/alfresco-ng2-components/commit/aa2de3bde6) AAE-45173 Adding background color to tooltip card (#11852)
|
||||
- [d1d06a68bc](https://github.com/Alfresco/alfresco-ng2-components/commit/d1d06a68bc) AAE-44098 Bottom tab navigation buttons (#11834)
|
||||
- [0a6da1ba13](https://github.com/Alfresco/alfresco-ng2-components/commit/0a6da1ba13) AAE-45076 Fix svg icon style (#11849)
|
||||
- [d3ac5362ba](https://github.com/Alfresco/alfresco-ng2-components/commit/d3ac5362ba) AAE-44946 - Sending also previous value to allow valuation and valida… (#11836)
|
||||
- [ddb8adc0e4](https://github.com/Alfresco/alfresco-ng2-components/commit/ddb8adc0e4) AAE-44752 Add type to ProcessInstanceCloud (#11847)
|
||||
- [85005c9c1c](https://github.com/Alfresco/alfresco-ng2-components/commit/85005c9c1c) AAE-44987 Applying color and background to sidenav (#11846)
|
||||
- [407c6c1829](https://github.com/Alfresco/alfresco-ng2-components/commit/407c6c1829) [ACS-11350] keyboard navigation user incorrect focus order after collapsing the left navigation menu (#11835)
|
||||
- [e3fc03c58d](https://github.com/Alfresco/alfresco-ng2-components/commit/e3fc03c58d) Revert "AAE-44098 Bottom Tab nav buttons (#11801)" (#11832)
|
||||
- [510a813ed2](https://github.com/Alfresco/alfresco-ng2-components/commit/510a813ed2) [ACS-11472] Fix file icon is not updated for version renditions (#11807)
|
||||
- [7864f1a8e0](https://github.com/Alfresco/alfresco-ng2-components/commit/7864f1a8e0) AAE-44098 Bottom Tab nav buttons (#11801)
|
||||
- [c09edd71ff](https://github.com/Alfresco/alfresco-ng2-components/commit/c09edd71ff) AAE-44761 Remove unused imports (#11829)
|
||||
- [64826c3a99](https://github.com/Alfresco/alfresco-ng2-components/commit/64826c3a99) AAE-40649 Material Design 3 migration (#11286)
|
||||
- [423c646bac](https://github.com/Alfresco/alfresco-ng2-components/commit/423c646bac) Post release version bump (#11828)
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
Title: Changelog for alfresco-ng2-components v9.0.0
|
||||
---
|
||||
|
||||
# Changelog
|
||||
|
||||
- [0a19be090e](git@github.com:Alfresco/alfresco-ng2-components/commit/0a19be090e) [ACS-12286] Pass includeFields through to getRecentFiles for -recent- (#12067)
|
||||
- [b69c3ae1ae](git@github.com:Alfresco/alfresco-ng2-components/commit/b69c3ae1ae) [MNT-25230] Displayed modified time for node version (#12066)
|
||||
- [ce907417b7](git@github.com:Alfresco/alfresco-ng2-components/commit/ce907417b7) AAE-48166 Compensate for VM/Citrix clock drift in token expiry check (#12024)
|
||||
- [4c7765e3fa](git@github.com:Alfresco/alfresco-ng2-components/commit/4c7765e3fa) AAE-46517 Add onRowCountChange form event for Repeatable Sections (#12062)
|
||||
- [407a64996e](git@github.com:Alfresco/alfresco-ng2-components/commit/407a64996e) AAE-46248 Format dropdown/radio option labels in display-text expressions (#12045)
|
||||
- [01cea60490](git@github.com:Alfresco/alfresco-ng2-components/commit/01cea60490) [MNT-25230] adw version history does not provide user information (#12050)
|
||||
- [09ef05038c](git@github.com:Alfresco/alfresco-ng2-components/commit/09ef05038c) chore: remove deprecated MaterialModule and its references (#12051)
|
||||
- [c7bd56f244](git@github.com:Alfresco/alfresco-ng2-components/commit/c7bd56f244) AAE-43974 Fix for alfresco-content-app e2e failure (#12055)
|
||||
- [b86e41515e](git@github.com:Alfresco/alfresco-ng2-components/commit/b86e41515e) [ACS-12037] Remove Knowledge Discovery from ADF (#12042)
|
||||
- [0b35118dee](git@github.com:Alfresco/alfresco-ng2-components/commit/0b35118dee) AAE-47880 UI breaks when pasting very large text into text field (#12043)
|
||||
- [fe2b3d85dd](git@github.com:Alfresco/alfresco-ng2-components/commit/fe2b3d85dd) [ACS-12108] Introduce signed commits into ADF workflows (#12040)
|
||||
- [b0dc85422c](git@github.com:Alfresco/alfresco-ng2-components/commit/b0dc85422c) Improvement/AAE-43974 Refactoring form fields (#11945)
|
||||
- [23f0392c12](git@github.com:Alfresco/alfresco-ng2-components/commit/23f0392c12) AAE-47634 Refactor: switch form service getTask to use runtime bundle API (#12020)
|
||||
- [997303e6a7](git@github.com:Alfresco/alfresco-ng2-components/commit/997303e6a7) [ACS-11325] remove chevron button from tab order in adf-tree (#12041)
|
||||
- [45d1818f04](git@github.com:Alfresco/alfresco-ng2-components/commit/45d1818f04) [ACS-12098] firefox headless race condition viewer fix (#12023)
|
||||
- [448e667c52](git@github.com:Alfresco/alfresco-ng2-components/commit/448e667c52) [MNT-25681] Content node selector panel filtering fixed (#12032)
|
||||
- [18e602aa85](git@github.com:Alfresco/alfresco-ng2-components/commit/18e602aa85) [PRODSEC-13253] Increased peerDependencies versions to allow to increase angular version in other projects (#12031)
|
||||
- [4cd8648a05](git@github.com:Alfresco/alfresco-ng2-components/commit/4cd8648a05) Adjust release triggers to use cache-writable token (#12030)
|
||||
- [7f57b3936b](git@github.com:Alfresco/alfresco-ng2-components/commit/7f57b3936b) AAE-39528 Session timeout features (#12008)
|
||||
- [5a30baad99](git@github.com:Alfresco/alfresco-ng2-components/commit/5a30baad99) Release cache read/write fix (#12029)
|
||||
- [5050c3d974](git@github.com:Alfresco/alfresco-ng2-components/commit/5050c3d974) [ACS-12041] Add debounceTime in PeopleWidgetComponent to limit API calls on every keystroke (#12027)
|
||||
- [d8b36606e2](git@github.com:Alfresco/alfresco-ng2-components/commit/d8b36606e2) [MNT-25681] Search refactoring and unification (#12019)
|
||||
- [37f8fe47ac](git@github.com:Alfresco/alfresco-ng2-components/commit/37f8fe47ac) AAE-46695 Upgrade to pnpm 11.9 (#12028)
|
||||
- [af0d1e4ead](git@github.com:Alfresco/alfresco-ng2-components/commit/af0d1e4ead) AAE-47093 Update Supply Chain Review GH AW to latest (#12025)
|
||||
- [bd7f393db9](git@github.com:Alfresco/alfresco-ng2-components/commit/bd7f393db9) AAE-47634 Fix block task claim checking status on Runtime Bundle (#12009)
|
||||
- [d2d6696c05](git@github.com:Alfresco/alfresco-ng2-components/commit/d2d6696c05) Migrate to Angular 20, TypeScript 5.9, and Angular Material 20 (#11657)
|
||||
- [7546aa91a3](git@github.com:Alfresco/alfresco-ng2-components/commit/7546aa91a3) AAE-47577 Form Spinner persists outside of Automate Form (#12005)
|
||||
- [74d67c39a0](git@github.com:Alfresco/alfresco-ng2-components/commit/74d67c39a0) [ACS-11317] a11y Fix: Tags interactive controls are not manageable via keyboard (#11845)
|
||||
- [20c20f2749](git@github.com:Alfresco/alfresco-ng2-components/commit/20c20f2749) AAE-46247 Add type-aware form field value adapter service (#11968)
|
||||
- [b498d5744c](git@github.com:Alfresco/alfresco-ng2-components/commit/b498d5744c) [AAE-47470] - Upgrade Pnpm to 11.8.0 (#12004)
|
||||
- [80eef35e1d](git@github.com:Alfresco/alfresco-ng2-components/commit/80eef35e1d) [ACS-11325] Add keyboard navigation and a11y support for adf-tree component (#11973)
|
||||
- [49a3f1e104](git@github.com:Alfresco/alfresco-ng2-components/commit/49a3f1e104) AAE-47412 Update suprocesses and linked processes for process instance model (#11996)
|
||||
- [0beaa18452](git@github.com:Alfresco/alfresco-ng2-components/commit/0beaa18452) [ACS-11973] Fix: context menu disappears during bulk upload (#11994)
|
||||
- [76fd461741](git@github.com:Alfresco/alfresco-ng2-components/commit/76fd461741) AAE-47042 Add auto grow support to multiline text widget (#11981)
|
||||
- [78697ee62a](git@github.com:Alfresco/alfresco-ng2-components/commit/78697ee62a) [AAE-0000] - Fixed js-api error index.js (#11970)
|
||||
- [43c5bc17fb](git@github.com:Alfresco/alfresco-ng2-components/commit/43c5bc17fb) [ACS-12020] Updated init-aps passwords with secret ones (#11993)
|
||||
- [cda20e0386](git@github.com:Alfresco/alfresco-ng2-components/commit/cda20e0386) Post-release version bump (#11988)
|
||||
- [8f5099e822](git@github.com:Alfresco/alfresco-ng2-components/commit/8f5099e822) [ACS-11928] convert ReadStream to Blob before appending to FormData (#11987)
|
||||
- [5dd709ed58](git@github.com:Alfresco/alfresco-ng2-components/commit/5dd709ed58) AAE-44809 Fix form multi-file attachment - document viewer not updated on file selection (#11980)
|
||||
- [9d353bf271](git@github.com:Alfresco/alfresco-ng2-components/commit/9d353bf271) [ACS-11974] [ACA] Upload new version button is no longer disabled when clicked once (#11977)
|
||||
- [633702860f](git@github.com:Alfresco/alfresco-ng2-components/commit/633702860f) Post-release version bump (#11984)
|
||||
- [bf5b3af285](git@github.com:Alfresco/alfresco-ng2-components/commit/bf5b3af285) AAE-47094 Add Stale PR Cleanup workflow (#11983)
|
||||
@@ -109,9 +109,10 @@ Now that the `my-preset` configuration is defined, let's use it in a view of the
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
|----------|-----------|---------------|------------------------------------------------------------------------------|
|
||||
| readOnly | `boolean` | false | (optional) This flag sets the metadata in read only mode preventing changes. |
|
||||
| Name | Type | Default value | Description |
|
||||
|----------------------------|-----------|---------------|------------------------------------------------------------------------------|
|
||||
| readOnly | `boolean` | false | (optional) This flag sets the metadata in read only mode preventing changes. |
|
||||
| displayCopyToClipboardIcon | `boolean` | true | Toggles whether or not to display the copy to clipboard icon. |
|
||||
|
||||
### Viewing the result
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Open the `src/app/login/login.component.html` file. The contents will look like
|
||||
|
||||
```html
|
||||
<adf-login
|
||||
copyrightText="© 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved."
|
||||
copyrightText="© 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved."
|
||||
successRoute="/documentlist">
|
||||
</adf-login>
|
||||
```
|
||||
@@ -49,7 +49,7 @@ Looking at the documentation, we can see that the `<adf-login/>` component has a
|
||||
<adf-login
|
||||
[showRememberMe]="false"
|
||||
[showLoginActions]="false"
|
||||
copyrightText="© 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved."
|
||||
copyrightText="© 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved."
|
||||
successRoute="/documentlist">
|
||||
</adf-login>
|
||||
```
|
||||
@@ -80,7 +80,7 @@ Open `src/app/login/login.component.html` and add `(executeSubmit)="myExecuteSub
|
||||
[showRememberMe]="false"
|
||||
[showLoginActions]="false"
|
||||
(executeSubmit)="myExecuteSubmitMethod($event)"
|
||||
copyrightText="© 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved."
|
||||
copyrightText="© 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved."
|
||||
successRoute="/documentlist">
|
||||
</adf-login>
|
||||
```
|
||||
@@ -147,7 +147,7 @@ Let's add a simple Hello World message in the footer. Open the template `src/app
|
||||
[showRememberMe]="false"
|
||||
[showLoginActions]="false"
|
||||
(executeSubmit)="myExecuteSubmitMethod($event)"
|
||||
copyrightText="© 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved."
|
||||
copyrightText="© 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved."
|
||||
successRoute="/documentlist">
|
||||
<adf-login-footer>
|
||||
<ng-template>
|
||||
|
||||
@@ -13,6 +13,50 @@ The authType parameter specifies the authentication method, with BASIC and OAUTH
|
||||
"authType": "OAUTH"
|
||||
}
|
||||
```
|
||||
|
||||
## Session Timeout
|
||||
|
||||
ADF can track user activity and show a countdown dialog before logging out an idle authenticated session. Register the feature with `provideSessionTimeout` in your application providers:
|
||||
|
||||
```ts
|
||||
import { ApplicationConfig } from '@angular/core';
|
||||
import { provideSessionTimeout } from '@alfresco/adf-core';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideSessionTimeout({
|
||||
enabled: true,
|
||||
idleTimeoutMs: 30 * 60 * 1000,
|
||||
dialogTimeoutMs: 60 * 1000
|
||||
})
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
The same values can be configured in `app.config.json` with the `sessionTimeout` key:
|
||||
|
||||
```json
|
||||
{
|
||||
"sessionTimeout": {
|
||||
"enabled": true,
|
||||
"idleTimeoutMs": 1800000,
|
||||
"dialogTimeoutMs": 60000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Registering `provideSessionTimeout` enables the feature: `enabled` defaults to `true`, so the countdown is active unless you set `enabled` to `false` in `app.config.json` or in the options passed to `provideSessionTimeout`. The default idle timeout is 30 minutes, and the default dialog timeout is 60 seconds. Values passed to `provideSessionTimeout` take precedence over values from `app.config.json`.
|
||||
|
||||
Applications can defer startup until another async condition is enabled:
|
||||
|
||||
```ts
|
||||
provideSessionTimeout({
|
||||
startWhen: () => featureService.isOn$('session-timeout-feature')
|
||||
});
|
||||
```
|
||||
|
||||
Whether the user clicks **Log out** in the countdown dialog or leaves it unanswered until the countdown elapses, the normal logout flow runs and the user is redirected to the configured IdP/login page. The same logout is broadcast to other tabs so every session ends together.
|
||||
|
||||
# OAuth2 Configuration
|
||||
OAuth2 is a protocol that allows the application to authorize operations without exposing user credentials. The configuration includes several parameters essential for setting up OAuth2 authentication.
|
||||
|
||||
|
||||
@@ -90,7 +90,6 @@ export class YourSearchComponent implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.queryBuilder.resetToDefaults();
|
||||
this.queryBuilder.updated.subscribe(() => void this.queryBuilder.execute());
|
||||
this.queryBuilder.executed.subscribe((data) => {
|
||||
this.queryBuilder.paging.skipCount = 0;
|
||||
this.onSearchResultLoaded(data);
|
||||
@@ -103,7 +102,7 @@ export class YourSearchComponent implements OnInit {
|
||||
|
||||
onSearchQueryChanged(string: string) {
|
||||
this.queryBuilder.userQuery = decodeURIComponent(string);
|
||||
this.queryBuilder.update();
|
||||
void this.queryBuilder.execute();
|
||||
}
|
||||
|
||||
async onPaginationChanged(pagination: Pagination) {
|
||||
@@ -111,7 +110,7 @@ export class YourSearchComponent implements OnInit {
|
||||
maxItems: pagination.maxItems,
|
||||
skipCount: pagination.skipCount
|
||||
};
|
||||
this.queryBuilder.update();
|
||||
void this.queryBuilder.execute();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -16,6 +16,7 @@ This page describes how you can configure the search configuration.
|
||||
- [Steps Involved In Search Configuration](#steps-involved-in-search-configuration)
|
||||
- [Configuration](#configuration)
|
||||
- [Extra fields and filter queries](#extra-fields-and-filter-queries)
|
||||
- [Search modes and wildcards](#search-modes-and-wildcards)
|
||||
- [Sorting](#sorting)
|
||||
- [Categories and widgets](#categories-and-widgets)
|
||||
- [Facet Fields](#facet-fields)
|
||||
@@ -267,6 +268,44 @@ settings:
|
||||
|
||||
Note that the entries of the `filterQueries` array are joined using the `AND` operator.
|
||||
|
||||
### Search modes and wildcards
|
||||
|
||||
When a user types free text into a search input, the [Search Query Builder Service](../../content-services/services/search-query-builder.service.md) turns that text (its `userQuery`) into the final query according to the configured *search mode*:
|
||||
|
||||
- **regular** (default) - the user input is parsed into a field query. Each term is matched
|
||||
against the fields listed in the `app:fields` array (falling back to `cm:name` when it is not
|
||||
set), and a `*` wildcard is appended to each term when wildcards are enabled. Words that are
|
||||
exactly `AND` or `OR` are preserved as logical operators.
|
||||
- **formula** - the user input is passed through verbatim as an
|
||||
[AFTS](https://docs.alfresco.com/content-services/latest/develop/search-api/) expression. Use
|
||||
this mode when the caller already builds valid query syntax.
|
||||
|
||||
The `app:fields` entry lists the fields used to expand a `regular` user query:
|
||||
|
||||
```json
|
||||
{
|
||||
"search": {
|
||||
...
|
||||
"app:fields": ["cm:name", "cm:title", "cm:description"]
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For example, with the configuration above and wildcards enabled, the user query `report` is
|
||||
expanded to `(cm:name:"report*" OR cm:title:"report*" OR cm:description:"report*")`.
|
||||
|
||||
Wildcard matching is controlled by the top-level `search-wildcards-enabled` flag in
|
||||
`app.config.json` (default `true`). When set to `false`, terms are matched exactly and the
|
||||
trailing `*` is not added (this also disables the `searchPrefix`/`searchSuffix` of the
|
||||
[Search text component](../content-services/components/search-text.component.md)):
|
||||
|
||||
```json
|
||||
{
|
||||
"search-wildcards-enabled": false
|
||||
}
|
||||
```
|
||||
|
||||
### Sorting
|
||||
|
||||
The Sorting configuration section consists of two blocks:
|
||||
|
||||
@@ -40,21 +40,6 @@ ADF is based on Angular Material library, which offers solutions for theming you
|
||||
|
||||
If you already setup Angular Material theming in the application you use ADF in, there is no need for taking additional steps to theme ADF components - colors, typography and other parts of the theme will be taken from your setup.
|
||||
|
||||
## Customizing deprecated theme variables
|
||||
|
||||
Currently we have an amount of custom variables around components to mange libraries look and feel consistently and globally.
|
||||
|
||||
While they are getting deprecated to be replaced with [Angular Material system variables](https://material.angular.dev/guide/system-variables), for seamless integration with Angular Material's theming, you can provide values for those variables inside the `:root` element.
|
||||
|
||||
For example:
|
||||
```css
|
||||
:root {
|
||||
--theme-primary-color: --mat-sys-primary;
|
||||
--theme-accent-color: --mat-sys-tertiary;
|
||||
}
|
||||
```
|
||||
**No new variables should be added to the project**
|
||||
|
||||
[Reference list of overridable variables](https://github.com/Alfresco/alfresco-ng2-components/blob/29d341cc3b6a0842a776464027dcb1154875a8f0/lib/core/src/lib/styles/_index.scss#L25)
|
||||
|
||||
## Default reusable class
|
||||
@@ -73,14 +58,14 @@ For example:
|
||||
|
||||
Avoid adding css variables with names related to components:
|
||||
```
|
||||
--my-component-nr-xxx-background-color: mat.get-color-from-palette($primary, 50), // bad
|
||||
--theme-primary-color-50: mat.get-color-from-palette($primary, 50) // good
|
||||
--my-component-nr-xxx-background-color: var(--mat-sys-primary), // bad
|
||||
--theme-primary-color-50: var(--mat-sys-primary) // good
|
||||
```
|
||||
|
||||
Avoid adding css variables with custom values, values should come from the theme:
|
||||
```
|
||||
--new-variable: yellow // bad
|
||||
--new-variable: mat.get-color-from-palette($primary, 50), // good
|
||||
--new-variable: var(--mat-sys-primary), // good
|
||||
```
|
||||
|
||||
When styling components use Angular Material system variables (colors, typography, elevation):
|
||||
|
||||
@@ -61,8 +61,8 @@ backend services have been tested with each released version of ADF.
|
||||
|
||||
<!--7.0.0-alpha.3 start-->
|
||||
|
||||
- [AgentService](content-services/services/agent.service.md)
|
||||
- [SearchAiService](content-services/services/search-ai.service.md)
|
||||
- AgentService — removed, see [Notes](README.md#knowledge-discovery-removal-v900)
|
||||
- SearchAiService — removed, see [Notes](README.md#knowledge-discovery-removal-v900)
|
||||
|
||||
<!--7.0.0-alpha.3 end-->
|
||||
|
||||
|
||||
@@ -59,3 +59,5 @@ The pages linked below contain the audit for all third party dependencies of ADF
|
||||
- [ADF 8.2.1](audit-info-8.2.1.md)
|
||||
- [ADF 8.3.1](audit-info-8.3.1.md)
|
||||
- [ADF 8.4.1](audit-info-8.4.1.md)
|
||||
- [ADF 8.5.0](audit-info-8.5.0.md)
|
||||
- [ADF 9.0.0](audit-info-9.0.0.md)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
Title: Audit info, alfresco-ng2-components 8.4.0
|
||||
Title: Audit info, alfresco-ng2-components 8.4.1
|
||||
---
|
||||
|
||||
# Audit information for alfresco-ng2-components 8.4.0
|
||||
# Audit information for alfresco-ng2-components 8.4.1
|
||||
|
||||
This page lists the security audit of the dependencies this project depends on.
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
Title: Audit info, alfresco-ng2-components 8.4.1
|
||||
---
|
||||
|
||||
# Audit information for alfresco-ng2-components 8.5.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,23 @@
|
||||
---
|
||||
Title: Audit info, alfresco-ng2-components 9.0.0
|
||||
---
|
||||
|
||||
# Audit information for alfresco-ng2-components 9.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: 297
|
||||
|
||||
## Libraries
|
||||
|
||||
| Severity | Module | Vulnerable versions |
|
||||
| --- | --- | --- |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
|
||||
@@ -0,0 +1,357 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import js from '@eslint/js';
|
||||
import { FlatCompat } from '@eslint/eslintrc';
|
||||
import typescriptEslint from '@typescript-eslint/eslint-plugin';
|
||||
import { fixupPluginRules } from '@eslint/compat';
|
||||
import unicorn from 'eslint-plugin-unicorn';
|
||||
import rxjs from 'eslint-plugin-rxjs';
|
||||
import prettier from 'eslint-plugin-prettier';
|
||||
import ban from 'eslint-plugin-ban';
|
||||
import licenseHeader from 'eslint-plugin-license-header';
|
||||
import cspell from '@cspell/eslint-plugin';
|
||||
import importPlugin from 'eslint-plugin-import';
|
||||
import storybook from 'eslint-plugin-storybook';
|
||||
import nxPlugin from '@nx/eslint-plugin';
|
||||
import angularEslintEslintPlugin from '@angular-eslint/eslint-plugin';
|
||||
import angularTemplateParser from '@angular-eslint/template-parser';
|
||||
import tsParser from '@typescript-eslint/parser';
|
||||
import jsonParser from 'jsonc-eslint-parser';
|
||||
import alfrescoEslintAngular from './lib/eslint-angular/main.js';
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all
|
||||
});
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: [
|
||||
'.angular',
|
||||
'.DS_Store',
|
||||
'.github',
|
||||
'.history',
|
||||
'.husky',
|
||||
'.nx',
|
||||
'.vscode',
|
||||
'coverage',
|
||||
'dist',
|
||||
'**/docs',
|
||||
'nxcache',
|
||||
'tmp',
|
||||
'projects/**/*',
|
||||
'**/node_modules/**/*',
|
||||
'lib/cli/node_modules/**/*',
|
||||
'lib/core/src/lib/icon',
|
||||
'**/node_modules',
|
||||
'**/assets',
|
||||
'/scripts'
|
||||
]
|
||||
},
|
||||
// You can uncomment unicorn.configs['recommended'], fix a few issues, and comment it out again until all issues are resolved.
|
||||
// Expect significant effort to fix all reported issues.
|
||||
// Note to developers: when enabling unicorn.configs['recommended'], remove unicorn from plugins to avoid plugin redefinition errors.
|
||||
// unicorn.configs['recommended'],
|
||||
...storybook.configs['flat/recommended'],
|
||||
{
|
||||
files: ['**/*.{js,mjs,cjs,ts}'],
|
||||
ignores: ['**/*.d.ts'],
|
||||
plugins: {
|
||||
'license-header': licenseHeader
|
||||
},
|
||||
rules: {
|
||||
'license-header/header': [
|
||||
'error',
|
||||
[
|
||||
'/*!',
|
||||
' * @license',
|
||||
' * Copyright © 2005-2026 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.',
|
||||
' */'
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts', '**/*.js', '**/*.mjs'],
|
||||
ignores: ['**/*.d.ts', '**/*.spec.ts'],
|
||||
...jsdoc.configs['flat/recommended-typescript-error']
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
ignores: ['**/*.d.ts', '**/*.mjs'],
|
||||
...compat.extends(
|
||||
'plugin:@nx/typescript',
|
||||
'plugin:@nx/angular',
|
||||
'plugin:@cspell/recommended',
|
||||
'plugin:@angular-eslint/recommended',
|
||||
'plugin:@angular-eslint/template/process-inline-templates'
|
||||
)[0],
|
||||
plugins: {
|
||||
'@nx': nxPlugin,
|
||||
jsdoc,
|
||||
unicorn,
|
||||
rxjs: fixupPluginRules(rxjs),
|
||||
prettier: prettier,
|
||||
ban: ban,
|
||||
'@cspell': cspell,
|
||||
import: importPlugin,
|
||||
'@angular-eslint': angularEslintEslintPlugin,
|
||||
'@typescript-eslint': typescriptEslint
|
||||
},
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
allowDefaultProject: true,
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module'
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
// Uncomment this to enable prettier checks as part of the ESLint
|
||||
// Note to developers:
|
||||
// you can uncomment the full ruleset locally when fixing issues, and then comment
|
||||
// that will allow splitting the work into smaller chunks
|
||||
// 'prettier/prettier': 'error',
|
||||
'ban/ban': [
|
||||
'error',
|
||||
{ name: 'eval', message: 'Calls to eval is not allowed.' },
|
||||
{ name: 'fdescribe', message: 'Calls to fdescribe is not allowed' },
|
||||
{ name: 'fit', message: 'Calls to fit is not allowed' },
|
||||
{ name: 'xit', message: 'Calls to xit is not allowed' },
|
||||
{ name: 'xdescribe', message: 'Calls to xdescribe is not allowed' },
|
||||
{ name: ['test', 'only'], message: 'Calls to test.only is not allowed' },
|
||||
{ name: ['describe', 'only'], message: 'Calls to describe.only is not allowed' }
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'error',
|
||||
{
|
||||
type: 'element',
|
||||
prefix: ['adf', 'app'],
|
||||
style: 'kebab-case'
|
||||
}
|
||||
],
|
||||
'@angular-eslint/directive-selector': [
|
||||
'error',
|
||||
{
|
||||
type: ['element', 'attribute'],
|
||||
prefix: ['adf', 'app'],
|
||||
style: 'kebab-case'
|
||||
}
|
||||
],
|
||||
'@angular-eslint/no-host-metadata-property': 'off',
|
||||
'@angular-eslint/no-input-prefix': 'error',
|
||||
'@angular-eslint/prefer-inject': 'error',
|
||||
'@typescript-eslint/consistent-type-definitions': 'error',
|
||||
'@typescript-eslint/dot-notation': 'off',
|
||||
'@typescript-eslint/explicit-member-accessibility': [
|
||||
'off',
|
||||
{
|
||||
accessibility: 'explicit'
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/await-thenable': 'error',
|
||||
'@typescript-eslint/prefer-optional-chain': 'warn',
|
||||
'@typescript-eslint/prefer-readonly': 'error',
|
||||
'@typescript-eslint/no-inferrable-types': 'off',
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'error',
|
||||
'jsdoc/tag-lines': [
|
||||
'error',
|
||||
'any',
|
||||
{
|
||||
startLines: 1
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: [
|
||||
'classProperty',
|
||||
'objectLiteralProperty',
|
||||
'typeProperty',
|
||||
'classMethod',
|
||||
'objectLiteralMethod',
|
||||
'typeMethod',
|
||||
'accessor',
|
||||
'enumMember'
|
||||
],
|
||||
format: null,
|
||||
modifiers: ['requiresQuotes']
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/member-ordering': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'prefer-promise-reject-errors': 'error',
|
||||
'brace-style': 'off',
|
||||
'comma-dangle': 'error',
|
||||
'default-case': 'error',
|
||||
'import/order': 'off',
|
||||
'max-len': [
|
||||
'error',
|
||||
{
|
||||
code: 240
|
||||
}
|
||||
],
|
||||
'no-bitwise': 'off',
|
||||
'no-console': [
|
||||
'error',
|
||||
{
|
||||
allow: [
|
||||
'warn',
|
||||
'dir',
|
||||
'timeLog',
|
||||
'assert',
|
||||
'clear',
|
||||
'count',
|
||||
'countReset',
|
||||
'group',
|
||||
'groupEnd',
|
||||
'table',
|
||||
'dirxml',
|
||||
'error',
|
||||
'groupCollapsed',
|
||||
'Console',
|
||||
'profile',
|
||||
'profileEnd',
|
||||
'timeStamp',
|
||||
'context'
|
||||
]
|
||||
}
|
||||
],
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-multiple-empty-lines': 'error',
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-redeclare': ['off', { ignoreDeclarationMerge: true }],
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_'
|
||||
}
|
||||
],
|
||||
'no-return-await': 'error',
|
||||
'rxjs/no-create': 'error',
|
||||
'rxjs/no-subject-unsubscribe': 'error',
|
||||
'rxjs/no-subject-value': 'error',
|
||||
'rxjs/no-unsafe-takeuntil': 'error',
|
||||
'unicorn/filename-case': 'error',
|
||||
'unicorn/prefer-optional-catch-binding': 'error',
|
||||
'@typescript-eslint/no-unused-expressions': [
|
||||
'error',
|
||||
{
|
||||
allowShortCircuit: true,
|
||||
allowTernary: true
|
||||
}
|
||||
],
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: "Identifier[name='CUSTOM_ELEMENTS_SCHEMA']",
|
||||
message: 'The use of CUSTOM_ELEMENTS_SCHEMA is not allowed. Consider alternatives for proper schema handling.'
|
||||
},
|
||||
{
|
||||
selector: "Identifier[name='NO_ERRORS_SCHEMA']",
|
||||
message: 'The use of NO_ERRORS_SCHEMA is not allowed. Consider alternatives for proper schema handling.'
|
||||
},
|
||||
{
|
||||
selector: 'TSEnumDeclaration',
|
||||
message: 'Enums are not allowed. Use string literal types (e.g., type Foo = "a" | "b") or const objects instead.'
|
||||
},
|
||||
{
|
||||
selector: ':matches(Literal[value=/ng-reflect-/], TemplateElement[value.cooked=/ng-reflect-/])',
|
||||
message: '*ng-reflect-* attributes should not be used. Consider alternatives for proper selectors.'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
...compat.extends(
|
||||
'plugin:@angular-eslint/template/recommended',
|
||||
'plugin:@angular-eslint/template/accessibility',
|
||||
'plugin:@nx/angular-template'
|
||||
)[0],
|
||||
languageOptions: {
|
||||
parser: angularTemplateParser
|
||||
},
|
||||
rules: {
|
||||
'@angular-eslint/template/prefer-self-closing-tags': 'error'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.spec.ts'],
|
||||
plugins: {
|
||||
'@alfresco/eslint-angular': alfrescoEslintAngular
|
||||
},
|
||||
rules: {
|
||||
'@alfresco/eslint-angular/no-angular-material-selectors': 'error',
|
||||
'@angular-eslint/component-class-suffix': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.json'],
|
||||
languageOptions: {
|
||||
parser: jsonParser
|
||||
},
|
||||
rules: {
|
||||
'comma-dangle': ['error', 'never']
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.stories.ts'],
|
||||
rules: {
|
||||
'@cspell/spellchecker': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.mjs'],
|
||||
rules: {
|
||||
'unicorn/no-null': 'off'
|
||||
},
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module'
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1,4 +0,0 @@
|
||||
// eslint-disable
|
||||
const nxPreset = require('@nx/jest/preset').default;
|
||||
|
||||
module.exports = {...nxPreset };
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.js"],
|
||||
"ignorePatterns": ["!**/*", "dist", "node_modules"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts"],
|
||||
"extends": ["plugin:@nx/angular"],
|
||||
"parserOptions": {
|
||||
"project": ["lib/cli/tsconfig.json"],
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"rules": {
|
||||
"prefer-arrow/prefer-arrow-functions": "off",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/naming-convention": "warn",
|
||||
"quote-props": "off",
|
||||
"no-shadow": "warn",
|
||||
"no-restricted-syntax": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"@typescript-eslint/consistent-type-assertions": "warn",
|
||||
"@typescript-eslint/prefer-for-of": "off",
|
||||
"@typescript-eslint/consistent-type-definitions": "error",
|
||||
"@typescript-eslint/dot-notation": "off",
|
||||
"@typescript-eslint/no-inferrable-types": "off",
|
||||
"@typescript-eslint/no-require-imports": "off",
|
||||
"default-case": "error",
|
||||
"import/order": "off",
|
||||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"code": 240
|
||||
}
|
||||
],
|
||||
"no-duplicate-imports": "error",
|
||||
"no-multiple-empty-lines": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-return-await": "error",
|
||||
"no-console": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.html"],
|
||||
"parserOptions": {
|
||||
"project": ["lib/cli/tsconfig.json"],
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"extends": ["plugin:@nx/angular-template"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import rootConfig from '../../eslint.config.mjs';
|
||||
|
||||
export default [
|
||||
...rootConfig,
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@nx/enforce-module-boundaries': [
|
||||
'error',
|
||||
{
|
||||
enforceBuildableLibDependency: true,
|
||||
allow: [],
|
||||
depConstraints: [
|
||||
{
|
||||
sourceTag: 'scope:cli',
|
||||
onlyDependOnLibsWithTags: ['scope:js-api']
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'quote-props': 'off',
|
||||
'no-shadow': 'warn',
|
||||
'no-restricted-syntax': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'@typescript-eslint/consistent-type-assertions': 'warn',
|
||||
'@typescript-eslint/prefer-for-of': 'off',
|
||||
'no-redeclare': 'error',
|
||||
'no-console': 'off',
|
||||
}
|
||||
}
|
||||
];
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
|
||||
Generated
-1239
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@alfresco/adf-cli",
|
||||
"description": "Alfresco ADF cli and utils",
|
||||
"version": "8.4.1",
|
||||
"version": "9.1.0",
|
||||
"author": "Hyland Software, Inc. and its affiliates",
|
||||
"bin": {
|
||||
"adf-cli": "bin/adf-cli",
|
||||
@@ -17,15 +17,12 @@
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"develop": "tsc -p tsconfig.json --watch",
|
||||
"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",
|
||||
"dist": "rm -rf ../../dist/libs/cli && npm run build && cp -R ./bin ../../dist/libs/cli && cp -R ./resources ../../dist/libs/cli && cp ./package.json ../../dist/libs/cli",
|
||||
"link": "npm run dist && cd ../../dist/libs/cli && npm link",
|
||||
"unlink": "cd ../../dist/libs/cli && npm unlink"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alfresco/js-api": ">=9.4.0",
|
||||
"ejs": "^3.1.10",
|
||||
"license-checker": "^25.0.1",
|
||||
"node-fetch": "^2.7.0",
|
||||
"@alfresco/js-api": ">=10.0.0",
|
||||
"spdx-license-list": "^5.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
@@ -33,7 +30,6 @@
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@types/ejs": "^3.1.2",
|
||||
"@types/node": "^20.1.7",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
"sourceRoot": "lib/cli",
|
||||
"projectType": "library",
|
||||
"prefix": "adf",
|
||||
"tags": ["scope:cli", "type:tooling"],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "nx:run-commands",
|
||||
"outputs": ["{workspaceRoot}/dist/libs/cli"],
|
||||
"options": {
|
||||
"command": "cd lib/cli && npm run dist"
|
||||
},
|
||||
@@ -30,6 +32,7 @@
|
||||
},
|
||||
"copyToNodeModules": {
|
||||
"executor": "nx:run-commands",
|
||||
"cache": false,
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
@@ -62,7 +65,7 @@
|
||||
"cwd": "dist/libs/cli",
|
||||
"commands": [
|
||||
{
|
||||
"command": "npm publish --tag {args.tag}",
|
||||
"command": "pnpm publish --no-git-checks --tag {args.tag}",
|
||||
"forwardAllArgs": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2026 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.
|
||||
*/
|
||||
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
function readJson(filePath) {
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
}
|
||||
|
||||
function resolvePackageJson(packageName, fromDirectory) {
|
||||
try {
|
||||
return require.resolve(`${packageName}/package.json`, {
|
||||
paths: [fromDirectory]
|
||||
});
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function getRepositoryUrl(repository) {
|
||||
if (typeof repository === 'string') {
|
||||
return repository;
|
||||
}
|
||||
|
||||
if (repository && typeof repository === 'object' && typeof repository.url === 'string') {
|
||||
return repository.url;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function getRawLicenseExpression(packageJson) {
|
||||
if (typeof packageJson.license === 'string' && packageJson.license.trim()) {
|
||||
return packageJson.license.trim();
|
||||
}
|
||||
|
||||
if (packageJson.license && typeof packageJson.license === 'object' && typeof packageJson.license.type === 'string') {
|
||||
return packageJson.license.type.trim();
|
||||
}
|
||||
|
||||
if (Array.isArray(packageJson.licenses)) {
|
||||
const values = packageJson.licenses
|
||||
.map((entry) => {
|
||||
if (typeof entry === 'string') {
|
||||
return entry.trim();
|
||||
}
|
||||
|
||||
if (entry && typeof entry === 'object' && typeof entry.type === 'string') {
|
||||
return entry.type.trim();
|
||||
}
|
||||
|
||||
return '';
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
if (values.length > 0) {
|
||||
return values.join(' OR ');
|
||||
}
|
||||
}
|
||||
|
||||
return 'UNKNOWN';
|
||||
}
|
||||
|
||||
function extractLicenseTokens(rawExpression) {
|
||||
const tokens = (rawExpression || '').match(/[A-Za-z0-9-.+]+/g) || [];
|
||||
const operators = new Set(['AND', 'OR', 'WITH']);
|
||||
|
||||
return tokens.map((token) => token.toUpperCase()).filter((token) => !operators.has(token));
|
||||
}
|
||||
|
||||
function hasDeniedLicense(rawExpression, denyList) {
|
||||
const licenseTokens = extractLicenseTokens(rawExpression);
|
||||
|
||||
return denyList.some((rule) => {
|
||||
const normalizedRule = (rule || '').trim().toUpperCase();
|
||||
if (!normalizedRule) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Treat common copyleft family keywords as SPDX id prefixes.
|
||||
if (normalizedRule === 'GPL' || normalizedRule === 'LGPL' || normalizedRule === 'AGPL') {
|
||||
return licenseTokens.some((token) => token === normalizedRule || token.startsWith(`${normalizedRule}-`));
|
||||
}
|
||||
|
||||
// Support explicit wildcard rules like "GPL-*".
|
||||
if (normalizedRule.endsWith('*')) {
|
||||
const prefix = normalizedRule.slice(0, -1);
|
||||
return prefix.length > 0 && licenseTokens.some((token) => token.startsWith(prefix));
|
||||
}
|
||||
|
||||
// Otherwise require exact SPDX token match.
|
||||
return licenseTokens.includes(normalizedRule);
|
||||
});
|
||||
}
|
||||
|
||||
function getDependencyNames(packageJson) {
|
||||
return Array.from(new Set([...Object.keys(packageJson.dependencies || {}), ...Object.keys(packageJson.optionalDependencies || {})]));
|
||||
}
|
||||
|
||||
function collectProductionLicenses(packagePath, options = {}) {
|
||||
const packageJsonFile = readJson(packagePath);
|
||||
const mainDependencies = getDependencyNames(packageJsonFile);
|
||||
const packageDirectory = path.dirname(packagePath);
|
||||
const missingRepositories = options.missingRepositories || {};
|
||||
const denyList = options.denyList || [];
|
||||
|
||||
const queue = mainDependencies.map((name) => ({
|
||||
name,
|
||||
fromDirectory: packageDirectory
|
||||
}));
|
||||
|
||||
const visited = new Set();
|
||||
const packages = [];
|
||||
const deniedPackages = [];
|
||||
|
||||
for (const current of queue) {
|
||||
const packageJsonPath = resolvePackageJson(current.name, current.fromDirectory);
|
||||
|
||||
if (!packageJsonPath || !fs.existsSync(packageJsonPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const currentPackage = readJson(packageJsonPath);
|
||||
const name = currentPackage.name || current.name;
|
||||
const version = currentPackage.version || 'unknown';
|
||||
const packageFolder = path.dirname(packageJsonPath);
|
||||
const uniqueKey = `${name}@${version}:${packageFolder}`;
|
||||
|
||||
if (visited.has(uniqueKey)) {
|
||||
continue;
|
||||
}
|
||||
visited.add(uniqueKey);
|
||||
|
||||
const rawLicenseExpression = getRawLicenseExpression(currentPackage);
|
||||
const packageKey = `${name}@${version}`;
|
||||
const repository = getRepositoryUrl(currentPackage.repository) || missingRepositories[name] || '';
|
||||
|
||||
const record = {
|
||||
key: packageKey,
|
||||
name,
|
||||
version,
|
||||
repository,
|
||||
rawLicenseExpression,
|
||||
dependencies: currentPackage.dependencies || {},
|
||||
optionalDependencies: currentPackage.optionalDependencies || {}
|
||||
};
|
||||
|
||||
packages.push(record);
|
||||
|
||||
if (hasDeniedLicense(rawLicenseExpression, denyList)) {
|
||||
deniedPackages.push(`${packageKey}: ${rawLicenseExpression}`);
|
||||
}
|
||||
|
||||
const dependencies = getDependencyNames(currentPackage);
|
||||
for (const dependencyName of dependencies) {
|
||||
queue.push({
|
||||
name: dependencyName,
|
||||
fromDirectory: packageFolder
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
packages.sort((a, b) => {
|
||||
const nameCompare = a.name.localeCompare(b.name);
|
||||
if (nameCompare !== 0) {
|
||||
return nameCompare;
|
||||
}
|
||||
|
||||
return a.version.localeCompare(b.version);
|
||||
});
|
||||
|
||||
return { packages, deniedPackages };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
collectProductionLicenses
|
||||
};
|
||||
+57
-33
@@ -2,7 +2,7 @@
|
||||
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -18,17 +18,64 @@
|
||||
*/
|
||||
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import * as ejs from 'ejs';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { argv, exit } from 'node:process';
|
||||
import { parseArgs } from 'node:util';
|
||||
import { escapeHtml } from './utils';
|
||||
|
||||
interface AuditCommandArgs {
|
||||
package?: string;
|
||||
outDir?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the audit report as a Markdown page.
|
||||
*
|
||||
* @param jsonAudit parsed npm audit JSON output
|
||||
* @param projName project name
|
||||
* @param projVersion project version
|
||||
* @returns rendered Markdown string
|
||||
*/
|
||||
function renderAuditPage(jsonAudit: any, projName: string, projVersion: string): string {
|
||||
const rows: string[] = [];
|
||||
if (jsonAudit.auditReportVersion >= 2) {
|
||||
for (const key in jsonAudit.vulnerabilities) {
|
||||
const v = jsonAudit.vulnerabilities[key];
|
||||
rows.push(`|${escapeHtml(v.severity)} | ${escapeHtml(v.name)} | ${JSON.stringify(v.range)} |`);
|
||||
}
|
||||
} else {
|
||||
for (const key in jsonAudit.advisories) {
|
||||
const a = jsonAudit.advisories[key];
|
||||
rows.push(`|${escapeHtml(a.severity)} | ${escapeHtml(a.module_name)} | ${JSON.stringify(a.vulnerable_versions)} |`);
|
||||
}
|
||||
}
|
||||
|
||||
return `---
|
||||
Title: Audit info, ${escapeHtml(projName)} ${escapeHtml(projVersion)}
|
||||
---
|
||||
|
||||
# Audit information for ${escapeHtml(projName)} ${escapeHtml(projVersion)}
|
||||
|
||||
This page lists the security audit of the dependencies this project depends on.
|
||||
|
||||
## Risks
|
||||
|
||||
- Critical risk: ${jsonAudit.metadata.vulnerabilities.critical}
|
||||
- High risk: ${jsonAudit.metadata.vulnerabilities.high}
|
||||
- Moderate risk: ${jsonAudit.metadata.vulnerabilities.moderate}
|
||||
- Low risk: ${jsonAudit.metadata.vulnerabilities.low}
|
||||
|
||||
Dependencies analyzed: ${jsonAudit.metadata.totalDependencies}
|
||||
|
||||
## Libraries
|
||||
|
||||
| Severity | Module | Vulnerable versions |
|
||||
| --- | --- | --- |
|
||||
${rows.join('\n')}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Audit report command
|
||||
*
|
||||
@@ -82,14 +129,7 @@ Options:
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const templatePath = path.resolve(__dirname, '../templates/auditPage.ejs');
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
console.error(`Cannot find the report template: ${templatePath}`);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Running audit on ${packagePath}`);
|
||||
|
||||
const packageJson = JSON.parse(fs.readFileSync(packagePath).toString());
|
||||
@@ -98,8 +138,8 @@ Options:
|
||||
const packageDir = path.dirname(packagePath);
|
||||
|
||||
// Use spawnSync with array arguments for safer command execution (prevents shell injection)
|
||||
// Cross-platform: npm is available on PATH on all platforms (Windows, macOS, Linux)
|
||||
const result = spawnSync('npm', ['audit', '--json', '--prod'], {
|
||||
// Cross-platform: pnpm is available on PATH on all platforms (Windows, macOS, Linux)
|
||||
const result = spawnSync('pnpm', ['audit', '--json', '--prod'], {
|
||||
cwd: packageDir,
|
||||
encoding: 'utf-8',
|
||||
// shell: false is the default and more secure (no shell interpretation)
|
||||
@@ -133,29 +173,13 @@ Options:
|
||||
return;
|
||||
}
|
||||
|
||||
ejs.renderFile(
|
||||
templatePath,
|
||||
{
|
||||
jsonAudit,
|
||||
projVersion: packageJson.version,
|
||||
projName: packageJson.name
|
||||
},
|
||||
{},
|
||||
(err: any, mdText: string) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
reject(err);
|
||||
} else {
|
||||
const outputPath = path.resolve(options.outDir || workingDir);
|
||||
const outputFile = path.join(outputPath, `audit-info-${packageJson.version}.md`);
|
||||
const mdText = renderAuditPage(jsonAudit, packageJson.name, packageJson.version);
|
||||
const outputPath = path.resolve(options.outDir || workingDir);
|
||||
const outputFile = path.join(outputPath, `audit-info-${packageJson.version}.md`);
|
||||
|
||||
fs.writeFileSync(outputFile, mdText);
|
||||
fs.writeFileSync(outputFile, mdText);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Report saved as ${outputFile}`);
|
||||
resolve(0);
|
||||
}
|
||||
}
|
||||
);
|
||||
console.log(`Report saved as ${outputFile}`);
|
||||
resolve(0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -17,15 +17,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import { argv, exit } from 'node:process';
|
||||
import { parseArgs } from 'node:util';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import * as path from 'path';
|
||||
import { logger } from './logger';
|
||||
import * as fs from 'fs';
|
||||
import * as ejs from 'ejs';
|
||||
import { escapeHtml } from './utils';
|
||||
|
||||
interface Commit {
|
||||
hash: string;
|
||||
@@ -146,7 +144,7 @@ function getCommits(options: DiffOptions): Array<Commit> {
|
||||
.map((str: string) => {
|
||||
try {
|
||||
return JSON.parse(str) as Commit;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
logger.error(`Unparsable commit message: ${str}, dropping it... Please apply manual fix.`);
|
||||
return null;
|
||||
}
|
||||
@@ -167,6 +165,57 @@ function commitAuthorAllowed(commit: Commit, authorFilter: string): boolean {
|
||||
return !(filterRegex.test(commit.author) || filterRegex.test(commit.author_email));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render changelog as Markdown.
|
||||
*
|
||||
* @param commits list of commits
|
||||
* @param projName project name
|
||||
* @param projVersion project version
|
||||
* @param repoUrl repository URL
|
||||
* @returns rendered Markdown string
|
||||
*/
|
||||
function renderChangelogMd(commits: Commit[], projName: string, projVersion: string, repoUrl: string): string {
|
||||
const lines = commits.map((c) => `- [${c.hash}](${repoUrl}/commit/${c.hash}) ${escapeHtml(c.subject)}`);
|
||||
return `---
|
||||
Title: Changelog for ${escapeHtml(projName)} v${escapeHtml(projVersion)}
|
||||
---
|
||||
|
||||
# Changelog
|
||||
|
||||
${lines.join('\n')}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render changelog as HTML.
|
||||
*
|
||||
* @param commits list of commits
|
||||
* @param projName project name
|
||||
* @param projVersion project version
|
||||
* @param repoUrl repository URL
|
||||
* @returns rendered HTML string
|
||||
*/
|
||||
function renderChangelogHtml(commits: Commit[], projName: string, projVersion: string, repoUrl: string): string {
|
||||
const items = commits
|
||||
.map((c) => ` <li>\n <a href="${repoUrl}/commit/${c.hash}">[${c.hash}]</a> ${escapeHtml(c.subject)}\n </li>`)
|
||||
.join('\n');
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Changelog for ${escapeHtml(projName)} v${escapeHtml(projVersion)}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Changelog</h1>
|
||||
<ul>
|
||||
${items}
|
||||
</ul>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changelog command
|
||||
*
|
||||
@@ -265,42 +314,23 @@ Options:
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const templatePath = path.resolve(__dirname, `../templates/changelog-${format}.ejs`);
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
console.error(`Cannot find the report template: ${templatePath}`);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise((resolve) => {
|
||||
const packageJson = JSON.parse(fs.readFileSync(packagePath).toString());
|
||||
|
||||
ejs.renderFile(
|
||||
templatePath,
|
||||
{
|
||||
remote,
|
||||
repo_url,
|
||||
commits,
|
||||
projVersion: packageJson.version,
|
||||
projName: packageJson.name
|
||||
},
|
||||
{},
|
||||
(err: any, text: string) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
reject(err);
|
||||
} else {
|
||||
if (output) {
|
||||
const outputDir = path.resolve(output);
|
||||
const outputFile = path.join(outputDir, `changelog-${packageJson.version}.${format}`);
|
||||
console.log('Writing changelog to', outputFile);
|
||||
const text =
|
||||
format === 'html'
|
||||
? renderChangelogHtml(commits, packageJson.name, packageJson.version, repo_url)
|
||||
: renderChangelogMd(commits, packageJson.name, packageJson.version, repo_url);
|
||||
|
||||
fs.writeFileSync(outputFile, text);
|
||||
} else {
|
||||
console.log(text);
|
||||
}
|
||||
resolve(0);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (output) {
|
||||
const outputDir = path.resolve(output);
|
||||
const outputFile = path.join(outputDir, `changelog-${packageJson.version}.${format}`);
|
||||
console.log('Writing changelog to', outputFile);
|
||||
|
||||
fs.writeFileSync(outputFile, text);
|
||||
} else {
|
||||
console.log(text);
|
||||
}
|
||||
resolve(0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -18,8 +18,9 @@
|
||||
*/
|
||||
|
||||
import { parseArgs } from 'node:util';
|
||||
import fetch from 'node-fetch';
|
||||
import * as fs from 'fs';
|
||||
import { Readable } from 'node:stream';
|
||||
import type { ReadableStream } from 'node:stream/web';
|
||||
import { logger } from './logger';
|
||||
import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api';
|
||||
import { argv, exit } from 'node:process';
|
||||
@@ -89,8 +90,9 @@ async function healthCheck(nameService: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get deployed application
|
||||
* Get deployed application.
|
||||
*
|
||||
* @returns list of deployed applications
|
||||
*/
|
||||
async function getApplications(): Promise<{ list: { entries: any[] } }> {
|
||||
const url = `${args.host}/deployment-service/v1/applications`;
|
||||
@@ -235,9 +237,10 @@ function getProjectRelease(projectId: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Release project
|
||||
* Release project.
|
||||
*
|
||||
* @param projectId project id
|
||||
* @returns release response
|
||||
*/
|
||||
async function releaseProject(projectId: string) {
|
||||
const url = `${args.host}/modeling-service/v1/projects/${projectId}/releases`;
|
||||
@@ -306,9 +309,10 @@ function deleteProject(projectId: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Import and release project
|
||||
* Import and release project.
|
||||
*
|
||||
* @param absoluteFilePath path to project file
|
||||
* @returns released project
|
||||
*/
|
||||
async function importAndReleaseProject(absoluteFilePath: string) {
|
||||
const fileContent = fs.createReadStream(absoluteFilePath);
|
||||
@@ -584,9 +588,10 @@ async function deployWithPayload(currentAbsentApp: any, projectRelease: any, env
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if descriptor exists
|
||||
* Check if descriptor exists.
|
||||
*
|
||||
* @param name descriptor name
|
||||
* @returns `true` if descriptor exists
|
||||
*/
|
||||
async function checkDescriptorExist(name: string): Promise<boolean> {
|
||||
logger.info(`Check descriptor ${name} exist in the list `);
|
||||
@@ -605,10 +610,11 @@ async function checkDescriptorExist(name: string): Promise<boolean> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Import and release project
|
||||
* Import and release project.
|
||||
*
|
||||
* @param app application
|
||||
* @param tag tag
|
||||
* @returns released project
|
||||
*/
|
||||
async function importProjectAndRelease(app: any, tag?: string) {
|
||||
const appLocationReplaced = app.file_location(tag);
|
||||
@@ -666,10 +672,11 @@ function findFailingApps(deployedApps: any[]): any[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file from the remote
|
||||
* Get file from the remote.
|
||||
*
|
||||
* @param url url to file
|
||||
* @param name name
|
||||
* @returns resolves when the file is downloaded
|
||||
*/
|
||||
async function getFileFromRemote(url: string, name: string): Promise<void> {
|
||||
return fetch(url)
|
||||
@@ -682,14 +689,18 @@ async function getFileFromRemote(url: string, name: string): Promise<void> {
|
||||
.then(
|
||||
(response) =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
if (!response.body) {
|
||||
reject(new Error('Response body is empty'));
|
||||
return;
|
||||
}
|
||||
const outputFile = fs.createWriteStream(`${name}.zip`);
|
||||
response.body.pipe(outputFile);
|
||||
Readable.fromWeb(response.body as ReadableStream<Uint8Array>).pipe(outputFile);
|
||||
outputFile.on('finish', () => {
|
||||
logger.info(`The file is finished downloading.`);
|
||||
resolve();
|
||||
});
|
||||
outputFile.on('error', (error) => {
|
||||
logger.error(`Not possible to download the project form remote`);
|
||||
logger.error(`Not possible to download the project from remote: ${error.message}`);
|
||||
reject(error);
|
||||
});
|
||||
})
|
||||
|
||||
+269
-128
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -28,12 +28,16 @@ interface InitAcsEnvArgs {
|
||||
username?: string;
|
||||
password?: string;
|
||||
}
|
||||
|
||||
const MAX_RETRY = 10;
|
||||
let counter = 0;
|
||||
const TIMEOUT = 6000;
|
||||
const RETRY_DELAY_MS = 6000;
|
||||
const ACS_DEFAULT = require('./resources').ACS_DEFAULT;
|
||||
|
||||
let alfrescoJsApi: AlfrescoApi;
|
||||
let nodesApi: NodesApi;
|
||||
let uploadApi: UploadApi;
|
||||
let sharedlinksApi: SharedlinksApi;
|
||||
let favoritesApi: FavoritesApi;
|
||||
|
||||
/**
|
||||
* Init ACS environment command
|
||||
@@ -46,7 +50,6 @@ Usage: init-acs-env [options]
|
||||
Initialize ACS environment
|
||||
|
||||
Options:
|
||||
-v, --version Output the version number
|
||||
--host <host> Remote environment host
|
||||
--clientId <id> SSO client (default: "alfresco")
|
||||
-p, --password <pass> Password
|
||||
@@ -56,11 +59,6 @@ Options:
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argv.includes('-v') || argv.includes('--version')) {
|
||||
console.log('0.1.0');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
const { values } = parseArgs({
|
||||
args: argv.slice(2),
|
||||
options: {
|
||||
@@ -92,160 +90,305 @@ Options:
|
||||
|
||||
await checkEnv(opts);
|
||||
|
||||
logger.info(`***** Step initialize ACS *****`);
|
||||
logger.info('***** Step initialize ACS *****');
|
||||
await initializeDefaultFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup default files
|
||||
* Initialize default files. Creates the e2e folder and ensures each file
|
||||
* exists with its required state (locked, shared, favorite).
|
||||
* Idempotent: only creates/modifies what is missing.
|
||||
*/
|
||||
async function initializeDefaultFiles() {
|
||||
const e2eFolder = ACS_DEFAULT.e2eFolder;
|
||||
const parentFolder = await createFolder(e2eFolder.name, '-my-');
|
||||
const parentFolderId = parentFolder.entry.id;
|
||||
const e2eFolderName: string = ACS_DEFAULT.e2eFolder.name;
|
||||
|
||||
for (let j = 0; j < ACS_DEFAULT.files.length; j++) {
|
||||
const fileInfo = ACS_DEFAULT.files[j];
|
||||
switch (fileInfo.action) {
|
||||
case 'UPLOAD': {
|
||||
await uploadFile(fileInfo.name, parentFolderId);
|
||||
break;
|
||||
}
|
||||
case 'LOCK': {
|
||||
const fileToLock = await uploadFile(fileInfo.name, parentFolderId);
|
||||
await lockFile(fileToLock.entry.id);
|
||||
break;
|
||||
}
|
||||
case 'SHARE': {
|
||||
const fileToShare = await uploadFile(fileInfo.name, parentFolderId);
|
||||
await shareFile(fileToShare.entry.id);
|
||||
break;
|
||||
}
|
||||
case 'FAVORITE': {
|
||||
const fileToFav = await uploadFile(fileInfo.name, parentFolderId);
|
||||
await favoriteFile(fileToFav.entry.id);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
logger.error('No action found for file ', fileInfo.name, parentFolderId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let parentFolder: NodeEntry;
|
||||
try {
|
||||
parentFolder = await withRetry(() => ensureFolder(e2eFolderName, '-my-'), `ensure folder ${e2eFolderName}`);
|
||||
} catch (error: any) {
|
||||
logger.warn(`Skipping file initialization: test-data folder could not be created: ${formatError(error)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const parentFolderId = getEntryId(parentFolder, `folder ${e2eFolderName}`);
|
||||
|
||||
for (const fileInfo of ACS_DEFAULT.files) {
|
||||
await withRetry(() => processFile(fileInfo, parentFolderId), `initialize ${fileInfo.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create folder
|
||||
* Process a single file: upload if missing, then apply its action (lock/share/favorite).
|
||||
*
|
||||
* @param fileInfo file descriptor from ACS_DEFAULT
|
||||
* @param fileInfo.name file name
|
||||
* @param fileInfo.action action to apply (LOCK, SHARE, FAVORITE)
|
||||
* @param parentFolderId parent folder node id
|
||||
*/
|
||||
async function processFile(fileInfo: { name: string; action: string }, parentFolderId: string) {
|
||||
const existingNode = await findNodeByRelativePath(parentFolderId, fileInfo.name);
|
||||
|
||||
let nodeId: string;
|
||||
if (existingNode?.entry?.id) {
|
||||
logger.info(`File ${fileInfo.name} already exists, verifying required state.`);
|
||||
nodeId = existingNode.entry.id;
|
||||
} else {
|
||||
const createdNode = await uploadFile(fileInfo.name, parentFolderId);
|
||||
nodeId = getEntryId(createdNode, `file ${fileInfo.name}`);
|
||||
}
|
||||
|
||||
switch (fileInfo.action) {
|
||||
case 'LOCK':
|
||||
await ensureLocked(nodeId, fileInfo.name, existingNode?.entry?.isLocked);
|
||||
break;
|
||||
case 'SHARE':
|
||||
await ensureShared(nodeId, fileInfo.name);
|
||||
break;
|
||||
case 'FAVORITE':
|
||||
await ensureFavorite(nodeId, fileInfo.name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a folder exists under the given parent. Creates it if missing.
|
||||
* Handles 409 conflict (race condition) by fetching the existing folder.
|
||||
*
|
||||
* @param folderName folder name
|
||||
* @param parentId parent folder id
|
||||
* @param parentId parent node id
|
||||
* @returns the folder node entry
|
||||
*/
|
||||
async function createFolder(folderName: string, parentId: string) {
|
||||
let createdFolder: NodeEntry;
|
||||
const body = {
|
||||
name: folderName,
|
||||
nodeType: 'cm:folder'
|
||||
};
|
||||
try {
|
||||
createdFolder = await new NodesApi(alfrescoJsApi).createNode(parentId, body, { overwrite: true });
|
||||
async function ensureFolder(folderName: string, parentId: string): Promise<NodeEntry> {
|
||||
const existingFolder = await findNodeByRelativePath(parentId, folderName);
|
||||
|
||||
logger.info(`Folder ${folderName} was created`);
|
||||
} catch (err) {
|
||||
if (err.status === 409) {
|
||||
const relativePath = `/${folderName}`;
|
||||
createdFolder = await new NodesApi(alfrescoJsApi).getNode('-my-', { relativePath });
|
||||
if (existingFolder?.entry?.id) {
|
||||
if (!existingFolder.entry.isFolder) {
|
||||
throw new Error(
|
||||
`Cannot use ${folderName} as test-data folder: a non-folder node with that name already exists (nodeType: ${existingFolder.entry.nodeType}, id: ${existingFolder.entry.id}).`
|
||||
);
|
||||
}
|
||||
logger.info(`Folder ${folderName} already exists.`);
|
||||
return existingFolder;
|
||||
}
|
||||
|
||||
try {
|
||||
const createdFolder = await nodesApi.createNode(parentId, { name: folderName, nodeType: 'cm:folder' }, { overwrite: true });
|
||||
logger.info(`Folder ${folderName} was created`);
|
||||
return createdFolder;
|
||||
} catch (error: any) {
|
||||
if (error?.status === 409) {
|
||||
const conflictingFolder = await findNodeByRelativePath(parentId, folderName);
|
||||
|
||||
if (conflictingFolder?.entry?.id) {
|
||||
if (!conflictingFolder.entry.isFolder) {
|
||||
throw new Error(
|
||||
`Cannot use ${folderName} as test-data folder: a non-folder node with that name already exists (nodeType: ${conflictingFolder.entry.nodeType}, id: ${conflictingFolder.entry.id}).`
|
||||
);
|
||||
}
|
||||
logger.info(`Folder ${folderName} already exists.`);
|
||||
return conflictingFolder;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Failed to ensure folder ${folderName}: ${formatError(error)}`);
|
||||
}
|
||||
return createdFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload file
|
||||
* Find a node by relative path under a parent. Returns null if not found (404).
|
||||
*
|
||||
* @param parentId parent node id
|
||||
* @param fileName relative path / file name
|
||||
* @returns the node entry or null if not found
|
||||
*/
|
||||
async function findNodeByRelativePath(parentId: string, fileName: string): Promise<NodeEntry | null> {
|
||||
try {
|
||||
return await nodesApi.getNode(parentId, { relativePath: `/${fileName}`, include: ['isLocked'] });
|
||||
} catch (error: any) {
|
||||
if (error?.status === 404) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new Error(`Failed to fetch ${fileName}: ${formatError(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a file to the given destination folder.
|
||||
*
|
||||
* @param fileName file name
|
||||
* @param fileDestination destination path
|
||||
* @param destinationId destination folder node id
|
||||
* @returns the uploaded node entry
|
||||
*/
|
||||
async function uploadFile(fileName: string, fileDestination: string): Promise<NodeEntry> {
|
||||
async function uploadFile(fileName: string, destinationId: string): Promise<NodeEntry> {
|
||||
const filePath = `../resources/content/${fileName}`;
|
||||
const file = createReadStream(path.join(__dirname, filePath));
|
||||
let uploadedFile: NodeEntry;
|
||||
|
||||
try {
|
||||
uploadedFile = await new UploadApi(alfrescoJsApi).uploadFile(file, '', fileDestination, null, {
|
||||
const uploadedFile = await uploadApi.uploadFile(file, '', destinationId, null, {
|
||||
name: fileName,
|
||||
nodeType: 'cm:content',
|
||||
renditions: 'doclib',
|
||||
overwrite: true
|
||||
});
|
||||
logger.info(`File ${fileName} was uploaded`);
|
||||
} catch (err) {
|
||||
logger.error(`Failed to upload file with error: `, err.stack);
|
||||
return uploadedFile;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Failed to upload ${fileName}: ${formatError(error)}`);
|
||||
}
|
||||
return uploadedFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock file node
|
||||
* Ensure a file is locked. Skips if already locked.
|
||||
*
|
||||
* @param nodeId node id
|
||||
* @param fileName file name (for logging)
|
||||
* @param isAlreadyLocked whether the node is already locked
|
||||
*/
|
||||
async function lockFile(nodeId: string): Promise<NodeEntry> {
|
||||
const data = {
|
||||
type: 'ALLOW_OWNER_CHANGES'
|
||||
};
|
||||
async function ensureLocked(nodeId: string, fileName: string, isAlreadyLocked = false) {
|
||||
if (isAlreadyLocked) {
|
||||
logger.info(`File ${fileName} is already locked.`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = new NodesApi(alfrescoJsApi).lockNode(nodeId, data);
|
||||
logger.info('File was locked');
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error('Failed to lock file with error: ', error.stack);
|
||||
return null;
|
||||
await nodesApi.lockNode(nodeId, { type: 'ALLOW_OWNER_CHANGES' });
|
||||
logger.info(`File ${fileName} was locked`);
|
||||
} catch (error: any) {
|
||||
throw new Error(`Failed to lock ${fileName}: ${formatError(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Share file node
|
||||
* Ensure a file is shared. Handles 409 (already shared) gracefully.
|
||||
*
|
||||
* @param nodeId node id
|
||||
* @param fileName file name (for logging)
|
||||
*/
|
||||
async function shareFile(nodeId: string) {
|
||||
const data = {
|
||||
nodeId
|
||||
};
|
||||
async function ensureShared(nodeId: string, fileName: string) {
|
||||
try {
|
||||
await new SharedlinksApi(alfrescoJsApi).createSharedLink(data);
|
||||
logger.info('File was shared');
|
||||
} catch (error) {
|
||||
logger.error('Failed to share file with error: ', error.stack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Favorite file node
|
||||
*
|
||||
* @param nodeId node id
|
||||
*/
|
||||
async function favoriteFile(nodeId: string) {
|
||||
const data = {
|
||||
target: {
|
||||
['file']: {
|
||||
guid: nodeId
|
||||
}
|
||||
await sharedlinksApi.createSharedLink({ nodeId });
|
||||
logger.info(`File ${fileName} was shared`);
|
||||
} catch (error: any) {
|
||||
if (error?.status === 409) {
|
||||
logger.info(`File ${fileName} is already shared.`);
|
||||
return;
|
||||
}
|
||||
};
|
||||
try {
|
||||
await new FavoritesApi(alfrescoJsApi).createFavorite('-me-', data);
|
||||
logger.info('File was add to favorites');
|
||||
} catch (error) {
|
||||
logger.error('Failed to add the file to favorites with error: ', error.stack);
|
||||
|
||||
throw new Error(`Failed to share ${fileName}: ${formatError(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check environment state
|
||||
* Ensure a file is favorite. Handles 409 (already favorite) gracefully.
|
||||
*
|
||||
* @param nodeId node id
|
||||
* @param fileName file name (for logging)
|
||||
*/
|
||||
async function ensureFavorite(nodeId: string, fileName: string) {
|
||||
try {
|
||||
await favoritesApi.createFavorite('-me-', {
|
||||
target: {
|
||||
file: {
|
||||
guid: nodeId
|
||||
}
|
||||
}
|
||||
});
|
||||
logger.info(`File ${fileName} was added to favorites`);
|
||||
} catch (error: any) {
|
||||
if (error?.status === 409) {
|
||||
logger.info(`File ${fileName} is already a favorite.`);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(`Failed to favorite ${fileName}: ${formatError(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract entry id from a node response. Throws if missing.
|
||||
*
|
||||
* @param nodeEntry node entry response
|
||||
* @param label label for error message
|
||||
* @returns the node id
|
||||
*/
|
||||
function getEntryId(nodeEntry: NodeEntry, label: string): string {
|
||||
const nodeId = nodeEntry?.entry?.id;
|
||||
|
||||
if (nodeId) {
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
throw new Error(`Missing ACS response entry for ${label}.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an error for logging.
|
||||
*
|
||||
* @param error error object
|
||||
* @returns formatted error string
|
||||
*/
|
||||
function formatError(error: any): string {
|
||||
if (!error) {
|
||||
return 'Unknown error';
|
||||
}
|
||||
|
||||
if (typeof error === 'string') {
|
||||
return error;
|
||||
}
|
||||
|
||||
try {
|
||||
return error?.message || error?.stack || JSON.stringify(error);
|
||||
} catch {
|
||||
return 'Unknown error (unable to serialize)';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry wrapper for transient failures.
|
||||
*
|
||||
* @param fn async function to execute
|
||||
* @param label label for logging
|
||||
* @param maxAttempts maximum retry attempts
|
||||
* @returns the result of the function
|
||||
*/
|
||||
async function withRetry<T>(fn: () => Promise<T>, label: string, maxAttempts = 3): Promise<T> {
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
try {
|
||||
return await fn();
|
||||
} catch (error: any) {
|
||||
if (attempt === maxAttempts) {
|
||||
logger.error(`${label}: failed after ${maxAttempts} attempts: ${formatError(error)}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
logger.warn(`${label}: attempt ${attempt} failed, retrying in ${RETRY_DELAY_MS / 1000}s: ${formatError(error)}`);
|
||||
await wait(RETRY_DELAY_MS);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`${label}: exhausted all ${maxAttempts} attempts`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Async delay.
|
||||
*
|
||||
* @param ms milliseconds to wait
|
||||
* @returns a promise that resolves after the delay
|
||||
*/
|
||||
function wait(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check environment state and authenticate. Retries on transient failures.
|
||||
*
|
||||
* @param opts command options
|
||||
* @param attempt current attempt number
|
||||
*/
|
||||
async function checkEnv(opts: InitAcsEnvArgs) {
|
||||
async function checkEnv(opts: InitAcsEnvArgs, attempt = 1) {
|
||||
try {
|
||||
alfrescoJsApi = new AlfrescoApi({
|
||||
provider: 'ALL',
|
||||
@@ -260,31 +403,29 @@ async function checkEnv(opts: InitAcsEnvArgs) {
|
||||
},
|
||||
contextRoot: 'alfresco'
|
||||
});
|
||||
|
||||
await alfrescoJsApi.login(opts.username, opts.password);
|
||||
} catch (e) {
|
||||
if (e.error.code === 'ETIMEDOUT') {
|
||||
logger.error('The env is not reachable. Terminating');
|
||||
exit(1);
|
||||
|
||||
nodesApi = new NodesApi(alfrescoJsApi);
|
||||
uploadApi = new UploadApi(alfrescoJsApi);
|
||||
sharedlinksApi = new SharedlinksApi(alfrescoJsApi);
|
||||
favoritesApi = new FavoritesApi(alfrescoJsApi);
|
||||
} catch (error: any) {
|
||||
const errorCode = error?.error?.code;
|
||||
|
||||
if (errorCode === 'ETIMEDOUT' || error?.status === 504) {
|
||||
logger.warn('Login attempt timed out or received a gateway error, environment may still be starting up.');
|
||||
} else {
|
||||
logger.error('Login error, environment down or inaccessible.');
|
||||
}
|
||||
logger.error('Login error environment down or inaccessible');
|
||||
counter++;
|
||||
if (MAX_RETRY === counter) {
|
||||
|
||||
if (attempt >= MAX_RETRY) {
|
||||
logger.error('Give up');
|
||||
exit(1);
|
||||
} else {
|
||||
logger.error(`Retry in 1 minute attempt N ${counter}`);
|
||||
sleep(TIMEOUT);
|
||||
await checkEnv(opts);
|
||||
}
|
||||
|
||||
logger.warn(`Retry in ${RETRY_DELAY_MS / 1000} seconds, attempt ${attempt}`);
|
||||
await wait(RETRY_DELAY_MS);
|
||||
await checkEnv(opts, attempt + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a delay
|
||||
*
|
||||
* @param delay timeout in milliseconds
|
||||
*/
|
||||
function sleep(delay: number) {
|
||||
const start = new Date().getTime();
|
||||
while (new Date().getTime() < start + delay) {}
|
||||
}
|
||||
|
||||
+154
-72
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -30,8 +30,11 @@ import { parseArgs } from 'node:util';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { createReadStream } from 'node:fs';
|
||||
import * as path from 'path';
|
||||
import { config } from 'dotenv';
|
||||
import { logger } from './logger';
|
||||
|
||||
config({ path: path.resolve(__dirname, '../../../.env') });
|
||||
|
||||
interface InitApsEnvArgs {
|
||||
host?: string;
|
||||
clientId?: string;
|
||||
@@ -40,12 +43,12 @@ interface InitApsEnvArgs {
|
||||
license?: string;
|
||||
}
|
||||
const MAX_RETRY = 10;
|
||||
let counter = 0;
|
||||
const TIMEOUT = 6000;
|
||||
const RETRY_DELAY_MS = 6000;
|
||||
const TENANT_DEFAULT_ID = 1;
|
||||
const TENANT_DEFAULT_NAME = 'default';
|
||||
const CONTENT_DEFAULT_NAME = 'adw-content';
|
||||
const ACTIVITI_APPS = require('./resources').ACTIVITI_APPS;
|
||||
const E2E_USER_PASSWORD = process.env.HR_USER_PASSWORD;
|
||||
|
||||
let alfrescoJsApi: AlfrescoApi;
|
||||
|
||||
@@ -60,7 +63,6 @@ Usage: init-aps-env [options]
|
||||
Initialize APS environment
|
||||
|
||||
Options:
|
||||
-v, --version Output the version number
|
||||
--host <host> Remote environment host
|
||||
--clientId <id> SSO client (default: "alfresco")
|
||||
-p, --password <pass> Password
|
||||
@@ -71,11 +73,6 @@ Options:
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argv.includes('-v') || argv.includes('--version')) {
|
||||
console.log('0.1.0');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
const { values } = parseArgs({
|
||||
args: argv.slice(2),
|
||||
options: {
|
||||
@@ -111,6 +108,14 @@ Options:
|
||||
|
||||
await checkEnv(opts);
|
||||
|
||||
const e2eAppReady = await ensureE2eApplicationDeployed();
|
||||
if (e2eAppReady) {
|
||||
logger.info(`APS environment already initialized (terraform). Skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
await alfrescoJsApi.login(opts.username, opts.password);
|
||||
|
||||
logger.info(`***** Step 1 - Check License *****`);
|
||||
|
||||
let licenceUploaded = false;
|
||||
@@ -146,25 +151,24 @@ Options:
|
||||
logger.info(`***** Step 4 - Create users *****`);
|
||||
const users = await getDefaultApsUsersFromRealm(opts);
|
||||
if (tenantId && users && users.length > 0) {
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
await createUsers(tenantId, users[i]);
|
||||
for (const user of users) {
|
||||
await createUsers(tenantId, user);
|
||||
}
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
logger.info('Impersonate user: ' + users[i].username);
|
||||
await alfrescoJsApi.login(users[i].username, 'password');
|
||||
await authorizeUserToContentRepo(opts, users[i]);
|
||||
for (const user of users) {
|
||||
logger.info('Impersonate user: ' + user.username);
|
||||
await alfrescoJsApi.login(user.username, E2E_USER_PASSWORD);
|
||||
await authorizeUserToContentRepo(opts, user);
|
||||
|
||||
const defaultUser = 'hruser';
|
||||
if (users[i].username.includes(defaultUser)) {
|
||||
logger.info(`***** Step initialize APS apps for user ${defaultUser} *****`);
|
||||
if (user.username.includes('hruser')) {
|
||||
logger.info(`***** Step initialize APS apps for user hruser *****`);
|
||||
await initializeDefaultApps();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.info('Something went wrong. Was not able to create the users');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Aps something went wrong. Tenant id ${tenantId}`, error);
|
||||
} catch (error: any) {
|
||||
logger.error(`Aps something went wrong. Tenant id ${tenantId}: ${formatError(error)}`);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
@@ -173,15 +177,57 @@ Options:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure e2e-Application is deployed for hruser.
|
||||
* If the app is already present, returns true (skip full init).
|
||||
* If hruser can log in but the app is missing, imports, publishes and deploys it.
|
||||
* Returns false only if hruser cannot log in or deployment fails.
|
||||
*
|
||||
* @returns `true` if app is deployed, otherwise `false`
|
||||
*/
|
||||
async function ensureE2eApplicationDeployed(): Promise<boolean> {
|
||||
try {
|
||||
await alfrescoJsApi.login('hruser', E2E_USER_PASSWORD);
|
||||
const runtimeAppDefinitionsApi = new RuntimeAppDefinitionsApi(alfrescoJsApi);
|
||||
const availableApps = await runtimeAppDefinitionsApi.getAppDefinitions();
|
||||
const e2eApp = availableApps.data?.filter((app) => app.name?.includes('e2e-Application'));
|
||||
if (e2eApp && e2eApp.length > 0) {
|
||||
logger.info(`e2e-Application is already deployed for hruser`);
|
||||
return true;
|
||||
}
|
||||
logger.info(`e2e-Application not found for hruser - uploading and deploying it now`);
|
||||
const appDefinition = await importPublishApp('e2e-Application');
|
||||
if (appDefinition?.appDefinition?.id) {
|
||||
await deployApp(appDefinition.appDefinition.id);
|
||||
const verifyApps = await runtimeAppDefinitionsApi.getAppDefinitions();
|
||||
const deployed = verifyApps.data?.some((app) => app.name?.includes('e2e-Application'));
|
||||
if (deployed) {
|
||||
logger.info(`e2e-Application successfully deployed for hruser`);
|
||||
return true;
|
||||
}
|
||||
logger.info(`e2e-Application deployment could not be verified - proceeding with full initialization`);
|
||||
return false;
|
||||
}
|
||||
logger.info(`Failed to import/deploy e2e-Application for hruser - proceeding with full initialization`);
|
||||
return false;
|
||||
} catch (error: any) {
|
||||
logger.info(`Unable to verify APS state for hruser - proceeding with initialization: ${formatError(error)}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise default applications
|
||||
*/
|
||||
async function initializeDefaultApps() {
|
||||
for (let x = 0; x < ACTIVITI_APPS.apps.length; x++) {
|
||||
const appInfo = ACTIVITI_APPS.apps[x];
|
||||
for (const appInfo of ACTIVITI_APPS.apps) {
|
||||
const isDeployed = await isDefaultAppDeployed(appInfo.name);
|
||||
if (isDeployed !== undefined && !isDeployed) {
|
||||
const appDefinition = await importPublishApp(`${appInfo.name}`);
|
||||
if (!isDeployed) {
|
||||
const appDefinition = await importPublishApp(appInfo.name);
|
||||
if (!appDefinition?.appDefinition?.id) {
|
||||
logger.error(`Failed to import app ${appInfo.name}, skipping deployment.`);
|
||||
continue;
|
||||
}
|
||||
await deployApp(appDefinition.appDefinition.id);
|
||||
} else {
|
||||
logger.info(`***** App ${appInfo.name} already deployed *****`);
|
||||
@@ -190,11 +236,12 @@ async function initializeDefaultApps() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check environment
|
||||
* Check environment state and authenticate. Retries on transient failures.
|
||||
*
|
||||
* @param opts command options
|
||||
* @param attempt current attempt number
|
||||
*/
|
||||
async function checkEnv(opts: InitApsEnvArgs) {
|
||||
async function checkEnv(opts: InitApsEnvArgs, attempt = 1) {
|
||||
try {
|
||||
alfrescoJsApi = new AlfrescoApi({
|
||||
provider: 'ALL',
|
||||
@@ -210,21 +257,23 @@ async function checkEnv(opts: InitApsEnvArgs) {
|
||||
}
|
||||
});
|
||||
await alfrescoJsApi.login(opts.username, opts.password);
|
||||
} catch (e) {
|
||||
if (e.error.code === 'ETIMEDOUT') {
|
||||
logger.error('The env is not reachable. Terminating');
|
||||
exit(1);
|
||||
} catch (error: any) {
|
||||
const errorCode = error?.error?.code;
|
||||
|
||||
if (errorCode === 'ETIMEDOUT' || error?.status === 504) {
|
||||
logger.warn('Login attempt timed out or received a gateway error, environment may still be starting up.');
|
||||
} else {
|
||||
logger.error('Login error, environment down or inaccessible.');
|
||||
}
|
||||
logger.info('Login error environment down or inaccessible');
|
||||
counter++;
|
||||
if (MAX_RETRY === counter) {
|
||||
|
||||
if (attempt >= MAX_RETRY) {
|
||||
logger.error('Give up');
|
||||
exit(1);
|
||||
} else {
|
||||
logger.error(`Retry in 1 minute attempt N ${counter}`);
|
||||
sleep(TIMEOUT);
|
||||
await checkEnv(opts);
|
||||
}
|
||||
|
||||
logger.warn(`Retry in ${RETRY_DELAY_MS / 1000} seconds, attempt ${attempt}`);
|
||||
await wait(RETRY_DELAY_MS);
|
||||
await checkEnv(opts, attempt + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +290,7 @@ async function hasDefaultTenant(tenantId: number, tenantName: string): Promise<b
|
||||
try {
|
||||
const adminTenantsApi = new AdminTenantsApi(alfrescoJsApi);
|
||||
tenant = await adminTenantsApi.getTenant(tenantId);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
logger.info(`Aps: does not have tenant with id: ${tenantId}`);
|
||||
return false;
|
||||
}
|
||||
@@ -260,6 +309,7 @@ async function hasDefaultTenant(tenantId: number, tenantName: string): Promise<b
|
||||
* Create default tenant
|
||||
*
|
||||
* @param tenantName tenant name
|
||||
* @returns the tenant id or null
|
||||
*/
|
||||
async function createDefaultTenant(tenantName: string) {
|
||||
const tenantPost = {
|
||||
@@ -273,8 +323,8 @@ async function createDefaultTenant(tenantName: string) {
|
||||
const tenant = await adminTenantsApi.createTenant(tenantPost);
|
||||
logger.info(`APS: Tenant ${tenantName} created with id: ${tenant.id}`);
|
||||
return tenant.id;
|
||||
} catch (error) {
|
||||
logger.info(`APS: not able to create the default tenant: ${JSON.parse(error.message)}`);
|
||||
} catch (error: any) {
|
||||
logger.info(`APS: not able to create the default tenant: ${formatError(error)}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -284,17 +334,17 @@ async function createDefaultTenant(tenantName: string) {
|
||||
*
|
||||
* @param tenantId tenant id
|
||||
* @param user user object
|
||||
* @returns the created user
|
||||
*/
|
||||
async function createUsers(tenantId: number, user: any) {
|
||||
logger.info(`Create user ${user.email} on tenant: ${tenantId}`);
|
||||
const passwordCamelCase = 'Password';
|
||||
const userJson = new UserRepresentation({
|
||||
email: user.email,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
status: 'active',
|
||||
type: 'enterprise',
|
||||
password: passwordCamelCase,
|
||||
password: E2E_USER_PASSWORD,
|
||||
tenantId
|
||||
});
|
||||
|
||||
@@ -303,8 +353,8 @@ async function createUsers(tenantId: number, user: any) {
|
||||
const userInfo = await adminUsersApi.createNewUser(userJson);
|
||||
logger.info(`APS: User ${userInfo.email} created with id: ${userInfo.id}`);
|
||||
return user;
|
||||
} catch (error) {
|
||||
logger.info(`APS: not able to create the default user: ${error.message}`);
|
||||
} catch (error: any) {
|
||||
logger.info(`APS: not able to create the default user: ${formatError(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,6 +362,7 @@ async function createUsers(tenantId: number, user: any) {
|
||||
* Update Activiti license
|
||||
*
|
||||
* @param opts command options
|
||||
* @returns `true` if license uploaded successfully, otherwise `false`
|
||||
*/
|
||||
async function updateLicense(opts: InitApsEnvArgs) {
|
||||
const fileContent = createReadStream(path.join(__dirname, '/activiti.lic'));
|
||||
@@ -330,8 +381,8 @@ async function updateLicense(opts: InitApsEnvArgs) {
|
||||
);
|
||||
logger.info(`Aps License uploaded!`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error(`Aps License failed!`, error.message);
|
||||
} catch (error: any) {
|
||||
logger.error(`Aps License failed! ${formatError(error)}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -349,8 +400,8 @@ async function isDefaultAppDeployed(appName: string): Promise<boolean> {
|
||||
const availableApps = await runtimeAppDefinitionsApi.getAppDefinitions();
|
||||
const defaultApp = availableApps.data?.filter((app) => app.name?.includes(appName));
|
||||
return defaultApp && defaultApp.length > 0;
|
||||
} catch (error) {
|
||||
logger.error(`Aps app failed to import/Publish!`);
|
||||
} catch (error: any) {
|
||||
logger.error(`Failed to check if ${appName} is deployed: ${formatError(error)}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -359,8 +410,9 @@ async function isDefaultAppDeployed(appName: string): Promise<boolean> {
|
||||
* Import and publish the application
|
||||
*
|
||||
* @param appName application name
|
||||
* @returns the app definition result
|
||||
*/
|
||||
async function importPublishApp(appName: string): Promise<AppDefinitionUpdateResultRepresentation> {
|
||||
async function importPublishApp(appName: string): Promise<AppDefinitionUpdateResultRepresentation | null> {
|
||||
const appNameExtension = `../resources/${appName}.zip`;
|
||||
logger.info(`Import app ${appNameExtension}`);
|
||||
const pathFile = path.join(__dirname, appNameExtension);
|
||||
@@ -371,8 +423,8 @@ async function importPublishApp(appName: string): Promise<AppDefinitionUpdateRes
|
||||
const result = await appDefinitionsApi.importAndPublishApp(fileContent, { renewIdmEntries: true });
|
||||
logger.info(`Aps app imported and published!`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error(`Aps app failed to import/Publish!`, error.message);
|
||||
} catch (error: any) {
|
||||
logger.error(`Aps app failed to import/Publish! ${formatError(error)}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -392,8 +444,8 @@ async function deployApp(appDefinitionId: number) {
|
||||
const runtimeAppDefinitionsApi = new RuntimeAppDefinitionsApi(alfrescoJsApi);
|
||||
await runtimeAppDefinitionsApi.deployAppDefinitions(body);
|
||||
logger.info(`Aps app deployed`);
|
||||
} catch (error) {
|
||||
logger.error(`Aps app failed to deploy!`);
|
||||
} catch (error: any) {
|
||||
logger.error(`Aps app failed to deploy: ${formatError(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,6 +453,7 @@ async function deployApp(appDefinitionId: number) {
|
||||
* Checks if Activiti app has license
|
||||
*
|
||||
* @param opts command options
|
||||
* @returns `true` if license is valid, otherwise `false`
|
||||
*/
|
||||
async function hasLicense(opts: InitApsEnvArgs): Promise<boolean> {
|
||||
try {
|
||||
@@ -415,13 +468,13 @@ async function hasLicense(opts: InitApsEnvArgs): Promise<boolean> {
|
||||
['application/json'],
|
||||
['application/json']
|
||||
);
|
||||
if (license && license.status === 'valid') {
|
||||
if (license?.status === 'valid') {
|
||||
logger.info(`Aps has a valid License!`);
|
||||
return true;
|
||||
}
|
||||
logger.info(`Aps does NOT have a valid License!`);
|
||||
return false;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
logger.error(`Aps not able to check the license`);
|
||||
return false;
|
||||
}
|
||||
@@ -431,6 +484,7 @@ async function hasLicense(opts: InitApsEnvArgs): Promise<boolean> {
|
||||
* Get default users from the realm
|
||||
*
|
||||
* @param opts command options
|
||||
* @returns array of default APS users or null
|
||||
*/
|
||||
async function getDefaultApsUsersFromRealm(opts: InitApsEnvArgs) {
|
||||
try {
|
||||
@@ -449,8 +503,8 @@ async function getDefaultApsUsersFromRealm(opts: InitApsEnvArgs) {
|
||||
const apsDefaultUsers = users.filter((user) => usernamesOfApsDefaultUsers.includes(user.username));
|
||||
logger.info(`Keycloak found ${apsDefaultUsers.length} users`);
|
||||
return apsDefaultUsers;
|
||||
} catch (error) {
|
||||
logger.error(`APS: not able to fetch user: ${error.message}`);
|
||||
} catch (error: any) {
|
||||
logger.error(`APS: not able to fetch user: ${formatError(error)}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -461,6 +515,7 @@ async function getDefaultApsUsersFromRealm(opts: InitApsEnvArgs) {
|
||||
* @param opts command options
|
||||
* @param tenantId tenant id
|
||||
* @param contentName content service name
|
||||
* @returns `true` if content repo is present, otherwise `false`
|
||||
*/
|
||||
async function isContentRepoPresent(opts: InitApsEnvArgs, tenantId: number, contentName: string): Promise<boolean> {
|
||||
try {
|
||||
@@ -476,9 +531,9 @@ async function isContentRepoPresent(opts: InitApsEnvArgs, tenantId: number, cont
|
||||
['application/json']
|
||||
);
|
||||
return !!contentRepos.data.find((repo) => repo.name === contentName);
|
||||
} catch (error) {
|
||||
logger.error(`APS: not able to create content: ${error.message}`);
|
||||
return null;
|
||||
} catch (error: any) {
|
||||
logger.error(`APS: not able to check content repo: ${formatError(error)}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,6 +543,7 @@ async function isContentRepoPresent(opts: InitApsEnvArgs, tenantId: number, cont
|
||||
* @param opts command options
|
||||
* @param tenantId tenant id
|
||||
* @param name content name
|
||||
* @returns the created content repo
|
||||
*/
|
||||
async function addContentRepoWithBasic(opts: InitApsEnvArgs, tenantId: number, name: string) {
|
||||
logger.info(`Create Content with name ${name} and basic auth`);
|
||||
@@ -517,8 +573,8 @@ async function addContentRepoWithBasic(opts: InitApsEnvArgs, tenantId: number, n
|
||||
);
|
||||
logger.info(`Content created!`);
|
||||
return content;
|
||||
} catch (error) {
|
||||
logger.error(`APS: not able to create content: ${error.message}`);
|
||||
} catch (error: any) {
|
||||
logger.error(`APS: not able to create content: ${formatError(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,8 +607,8 @@ async function authorizeUserToContentRepo(opts: InitApsEnvArgs, user: any) {
|
||||
}
|
||||
}
|
||||
return;
|
||||
} catch (error) {
|
||||
logger.error(`APS: not able to authorize content: ${error.message}`);
|
||||
} catch (error: any) {
|
||||
logger.error(`APS: not able to authorize content: ${formatError(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,11 +618,12 @@ async function authorizeUserToContentRepo(opts: InitApsEnvArgs, user: any) {
|
||||
* @param opts command options
|
||||
* @param username username
|
||||
* @param contentId content id
|
||||
* @returns the authorized content
|
||||
*/
|
||||
async function authorizeUserToContentWithBasic(opts: InitApsEnvArgs, username: string, contentId: string) {
|
||||
logger.info(`Authorize ${username} on contentId: ${contentId} in basic auth`);
|
||||
try {
|
||||
const body = { username, password: 'password' };
|
||||
const body = { username, password: E2E_USER_PASSWORD };
|
||||
const content = await alfrescoJsApi.oauth2Auth.callCustomApi(
|
||||
`${opts.host}/activiti-app/api/enterprise/integration/alfresco/${contentId}/account`,
|
||||
'POST',
|
||||
@@ -580,8 +637,8 @@ async function authorizeUserToContentWithBasic(opts: InitApsEnvArgs, username: s
|
||||
);
|
||||
logger.info(`User authorized!`);
|
||||
return content;
|
||||
} catch (error) {
|
||||
logger.error(`APS: not able to authorize content: ${error.message}`);
|
||||
} catch (error: any) {
|
||||
logger.error(`APS: not able to authorize content: ${formatError(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,6 +646,7 @@ async function authorizeUserToContentWithBasic(opts: InitApsEnvArgs, username: s
|
||||
* Download APS license file
|
||||
*
|
||||
* @param apsLicensePath path to license file
|
||||
* @returns `true` if download succeeded, otherwise `false`
|
||||
*/
|
||||
async function downloadLicenseFile(apsLicensePath: string) {
|
||||
const args = [`s3`, `cp`, apsLicensePath, `./`];
|
||||
@@ -606,11 +664,35 @@ async function downloadLicenseFile(apsLicensePath: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a delay
|
||||
* Format an error for logging.
|
||||
*
|
||||
* @param delay timeout in milliseconds
|
||||
* @param error error object
|
||||
* @returns formatted error string
|
||||
*/
|
||||
function sleep(delay: number) {
|
||||
const start = new Date().getTime();
|
||||
while (new Date().getTime() < start + delay) {}
|
||||
function formatError(error: any): string {
|
||||
if (!error) {
|
||||
return 'Unknown error';
|
||||
}
|
||||
|
||||
if (typeof error === 'string') {
|
||||
return error;
|
||||
}
|
||||
|
||||
try {
|
||||
return error?.message || error?.stack || JSON.stringify(error);
|
||||
} catch {
|
||||
return 'Unknown error (unable to serialize)';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async delay.
|
||||
*
|
||||
* @param ms milliseconds to wait
|
||||
* @returns a promise that resolves after the delay
|
||||
*/
|
||||
function wait(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
+89
-78
@@ -2,7 +2,7 @@
|
||||
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -21,9 +21,10 @@ import { argv, exit } from 'node:process';
|
||||
import { parseArgs } from 'node:util';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as checker from 'license-checker';
|
||||
import * as licenseList from 'spdx-license-list';
|
||||
import * as ejs from 'ejs';
|
||||
import { escapeHtml } from './utils';
|
||||
|
||||
const { collectProductionLicenses } = require('../resources/license-collector.cjs');
|
||||
|
||||
interface LicensesCommandArgs {
|
||||
package?: string;
|
||||
@@ -34,7 +35,14 @@ interface PackageInfo {
|
||||
name: string;
|
||||
description: string;
|
||||
version: string;
|
||||
dependencies: Record<string, string>;
|
||||
dependencies?: Record<string, string>;
|
||||
}
|
||||
|
||||
interface PackageInfoWithMetadata {
|
||||
name: string;
|
||||
version: string;
|
||||
licenseExp: string;
|
||||
repository?: string;
|
||||
}
|
||||
|
||||
const nonStandardLicenses = {
|
||||
@@ -93,6 +101,57 @@ function getPackageFile(packagePath: string): PackageInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a license expression to linked Markdown.
|
||||
*
|
||||
* @param rawExpression raw SPDX license expression
|
||||
* @returns expression with Markdown links
|
||||
*/
|
||||
function toLinkedLicenseExpression(rawExpression: string): string {
|
||||
return rawExpression.replace(/\*/g, '').replace(/[a-zA-Z0-9\-.]+/g, (match: string) => {
|
||||
const lowerMatch = match.toLowerCase();
|
||||
if (lowerMatch !== 'and' && lowerMatch !== 'or' && lowerMatch !== 'with') {
|
||||
return licenseWithMDLinks(match);
|
||||
}
|
||||
|
||||
return match;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the license page as Markdown.
|
||||
*
|
||||
* @param filteredPackages packages with license metadata
|
||||
* @param projName project name
|
||||
* @param projVersion project version
|
||||
* @returns rendered Markdown string
|
||||
*/
|
||||
function renderLicensePage(filteredPackages: Record<string, PackageInfoWithMetadata>, projName: string, projVersion: string): string {
|
||||
const rows = Object.entries(filteredPackages).map(([packageName, pack]) => {
|
||||
const lastAtSignPos = packageName.lastIndexOf('@');
|
||||
const name = packageName.substring(0, lastAtSignPos);
|
||||
const version = packageName.substring(lastAtSignPos + 1);
|
||||
const licenses = escapeHtml(pack.licenseExp || 'N/A');
|
||||
const linkedName = pack.repository ? `[${escapeHtml(name)}](${pack.repository})` : escapeHtml(name);
|
||||
return `| ${linkedName} | ${escapeHtml(version)} | ${licenses} |`;
|
||||
});
|
||||
|
||||
return `---
|
||||
Title: License info, ${escapeHtml(projName)} ${escapeHtml(projVersion)}
|
||||
---
|
||||
|
||||
# License information for ${escapeHtml(projName)} ${escapeHtml(projVersion)}
|
||||
|
||||
This page lists all third party libraries the project depends on.
|
||||
|
||||
## Libraries
|
||||
|
||||
| Name | Version | License |
|
||||
| --- | --- | --- |
|
||||
${rows.join('\n')}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Licenses command
|
||||
*
|
||||
@@ -146,87 +205,39 @@ Options:
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const templatePath = path.resolve(__dirname, '../templates/licensePage.ejs');
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
console.error(`Cannot find the report template: ${templatePath}`);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.info(`Checking ${packagePath}`);
|
||||
const packageJsonFile = getPackageFile(packagePath);
|
||||
const mainDependencies = Object.keys(packageJsonFile.dependencies || {});
|
||||
const licenseScan = collectProductionLicenses(packagePath, {
|
||||
denyList: ['GPL'],
|
||||
missingRepositories
|
||||
});
|
||||
|
||||
checker.init(
|
||||
{
|
||||
start: workingDir,
|
||||
production: true,
|
||||
failOn: 'GPL'
|
||||
},
|
||||
(err: any, packages: any[]) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
reject(err);
|
||||
} else {
|
||||
const filteredPackages = {};
|
||||
const filteredPackages: Record<string, PackageInfoWithMetadata> = {};
|
||||
for (const pack of licenseScan.packages) {
|
||||
filteredPackages[pack.key] = {
|
||||
name: pack.name,
|
||||
version: pack.version,
|
||||
licenseExp: toLinkedLicenseExpression(pack.rawLicenseExpression),
|
||||
repository: pack.repository
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line guard-for-in
|
||||
for (const packageName in packages) {
|
||||
const pack = packages[packageName];
|
||||
if (licenseScan.deniedPackages.length > 0) {
|
||||
const deniedError = new Error(`Denied licenses found:\n${licenseScan.deniedPackages.join('\n')}`);
|
||||
console.error(deniedError.message);
|
||||
reject(deniedError);
|
||||
return;
|
||||
}
|
||||
|
||||
const lastAtSignPos = packageName.lastIndexOf('@');
|
||||
const basePackageName = packageName.substring(0, lastAtSignPos);
|
||||
const packageJson: PackageInfo = getPackageFile(packagePath);
|
||||
|
||||
if (mainDependencies.includes(basePackageName)) {
|
||||
pack['licenseExp'] = pack['licenses']
|
||||
.toString()
|
||||
.replace(/\*/g, '')
|
||||
.replace(/[a-zA-Z0-9\-.]+/g, (match: string) => {
|
||||
const lowerMatch = match.toLowerCase();
|
||||
if (lowerMatch !== 'and' && lowerMatch !== 'or' && lowerMatch !== 'with') {
|
||||
return licenseWithMDLinks(match);
|
||||
} else {
|
||||
return match;
|
||||
}
|
||||
});
|
||||
const mdText = renderLicensePage(filteredPackages, packageJson.name, packageJson.version);
|
||||
const outputPath = path.resolve(options.outDir || workingDir);
|
||||
const outputFile = path.join(outputPath, `license-info-${packageJson.version}.md`);
|
||||
|
||||
filteredPackages[packageName] = pack;
|
||||
}
|
||||
fs.writeFileSync(outputFile, mdText);
|
||||
|
||||
if (!pack['repository'] && missingRepositories[basePackageName]) {
|
||||
pack['repository'] = missingRepositories[basePackageName];
|
||||
filteredPackages[packageName] = pack;
|
||||
}
|
||||
}
|
||||
|
||||
const packageJson: PackageInfo = getPackageFile(packagePath);
|
||||
|
||||
ejs.renderFile(
|
||||
templatePath,
|
||||
{
|
||||
filteredPackages,
|
||||
projVersion: packageJson.version,
|
||||
projName: packageJson.name
|
||||
},
|
||||
{},
|
||||
(ejsError: any, mdText: string) => {
|
||||
if (ejsError) {
|
||||
console.error(ejsError);
|
||||
reject(ejsError);
|
||||
} else {
|
||||
const outputPath = path.resolve(options.outDir || workingDir);
|
||||
const outputFile = path.join(outputPath, `license-info-${packageJson.version}.md`);
|
||||
|
||||
fs.writeFileSync(outputFile, mdText);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Report saved as ${outputFile}`);
|
||||
resolve(0);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
console.log(`Report saved as ${outputFile}`);
|
||||
resolve(0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
import { exit } from 'node:process';
|
||||
|
||||
/* eslint-disable */
|
||||
let log = null;
|
||||
|
||||
log = {
|
||||
@@ -33,4 +32,3 @@ log = {
|
||||
};
|
||||
|
||||
export let logger = log;
|
||||
/* eslint-enable */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -25,7 +25,12 @@ export class CheckEnv {
|
||||
_alfrescoJsApi: AlfrescoApi;
|
||||
counter = 0;
|
||||
|
||||
constructor(private host: string, private username: string, private password: string, private clientId: string = 'alfresco') {}
|
||||
constructor(
|
||||
private readonly host: string,
|
||||
private readonly username: string,
|
||||
private readonly password: string,
|
||||
private readonly clientId: string = 'alfresco'
|
||||
) {}
|
||||
|
||||
async checkEnv() {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -21,7 +21,10 @@ import { AlfrescoApi } from '@alfresco/js-api';
|
||||
|
||||
export class GovernanceCheckPlugin {
|
||||
governanceHealth: GovernanceHealth;
|
||||
constructor(private pluginInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
|
||||
constructor(
|
||||
private readonly pluginInfo: PluginInterface,
|
||||
private readonly alfrescoJsApi: AlfrescoApi
|
||||
) {
|
||||
this.governanceHealth = new GovernanceHealth(this.pluginInfo, this.alfrescoJsApi);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -15,14 +15,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import { logger } from '../logger';
|
||||
import { PluginInterface } from './plugin-model';
|
||||
import { AlfrescoApi, GsSitesApi } from '@alfresco/js-api';
|
||||
|
||||
export class GovernanceHealth {
|
||||
constructor(private pluginInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {}
|
||||
constructor(
|
||||
private readonly pluginInfo: PluginInterface,
|
||||
private readonly alfrescoJsApi: AlfrescoApi
|
||||
) {}
|
||||
|
||||
async isRecordManagementAvailable(): Promise<boolean> {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -20,7 +20,10 @@ import { logger } from '../logger';
|
||||
import { AlfrescoApi } from '@alfresco/js-api';
|
||||
|
||||
export class PluginConfiguration {
|
||||
constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {}
|
||||
constructor(
|
||||
private readonly plugInInfo: PluginInterface,
|
||||
private readonly alfrescoJsApi: AlfrescoApi
|
||||
) {}
|
||||
|
||||
async getAppConfig(url: string) {
|
||||
return this.callCustomApi(url);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
* Copyright © 2005-2026 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.
|
||||
@@ -15,8 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import { PluginInterface } from './plugin-model';
|
||||
import { logger } from '../logger';
|
||||
import { ProcessAutomationHealth } from './process-automation-health';
|
||||
@@ -26,7 +24,10 @@ import { exit } from 'node:process';
|
||||
export class ProcessAutomationCheckPlugin {
|
||||
processAutomationHealth: ProcessAutomationHealth;
|
||||
|
||||
constructor(private plugInInfo: PluginInterface, private alfrescoJsApi: AlfrescoApi) {
|
||||
constructor(
|
||||
private readonly plugInInfo: PluginInterface,
|
||||
private readonly alfrescoJsApi: AlfrescoApi
|
||||
) {
|
||||
this.processAutomationHealth = new ProcessAutomationHealth(this.plugInInfo, this.alfrescoJsApi);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user