mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-16 18:13:06 +00:00
Compare commits
45
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fdc76b48f | ||
|
|
4edd377cd3 | ||
|
|
eda59a1de8 | ||
|
|
6d5cda887d | ||
|
|
3009fa6dec | ||
|
|
441a6aab19 | ||
|
|
47c1f92ed5 | ||
|
|
402725d179 | ||
|
|
8cfc8d32f2 | ||
|
|
cdc7553915 | ||
|
|
7a568baf72 | ||
|
|
f8a75d4af7 | ||
|
|
31c2cb2162 | ||
|
|
2c4764f89e | ||
|
|
e2693f9304 | ||
|
|
5d9acaec0d | ||
|
|
0c7bf62097 | ||
|
|
84116ad2bf | ||
|
|
cd6c41305a | ||
|
|
0c147513cc | ||
|
|
ac14541c2e | ||
|
|
920b7d3585 | ||
|
|
643b5f723a | ||
|
|
a6ab5fcbdd | ||
|
|
35970b4278 | ||
|
|
6f8762f46e | ||
|
|
379fbbb508 | ||
|
|
342f165b41 | ||
|
|
ecba77dfa9 | ||
|
|
a5b55c5861 | ||
|
|
2347ca68c4 | ||
|
|
cdb65bf204 | ||
|
|
8cb7a1719f | ||
|
|
1971980216 | ||
|
|
467a19f3ec | ||
|
|
d1e48f9c33 | ||
|
|
79163cbae0 | ||
|
|
5bbb5c5716 | ||
|
|
0018cd7f8f | ||
|
|
06921783bf | ||
|
|
1462560e6e | ||
|
|
ecbfae5648 | ||
|
|
413fce8cb7 | ||
|
|
f2fa458fe5 | ||
|
|
e37ef279e4 |
@@ -1 +0,0 @@
|
||||
dist
|
||||
@@ -1,21 +0,0 @@
|
||||
name: "print affected libs"
|
||||
description: "Retrive the affected libs based on the based and head input"
|
||||
inputs:
|
||||
base:
|
||||
description: 'the base sha'
|
||||
required: true
|
||||
type: string
|
||||
default: main
|
||||
head:
|
||||
description: 'the head sha'
|
||||
required: true
|
||||
type: string
|
||||
default: HEAD
|
||||
output:
|
||||
affected:
|
||||
description: 'the affected libs of the repo'
|
||||
affected_is_empty:
|
||||
description: 'true or false accondingly'
|
||||
runs:
|
||||
using: "node16"
|
||||
main: 'dist/index.js'
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-521
@@ -1,521 +0,0 @@
|
||||
{
|
||||
"name": "print-affected-libs",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "print-affected-libs",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.36.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/exec": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
|
||||
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
|
||||
"dependencies": {
|
||||
"@actions/io": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/github": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.0.tgz",
|
||||
"integrity": "sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.2.0",
|
||||
"@octokit/core": "^5.0.1",
|
||||
"@octokit/plugin-paginate-rest": "^9.0.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/http-client": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
|
||||
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6",
|
||||
"undici": "^5.25.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/io": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
|
||||
},
|
||||
"node_modules/@fastify/busboy": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
|
||||
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
|
||||
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz",
|
||||
"integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/graphql": "^7.1.0",
|
||||
"@octokit/request": "^8.3.1",
|
||||
"@octokit/request-error": "^5.1.0",
|
||||
"@octokit/types": "^13.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "9.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
|
||||
"integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.1.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz",
|
||||
"integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/request": "^8.3.0",
|
||||
"@octokit/types": "^13.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz",
|
||||
"integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^12.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": "5"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "10.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz",
|
||||
"integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^12.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": "5"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.0.tgz",
|
||||
"integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^9.0.1",
|
||||
"@octokit/request-error": "^5.1.0",
|
||||
"@octokit/types": "^13.1.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz",
|
||||
"integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.1.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/ncc": {
|
||||
"version": "0.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.36.1.tgz",
|
||||
"integrity": "sha512-S4cL7Taa9yb5qbv+6wLgiKVZ03Qfkc4jGRuiUQMQ8HGBD5pcNRnHeYM33zBvJE4/zJGjJJ8GScB+WmTsn9mORw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"ncc": "dist/ncc/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||
"engines": {
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "5.29.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
|
||||
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
|
||||
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
|
||||
"requires": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"@actions/exec": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
|
||||
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
|
||||
"requires": {
|
||||
"@actions/io": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"@actions/github": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.0.tgz",
|
||||
"integrity": "sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==",
|
||||
"requires": {
|
||||
"@actions/http-client": "^2.2.0",
|
||||
"@octokit/core": "^5.0.1",
|
||||
"@octokit/plugin-paginate-rest": "^9.0.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^10.0.0"
|
||||
}
|
||||
},
|
||||
"@actions/http-client": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
|
||||
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
|
||||
"requires": {
|
||||
"tunnel": "^0.0.6",
|
||||
"undici": "^5.25.4"
|
||||
}
|
||||
},
|
||||
"@actions/io": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
|
||||
},
|
||||
"@fastify/busboy": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
|
||||
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="
|
||||
},
|
||||
"@octokit/auth-token": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
|
||||
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="
|
||||
},
|
||||
"@octokit/core": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz",
|
||||
"integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==",
|
||||
"requires": {
|
||||
"@octokit/auth-token": "^4.0.0",
|
||||
"@octokit/graphql": "^7.1.0",
|
||||
"@octokit/request": "^8.3.1",
|
||||
"@octokit/request-error": "^5.1.0",
|
||||
"@octokit/types": "^13.0.0",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/endpoint": {
|
||||
"version": "9.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
|
||||
"integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==",
|
||||
"requires": {
|
||||
"@octokit/types": "^13.1.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/graphql": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz",
|
||||
"integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==",
|
||||
"requires": {
|
||||
"@octokit/request": "^8.3.0",
|
||||
"@octokit/types": "^13.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g=="
|
||||
},
|
||||
"@octokit/plugin-paginate-rest": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz",
|
||||
"integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==",
|
||||
"requires": {
|
||||
"@octokit/types": "^12.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/plugin-rest-endpoint-methods": {
|
||||
"version": "10.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz",
|
||||
"integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==",
|
||||
"requires": {
|
||||
"@octokit/types": "^12.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
|
||||
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "12.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
|
||||
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^20.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@octokit/request": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.0.tgz",
|
||||
"integrity": "sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==",
|
||||
"requires": {
|
||||
"@octokit/endpoint": "^9.0.1",
|
||||
"@octokit/request-error": "^5.1.0",
|
||||
"@octokit/types": "^13.1.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"@octokit/request-error": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz",
|
||||
"integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==",
|
||||
"requires": {
|
||||
"@octokit/types": "^13.1.0",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
|
||||
"requires": {
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"@vercel/ncc": {
|
||||
"version": "0.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.36.1.tgz",
|
||||
"integrity": "sha512-S4cL7Taa9yb5qbv+6wLgiKVZ03Qfkc4jGRuiUQMQ8HGBD5pcNRnHeYM33zBvJE4/zJGjJJ8GScB+WmTsn9mORw==",
|
||||
"dev": true
|
||||
},
|
||||
"before-after-hook": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
|
||||
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
|
||||
},
|
||||
"deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||
},
|
||||
"undici": {
|
||||
"version": "5.29.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
|
||||
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
|
||||
"requires": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"universal-user-agent": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
|
||||
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"name": "print-affected-libs",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "ncc build src/index.js -o dist --source-map"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/github": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.36.1"
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
const core = require('@actions/core');
|
||||
const exec = require('@actions/exec');
|
||||
|
||||
async function run() {
|
||||
const base = core.getInput('base', {required: false }) || '5288597580';
|
||||
core.setOutput('affected_is_empty', 'true');
|
||||
|
||||
let affected = '';
|
||||
let myError = '';
|
||||
|
||||
const options = {};
|
||||
options.listeners = {
|
||||
stdout: (data) => {
|
||||
affected += data.toString()
|
||||
},
|
||||
stderr: (data) => {
|
||||
myError += data.toString();
|
||||
}
|
||||
};
|
||||
|
||||
await exec.exec(`npx nx print-affected --target=build --select=tasks.target.project --base=${base} --head=${head}`, [], options)
|
||||
|
||||
const affectedTrimmed = affected.trim();
|
||||
if (affectedTrimmed !== '') {
|
||||
core.setOutput('affected_is_empty', 'false');
|
||||
}
|
||||
core.notice(`Retriving affected libs: ${affectedTrimmed}`);
|
||||
|
||||
core.setOutput('affected', affectedTrimmed);
|
||||
}
|
||||
|
||||
run();
|
||||
@@ -26,7 +26,7 @@ runs:
|
||||
cache-dependency-path: package-lock.json
|
||||
- name: get latest tag sha
|
||||
id: tag-sha
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/git-latest-tag@95f68dc050fba62b3331d9b47bc659526cdfb343 # v8.21.1
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/git-latest-tag@c2278c8ec6744d3595478217e9736ebb47d501db # v8.23.3
|
||||
# CACHE
|
||||
- name: Node Modules cache
|
||||
id: node-modules-cache
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
name: Identify the slack group
|
||||
description: 'Identify the slack group area based on the affected'
|
||||
|
||||
inputs:
|
||||
affected:
|
||||
description: 'The name of the affected lib'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
outputs:
|
||||
groups:
|
||||
description: "the slack groups"
|
||||
value: ${{ steps.group.outputs.result }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
|
||||
steps:
|
||||
- name: Append group
|
||||
id: group
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
env:
|
||||
affectedLib: ${{ inputs.affected }}
|
||||
with:
|
||||
script: |
|
||||
const affectedLib = process.env.affectedLib;
|
||||
core.info(`Input ${affectedLib}`);
|
||||
|
||||
const slackGroups = new Set();
|
||||
const AlfrescoQAGroup = '@alfresco-testing-qa';
|
||||
const HxpQAGroup = '@hxp-studio-qa-group';
|
||||
|
||||
const libs = affectedLib.split(' ')
|
||||
|
||||
if (libs.includes('content-services') || libs.includes('process-services')) {
|
||||
slackGroups.add(AlfrescoQAGroup);
|
||||
}
|
||||
if (libs.includes('process-services-cloud')) {
|
||||
slackGroups.add(HxpQAGroup);
|
||||
}
|
||||
if (libs.includes('core')) {
|
||||
slackGroups.add(AlfrescoQAGroup);
|
||||
slackGroups.add(HxpQAGroup);
|
||||
}
|
||||
|
||||
const result = Array.from(slackGroups.values()).join(' ');
|
||||
core.info(`Result ${result}`);
|
||||
return result;
|
||||
|
||||
@@ -50,10 +50,6 @@ updates:
|
||||
directory: "/.github/actions/npm-check-bundle"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/print-affected-libs"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/set-npm-tag"
|
||||
schedule:
|
||||
@@ -62,10 +58,6 @@ updates:
|
||||
directory: "/.github/actions/setup"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/slack-group-area"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/.github/actions/upload-node-modules-and-artifacts"
|
||||
schedule:
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||
# 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@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||
|
||||
# ℹ️ 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@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
||||
uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Pull translations from Crowdin
|
||||
uses: crowdin/github-action@b8012bd5491b8aa8578b73ab5b5f5e7c94aaa6e2 # v2.7.0
|
||||
uses: crowdin/github-action@f214c8723025f41fc55b2ad26e67b60b80b1885d # v2.7.1
|
||||
with:
|
||||
upload_sources: false
|
||||
download_translations: true
|
||||
|
||||
@@ -84,10 +84,10 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get branch name
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@95f68dc050fba62b3331d9b47bc659526cdfb343 # v8.21.1
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/get-branch-name@c2278c8ec6744d3595478217e9736ebb47d501db # v8.23.3
|
||||
|
||||
- name: Save commit message
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/get-commit-message@95f68dc050fba62b3331d9b47bc659526cdfb343 # v8.21.1
|
||||
uses: Alfresco/alfresco-build-tools/.github/actions/get-commit-message@c2278c8ec6744d3595478217e9736ebb47d501db # v8.23.3
|
||||
|
||||
- name: ci:force flag parser
|
||||
shell: bash
|
||||
@@ -270,27 +270,10 @@ jobs:
|
||||
name: Final Results
|
||||
needs: [check-if-pr-is-approved, pre-checks, setup, unit-tests, lint, build-libs]
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: identify-slack-group
|
||||
id: groups
|
||||
if: ${{ github.event_name == 'schedule' }}
|
||||
uses: ./.github/actions/slack-group-area
|
||||
with:
|
||||
affected: ${{ steps.e2e-result.outputs.result }}
|
||||
- uses: slackapi/slack-github-action@b0fa283ad8fea605de13dc3f449259339835fc52 # v2.1.0
|
||||
name: Nofify QA failure
|
||||
if: ${{ github.event_name == 'schedule' && contains(needs.*.result, 'failure') }}
|
||||
env:
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
channel-id: 'C016SMNNL8L' #guild-channel
|
||||
slack-message: "🔴 Warning: The daily ADF cronjob failed\nWorkflow run : <https://github.com/Alfresco/alfresco-ng2-components/actions/runs/${{ github.run_id }}| here>\nDetails: ${{ steps.e2e-result.outputs.result }}\nArea: ${{ steps.groups.outputs.groups}}"
|
||||
- name: workflow failure
|
||||
- name: Check job execution status
|
||||
if: >-
|
||||
${{
|
||||
contains(needs.*.result, 'failure')
|
||||
|| contains(needs.*.result, 'cancelled')
|
||||
}}
|
||||
run: exit 1
|
||||
if: ${{ contains(needs.*.result, 'failure') }}
|
||||
- name: workflow canceled
|
||||
run: exit 1
|
||||
if: ${{ contains(needs.*.result, 'cancelled') }}
|
||||
- name: workflow success
|
||||
run: exit 0
|
||||
if: ${{ contains(needs.*.result, 'success') }}
|
||||
|
||||
@@ -215,7 +215,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Push Source Files to Crowdin
|
||||
uses: crowdin/github-action@b8012bd5491b8aa8578b73ab5b5f5e7c94aaa6e2 # v2.7.0
|
||||
uses: crowdin/github-action@f214c8723025f41fc55b2ad26e67b60b80b1885d # v2.7.1
|
||||
with:
|
||||
upload_sources: true
|
||||
upload_sources_args: --delete-obsolete
|
||||
@@ -228,12 +228,10 @@ jobs:
|
||||
name: Final Results
|
||||
needs: [release-storybook, release-npm, npm-check-bundle]
|
||||
steps:
|
||||
|
||||
- uses: slackapi/slack-github-action@b0fa283ad8fea605de13dc3f449259339835fc52 # v2.1.0
|
||||
name: Nofify FE eng-guild-front-end workflow failed
|
||||
if: ${{ contains(toJson(needs.*.result), 'failure') }}
|
||||
env:
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
channel-id: 'C016SMNNL8L' #eng-guild-front-end
|
||||
slack-message: "🔴 Warning: The release workflow of alfresco-ng2-components pipe failed\n Author username: ${{ github.event.pull_request.user.login }}\n Workflow run <https://github.com/Alfresco/alfresco-ng2-components/actions/runs/${{ github.run_id }}| here>\n>"
|
||||
- name: Check job execution status
|
||||
if: >-
|
||||
${{
|
||||
contains(needs.*.result, 'failure')
|
||||
|| contains(needs.*.result, 'cancelled')
|
||||
}}
|
||||
run: exit 1
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
# Migrating from Angular 17 to Angular 18
|
||||
|
||||
This guide describes how to migrate ADF from Angular version 17 to version 18. Follow these steps to ensure a smooth transition.
|
||||
|
||||
## 1. Update changed dependencies
|
||||
|
||||
Update the following packages in your `package.json`:
|
||||
|
||||
### dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"@angular/animations": "18.2.13",
|
||||
"@angular/cdk": "18.2.14",
|
||||
"@angular/common": "18.2.13",
|
||||
"@angular/compiler": "18.2.13",
|
||||
"@angular/core": "18.2.13",
|
||||
"@angular/forms": "18.2.13",
|
||||
"@angular/material": "18.2.14",
|
||||
"@angular/material-date-fns-adapter": "18.2.14",
|
||||
"@angular/platform-browser": "18.2.13",
|
||||
"@angular/platform-browser-dynamic": "18.2.13",
|
||||
"@angular/router": "18.2.13",
|
||||
"@apollo/client": "3.13.1",
|
||||
"@mat-datetimepicker/core": "14.0.0",
|
||||
"apollo-angular": "10.0.3",
|
||||
"minimatch-browser": "1.0.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"zone.js": "0.14.10"
|
||||
}
|
||||
```
|
||||
|
||||
### devDependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"@angular-devkit/architect": "0.1802.13",
|
||||
"@angular-devkit/build-angular": "18.2.14",
|
||||
"@angular-devkit/core": "18.2.13",
|
||||
"@angular-devkit/schematics": "18.2.13",
|
||||
"@angular/compiler-cli": "18.2.13",
|
||||
"@nx/angular": "19.2.0",
|
||||
"@nx/js": "18.3.5",
|
||||
"@nx/workspace": "18.3.5",
|
||||
"@storybook/angular": "8.4.7",
|
||||
"ng-packagr": "18.2.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "8.4.41",
|
||||
"postcss-sass": "^0.5.0",
|
||||
"tsconfig-paths": "^4.1.1",
|
||||
"typescript": "5.5.4",
|
||||
"webpack-cli": "^5.1.4"
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Material mixins update
|
||||
|
||||
Angular Material 18 introduced Material 3 mixins as new default. As we are still using Material 2, we need to ensure that we are still using the Material 2 version.
|
||||
|
||||
In order to use Material 2 mixins, you need to add a `m2-` prefix to the mixins in your stylesheets. For example:
|
||||
|
||||
```scss
|
||||
mat.define-typography-config()
|
||||
mat.get-color-from-palette()
|
||||
```
|
||||
|
||||
should be changed to:
|
||||
|
||||
```scss
|
||||
mat.m2-define-typography-config()
|
||||
mat.m2-get-color-from-palette()
|
||||
```
|
||||
|
||||
## 3. Fixing CI/CD issues
|
||||
|
||||
After running the migration script, you may need to manually fix some issues. Run common build targets to identify any problems.
|
||||
|
||||
```bash
|
||||
npx nx run-many --target=build --skip-nx-cache
|
||||
```
|
||||
|
||||
If blocked by linting issues, disable the linting rules in the affected files. You can re-enable them in the next step.
|
||||
|
||||
### Lint jobs
|
||||
|
||||
After getting the build to work, run the lint jobs. Re-enable previously disabled linting rules and fix any issues that arise.
|
||||
|
||||
```bash
|
||||
npx nx run-many --target=lint --skip-nx-cache
|
||||
```
|
||||
|
||||
### Unit tests
|
||||
|
||||
Run the unit tests and fix any problems that arise.
|
||||
|
||||
```bash
|
||||
npx nx run-many --target=test --skip-nx-cache
|
||||
```
|
||||
|
||||
## 4. Review Angular 18 breaking changes
|
||||
|
||||
Angular 18 is a minor update with no major breaking changes for most projects. However, always review the [Angular 18 changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) and [official update guide](https://angular.dev/update-guide?v=17.0-18.0).
|
||||
@@ -245,16 +245,17 @@ The Viewer supports dynamically-loaded viewer preview extensions, to know more a
|
||||
|
||||
You can define your own custom handler to override supported file formats or handle other file formats that are not yet supported by
|
||||
the component. Below is an example that shows how to use the `adf-viewer-extension`
|
||||
to handle 3D data files:
|
||||
to handle 3D data files. `contentLoaded` should be an `EventEmitter` that will emit as soon as the component responsible for rendering finishes.
|
||||
|
||||
```html
|
||||
<adf-alfresco-viewer [nodeId]="nodeId">
|
||||
<ng-template #viewerExtensions>
|
||||
<adf-viewer-extension [supportedExtensions]="['obj','3ds']" #extension>
|
||||
<ng-template let-urlFileContent="urlFileContent" let-extension="extension">
|
||||
<ng-template let-urlFileContent="urlFileContent" let-extension="extension" let-markAsLoaded="markAsLoaded">
|
||||
<threed-viewer
|
||||
[urlFile]="urlFileContent"
|
||||
[extension]="extension">
|
||||
[extension]="extension"
|
||||
(contentLoaded)="markAsLoaded()">
|
||||
</threed-viewer>
|
||||
</ng-template>
|
||||
</adf-viewer-extension>
|
||||
@@ -270,17 +271,19 @@ You need to keep all instances of `adf-viewer-extension` inside `viewerExtension
|
||||
<adf-alfresco-viewer [nodeId]="nodeId">
|
||||
<ng-template #viewerExtensions>
|
||||
<adf-viewer-extension [supportedExtensions]="['xls','xlsx']" #extension>
|
||||
<ng-template let-urlFileContent="urlFileContent">
|
||||
<ng-template let-urlFileContent="urlFileContent" let-markAsLoaded="markAsLoaded">
|
||||
<my-custom-xls-component
|
||||
urlFileContent="urlFileContent">
|
||||
urlFileContent="urlFileContent"
|
||||
(contentLoaded)="markAsLoaded()">
|
||||
</my-custom-xls-component>
|
||||
</ng-template>
|
||||
</adf-viewer-extension>
|
||||
|
||||
<adf-viewer-extension [supportedExtensions]="['txt']" #extension>
|
||||
<ng-template let-urlFileContent="urlFileContent" >
|
||||
<ng-template let-urlFileContent="urlFileContent" let-markAsLoaded="markAsLoaded">
|
||||
<my-custom-txt-component
|
||||
urlFileContent="urlFileContent">
|
||||
urlFileContent="urlFileContent"
|
||||
(contentLoaded)="markAsLoaded()">
|
||||
</my-custom-txt-component>
|
||||
</ng-template>
|
||||
</adf-viewer-extension>
|
||||
|
||||
@@ -206,22 +206,24 @@ The Viewer supports dynamically-loaded viewer preview extensions, to know more a
|
||||
#### Code extension mechanism
|
||||
|
||||
You can define your own custom handler to override supported file formats or handle other file formats that are not yet supported by
|
||||
the [Viewer render component](viewer.component.md). In order to do that first you need to define a template containing at least one `adf-viewer-extension`:
|
||||
the [Viewer render component](viewer.component.md). In order to do that first you need to define a template containing at least one `adf-viewer-extension`. `contentLoaded` should be an `EventEmitter` that will emit as soon as the component responsible for rendering finishes.
|
||||
|
||||
```html
|
||||
<ng-template #viewerExtensions>
|
||||
<adf-viewer-extension [supportedExtensions]="['xls','xlsx']" #extension>
|
||||
<ng-template let-urlFileContent="urlFileContent">
|
||||
<ng-template let-urlFileContent="urlFileContent" let-markAsLoaded="markAsLoaded">
|
||||
<my-custom-xls-component
|
||||
urlFileContent="urlFileContent">
|
||||
urlFileContent="urlFileContent"
|
||||
(contentLoaded)="markAsLoaded()">
|
||||
</my-custom-xls-component>
|
||||
</ng-template>
|
||||
</adf-viewer-extension>
|
||||
|
||||
<adf-viewer-render-extension [supportedExtensions]="['txt']" #extension>
|
||||
<ng-template let-urlFileContent="urlFileContent" >
|
||||
<ng-template let-urlFileContent="urlFileContent" let-markAsLoaded="markAsLoaded">
|
||||
<my-custom-txt-component
|
||||
urlFileContent="urlFileContent">
|
||||
urlFileContent="urlFileContent"
|
||||
(contentLoaded)="markAsLoaded()">
|
||||
</my-custom-txt-component>
|
||||
</ng-template>
|
||||
</adf-viewer-render-extension>
|
||||
|
||||
@@ -215,16 +215,17 @@ The Viewer supports dynamically-loaded viewer preview extensions, to know more a
|
||||
|
||||
You can define your own custom handler to override supported file formats or handle other file formats that are not yet supported by
|
||||
the [Viewer component](viewer.component.md). Below is an example that shows how to use the `adf-viewer-extension`
|
||||
to handle 3D data files:
|
||||
to handle 3D data files. `contentLoaded` should be an `EventEmitter` that will emit as soon as the component responsible for rendering finishes.
|
||||
|
||||
```html
|
||||
<adf-viewer [urlFile]="urlFile">
|
||||
<ng-template #viewerExtensions>
|
||||
<adf-viewer-extension [supportedExtensions]="['obj','3ds']" #extension>
|
||||
<ng-template let-urlFileContent="urlFileContent" let-extension="extension">
|
||||
<ng-template let-urlFileContent="urlFileContent" let-extension="extension" let-markAsLoaded="markAsLoaded">
|
||||
<threed-viewer
|
||||
[urlFile]="urlFileContent"
|
||||
[extension]="extension">
|
||||
[extension]="extension"
|
||||
(contentLoaded)="markAsLoaded()">
|
||||
</threed-viewer>
|
||||
</ng-template>
|
||||
</adf-viewer-extension>
|
||||
@@ -239,17 +240,19 @@ You need to keep all instances of `adf-viewer-extension` inside `viewerExtension
|
||||
<adf-viewer [urlFile]="urlFile">
|
||||
<ng-template #viewerExtensions>
|
||||
<adf-viewer-extension [supportedExtensions]="['xls','xlsx']" #extension>
|
||||
<ng-template let-urlFileContent="urlFileContent">
|
||||
<ng-template let-urlFileContent="urlFileContent" let-markAsLoaded="markAsLoaded">
|
||||
<my-custom-xls-component
|
||||
urlFileContent="urlFileContent">
|
||||
urlFileContent="urlFileContent"
|
||||
(contentLoaded)="markAsLoaded()">
|
||||
</my-custom-xls-component>
|
||||
</ng-template>
|
||||
</adf-viewer-extension>
|
||||
|
||||
<adf-viewer-extension [supportedExtensions]="['txt']" #extension>
|
||||
<ng-template let-urlFileContent="urlFileContent" >
|
||||
<ng-template let-urlFileContent="urlFileContent" let-markAsLoaded="markAsLoaded" >
|
||||
<my-custom-txt-component
|
||||
urlFileContent="urlFileContent">
|
||||
urlFileContent="urlFileContent"
|
||||
(contentLoaded)="markAsLoaded()">
|
||||
</my-custom-txt-component>
|
||||
</ng-template>
|
||||
</adf-viewer-extension>
|
||||
|
||||
Binary file not shown.
@@ -25,7 +25,7 @@
|
||||
"ejs": "^3.1.9",
|
||||
"license-checker": "^25.0.1",
|
||||
"node-fetch": "^2.7.0",
|
||||
"rxjs": "^6.6.6",
|
||||
"rxjs": "7.8.2",
|
||||
"shelljs": "^0.8.3",
|
||||
"spdx-license-list": "^5.0.0"
|
||||
},
|
||||
|
||||
@@ -19,6 +19,7 @@ import { AlfrescoApiConfig } from '@alfresco/js-api';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AppConfigService, AppConfigValues, StorageService } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService } from '../services/alfresco-api.service';
|
||||
import { SecurityOptionsLoaderService } from '../security-options-loader/security-options-loader.service';
|
||||
|
||||
/**
|
||||
* Create a factory to resolve an api service instance
|
||||
@@ -37,11 +38,12 @@ export class AlfrescoApiLoaderService {
|
||||
constructor(
|
||||
private readonly appConfig: AppConfigService,
|
||||
private readonly apiService: AlfrescoApiService,
|
||||
private readonly securityOptionsLoaderService: SecurityOptionsLoaderService,
|
||||
private storageService: StorageService
|
||||
) {}
|
||||
|
||||
async init(): Promise<any> {
|
||||
await this.appConfig.load();
|
||||
await this.appConfig.load(this.securityOptionsLoaderService.load);
|
||||
return this.initAngularAlfrescoApi();
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ describe('DownloadZipDialogComponent', () => {
|
||||
spyOn(downloadZipService, 'createDownload').and.callFake(
|
||||
() =>
|
||||
new Observable((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -112,7 +112,7 @@ describe('DownloadZipDialogComponent', () => {
|
||||
const createDownloadSpy = spyOn(downloadZipService, 'createDownload').and.callFake(
|
||||
() =>
|
||||
new Observable((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -125,7 +125,7 @@ describe('DownloadZipDialogComponent', () => {
|
||||
spyOn(downloadZipService, 'createDownload').and.callFake(
|
||||
() =>
|
||||
new Observable((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -140,7 +140,7 @@ describe('DownloadZipDialogComponent', () => {
|
||||
spyOn(downloadZipService, 'createDownload').and.callFake(
|
||||
() =>
|
||||
new Observable((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
|
||||
+15
@@ -92,4 +92,19 @@ describe('LibraryRoleColumnComponent', () => {
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.ROLE.NONE');
|
||||
});
|
||||
|
||||
it('should take role from obj when node entry role is not provided', () => {
|
||||
component.context = {
|
||||
row: {
|
||||
node: { entry: {} },
|
||||
obj: { role: 'SiteManager' }
|
||||
}
|
||||
};
|
||||
|
||||
let value = '';
|
||||
component.displayText$.subscribe((val) => (value = val));
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.ROLE.MANAGER');
|
||||
});
|
||||
});
|
||||
|
||||
+18
-21
@@ -17,7 +17,7 @@
|
||||
|
||||
import { ChangeDetectionStrategy, Component, DestroyRef, inject, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { Site, SiteEntry } from '@alfresco/js-api';
|
||||
import { Site } from '@alfresco/js-api';
|
||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
@@ -64,26 +64,23 @@ export class LibraryRoleColumnComponent implements OnInit {
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
const node: SiteEntry = this.context.row.node;
|
||||
if (node?.entry) {
|
||||
const role: string = node.entry.role;
|
||||
switch (role) {
|
||||
case Site.RoleEnum.SiteManager:
|
||||
this.displayText$.next('LIBRARY.ROLE.MANAGER');
|
||||
break;
|
||||
case Site.RoleEnum.SiteCollaborator:
|
||||
this.displayText$.next('LIBRARY.ROLE.COLLABORATOR');
|
||||
break;
|
||||
case Site.RoleEnum.SiteContributor:
|
||||
this.displayText$.next('LIBRARY.ROLE.CONTRIBUTOR');
|
||||
break;
|
||||
case Site.RoleEnum.SiteConsumer:
|
||||
this.displayText$.next('LIBRARY.ROLE.CONSUMER');
|
||||
break;
|
||||
default:
|
||||
this.displayText$.next('LIBRARY.ROLE.NONE');
|
||||
break;
|
||||
}
|
||||
const role = this.context.row.node?.entry.role ?? this.context.row.obj.role;
|
||||
switch (role) {
|
||||
case Site.RoleEnum.SiteManager:
|
||||
this.displayText$.next('LIBRARY.ROLE.MANAGER');
|
||||
break;
|
||||
case Site.RoleEnum.SiteCollaborator:
|
||||
this.displayText$.next('LIBRARY.ROLE.COLLABORATOR');
|
||||
break;
|
||||
case Site.RoleEnum.SiteContributor:
|
||||
this.displayText$.next('LIBRARY.ROLE.CONTRIBUTOR');
|
||||
break;
|
||||
case Site.RoleEnum.SiteConsumer:
|
||||
this.displayText$.next('LIBRARY.ROLE.CONSUMER');
|
||||
break;
|
||||
default:
|
||||
this.displayText$.next('LIBRARY.ROLE.NONE');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+48
-3
@@ -16,9 +16,54 @@
|
||||
*/
|
||||
|
||||
import { LibraryStatusColumnComponent } from './library-status-column.component';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ContentTestingModule } from '../../../testing/content.testing.module';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { Site } from '@alfresco/js-api';
|
||||
|
||||
describe('LibraryStatusColumnComponent', () => {
|
||||
it('should be defined', () => {
|
||||
expect(LibraryStatusColumnComponent).toBeDefined();
|
||||
});
|
||||
let fixture: ComponentFixture<LibraryStatusColumnComponent>;
|
||||
let component: LibraryStatusColumnComponent;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ContentTestingModule, LibraryStatusColumnComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
});
|
||||
fixture = TestBed.createComponent(LibraryStatusColumnComponent);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(LibraryStatusColumnComponent).toBeDefined();
|
||||
});
|
||||
|
||||
it('should take default visibility from node entry', () => {
|
||||
component.context = {
|
||||
row: {
|
||||
node: { entry: { visibility: Site.VisibilityEnum.PUBLIC } }
|
||||
}
|
||||
};
|
||||
|
||||
let value = '';
|
||||
component.displayText$.subscribe((val) => (value = val));
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.VISIBILITY.PUBLIC');
|
||||
});
|
||||
|
||||
it('should take visibility from obj when node entry visibility is not provided', () => {
|
||||
component.context = {
|
||||
row: {
|
||||
node: { entry: {} },
|
||||
obj: { visibility: Site.VisibilityEnum.PUBLIC }
|
||||
}
|
||||
};
|
||||
|
||||
let value = '';
|
||||
component.displayText$.subscribe((val) => (value = val));
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(value).toBe('LIBRARY.VISIBILITY.PUBLIC');
|
||||
});
|
||||
});
|
||||
|
||||
+15
-18
@@ -18,7 +18,7 @@
|
||||
import { Component, DestroyRef, inject, Input, OnInit } from '@angular/core';
|
||||
import { NodesApiService } from '../../../common/services/nodes-api.service';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { Site, SiteEntry } from '@alfresco/js-api';
|
||||
import { Site } from '@alfresco/js-api';
|
||||
import { ShareDataRow } from '../../data/share-data-row.model';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
@@ -62,24 +62,21 @@ export class LibraryStatusColumnComponent implements OnInit {
|
||||
}
|
||||
|
||||
protected updateValue() {
|
||||
const node: SiteEntry = this.context.row.node;
|
||||
if (node?.entry) {
|
||||
const visibility: string = node.entry.visibility;
|
||||
const visibility = this.context.row.node?.entry.visibility ?? this.context.row.obj.visibility;
|
||||
|
||||
switch (visibility) {
|
||||
case Site.VisibilityEnum.PUBLIC:
|
||||
this.displayText$.next('LIBRARY.VISIBILITY.PUBLIC');
|
||||
break;
|
||||
case Site.VisibilityEnum.PRIVATE:
|
||||
this.displayText$.next('LIBRARY.VISIBILITY.PRIVATE');
|
||||
break;
|
||||
case Site.VisibilityEnum.MODERATED:
|
||||
this.displayText$.next('LIBRARY.VISIBILITY.MODERATED');
|
||||
break;
|
||||
default:
|
||||
this.displayText$.next('UNKNOWN');
|
||||
break;
|
||||
}
|
||||
switch (visibility) {
|
||||
case Site.VisibilityEnum.PUBLIC:
|
||||
this.displayText$.next('LIBRARY.VISIBILITY.PUBLIC');
|
||||
break;
|
||||
case Site.VisibilityEnum.PRIVATE:
|
||||
this.displayText$.next('LIBRARY.VISIBILITY.PRIVATE');
|
||||
break;
|
||||
case Site.VisibilityEnum.MODERATED:
|
||||
this.displayText$.next('LIBRARY.VISIBILITY.MODERATED');
|
||||
break;
|
||||
default:
|
||||
this.displayText$.next('UNKNOWN');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ describe('FolderActionsService', () => {
|
||||
spyOn(documentListService, 'deleteNode').and.callFake(
|
||||
() =>
|
||||
new Observable<any>((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -115,7 +115,7 @@ describe('FolderActionsService', () => {
|
||||
spyOn(documentListService, 'deleteNode').and.callFake(
|
||||
() =>
|
||||
new Observable<any>((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -136,7 +136,7 @@ describe('FolderActionsService', () => {
|
||||
spyOn(documentListService, 'deleteNode').and.callFake(
|
||||
() =>
|
||||
new Observable<any>((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -157,7 +157,7 @@ describe('FolderActionsService', () => {
|
||||
spyOn(documentListService, 'deleteNode').and.callFake(
|
||||
() =>
|
||||
new Observable<any>((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -175,7 +175,7 @@ describe('FolderActionsService', () => {
|
||||
spyOn(documentListService, 'deleteNode').and.callFake(
|
||||
() =>
|
||||
new Observable<any>((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -196,7 +196,7 @@ describe('FolderActionsService', () => {
|
||||
spyOn(documentListService, 'deleteNode').and.callFake(
|
||||
() =>
|
||||
new Observable<any>((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -212,7 +212,7 @@ describe('FolderActionsService', () => {
|
||||
spyOn(documentListService, 'deleteNode').and.callFake(
|
||||
() =>
|
||||
new Observable<any>((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -236,7 +236,7 @@ describe('FolderActionsService', () => {
|
||||
spyOn(documentListService, 'deleteNode').and.callFake(
|
||||
() =>
|
||||
new Observable<any>((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
|
||||
@@ -69,6 +69,7 @@ export abstract class InfiniteScrollDatasource<T> extends DataSource<T> {
|
||||
|
||||
reset(): void {
|
||||
this.isLoading$.next(true);
|
||||
this.dataStream.next([]);
|
||||
this.getNextBatch({ skipCount: 0, maxItems: this.batchSize })
|
||||
.pipe(take(1))
|
||||
.subscribe((firstBatch) => {
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { SecurityOptionsLoaderService } from './security-options-loader.service';
|
||||
import { AppConfigService, AppConfigValues } from '@alfresco/adf-core';
|
||||
import { AdfHttpClient } from '@alfresco/adf-core/api';
|
||||
|
||||
describe('SecurityOptionsLoaderService', () => {
|
||||
let service: SecurityOptionsLoaderService;
|
||||
let appConfigServiceSpy: jasmine.SpyObj<AppConfigService>;
|
||||
let adfHttpClientSpy: jasmine.SpyObj<AdfHttpClient>;
|
||||
|
||||
beforeEach(() => {
|
||||
appConfigServiceSpy = jasmine.createSpyObj('AppConfigService', ['get']);
|
||||
adfHttpClientSpy = jasmine.createSpyObj('AdfHttpClient', ['setDefaultSecurityOption']);
|
||||
|
||||
service = new SecurityOptionsLoaderService(appConfigServiceSpy, adfHttpClientSpy);
|
||||
});
|
||||
|
||||
it('should set withCredentials when value is true', () => {
|
||||
appConfigServiceSpy.get.and.callFake((key: string): any => {
|
||||
if (key === AppConfigValues.AUTH_WITH_CREDENTIALS) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
service.load();
|
||||
|
||||
expect(adfHttpClientSpy.setDefaultSecurityOption).toHaveBeenCalledWith({ withCredentials: true });
|
||||
});
|
||||
|
||||
it('should set withCredentials when value is false', () => {
|
||||
appConfigServiceSpy.get.and.callFake((key: string): any => {
|
||||
if (key === AppConfigValues.AUTH_WITH_CREDENTIALS) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
service.load();
|
||||
|
||||
expect(adfHttpClientSpy.setDefaultSecurityOption).toHaveBeenCalledWith({ withCredentials: false });
|
||||
});
|
||||
|
||||
it('should not call setDefaultSecurityOption when value is undefined', () => {
|
||||
appConfigServiceSpy.get.and.returnValue(undefined);
|
||||
|
||||
service.load();
|
||||
|
||||
expect(adfHttpClientSpy.setDefaultSecurityOption).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call setDefaultSecurityOption when value is null', () => {
|
||||
appConfigServiceSpy.get.and.returnValue(null);
|
||||
|
||||
service.load();
|
||||
|
||||
expect(adfHttpClientSpy.setDefaultSecurityOption).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AppConfigService, AppConfigValues } from '@alfresco/adf-core';
|
||||
import { AdfHttpClient } from '@alfresco/adf-core/api';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SecurityOptionsLoaderService {
|
||||
constructor(private appConfigService: AppConfigService, private adfHttpClient: AdfHttpClient) {}
|
||||
|
||||
load = () => {
|
||||
const withCredentials = this.appConfigService.get<boolean>(AppConfigValues.AUTH_WITH_CREDENTIALS);
|
||||
if (withCredentials !== undefined && withCredentials !== null) {
|
||||
this.adfHttpClient.setDefaultSecurityOption({ withCredentials });
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -45,7 +45,7 @@ export class AuthenticationInterceptor implements HttpInterceptor {
|
||||
if (req.context.get(SHOULD_ADD_AUTH_TOKEN)) {
|
||||
return this.authService.addTokenToHeader(req.url, req.headers).pipe(
|
||||
mergeMap((headersWithBearer) => {
|
||||
const headerWithContentType = this.appendJsonContentType(headersWithBearer);
|
||||
const headerWithContentType = this.appendJsonContentType(headersWithBearer, req.body);
|
||||
const kcReq = req.clone({ headers: headerWithContentType });
|
||||
return next.handle(kcReq).pipe(catchError((error) => observableThrowError(error)));
|
||||
})
|
||||
@@ -55,7 +55,7 @@ export class AuthenticationInterceptor implements HttpInterceptor {
|
||||
return next.handle(req).pipe(catchError((error) => observableThrowError(error)));
|
||||
}
|
||||
|
||||
private appendJsonContentType(headers: HttpHeaders): HttpHeaders {
|
||||
private appendJsonContentType(headers: HttpHeaders, reqBody: any): HttpHeaders {
|
||||
// prevent adding any content type, to properly handle formData with boundary browser generated value,
|
||||
// as adding any Content-Type its going to break the upload functionality
|
||||
|
||||
@@ -63,7 +63,7 @@ export class AuthenticationInterceptor implements HttpInterceptor {
|
||||
return headers.delete('Content-Type');
|
||||
}
|
||||
|
||||
if (!headers.get('Content-Type')) {
|
||||
if (!headers.get('Content-Type') && !(reqBody instanceof FormData)) {
|
||||
return headers.set('Content-Type', 'application/json;charset=UTF-8');
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"angular-oauth2-oidc": "17.0.2",
|
||||
"angular-oauth2-oidc-jwks": "17.0.2",
|
||||
"date-fns": "^2.30.0",
|
||||
"rxjs": "7.8.1"
|
||||
"rxjs": "7.8.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/animations": ">=16.0.0",
|
||||
|
||||
@@ -20,20 +20,30 @@ import { BasicAlfrescoAuthService } from './basic-alfresco-auth.service';
|
||||
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
||||
import { ProcessAuth } from './process-auth';
|
||||
import { ContentAuth } from './content-auth';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
describe('BasicAlfrescoAuthService', () => {
|
||||
let basicAlfrescoAuthService: BasicAlfrescoAuthService;
|
||||
let processAuth: ProcessAuth;
|
||||
let contentAuth: ContentAuth;
|
||||
let appConfig: AppConfigService;
|
||||
let appConfigSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule],
|
||||
providers: [BasicAlfrescoAuthService]
|
||||
providers: [BasicAlfrescoAuthService, provideHttpClient()]
|
||||
});
|
||||
basicAlfrescoAuthService = TestBed.inject(BasicAlfrescoAuthService);
|
||||
spyOn(TestBed.inject(ProcessAuth), 'getToken').and.returnValue('Mock Process Auth ticket');
|
||||
spyOn(TestBed.inject(ContentAuth), 'getToken').and.returnValue('Mock Content Auth ticket');
|
||||
const appConfigSpy = spyOn(TestBed.inject(AppConfigService), 'get');
|
||||
|
||||
processAuth = TestBed.inject(ProcessAuth);
|
||||
spyOn(processAuth, 'getToken').and.returnValue('Mock Process Auth ticket');
|
||||
contentAuth = TestBed.inject(ContentAuth);
|
||||
spyOn(contentAuth, 'getToken').and.returnValue('Mock Content Auth ticket');
|
||||
|
||||
appConfig = TestBed.inject(AppConfigService);
|
||||
appConfigSpy = spyOn(appConfig, 'get');
|
||||
appConfigSpy.withArgs(AppConfigValues.CONTEXTROOTBPM).and.returnValue('activiti-app');
|
||||
appConfigSpy.withArgs(AppConfigValues.CONTEXTROOTECM).and.returnValue('alfresco');
|
||||
});
|
||||
@@ -59,4 +69,159 @@ describe('BasicAlfrescoAuthService', () => {
|
||||
const ticket = basicAlfrescoAuthService.getTicketEcmBase64('http://www.example.com/activiti-app/alfresco/mock-api-url');
|
||||
expect(ticket).toEqual('Basic Mock Process Auth ticket');
|
||||
});
|
||||
|
||||
describe('login', () => {
|
||||
let contentAuthSpy: jasmine.Spy;
|
||||
let processAuthSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
contentAuthSpy = spyOn(contentAuth, 'login');
|
||||
processAuthSpy = spyOn(processAuth, 'login');
|
||||
});
|
||||
|
||||
it('should return both ECM and BPM tickets after the login', async () => {
|
||||
appConfigSpy.withArgs(AppConfigValues.PROVIDERS).and.returnValue('ALL');
|
||||
const mockContentTicket = { ticket: 'mock-content-ticket' };
|
||||
const mockProcessTicket = { ticket: 'mock-process-ticket' };
|
||||
const onLogin = firstValueFrom(basicAlfrescoAuthService.onLogin.pipe(take(1)));
|
||||
contentAuthSpy.and.returnValue(Promise.resolve(mockContentTicket));
|
||||
processAuthSpy.and.returnValue(Promise.resolve(mockProcessTicket));
|
||||
|
||||
const result = await firstValueFrom(basicAlfrescoAuthService.login('username', 'password'));
|
||||
|
||||
expect(result).toEqual({
|
||||
type: 'ALL',
|
||||
ticket: [mockContentTicket, mockProcessTicket]
|
||||
});
|
||||
expect(contentAuth.login).toHaveBeenCalledWith('username', 'password');
|
||||
expect(processAuth.login).toHaveBeenCalledWith('username', 'password');
|
||||
expect(await onLogin).toBe('success');
|
||||
});
|
||||
|
||||
it('should return login fail on ECM login failure', async () => {
|
||||
appConfigSpy.withArgs(AppConfigValues.PROVIDERS).and.returnValue('ECM');
|
||||
const mockError = 'ECM login failed';
|
||||
contentAuthSpy.and.returnValue(Promise.reject(mockError));
|
||||
|
||||
const onError = firstValueFrom(basicAlfrescoAuthService.onError.pipe(take(1)));
|
||||
|
||||
await expectAsync(firstValueFrom(basicAlfrescoAuthService.login('username', 'password'))).toBeRejectedWith(mockError);
|
||||
|
||||
expect(contentAuth.login).toHaveBeenCalledWith('username', 'password');
|
||||
expect(processAuth.login).not.toHaveBeenCalled();
|
||||
expect(await onError).toBe('ECM login failed');
|
||||
});
|
||||
|
||||
it('should return login fail on BPM login failure', async () => {
|
||||
appConfigSpy.withArgs(AppConfigValues.PROVIDERS).and.returnValue('BPM');
|
||||
const mockError = 'BPM login failed';
|
||||
processAuthSpy.and.returnValue(Promise.reject(mockError));
|
||||
|
||||
const onError = firstValueFrom(basicAlfrescoAuthService.onError.pipe(take(1)));
|
||||
|
||||
await expectAsync(firstValueFrom(basicAlfrescoAuthService.login('username', 'password'))).toBeRejectedWith(mockError);
|
||||
|
||||
expect(contentAuth.login).not.toHaveBeenCalled();
|
||||
expect(processAuth.login).toHaveBeenCalledWith('username', 'password');
|
||||
expect(await onError).toBe('BPM login failed');
|
||||
});
|
||||
});
|
||||
|
||||
it('isBpmLoggedIn should return value from processAuth', () => {
|
||||
spyOn(processAuth, 'isLoggedIn').and.returnValue(true);
|
||||
const result = basicAlfrescoAuthService.isBpmLoggedIn();
|
||||
|
||||
expect(result).toBeTrue();
|
||||
expect(processAuth.isLoggedIn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('isEcmLoggedIn should return value from contentAuth', () => {
|
||||
spyOn(contentAuth, 'isLoggedIn').and.returnValue(true);
|
||||
const result = basicAlfrescoAuthService.isEcmLoggedIn();
|
||||
|
||||
expect(result).toBeTrue();
|
||||
expect(contentAuth.isLoggedIn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('isLoggedIn', () => {
|
||||
let contentAuthSpy: jasmine.Spy;
|
||||
let processAuthSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
contentAuthSpy = spyOn(contentAuth, 'isLoggedIn');
|
||||
processAuthSpy = spyOn(processAuth, 'isLoggedIn');
|
||||
});
|
||||
|
||||
it('should default to false when no provider is set', () => {
|
||||
appConfigSpy.withArgs(AppConfigValues.AUTH_WITH_CREDENTIALS, false).and.returnValue(false);
|
||||
appConfigSpy.withArgs(AppConfigValues.PROVIDERS).and.returnValue(null);
|
||||
|
||||
const result = basicAlfrescoAuthService.isLoggedIn();
|
||||
|
||||
expect(result).toBeFalse();
|
||||
expect(contentAuth.isLoggedIn).not.toHaveBeenCalled();
|
||||
expect(processAuth.isLoggedIn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('BPM provider', () => {
|
||||
it('should return processAuth value', () => {
|
||||
appConfigSpy.withArgs(AppConfigValues.AUTH_WITH_CREDENTIALS, false).and.returnValue(true);
|
||||
appConfigSpy.withArgs(AppConfigValues.PROVIDERS).and.returnValue('BPM');
|
||||
processAuthSpy.and.returnValue(true);
|
||||
|
||||
const result = basicAlfrescoAuthService.isLoggedIn();
|
||||
|
||||
expect(result).toBeTrue();
|
||||
expect(processAuth.isLoggedIn).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ECM provider', () => {
|
||||
it('should return true when kerberos enabled', () => {
|
||||
appConfigSpy.withArgs(AppConfigValues.AUTH_WITH_CREDENTIALS, false).and.returnValue(true);
|
||||
appConfigSpy.withArgs(AppConfigValues.PROVIDERS).and.returnValue('ECM');
|
||||
|
||||
const result = basicAlfrescoAuthService.isLoggedIn();
|
||||
|
||||
expect(result).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return contentAuth value when kerberos disabled', () => {
|
||||
appConfigSpy.withArgs(AppConfigValues.AUTH_WITH_CREDENTIALS, false).and.returnValue(false);
|
||||
appConfigSpy.withArgs(AppConfigValues.PROVIDERS).and.returnValue('ECM');
|
||||
contentAuthSpy.and.returnValue(true);
|
||||
|
||||
const result = basicAlfrescoAuthService.isLoggedIn();
|
||||
|
||||
expect(result).toBeTrue();
|
||||
expect(contentAuth.isLoggedIn).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ALL provider', () => {
|
||||
it('should return true when kerberos enabled', () => {
|
||||
appConfigSpy.withArgs(AppConfigValues.AUTH_WITH_CREDENTIALS, false).and.returnValue(true);
|
||||
appConfigSpy.withArgs(AppConfigValues.PROVIDERS).and.returnValue('ALL');
|
||||
|
||||
const result = basicAlfrescoAuthService.isLoggedIn();
|
||||
|
||||
expect(result).toBeTrue();
|
||||
expect(processAuth.isLoggedIn).not.toHaveBeenCalled();
|
||||
expect(contentAuth.isLoggedIn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return true if both contentAuth or processAuth is logged in when kerberos disabled', () => {
|
||||
appConfigSpy.withArgs(AppConfigValues.AUTH_WITH_CREDENTIALS, false).and.returnValue(false);
|
||||
appConfigSpy.withArgs(AppConfigValues.PROVIDERS).and.returnValue('ALL');
|
||||
contentAuthSpy.and.returnValue(true);
|
||||
processAuthSpy.and.returnValue(true);
|
||||
|
||||
const result = basicAlfrescoAuthService.isLoggedIn();
|
||||
|
||||
expect(result).toBeTrue();
|
||||
expect(contentAuth.isLoggedIn).toHaveBeenCalled();
|
||||
expect(processAuth.isLoggedIn).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ import { OidcAuthenticationService } from './oidc-authentication.service';
|
||||
import { OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
|
||||
import { AppConfigService, AuthService } from '@alfresco/adf-core';
|
||||
import { AUTH_MODULE_CONFIG } from './auth-config';
|
||||
import { of } from 'rxjs';
|
||||
import { firstValueFrom, of, take, throwError } from 'rxjs';
|
||||
|
||||
interface MockAppConfigOAuth2 {
|
||||
oauth2: {
|
||||
@@ -28,59 +28,99 @@ interface MockAppConfigOAuth2 {
|
||||
};
|
||||
}
|
||||
|
||||
class MockAppConfigService {
|
||||
config: MockAppConfigOAuth2 = {
|
||||
const mockAppConfigService = {
|
||||
config: {
|
||||
oauth2: {
|
||||
logoutParameters: ['client_id', 'returnTo', 'response_type']
|
||||
}
|
||||
};
|
||||
} as MockAppConfigOAuth2,
|
||||
|
||||
setConfig(newConfig: { logoutParameters: Array<string> }) {
|
||||
this.config.oauth2 = newConfig;
|
||||
}
|
||||
},
|
||||
|
||||
get(key: string, defaultValue?: { logoutParameters: Array<string> }) {
|
||||
if (key === 'oauth2') {
|
||||
return this.config.oauth2;
|
||||
}
|
||||
|
||||
if (key === 'providers') {
|
||||
return 'mock-providers';
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MockOAuthService {
|
||||
clientId = 'testClientId';
|
||||
redirectUri = 'testRedirectUri';
|
||||
logOut = jasmine.createSpy();
|
||||
}
|
||||
const mockOAuthService = {
|
||||
clientId: 'testClientId',
|
||||
redirectUri: 'testRedirectUri',
|
||||
logOut: jasmine.createSpy(),
|
||||
hasValidAccessToken: jasmine.createSpy(),
|
||||
hasValidIdToken: jasmine.createSpy()
|
||||
};
|
||||
|
||||
const mockAuthService = {
|
||||
baseAuthLogin: jasmine.createSpy()
|
||||
};
|
||||
|
||||
describe('OidcAuthenticationService', () => {
|
||||
let service: OidcAuthenticationService;
|
||||
let oauthService: OAuthService;
|
||||
let appConfig: AppConfigService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
OidcAuthenticationService,
|
||||
{ provide: AppConfigService, useClass: MockAppConfigService },
|
||||
{ provide: OAuthService, useClass: MockOAuthService },
|
||||
{ provide: AppConfigService, useValue: mockAppConfigService },
|
||||
{ provide: OAuthService, useValue: mockOAuthService },
|
||||
{ provide: OAuthStorage, useValue: {} },
|
||||
{ provide: AUTH_MODULE_CONFIG, useValue: {} },
|
||||
{ provide: AuthService, useValue: {} }
|
||||
{ provide: AuthService, useValue: mockAuthService }
|
||||
]
|
||||
});
|
||||
service = TestBed.inject(OidcAuthenticationService);
|
||||
oauthService = TestBed.inject(OAuthService);
|
||||
appConfig = TestBed.inject(AppConfigService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('login', () => {
|
||||
it('should call AuthService with credentials', async () => {
|
||||
const appConfigSpy = spyOn(mockAppConfigService, 'get').and.callThrough();
|
||||
const mockTokenResponse = { access_token: 'mock-token' };
|
||||
mockAuthService.baseAuthLogin.and.returnValue(of(mockTokenResponse));
|
||||
const onLogin = firstValueFrom(service.onLogin.pipe(take(1)));
|
||||
|
||||
const response = await firstValueFrom(service.login('username', 'password'));
|
||||
|
||||
expect(mockAuthService.baseAuthLogin).toHaveBeenCalledWith('username', 'password');
|
||||
expect(await onLogin).toEqual(mockTokenResponse);
|
||||
expect(response).toEqual({
|
||||
type: 'mock-providers',
|
||||
ticket: mockTokenResponse
|
||||
});
|
||||
expect(appConfigSpy).toHaveBeenCalledWith('providers');
|
||||
});
|
||||
|
||||
it('should handle login errors', async () => {
|
||||
const mockError = 'Login failed';
|
||||
mockAuthService.baseAuthLogin.and.returnValue(throwError(() => mockError));
|
||||
const onError = firstValueFrom(service.onError.pipe(take(1)));
|
||||
|
||||
await expectAsync(firstValueFrom(service.login('username', 'password'))).toBeRejectedWith(mockError);
|
||||
expect(await onError).toEqual(mockError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('logout', () => {
|
||||
let mockAppConfigService: MockAppConfigService;
|
||||
let appConfigService: AppConfigService;
|
||||
|
||||
beforeEach(() => {
|
||||
mockAppConfigService = TestBed.inject(AppConfigService) as any;
|
||||
appConfigService = TestBed.inject(AppConfigService) as any;
|
||||
});
|
||||
|
||||
it('should handle logout with default parameters', () => {
|
||||
@@ -93,7 +133,7 @@ describe('OidcAuthenticationService', () => {
|
||||
});
|
||||
|
||||
it('should handle logout with additional parameter redirect_uri', () => {
|
||||
mockAppConfigService.setConfig({
|
||||
appConfigService['setConfig']({
|
||||
logoutParameters: ['client_id', 'returnTo', 'redirect_uri', 'response_type']
|
||||
});
|
||||
|
||||
@@ -108,7 +148,7 @@ describe('OidcAuthenticationService', () => {
|
||||
});
|
||||
|
||||
it('should handle logout with an empty configuration object', () => {
|
||||
mockAppConfigService.setConfig({ logoutParameters: [] });
|
||||
appConfigService['setConfig']({ logoutParameters: [] });
|
||||
|
||||
service.logout();
|
||||
|
||||
@@ -116,7 +156,7 @@ describe('OidcAuthenticationService', () => {
|
||||
});
|
||||
|
||||
it('should ignore undefined parameters', () => {
|
||||
mockAppConfigService.setConfig({
|
||||
appConfigService['setConfig']({
|
||||
logoutParameters: ['client_id', 'unknown_param']
|
||||
});
|
||||
service.logout();
|
||||
@@ -127,6 +167,82 @@ describe('OidcAuthenticationService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('loggedIn', () => {
|
||||
it('should return true if has valid tokens', () => {
|
||||
mockOAuthService.hasValidAccessToken.and.returnValue(true);
|
||||
mockOAuthService.hasValidIdToken.and.returnValue(true);
|
||||
|
||||
expect(service.isLoggedIn()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return false if does not have valid access token', () => {
|
||||
mockOAuthService.hasValidAccessToken.and.returnValue(false);
|
||||
mockOAuthService.hasValidIdToken.and.returnValue(true);
|
||||
|
||||
expect(service.isLoggedIn()).toBeFalse();
|
||||
});
|
||||
|
||||
it('should return false if does not have valid id token', () => {
|
||||
mockOAuthService.hasValidAccessToken.and.returnValue(true);
|
||||
mockOAuthService.hasValidIdToken.and.returnValue(false);
|
||||
|
||||
expect(service.isLoggedIn()).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isEcmLoggedIn', () => {
|
||||
beforeEach(() => {
|
||||
mockOAuthService.hasValidAccessToken.and.returnValue(true);
|
||||
mockOAuthService.hasValidIdToken.and.returnValue(true);
|
||||
});
|
||||
|
||||
it('should return true if is ECM provider', () => {
|
||||
spyOn(appConfig, 'get').and.returnValue('ECM');
|
||||
expect(service.isEcmLoggedIn()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return true if is all provider', () => {
|
||||
spyOn(appConfig, 'get').and.returnValue('ALL');
|
||||
expect(service.isEcmLoggedIn()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return false if is not ECM provider', () => {
|
||||
spyOn(appConfig, 'get').and.returnValue('BPM');
|
||||
expect(service.isEcmLoggedIn()).toBeFalse();
|
||||
});
|
||||
|
||||
it('should return false if provider is not defined', () => {
|
||||
spyOn(appConfig, 'get').and.returnValue(undefined);
|
||||
expect(service.isEcmLoggedIn()).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBpmLoggedIn', () => {
|
||||
beforeEach(() => {
|
||||
mockOAuthService.hasValidAccessToken.and.returnValue(true);
|
||||
mockOAuthService.hasValidIdToken.and.returnValue(true);
|
||||
});
|
||||
|
||||
it('should return true if is BPM provider', () => {
|
||||
spyOn(appConfig, 'get').and.returnValue('BPM');
|
||||
expect(service.isBpmLoggedIn()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return true if is all provider', () => {
|
||||
spyOn(appConfig, 'get').and.returnValue('ALL');
|
||||
expect(service.isBpmLoggedIn()).toBeTrue();
|
||||
});
|
||||
|
||||
it('should return false if is not BPM provider', () => {
|
||||
spyOn(appConfig, 'get').and.returnValue('ECM');
|
||||
expect(service.isBpmLoggedIn()).toBeFalse();
|
||||
});
|
||||
|
||||
it('should return false if provider is not defined', () => {
|
||||
spyOn(appConfig, 'get').and.returnValue(undefined);
|
||||
expect(service.isBpmLoggedIn()).toBeFalse();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('OidcAuthenticationService shouldPerformSsoLogin', () => {
|
||||
@@ -136,8 +252,8 @@ describe('OidcAuthenticationService shouldPerformSsoLogin', () => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
OidcAuthenticationService,
|
||||
{ provide: AppConfigService, useClass: MockAppConfigService },
|
||||
{ provide: OAuthService, useClass: MockOAuthService },
|
||||
{ provide: AppConfigService, useValue: mockAppConfigService },
|
||||
{ provide: OAuthService, useValue: mockOAuthService },
|
||||
{ provide: OAuthStorage, useValue: {} },
|
||||
{ provide: AUTH_MODULE_CONFIG, useValue: {} },
|
||||
{ provide: AuthService, useValue: {} },
|
||||
|
||||
@@ -15,35 +15,37 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { fakeAsync, TestBed } from '@angular/core/testing';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
import { CookieService } from '../../common/services/cookie.service';
|
||||
import { AppConfigService } from '../../app-config/app-config.service';
|
||||
import { BasicAlfrescoAuthService } from '../basic-auth/basic-alfresco-auth.service';
|
||||
import { AuthModule } from '../oidc/auth.module';
|
||||
import { HttpClientModule, HttpHeaders } from '@angular/common/http';
|
||||
import { HttpHeaders, provideHttpClient } from '@angular/common/http';
|
||||
import { CookieServiceMock } from '../../mock';
|
||||
import { AppConfigServiceMock } from '../../common';
|
||||
import { OidcAuthenticationService } from '../oidc/oidc-authentication.service';
|
||||
import { OAuthEvent } from 'angular-oauth2-oidc';
|
||||
import { Subject } from 'rxjs';
|
||||
import { firstValueFrom, of, Subject, throwError } from 'rxjs';
|
||||
import { RedirectAuthService } from '../oidc/redirect-auth.service';
|
||||
import { Injector } from '@angular/core';
|
||||
import { NoopTranslateModule } from '../../testing/noop-translate.module';
|
||||
import { ContentAuth, ProcessAuth } from '../public-api';
|
||||
|
||||
declare let jasmine: any;
|
||||
// eslint-disable-next-line
|
||||
xdescribe('AuthenticationService', () => {
|
||||
describe('AuthenticationService', () => {
|
||||
let authService: AuthenticationService;
|
||||
let basicAlfrescoAuthService: BasicAlfrescoAuthService;
|
||||
let appConfigService: AppConfigService;
|
||||
let cookie: CookieService;
|
||||
let oidcAuthenticationService: OidcAuthenticationService;
|
||||
let headers: HttpHeaders;
|
||||
let processAuth: ProcessAuth;
|
||||
let contentAuth: ContentAuth;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [NoopTranslateModule, AuthModule.forRoot({ useHash: true }), HttpClientModule],
|
||||
imports: [NoopTranslateModule, AuthModule.forRoot({ useHash: true })],
|
||||
providers: [
|
||||
{
|
||||
provide: CookieService,
|
||||
@@ -52,7 +54,8 @@ xdescribe('AuthenticationService', () => {
|
||||
{
|
||||
provide: AppConfigService,
|
||||
useClass: AppConfigServiceMock
|
||||
}
|
||||
},
|
||||
provideHttpClient()
|
||||
]
|
||||
});
|
||||
|
||||
@@ -61,11 +64,16 @@ xdescribe('AuthenticationService', () => {
|
||||
authService = TestBed.inject(AuthenticationService);
|
||||
basicAlfrescoAuthService = TestBed.inject(BasicAlfrescoAuthService);
|
||||
oidcAuthenticationService = TestBed.inject(OidcAuthenticationService);
|
||||
|
||||
spyOn(oidcAuthenticationService, 'logout').and.returnValue(of());
|
||||
cookie = TestBed.inject(CookieService);
|
||||
|
||||
processAuth = TestBed.inject(ProcessAuth);
|
||||
spyOn(processAuth, 'login').and.returnValue(Promise.resolve());
|
||||
contentAuth = TestBed.inject(ContentAuth);
|
||||
spyOn(contentAuth, 'login').and.returnValue(Promise.resolve());
|
||||
|
||||
cookie.clear();
|
||||
|
||||
jasmine.Ajax.install();
|
||||
appConfigService = TestBed.inject(AppConfigService);
|
||||
appConfigService.config.pagination = {
|
||||
supportedPageSizes: []
|
||||
@@ -74,7 +82,6 @@ xdescribe('AuthenticationService', () => {
|
||||
|
||||
afterEach(() => {
|
||||
cookie.clear();
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
describe('kerberos', () => {
|
||||
@@ -147,56 +154,18 @@ xdescribe('AuthenticationService', () => {
|
||||
expect(authService.isEcmLoggedIn()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('[ECM] should return an ECM ticket after the login done', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe(() => {
|
||||
expect(authService.isLoggedIn()).toBe(true);
|
||||
expect(authService.getToken()).toEqual('fake-post-ticket');
|
||||
expect(authService.isEcmLoggedIn()).toBe(true);
|
||||
disposableLogin.unsubscribe();
|
||||
done();
|
||||
});
|
||||
it('[ECM] should login in the ECM if no provider are defined calling the login', async () => {
|
||||
contentAuth.login = jasmine.createSpy().and.returnValue(Promise.resolve(fakeECMLoginResponse.ticket));
|
||||
const loginResponse = await firstValueFrom(basicAlfrescoAuthService.login('fake-username', 'fake-password'));
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ entry: { id: 'fake-post-ticket', userId: 'admin' } })
|
||||
});
|
||||
expect(contentAuth.login).toHaveBeenCalled();
|
||||
expect(loginResponse).toEqual(fakeECMLoginResponse);
|
||||
});
|
||||
|
||||
it('[ECM] should login in the ECM if no provider are defined calling the login', fakeAsync(() => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe((loginResponse) => {
|
||||
expect(loginResponse).toEqual(fakeECMLoginResponse);
|
||||
disposableLogin.unsubscribe();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ entry: { id: 'fake-post-ticket', userId: 'admin' } })
|
||||
});
|
||||
}));
|
||||
|
||||
it('[ECM] should return a ticket undefined after logout', fakeAsync(() => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe(() => {
|
||||
const disposableLogout = authService.logout().subscribe(() => {
|
||||
expect(authService.isLoggedIn()).toBe(false);
|
||||
expect(authService.getToken()).toBe(null);
|
||||
expect(authService.isEcmLoggedIn()).toBe(false);
|
||||
disposableLogin.unsubscribe();
|
||||
disposableLogout.unsubscribe();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 204
|
||||
});
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ entry: { id: 'fake-post-ticket', userId: 'admin' } })
|
||||
});
|
||||
}));
|
||||
it('[ECM] should get token when provider is ECM', () => {
|
||||
spyOn(basicAlfrescoAuthService, 'getToken').and.returnValue('fake-ecm-token');
|
||||
expect(basicAlfrescoAuthService.getToken()).toEqual('fake-ecm-token');
|
||||
});
|
||||
|
||||
it('[ECM] should return false if the user is not logged in', () => {
|
||||
expect(authService.isLoggedIn()).toBe(false);
|
||||
@@ -261,55 +230,12 @@ xdescribe('AuthenticationService', () => {
|
||||
expect(authService.isBpmLoggedIn()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('[BPM] should return an BPM ticket after the login done', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe(() => {
|
||||
expect(authService.isLoggedIn()).toBe(true);
|
||||
// cspell: disable-next
|
||||
expect(authService.getToken()).toEqual('Basic ZmFrZS11c2VybmFtZTpmYWtlLXBhc3N3b3Jk');
|
||||
expect(authService.isBpmLoggedIn()).toBe(true);
|
||||
disposableLogin.unsubscribe();
|
||||
done();
|
||||
});
|
||||
it('[BPM] should return an error when the logout return error', async () => {
|
||||
oidcAuthenticationService.logout = jasmine.createSpy().and.returnValue(throwError(() => 'logout'));
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200,
|
||||
contentType: 'application/json'
|
||||
});
|
||||
});
|
||||
|
||||
it('[BPM] should return a ticket undefined after logout', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe(() => {
|
||||
const disposableLogout = authService.logout().subscribe(() => {
|
||||
expect(authService.isLoggedIn()).toBe(false);
|
||||
expect(authService.getToken()).toBe(null);
|
||||
expect(authService.isBpmLoggedIn()).toBe(false);
|
||||
disposableLogout.unsubscribe();
|
||||
disposableLogin.unsubscribe();
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200
|
||||
});
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 200
|
||||
});
|
||||
});
|
||||
|
||||
it('[BPM] should return an error when the logout return error', (done) => {
|
||||
authService.logout().subscribe(
|
||||
() => {},
|
||||
(err: any) => {
|
||||
expect(err).toBeDefined();
|
||||
expect(authService.getToken()).toBe(null);
|
||||
done();
|
||||
}
|
||||
);
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 403
|
||||
await firstValueFrom(authService.logout()).catch((err) => {
|
||||
expect(err).toBeDefined();
|
||||
expect(authService.getToken()).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -350,59 +276,23 @@ xdescribe('AuthenticationService', () => {
|
||||
appConfigService.load();
|
||||
});
|
||||
|
||||
it('[ECM] should save the remember me cookie as a session cookie after successful login', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password', false).subscribe(() => {
|
||||
expect(cookie['ALFRESCO_REMEMBER_ME']).not.toBeUndefined();
|
||||
expect(cookie['ALFRESCO_REMEMBER_ME'].expiration).toBeNull();
|
||||
disposableLogin.unsubscribe();
|
||||
done();
|
||||
});
|
||||
it('[ECM] should save the remember me cookie as a session cookie after successful login', async () => {
|
||||
await firstValueFrom(basicAlfrescoAuthService.login('fake-username', 'fake-password', false));
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ entry: { id: 'fake-post-ticket', userId: 'admin' } })
|
||||
});
|
||||
expect(cookie.getItem('ALFRESCO_REMEMBER_ME')).toBe('1');
|
||||
});
|
||||
|
||||
it('[ECM] should save the remember me cookie as a persistent cookie after successful login', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password', true).subscribe(() => {
|
||||
expect(cookie['ALFRESCO_REMEMBER_ME']).not.toBeUndefined();
|
||||
expect(cookie['ALFRESCO_REMEMBER_ME'].expiration).not.toBeNull();
|
||||
disposableLogin.unsubscribe();
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ entry: { id: 'fake-post-ticket', userId: 'admin' } })
|
||||
});
|
||||
it('[ECM] should save the remember me cookie as a persistent cookie after successful login', async () => {
|
||||
await firstValueFrom(basicAlfrescoAuthService.login('fake-username', 'fake-password', true));
|
||||
expect(cookie.getItem('ALFRESCO_REMEMBER_ME')).not.toBeUndefined();
|
||||
expect(JSON.parse(cookie.getItem('ALFRESCO_REMEMBER_ME')).expiration).not.toBeNull();
|
||||
});
|
||||
|
||||
it('[ECM] should not save the remember me cookie after failed login', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe(
|
||||
() => {},
|
||||
() => {
|
||||
expect(cookie['ALFRESCO_REMEMBER_ME']).toBeUndefined();
|
||||
disposableLogin.unsubscribe();
|
||||
done();
|
||||
}
|
||||
);
|
||||
it('[ECM] should not save the remember me cookie after failed login', async () => {
|
||||
contentAuth.login = jasmine.createSpy().and.returnValue(Promise.reject(new Error('Login failed')));
|
||||
|
||||
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||
status: 403,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({
|
||||
error: {
|
||||
errorKey: 'Login failed',
|
||||
statusCode: 403,
|
||||
briefSummary: '05150009 Login failed',
|
||||
stackTrace: 'For security reasons the stack trace is no longer displayed, but the property is kept for previous versions.',
|
||||
descriptionURL: 'https://api-explorer.alfresco.com'
|
||||
}
|
||||
})
|
||||
await firstValueFrom(basicAlfrescoAuthService.login('fake-username', 'fake-password')).catch(() => {
|
||||
expect(cookie.getItem('ALFRESCO_REMEMBER_ME')).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -413,99 +303,6 @@ xdescribe('AuthenticationService', () => {
|
||||
appConfigService.load();
|
||||
});
|
||||
|
||||
it('[ALL] should return both ECM and BPM tickets after the login done', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe(() => {
|
||||
expect(authService.isLoggedIn()).toBe(true);
|
||||
expect(basicAlfrescoAuthService.getTicketEcm()).toEqual('fake-post-ticket');
|
||||
// cspell: disable-next
|
||||
expect(basicAlfrescoAuthService.getTicketBpm()).toEqual('Basic ZmFrZS11c2VybmFtZTpmYWtlLXBhc3N3b3Jk');
|
||||
expect(authService.isBpmLoggedIn()).toBe(true);
|
||||
expect(authService.isEcmLoggedIn()).toBe(true);
|
||||
disposableLogin.unsubscribe();
|
||||
done();
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.at(0).respondWith({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ entry: { id: 'fake-post-ticket', userId: 'admin' } })
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.at(1).respondWith({
|
||||
status: 200
|
||||
});
|
||||
});
|
||||
|
||||
it('[ALL] should return login fail if only ECM call fail', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe(
|
||||
() => {},
|
||||
() => {
|
||||
expect(authService.isLoggedIn()).toBe(false, 'isLoggedIn');
|
||||
expect(authService.getToken()).toBe(null, 'getTicketEcm');
|
||||
// cspell: disable-next
|
||||
expect(authService.getToken()).toBe(null, 'getTicketBpm');
|
||||
expect(authService.isEcmLoggedIn()).toBe(false, 'isEcmLoggedIn');
|
||||
disposableLogin.unsubscribe();
|
||||
done();
|
||||
}
|
||||
);
|
||||
|
||||
jasmine.Ajax.requests.at(0).respondWith({
|
||||
status: 403
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.at(1).respondWith({
|
||||
status: 200
|
||||
});
|
||||
});
|
||||
|
||||
it('[ALL] should return login fail if only BPM call fail', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe(
|
||||
() => {},
|
||||
() => {
|
||||
expect(authService.isLoggedIn()).toBe(false);
|
||||
expect(authService.getToken()).toBe(null);
|
||||
expect(authService.getToken()).toBe(null);
|
||||
expect(authService.isBpmLoggedIn()).toBe(false);
|
||||
disposableLogin.unsubscribe();
|
||||
done();
|
||||
}
|
||||
);
|
||||
|
||||
jasmine.Ajax.requests.at(0).respondWith({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
responseText: JSON.stringify({ entry: { id: 'fake-post-ticket', userId: 'admin' } })
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.at(1).respondWith({
|
||||
status: 403
|
||||
});
|
||||
});
|
||||
|
||||
it('[ALL] should return ticket undefined when the credentials are wrong', (done) => {
|
||||
const disposableLogin = basicAlfrescoAuthService.login('fake-username', 'fake-password').subscribe(
|
||||
() => {},
|
||||
() => {
|
||||
expect(authService.isLoggedIn()).toBe(false);
|
||||
expect(authService.getToken()).toBe(null);
|
||||
expect(authService.getToken()).toBe(null);
|
||||
expect(authService.isBpmLoggedIn()).toBe(false);
|
||||
expect(authService.isEcmLoggedIn()).toBe(false);
|
||||
disposableLogin.unsubscribe();
|
||||
done();
|
||||
}
|
||||
);
|
||||
|
||||
jasmine.Ajax.requests.at(0).respondWith({
|
||||
status: 403
|
||||
});
|
||||
|
||||
jasmine.Ajax.requests.at(1).respondWith({
|
||||
status: 403
|
||||
});
|
||||
});
|
||||
|
||||
it('[ALL] should return isECMProvider false', () => {
|
||||
expect(authService.isECMProvider()).toBe(false);
|
||||
});
|
||||
|
||||
@@ -123,7 +123,7 @@ export abstract class BaseAuthenticationService implements AuthenticationService
|
||||
*/
|
||||
handleError(error: any): Observable<any> {
|
||||
this.onError.next(error || 'Server error');
|
||||
return throwError(error || 'Server error');
|
||||
return throwError(() => error || 'Server error');
|
||||
}
|
||||
|
||||
isOauth(): boolean {
|
||||
|
||||
@@ -78,7 +78,6 @@ describe('DateFnsUtils', () => {
|
||||
|
||||
it('should parse alternative ISO datetime', () => {
|
||||
const result = DateFnsUtils.parseDate('1982-03-13T10:00:000Z', `yyyy-MM-dd'T'HH:mm:sssXXX`);
|
||||
|
||||
expect(result.toISOString()).toBe('1982-03-13T10:00:00.000Z');
|
||||
});
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
import { Directive, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { ThemePalette } from '@angular/material/core';
|
||||
import { FormFieldModel, FormFieldValidator, FormModel, FormOutcomeEvent, FormOutcomeModel } from './widgets';
|
||||
import { isOutcomeButtonVisible } from './helpers/buttons-visibility';
|
||||
|
||||
@Directive({
|
||||
standalone: true
|
||||
@@ -103,10 +104,6 @@ export abstract class FormBaseComponent {
|
||||
*/
|
||||
formStyle: string = '';
|
||||
|
||||
get hasVisibleOutcomes(): boolean {
|
||||
return this.form?.outcomes?.some((outcome) => this.isOutcomeButtonVisible(outcome, this.form.readOnly));
|
||||
}
|
||||
|
||||
get form(): FormModel {
|
||||
return this._form;
|
||||
}
|
||||
@@ -169,22 +166,7 @@ export abstract class FormBaseComponent {
|
||||
}
|
||||
|
||||
isOutcomeButtonVisible(outcome: FormOutcomeModel, isFormReadOnly: boolean): boolean {
|
||||
if (outcome?.name) {
|
||||
if (outcome.name === FormOutcomeModel.COMPLETE_ACTION) {
|
||||
return this.showCompleteButton;
|
||||
}
|
||||
if (isFormReadOnly) {
|
||||
return outcome.isSelected;
|
||||
}
|
||||
if (outcome.name === FormOutcomeModel.SAVE_ACTION) {
|
||||
return this.showSaveButton;
|
||||
}
|
||||
if (outcome.name === FormOutcomeModel.START_PROCESS_ACTION) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return isOutcomeButtonVisible(outcome, { isFormReadOnly, showCompleteButton: this.showCompleteButton, showSaveButton: this.showSaveButton });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,6 +73,7 @@ export class FormFieldComponent implements OnInit, OnDestroy {
|
||||
if (w.adf === undefined) {
|
||||
w.adf = {};
|
||||
}
|
||||
|
||||
const originalField = this.getField();
|
||||
if (originalField) {
|
||||
const customTemplate = this.field.form.customFieldTemplates[originalField.type];
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
[ngClass]="{ 'adf-readonly-form': formDefinition.readOnly }">
|
||||
<div *ngIf="formDefinition.hasTabs()">
|
||||
<div *ngIf="hasTabs()" class="alfresco-tabs-widget">
|
||||
<mat-tab-group>
|
||||
<mat-tab *ngFor="let tab of visibleTabs()" [label]="tab.title | translate ">
|
||||
<ng-container class="adf-form-tab-content">
|
||||
<ng-template *ngTemplateOutlet="render; context: { fieldToRender: tab.fields }" />
|
||||
</ng-container>
|
||||
<mat-tab-group [preserveContent]="true">
|
||||
<mat-tab *ngFor="let tab of visibleTabs()" [label]="tab.title | translate ">
|
||||
<ng-template matTabContent>
|
||||
<div class="adf-form-tab-content">
|
||||
<ng-template *ngTemplateOutlet="render; context: { fieldToRender: tab.fields }" />
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
@@ -40,7 +42,8 @@
|
||||
<section class="adf-grid-list-column-view" *ngIf="currentRootElement?.isExpanded">
|
||||
<div class="adf-grid-list-single-column"
|
||||
*ngFor="let column of currentRootElement?.columns"
|
||||
[style.width.%]="getColumnWidth(currentRootElement)">
|
||||
[style.width.%]="getColumnWidth(currentRootElement)"
|
||||
>
|
||||
<ng-container *ngFor="let field of column?.fields">
|
||||
<ng-container *ngIf="field.type === 'section'; else formField">
|
||||
<adf-form-section [field]="field"/>
|
||||
@@ -61,9 +64,11 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
<div *ngIf="currentRootElement.type === 'dynamic-table'" class="adf-container-widget">
|
||||
<adf-form-field [field]="currentRootElement" />
|
||||
</div>
|
||||
|
||||
<div class="adf-container-widget"
|
||||
*ngIf="currentRootElement.type === 'readonly' && currentRootElement.field.params.field.type === 'dynamic-table'">
|
||||
<adf-form-field [field]="currentRootElement.field"/>
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
.alfresco-tabs-widget {
|
||||
width: 100%;
|
||||
|
||||
.adf-form-tab-content {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.adf-form-tab-group {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FormOutcomeModel } from '../widgets';
|
||||
|
||||
interface IsOutcomeButtonVisibleProps {
|
||||
isFormReadOnly: boolean;
|
||||
showCompleteButton: boolean;
|
||||
showSaveButton: boolean;
|
||||
}
|
||||
|
||||
export const isOutcomeButtonVisible = (outcome: FormOutcomeModel, props: IsOutcomeButtonVisibleProps): boolean => {
|
||||
const { isFormReadOnly, showCompleteButton, showSaveButton } = props;
|
||||
|
||||
if (outcome?.name) {
|
||||
if (outcome.name === FormOutcomeModel.COMPLETE_ACTION) {
|
||||
return showCompleteButton;
|
||||
}
|
||||
if (isFormReadOnly) {
|
||||
return outcome.isSelected;
|
||||
}
|
||||
if (outcome.name === FormOutcomeModel.SAVE_ACTION) {
|
||||
return showSaveButton;
|
||||
}
|
||||
if (outcome.name === FormOutcomeModel.START_PROCESS_ACTION) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -10,9 +10,9 @@
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<mat-form-field class="adf-amount-widget__input" [hideRequiredMarker]="true">
|
||||
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id"
|
||||
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></label
|
||||
<mat-form-field class="adf-amount-widget__input" [hideRequiredMarker]="true" [floatLabel]="placeholder ? 'always' : 'auto'">
|
||||
<mat-label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id"
|
||||
>{{field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span></mat-label
|
||||
>
|
||||
<span matTextPrefix class="adf-amount-widget__prefix-spacing">{{ currency }} </span>
|
||||
<input
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.adf-input {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
&:not(#{ms.$mat-focused}):not(#{ms.$mat-form-field-invalid}) {
|
||||
.adf-amount-widget__prefix-spacing {
|
||||
color: var(--adf-theme-foreground-secondary-text-color);
|
||||
|
||||
@@ -192,7 +192,7 @@ describe('AmountWidgetComponent - rendering', () => {
|
||||
expect(inputField).toBeTruthy();
|
||||
expect(await field.getPrefixText()).toBe('$');
|
||||
|
||||
const widgetLabel = testingUtils.getByCSS('label.adf-label').nativeElement;
|
||||
const widgetLabel = testingUtils.getByCSS('.adf-label').nativeElement;
|
||||
expect(widgetLabel.textContent.trim()).toBe('Test Amount*');
|
||||
expect(widget.field.isValid).toBe(false);
|
||||
|
||||
@@ -228,7 +228,7 @@ describe('AmountWidgetComponent - rendering', () => {
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
|
||||
const widgetLabel = testingUtils.getByCSS('label.adf-label').nativeElement;
|
||||
const widgetLabel = testingUtils.getByCSS('.adf-label').nativeElement;
|
||||
expect(widgetLabel.textContent.trim()).toBe('Test Amount*');
|
||||
|
||||
const field = await testingUtils.getMatFormField();
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
<mat-form-field class="adf-date-time-widget"
|
||||
[class.adf-left-label-input-datepicker]="field.leftLabels"
|
||||
[hideRequiredMarker]="true">
|
||||
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">
|
||||
<mat-label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">
|
||||
{{ field.name | translate }} ({{ field.dateDisplayFormat }})<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
|
||||
</label>
|
||||
</mat-label>
|
||||
<input matInput
|
||||
[matDatetimepicker]="datetimePicker"
|
||||
[id]="field.id"
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
<div>
|
||||
<mat-form-field [hideRequiredMarker]="true">
|
||||
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">
|
||||
<mat-label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">
|
||||
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
|
||||
</label>
|
||||
</mat-label>
|
||||
|
||||
<input matInput
|
||||
class="adf-input"
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
[class.adf-invalid]="!field.isValid && isTouched()"
|
||||
[class.adf-readonly]="field.readOnly">
|
||||
<mat-form-field floatPlaceholder="never" [hideRequiredMarker]="true">
|
||||
<label class="adf-label" [attr.for]="field.id">
|
||||
<mat-label class="adf-label" [attr.for]="field.id">
|
||||
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
|
||||
</label>
|
||||
</mat-label>
|
||||
<textarea matInput
|
||||
class="adf-input"
|
||||
[cdkTextareaAutosize]="true"
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
</div>
|
||||
<div>
|
||||
<mat-form-field [hideRequiredMarker]="true">
|
||||
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">
|
||||
<mat-label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id">
|
||||
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
|
||||
</label>
|
||||
</mat-label>
|
||||
<input matInput
|
||||
class="adf-input"
|
||||
type="text"
|
||||
@@ -21,7 +21,7 @@
|
||||
[required]="isRequired()"
|
||||
[value]="displayValue"
|
||||
[(ngModel)]="field.value"
|
||||
(ngModelChange)="onFieldChanged(field)"
|
||||
(ngModelChange)="onNumberChange($event)"
|
||||
[disabled]="field.readOnly"
|
||||
[placeholder]="field.placeholder"
|
||||
[title]="field.tooltip"
|
||||
|
||||
@@ -23,23 +23,100 @@ import { MatInputModule } from '@angular/material/input';
|
||||
import { CoreTestingModule, UnitTestingUtils } from '../../../../testing';
|
||||
import { FormFieldModel, FormFieldTypes, FormModel } from '../core';
|
||||
import { NumberWidgetComponent } from './number.widget';
|
||||
import { DecimalNumberPipe } from '../../../../pipes';
|
||||
|
||||
describe('NumberWidgetComponent', () => {
|
||||
let loader: HarnessLoader;
|
||||
let widget: NumberWidgetComponent;
|
||||
let fixture: ComponentFixture<NumberWidgetComponent>;
|
||||
let testingUtils: UnitTestingUtils;
|
||||
let mockDecimalNumberPipe: jasmine.SpyObj<DecimalNumberPipe>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
beforeEach(async () => {
|
||||
mockDecimalNumberPipe = jasmine.createSpyObj('DecimalNumberPipe', ['transform']);
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [CoreTestingModule, MatInputModule, MatIconModule]
|
||||
});
|
||||
})
|
||||
.overrideComponent(NumberWidgetComponent, {
|
||||
set: {
|
||||
providers: [{ provide: DecimalNumberPipe, useValue: mockDecimalNumberPipe }]
|
||||
}
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(NumberWidgetComponent);
|
||||
widget = fixture.componentInstance;
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
testingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(widget).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('with readonly true', () => {
|
||||
beforeEach(() => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
|
||||
type: FormFieldTypes.NUMBER,
|
||||
value: 123.45,
|
||||
id: 'number-id',
|
||||
readOnly: true
|
||||
});
|
||||
});
|
||||
|
||||
it('should set displayValue using decimalNumberPipe', () => {
|
||||
const expectedValue = '2000';
|
||||
mockDecimalNumberPipe.transform.and.returnValue(expectedValue);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(mockDecimalNumberPipe.transform).toHaveBeenCalled();
|
||||
expect(widget.displayValue).toBe(expectedValue);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with default value', () => {
|
||||
beforeEach(() => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
|
||||
type: FormFieldTypes.NUMBER,
|
||||
value: 123,
|
||||
id: 'number-id',
|
||||
readOnly: false
|
||||
});
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display the value', async () => {
|
||||
const input = await testingUtils.getMatInput();
|
||||
|
||||
expect(widget.displayValue).toBe(123);
|
||||
expect(await input.getValue()).toBe('123');
|
||||
expect(widget.field.value).toBe(123);
|
||||
});
|
||||
|
||||
it('should have value null when field is cleared', async () => {
|
||||
const input = await testingUtils.getMatInput();
|
||||
await input.setValue('');
|
||||
|
||||
expect(widget.field.value).toBeNull();
|
||||
});
|
||||
|
||||
it('should have value null when value is undefined', async () => {
|
||||
const input = await testingUtils.getMatInput();
|
||||
await input.setValue(undefined);
|
||||
|
||||
expect(widget.field.value).toBeNull();
|
||||
});
|
||||
|
||||
it('should have value null when value is null', async () => {
|
||||
const input = await testingUtils.getMatInput();
|
||||
await input.setValue(null);
|
||||
|
||||
expect(widget.field.value).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when tooltip is set', () => {
|
||||
beforeEach(() => {
|
||||
widget.field = new FormFieldModel(new FormModel({ taskId: '<id>' }), {
|
||||
|
||||
@@ -62,4 +62,12 @@ export class NumberWidgetComponent extends WidgetComponent implements OnInit {
|
||||
this.displayValue = this.field.value;
|
||||
}
|
||||
}
|
||||
|
||||
protected onNumberChange(value: string) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
this.field.value = null;
|
||||
}
|
||||
|
||||
this.onFieldChanged(this.field);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
</div>
|
||||
<div>
|
||||
<mat-form-field [hideRequiredMarker]="true">
|
||||
<label *ngIf="!field.leftLabels" class="adf-label" [attr.for]="field.id">
|
||||
<mat-label *ngIf="!field.leftLabels" class="adf-label" [attr.for]="field.id">
|
||||
{{ field.name | translate }}<span class="adf-asterisk" [style.visibility]="isRequired() ? 'visible' : 'hidden'">*</span>
|
||||
</label>
|
||||
</mat-label>
|
||||
<input matInput
|
||||
class="adf-input"
|
||||
type="text"
|
||||
|
||||
@@ -23,6 +23,7 @@ export * from './components/form-renderer.component';
|
||||
export * from './components/widgets';
|
||||
export * from './components/middlewares/middleware';
|
||||
export * from './components/middlewares/decimal-middleware.service';
|
||||
export * from './components/helpers/buttons-visibility';
|
||||
|
||||
export * from './services/form-rendering.service';
|
||||
export * from './services/form.service';
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"COMPLETE": "Abschließen",
|
||||
"CANCEL": "Abbrechen",
|
||||
"CLAIM": "Beanspruchen",
|
||||
"UNCLAIM": "Freigeben ",
|
||||
"UNCLAIM": "FREIGEBEN",
|
||||
"START PROCESS": "Prozess starten",
|
||||
"DATA_LOADING": "Daten werden geladen",
|
||||
"CLOSE": "Schließen",
|
||||
@@ -452,7 +452,8 @@
|
||||
"CANCEL": "Abbrechen",
|
||||
"RESET": "Zurücksetzen",
|
||||
"THUMBNAILS": "Dokumenten-Miniaturansichten",
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Miniaturansichten-Fenster schließen"
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Miniaturansichten-Fenster schließen",
|
||||
"LOADING": "Document is loading"
|
||||
},
|
||||
"PAGE_LABEL": {
|
||||
"SHOWING": "Angezeigt",
|
||||
|
||||
@@ -452,7 +452,8 @@
|
||||
"CANCEL": "Cancel",
|
||||
"RESET": "Reset",
|
||||
"THUMBNAILS": "Document thumbnails",
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Close thumbnails panel"
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Close thumbnails panel",
|
||||
"LOADING": "Document is loading"
|
||||
},
|
||||
"PAGE_LABEL": {
|
||||
"SHOWING": "Showing",
|
||||
|
||||
@@ -452,7 +452,8 @@
|
||||
"CANCEL": "Cancelar",
|
||||
"RESET": "Reiniciar",
|
||||
"THUMBNAILS": "Miniaturas de documento",
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Cerrar panel de miniaturas"
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Cerrar panel de miniaturas",
|
||||
"LOADING": "Document is loading"
|
||||
},
|
||||
"PAGE_LABEL": {
|
||||
"SHOWING": "Mostrando",
|
||||
|
||||
@@ -452,7 +452,8 @@
|
||||
"CANCEL": "Annuler",
|
||||
"RESET": "Réinitialiser",
|
||||
"THUMBNAILS": "Miniatures des documents",
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Fermer le panneau des miniatures"
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Fermer le panneau des miniatures",
|
||||
"LOADING": "Document is loading"
|
||||
},
|
||||
"PAGE_LABEL": {
|
||||
"SHOWING": "Affichage en cours",
|
||||
|
||||
@@ -452,7 +452,8 @@
|
||||
"CANCEL": "Annulla",
|
||||
"RESET": "Reimposta",
|
||||
"THUMBNAILS": "Miniature documento",
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Chiudi pannello miniature"
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Chiudi pannello miniature",
|
||||
"LOADING": "Document is loading"
|
||||
},
|
||||
"PAGE_LABEL": {
|
||||
"SHOWING": "Visualizzazione di",
|
||||
|
||||
@@ -452,7 +452,8 @@
|
||||
"CANCEL": "Anuluj",
|
||||
"RESET": "Resetuj",
|
||||
"THUMBNAILS": "Miniatura dokumentu",
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Zamknij panel miniatur"
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Zamknij panel miniatur",
|
||||
"LOADING": "Document is loading"
|
||||
},
|
||||
"PAGE_LABEL": {
|
||||
"SHOWING": "Wyświetlanie",
|
||||
|
||||
@@ -452,7 +452,8 @@
|
||||
"CANCEL": "Cancelar",
|
||||
"RESET": "Redefinir",
|
||||
"THUMBNAILS": "Miniaturas do documento",
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Fechar painel de miniaturas"
|
||||
"THUMBNAILS_PANLEL_CLOSE": "Fechar painel de miniaturas",
|
||||
"LOADING": "Document is loading"
|
||||
},
|
||||
"PAGE_LABEL": {
|
||||
"SHOWING": "A mostrar",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
@import './mat-selectors';
|
||||
@import '../form/components/widgets/form.theme';
|
||||
@import '../clipboard/clipboard.theme';
|
||||
@import './snackbar.theme';
|
||||
@import './material.theme';
|
||||
|
||||
@mixin alfresco-material-theme($theme) {
|
||||
@@ -115,7 +114,6 @@
|
||||
}
|
||||
|
||||
@include datetimepicker-theme.mat-datetimepicker-theme($theme);
|
||||
@include adf-snackbar-theme;
|
||||
@include adf-material-theme;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
@mixin adf-snackbar-theme() {
|
||||
.adf-error-snackbar {
|
||||
background-color: var(--theme-warn-color);
|
||||
}
|
||||
|
||||
.adf-warning-snackbar {
|
||||
background-color: var(--theme-accent-color);
|
||||
}
|
||||
|
||||
.adf-info-snackbar {
|
||||
background-color: var(--theme-primary-color);
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,8 @@
|
||||
aria-expanded="true">
|
||||
<div id="loader-container" class="adf-loader-container">
|
||||
<div class="adf-loader-item">
|
||||
<mat-progress-bar class="adf-loader-item-progress-bar" mode="indeterminate" />
|
||||
<mat-progress-bar [attr.aria-label]="'ADF_VIEWER.ARIA.LOADING' | translate"
|
||||
class="adf-loader-item-progress-bar" mode="indeterminate" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -254,7 +254,9 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
||||
|
||||
return pdfDocument.getPage(1);
|
||||
})
|
||||
.then(() => this.scalePage('init'))
|
||||
.then(() => {
|
||||
setTimeout(() => this.scalePage('init'));
|
||||
})
|
||||
.catch(() => this.error.emit());
|
||||
});
|
||||
}
|
||||
@@ -618,8 +620,8 @@ export class PdfViewerComponent implements OnChanges, OnDestroy {
|
||||
*
|
||||
*/
|
||||
onPagesLoaded() {
|
||||
this.pagesLoaded.emit();
|
||||
this.isPanelDisabled = false;
|
||||
this.pagesLoaded.emit();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,7 @@ describe('Text View component', () => {
|
||||
|
||||
describe('View', () => {
|
||||
it('Should text container be present with urlFile', async () => {
|
||||
spyOn(component.contentLoaded, 'emit');
|
||||
fixture.detectChanges();
|
||||
const urlFile = './fake-test-file.txt';
|
||||
const change = new SimpleChange(null, urlFile, true);
|
||||
@@ -52,9 +53,11 @@ describe('Text View component', () => {
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(testingUtils.getByCSS('.adf-txt-viewer-content').nativeElement.textContent).toContain('example');
|
||||
expect(component.contentLoaded.emit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Should text container be present with Blob file', async () => {
|
||||
spyOn(component.contentLoaded, 'emit');
|
||||
const blobFile = new Blob(['text example'], { type: 'text/txt' });
|
||||
|
||||
const change = new SimpleChange(null, blobFile, true);
|
||||
@@ -65,6 +68,7 @@ describe('Text View component', () => {
|
||||
await fixture.whenStable();
|
||||
|
||||
expect(testingUtils.getByCSS('.adf-txt-viewer-content').nativeElement.textContent).toContain('example');
|
||||
expect(component.contentLoaded.emit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { AppConfigService } from '../../../app-config';
|
||||
|
||||
@Component({
|
||||
@@ -34,6 +34,9 @@ export class TxtViewerComponent implements OnChanges {
|
||||
@Input()
|
||||
blobFile: Blob;
|
||||
|
||||
@Output()
|
||||
contentLoaded = new EventEmitter<void>();
|
||||
|
||||
content: string | ArrayBuffer;
|
||||
|
||||
constructor(private http: HttpClient, private appConfigService: AppConfigService) {}
|
||||
@@ -67,6 +70,9 @@ export class TxtViewerComponent implements OnChanges {
|
||||
},
|
||||
(event) => {
|
||||
reject(event);
|
||||
},
|
||||
() => {
|
||||
this.contentLoaded.emit();
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -78,13 +84,17 @@ export class TxtViewerComponent implements OnChanges {
|
||||
|
||||
reader.onload = () => {
|
||||
this.content = reader.result;
|
||||
resolve();
|
||||
};
|
||||
|
||||
reader.onerror = (error: any) => {
|
||||
reject(error);
|
||||
};
|
||||
|
||||
reader.onloadend = () => {
|
||||
this.contentLoaded.emit();
|
||||
resolve();
|
||||
};
|
||||
|
||||
reader.readAsText(blob);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,95 +1,110 @@
|
||||
<div *ngIf="(viewerType === 'media' || viewerType === 'pdf' || viewerType === 'image') ? isLoading || !isContentReady : isLoading"
|
||||
class="adf-viewer-render-main-loader">
|
||||
<div *ngIf="isLoading" class="adf-viewer-render-main-loader">
|
||||
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
|
||||
<div class="adf-viewer-render-content-container">
|
||||
<div class="adf-viewer-render__loading-screen ">
|
||||
<h2>{{ 'ADF_VIEWER.LOADING' | translate }}</h2>
|
||||
<div class="adf-viewer-render__loading-screen">
|
||||
<h2 id="loading-spinner-label">{{ 'ADF_VIEWER.LOADING' | translate }}</h2>
|
||||
<div>
|
||||
<mat-spinner class="adf-viewer-render__loading-screen__spinner"/>
|
||||
<mat-spinner aria-labelledby="loading-spinner-label"
|
||||
class="adf-viewer-render__loading-screen__spinner" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="!isLoading"
|
||||
class="adf-viewer-render-main">
|
||||
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
|
||||
<div class="adf-viewer-render-content-container" [ngSwitch]="viewerType">
|
||||
<ng-container *ngSwitchCase="'external'">
|
||||
<adf-preview-extension *ngIf="!!externalViewer"
|
||||
[id]="externalViewer.component"
|
||||
[url]="urlFile"
|
||||
[extension]="externalViewer.fileExtension"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="externalViewer.component" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'pdf'">
|
||||
<adf-pdf-viewer [thumbnailsTemplate]="thumbnailsTemplate"
|
||||
[allowThumbnails]="allowThumbnails"
|
||||
[blobFile]="blobFile"
|
||||
[urlFile]="urlFile"
|
||||
[fileName]="internalFileName"
|
||||
[cacheType]="cacheTypeForContent"
|
||||
(pagesLoaded)="isContentReady = true"
|
||||
(close)="onClose()"
|
||||
(error)="onUnsupportedFile()" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'image'">
|
||||
<adf-img-viewer [urlFile]="urlFile"
|
||||
[readOnly]="readOnly"
|
||||
[fileName]="internalFileName"
|
||||
[allowedEditActions]="allowedEditActions"
|
||||
[blobFile]="blobFile"
|
||||
(error)="onUnsupportedFile()"
|
||||
(submit)="onSubmitFile($event)"
|
||||
(imageLoaded)="isContentReady = true"
|
||||
(isSaving)="isSaving.emit($event)"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'media'">
|
||||
<adf-media-player id="adf-mdedia-player"
|
||||
[urlFile]="urlFile"
|
||||
[tracks]="tracks"
|
||||
[mimeType]="mimeType"
|
||||
[blobFile]="blobFile"
|
||||
[fileName]="internalFileName"
|
||||
(error)="onUnsupportedFile()"
|
||||
(canPlay)="isContentReady = true"/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'text'">
|
||||
<adf-txt-viewer [urlFile]="urlFile"
|
||||
[blobFile]="blobFile" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'custom'">
|
||||
<ng-container *ngFor="let ext of viewerExtensions">
|
||||
<adf-preview-extension *ngIf="checkExtensions(ext.fileExtension)"
|
||||
[id]="ext.component"
|
||||
[url]="urlFile"
|
||||
[extension]="extension"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="ext.component" />
|
||||
@if (urlFile || blobFile) {
|
||||
<div [style.visibility]="isLoading ? 'hidden' : 'visible'" class="adf-viewer-render-main">
|
||||
<div class="adf-viewer-render-layout-content adf-viewer__fullscreen-container">
|
||||
<div class="adf-viewer-render-content-container" [ngSwitch]="viewerType">
|
||||
<ng-container *ngSwitchCase="'external'">
|
||||
<adf-preview-extension
|
||||
*ngIf="!!externalViewer"
|
||||
[id]="externalViewer.component"
|
||||
[url]="urlFile"
|
||||
[extension]="externalViewer.fileExtension"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="externalViewer.component"
|
||||
(contentLoaded)="markAsLoaded()"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let extensionTemplate of extensionTemplates">
|
||||
<span *ngIf="extensionTemplate.isVisible" class="adf-viewer-render-custom-content">
|
||||
<ng-template [ngTemplateOutlet]="extensionTemplate.template"
|
||||
[ngTemplateOutletContext]="{ urlFile: urlFile, extension: extension }" />
|
||||
</span>
|
||||
<ng-container *ngSwitchCase="'pdf'">
|
||||
<adf-pdf-viewer
|
||||
[thumbnailsTemplate]="thumbnailsTemplate"
|
||||
[allowThumbnails]="allowThumbnails"
|
||||
[blobFile]="blobFile"
|
||||
[urlFile]="urlFile"
|
||||
[fileName]="internalFileName"
|
||||
[cacheType]="cacheTypeForContent"
|
||||
(pagesLoaded)="markAsLoaded()"
|
||||
(close)="onClose()"
|
||||
(error)="onUnsupportedFile()"
|
||||
/>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchDefault>
|
||||
<adf-viewer-unknown-format [customError]="customError"/>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="'image'">
|
||||
<adf-img-viewer
|
||||
[urlFile]="urlFile"
|
||||
[readOnly]="readOnly"
|
||||
[fileName]="internalFileName"
|
||||
[allowedEditActions]="allowedEditActions"
|
||||
[blobFile]="blobFile"
|
||||
(error)="onUnsupportedFile()"
|
||||
(submit)="onSubmitFile($event)"
|
||||
(imageLoaded)="markAsLoaded()"
|
||||
(isSaving)="isSaving.emit($event)"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'media'">
|
||||
<adf-media-player
|
||||
id="adf-mdedia-player"
|
||||
[urlFile]="urlFile"
|
||||
[tracks]="tracks"
|
||||
[mimeType]="mimeType"
|
||||
[blobFile]="blobFile"
|
||||
[fileName]="internalFileName"
|
||||
(error)="onUnsupportedFile()"
|
||||
(canPlay)="markAsLoaded()"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'text'">
|
||||
<adf-txt-viewer [urlFile]="urlFile" [blobFile]="blobFile" (contentLoaded)="markAsLoaded()" />
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'custom'">
|
||||
<ng-container *ngFor="let ext of viewerExtensions">
|
||||
<adf-preview-extension
|
||||
*ngIf="checkExtensions(ext.fileExtension)"
|
||||
[id]="ext.component"
|
||||
[url]="urlFile"
|
||||
[extension]="extension"
|
||||
[nodeId]="nodeId"
|
||||
[attr.data-automation-id]="ext.component"
|
||||
(contentLoaded)="markAsLoaded()"
|
||||
/>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let extensionTemplate of extensionTemplates">
|
||||
<span *ngIf="extensionTemplate.isVisible" class="adf-viewer-render-custom-content">
|
||||
<ng-template
|
||||
[ngTemplateOutlet]="extensionTemplate.template"
|
||||
[ngTemplateOutletContext]="{ urlFile: urlFile, extension: extension, markAsLoaded: markAsLoaded.bind(this) }"
|
||||
/>
|
||||
</span>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchDefault>
|
||||
<adf-viewer-unknown-format [customError]="customError" />
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<ng-container *ngIf="viewerTemplateExtensions">
|
||||
<ng-template [ngTemplateOutlet]="viewerTemplateExtensions" [ngTemplateOutletInjector]="injector" />
|
||||
<ng-template [ngTemplateOutlet]="viewerTemplateExtensions"
|
||||
[ngTemplateOutletContext]="{ urlFile: urlFile, extension: extension, markAsLoaded: markAsLoaded.bind(this) }"
|
||||
[ngTemplateOutletInjector]="injector" />
|
||||
</ng-container>
|
||||
|
||||
@@ -24,7 +24,7 @@ import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
||||
import { NoopTranslateModule, UnitTestingUtils } from '../../../testing';
|
||||
import { RenderingQueueServices } from '../../services/rendering-queue.services';
|
||||
import { ViewerRenderComponent } from './viewer-render.component';
|
||||
import { ImgViewerComponent, MediaPlayerComponent, ViewerExtensionDirective } from '@alfresco/adf-core';
|
||||
import { ImgViewerComponent, MediaPlayerComponent, PdfViewerComponent, ViewerExtensionDirective } from '@alfresco/adf-core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
@Component({
|
||||
@@ -278,6 +278,9 @@ describe('ViewerComponent', () => {
|
||||
fixtureCustom.detectChanges();
|
||||
await fixtureCustom.whenStable();
|
||||
|
||||
fixtureCustom.componentInstance.viewer1.markAsLoaded();
|
||||
fixtureCustom.detectChanges();
|
||||
|
||||
let customContent = getCustomViewerContent(fixtureCustom);
|
||||
expect(customComponent.extensionsSupportedByTemplates).toEqual(['json', 'test']);
|
||||
expect(customComponent.extensionTemplates.length).toBe(2);
|
||||
@@ -291,6 +294,9 @@ describe('ViewerComponent', () => {
|
||||
fixtureCustom.detectChanges();
|
||||
await fixtureCustom.whenStable();
|
||||
|
||||
fixtureCustom.componentInstance.viewer1.markAsLoaded();
|
||||
fixtureCustom.detectChanges();
|
||||
|
||||
customContent = getCustomViewerContent(fixtureCustom);
|
||||
expect(customComponent.extensionTemplates[0].isVisible).toBeFalse();
|
||||
expect(customComponent.extensionTemplates[1].isVisible).toBeTrue();
|
||||
@@ -410,6 +416,21 @@ describe('ViewerComponent', () => {
|
||||
expect(component.isSaving.emit).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('should render invisible container during loading', async () => {
|
||||
component.urlFile = 'fake-url-file.png';
|
||||
component.viewerType = 'image';
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges();
|
||||
component.isLoading = true;
|
||||
await fixture.whenStable();
|
||||
|
||||
const container: HTMLDivElement = testingUtils.getByCSS('.adf-viewer-render-main')?.nativeElement;
|
||||
expect(container).toBeDefined();
|
||||
expect(container.style.display).not.toBe('none');
|
||||
expect(container.clientWidth).toBe(0);
|
||||
expect(container.clientHeight).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
describe('Attribute', () => {
|
||||
it('should urlFile present not thrown any error ', () => {
|
||||
expect(() => {
|
||||
@@ -506,23 +527,22 @@ describe('ViewerComponent', () => {
|
||||
expect(component.viewerType).toBe('media');
|
||||
});
|
||||
|
||||
// eslint-disable-next-line ban/ban
|
||||
xit('should show spinner until content is ready when viewerType is pdf', () => {
|
||||
component.isLoading = false;
|
||||
it('should display spinner when viewerType is pdf', () => {
|
||||
component.urlFile = 'some-url.pdf';
|
||||
expect(getMainLoader()).toBeNull();
|
||||
|
||||
component.ngOnChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getMainLoader()).not.toBeNull();
|
||||
|
||||
const imgViewer = testingUtils.getByDirective(PdfViewerComponent);
|
||||
imgViewer.triggerEventHandler('pagesLoaded', null);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getMainLoader()).toBeNull();
|
||||
expect(component.viewerType).toBe('pdf');
|
||||
});
|
||||
|
||||
it('should show spinner until content is ready when viewerType is image', () => {
|
||||
it('should show spinner until renderer calls markAsLoaded', () => {
|
||||
spyOn(component, 'markAsLoaded').and.callThrough();
|
||||
component.isLoading = false;
|
||||
component.urlFile = 'some-url.png';
|
||||
|
||||
@@ -536,17 +556,18 @@ describe('ViewerComponent', () => {
|
||||
|
||||
expect(getMainLoader()).toBeNull();
|
||||
expect(component.viewerType).toBe('image');
|
||||
expect(component.markAsLoaded).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not show spinner when isLoading = false and isContentReady = false for other viewer types', () => {
|
||||
component.isLoading = false;
|
||||
component.urlFile = 'some-url.txt';
|
||||
|
||||
component.ngOnChanges();
|
||||
it('should not show spinner and set viewerType to unknown if subsequent renderer throws an error', () => {
|
||||
component.urlFile = 'some-url.png';
|
||||
fixture.detectChanges();
|
||||
expect(getMainLoader()).not.toBeNull();
|
||||
|
||||
component.onUnsupportedFile();
|
||||
fixture.detectChanges();
|
||||
expect(getMainLoader()).toBeNull();
|
||||
expect(component.isContentReady).toBeFalse();
|
||||
expect(component.viewerType).toBe('unknown');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,10 +86,6 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
|
||||
@Input()
|
||||
fileName: string;
|
||||
|
||||
/** Override loading status */
|
||||
@Input()
|
||||
isLoading = false;
|
||||
|
||||
/** Enable when where is possible the editing functionalities */
|
||||
@Input()
|
||||
readOnly = true;
|
||||
@@ -142,7 +138,7 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
|
||||
extension: string;
|
||||
internalFileName: string;
|
||||
viewerType: string = 'unknown';
|
||||
isContentReady = false;
|
||||
isLoading = false;
|
||||
|
||||
/**
|
||||
* Returns a list of the active Viewer content extensions.
|
||||
@@ -182,12 +178,11 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
this.cacheTypeForContent = 'no-cache';
|
||||
this.isLoading = true;
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.isContentReady = false;
|
||||
this.isLoading = !this.blobFile && !this.urlFile;
|
||||
|
||||
this.isLoading = true;
|
||||
if (this.blobFile) {
|
||||
this.setUpBlobData();
|
||||
} else if (this.urlFile) {
|
||||
@@ -195,9 +190,16 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
markAsLoaded() {
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
private setUpBlobData() {
|
||||
this.internalFileName = this.fileName;
|
||||
this.viewerType = this.viewUtilService.getViewerTypeByMimeType(this.blobFile.type);
|
||||
if (this.viewerType === 'unknown') {
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
this.extensionChange.emit(this.blobFile.type);
|
||||
this.scrollTop();
|
||||
@@ -207,6 +209,9 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
|
||||
this.internalFileName = this.fileName ? this.fileName : this.viewUtilService.getFilenameFromUrl(this.urlFile);
|
||||
this.extension = this.viewUtilService.getFileExtension(this.internalFileName);
|
||||
this.viewerType = this.viewUtilService.getViewerType(this.extension, this.mimeType, this.extensionsSupportedByTemplates);
|
||||
if (this.viewerType === 'unknown') {
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
this.extensionChange.emit(this.extension);
|
||||
this.scrollTop();
|
||||
@@ -230,6 +235,7 @@ export class ViewerRenderComponent implements OnChanges, OnInit {
|
||||
|
||||
onUnsupportedFile() {
|
||||
this.viewerType = 'unknown';
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
onClose() {
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
<ng-container *ngIf="showToolbar && !toolbar">
|
||||
<adf-toolbar id="adf-viewer-toolbar" class="adf-viewer-toolbar">
|
||||
<adf-toolbar-title>
|
||||
<adf-toolbar-divider />
|
||||
|
||||
<ng-container *ngIf="allowLeftSidebar">
|
||||
<button mat-icon-button
|
||||
[attr.aria-expanded]="showLeftSidebar"
|
||||
@@ -21,7 +23,6 @@
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<button *ngIf="allowGoBack && closeButtonPosition === CloseButtonPosition.Left"
|
||||
class="adf-viewer-close-button"
|
||||
data-automation-id="adf-toolbar-left-back"
|
||||
@@ -31,9 +32,6 @@
|
||||
(click)="onClose()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</adf-toolbar-title>
|
||||
|
||||
<div class="adf-viewer__file-title">
|
||||
<button *ngIf="allowNavigate && canNavigateBefore"
|
||||
data-automation-id="adf-toolbar-pref-file"
|
||||
mat-icon-button
|
||||
@@ -42,16 +40,6 @@
|
||||
(click)="onNavigateBeforeClick($event)">
|
||||
<mat-icon>navigate_before</mat-icon>
|
||||
</button>
|
||||
<img class="adf-viewer__mimeicon"
|
||||
[alt]="'ADF_VIEWER.ARIA.MIME_TYPE_ICON' | translate"
|
||||
[src]="mimeTypeIconUrl"
|
||||
data-automation-id="adf-file-thumbnail">
|
||||
<div class="adf-viewer__display-name"
|
||||
id="adf-viewer-display-name"
|
||||
[title]="fileName">
|
||||
<span class="adf-viewer__display-name-without-extension">{{ fileNameWithoutExtension }}</span>
|
||||
<span class="adf-viewer__display-name-extension">{{ fileExtension }}</span>
|
||||
</div>
|
||||
<button *ngIf="allowNavigate && canNavigateNext"
|
||||
data-automation-id="adf-toolbar-next-file"
|
||||
mat-icon-button
|
||||
@@ -60,7 +48,7 @@
|
||||
(click)="onNavigateNextClick($event)">
|
||||
<mat-icon>navigate_next</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</adf-toolbar-title>
|
||||
|
||||
<ng-content select="adf-viewer-toolbar-actions" />
|
||||
|
||||
@@ -79,8 +67,6 @@
|
||||
</mat-menu>
|
||||
</ng-container>
|
||||
|
||||
<adf-toolbar-divider />
|
||||
|
||||
<ng-content select="adf-viewer-toolbar-custom-actions" />
|
||||
|
||||
<button id="adf-viewer-fullscreen"
|
||||
@@ -95,7 +81,6 @@
|
||||
|
||||
<ng-container *ngIf="allowRightSidebar && !hideInfoButton">
|
||||
<adf-toolbar-divider />
|
||||
|
||||
<button mat-icon-button
|
||||
[attr.aria-expanded]="showRightSidebar"
|
||||
[attr.aria-label]="'ADF_VIEWER.ACTIONS.INFO' | translate"
|
||||
@@ -105,7 +90,6 @@
|
||||
(click)="toggleRightSidebar()">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
</button>
|
||||
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="mnuMoreActions">
|
||||
@@ -125,7 +109,6 @@
|
||||
|
||||
<ng-container *ngIf="allowGoBack && closeButtonPosition === CloseButtonPosition.Right">
|
||||
<adf-toolbar-divider />
|
||||
|
||||
<button class="adf-viewer-close-button"
|
||||
data-automation-id="adf-toolbar-right-back"
|
||||
[attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
|
||||
@@ -136,11 +119,21 @@
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<div class="adf-viewer__file-title">
|
||||
<img class="adf-viewer__mimeicon"
|
||||
[alt]="'ADF_VIEWER.ARIA.MIME_TYPE_ICON' | translate"
|
||||
[src]="mimeTypeIconUrl"
|
||||
data-automation-id="adf-file-thumbnail">
|
||||
<div class="adf-viewer__display-name"
|
||||
id="adf-viewer-display-name"
|
||||
[title]="fileName">
|
||||
<span>{{ displayName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</adf-toolbar>
|
||||
</ng-container>
|
||||
|
||||
<div class="adf-viewer-sidebars">
|
||||
|
||||
<ng-container *ngIf="allowRightSidebar && showRightSidebar">
|
||||
<div class="adf-viewer__sidebar adf-viewer__sidebar__right"
|
||||
id="adf-right-sidebar">
|
||||
@@ -176,7 +169,6 @@
|
||||
[viewerTemplateExtensions]="viewerExtensions ?? viewerTemplateExtensions"
|
||||
[nodeId]="nodeId"
|
||||
[customError]="customError" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
&-toolbar {
|
||||
#{ms.$mat-toolbar} {
|
||||
background-color: var(--adf-theme-background-card-color-087);
|
||||
|
||||
adf-toolbar-divider:first-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,23 +59,10 @@
|
||||
|
||||
&__display-name {
|
||||
font-size: var(--theme-subheading-2-font-size);
|
||||
opacity: 0.87;
|
||||
line-height: 1.5;
|
||||
letter-spacing: -0.4px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
vertical-align: middle;
|
||||
color: var(--adf-theme-foreground-text-color);
|
||||
|
||||
&-without-extension {
|
||||
display: inline-block;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
max-width: 400px;
|
||||
white-space: nowrap;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&-container {
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, SimpleChanges } from '@angular/core';
|
||||
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { of } from 'rxjs';
|
||||
import { AppConfigService } from '../../app-config';
|
||||
import { EventMock } from '../../mock';
|
||||
@@ -143,36 +144,61 @@ describe('ViewerComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('File Name Test', () => {
|
||||
const getFileNameWithoutExtension = (): string =>
|
||||
testingUtils.getByCSS('.adf-viewer__display-name-without-extension').nativeElement.textContent;
|
||||
const getExtension = (): string => testingUtils.getByCSS('.adf-viewer__display-name-extension').nativeElement.textContent;
|
||||
describe('File Name Display Tests', () => {
|
||||
describe('displayFileName method', () => {
|
||||
it('should return full filename when total length is 80 characters or less', () => {
|
||||
const fileShortName = 'shortname.txt';
|
||||
component.fileName = fileShortName;
|
||||
fixture.detectChanges();
|
||||
|
||||
it('should fileName be set by urlFile input if the fileName is not provided as Input', () => {
|
||||
component.fileName = '';
|
||||
spyOn(viewUtilService, 'getFilenameFromUrl').and.returnValue('fakeFileName.jpeg');
|
||||
const mockSimpleChanges: any = { urlFile: { currentValue: 'https://fakefile.url/fakeFileName.jpeg' } };
|
||||
expect(component.getDisplayFileName()).toBe(fileShortName);
|
||||
expect(getFileName()).toBe(fileShortName);
|
||||
});
|
||||
|
||||
component.ngOnChanges(mockSimpleChanges);
|
||||
fixture.detectChanges();
|
||||
it('should truncate filename when total length exceeds 80 characters', () => {
|
||||
const longName =
|
||||
'verylongfilenamethatexceedsmaximumlengthallowedverylongfilenamethatexceedsmaximumlengthallowed.verylongextensionnamethatistoolongverylongextensionnamethatistoolong';
|
||||
|
||||
expect(getFileName()).toEqual('fakeFileName.jpeg');
|
||||
expect(getFileNameWithoutExtension()).toBe('fakeFileName.');
|
||||
expect(getExtension()).toBe('jpeg');
|
||||
component.fileName = longName;
|
||||
fixture.detectChanges();
|
||||
|
||||
const result = component.getDisplayFileName();
|
||||
|
||||
expect(result).toContain('.....');
|
||||
expect(result.length).toBe(50);
|
||||
});
|
||||
|
||||
it('should handle empty filename', () => {
|
||||
component.fileName = '';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.getDisplayFileName()).toBe('');
|
||||
expect(getFileName()).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
it('should set fileName providing fileName input', () => {
|
||||
component.fileName = 'testFileName.jpg';
|
||||
spyOn(viewUtilService, 'getFilenameFromUrl').and.returnValue('fakeFileName.jpeg');
|
||||
const mockSimpleChanges: any = { urlFile: { currentValue: 'https://fakefile.url/fakeFileName.jpeg' } };
|
||||
describe('fileName setter integration', () => {
|
||||
it('should fileName be set by urlFile input if the fileName is not provided as Input', () => {
|
||||
component.fileName = '';
|
||||
spyOn(viewUtilService, 'getFilenameFromUrl').and.returnValue('fakeFileName.jpeg');
|
||||
const mockSimpleChanges = { urlFile: { currentValue: 'https://fakefile.url/fakeFileName.jpeg' } } as unknown as SimpleChanges;
|
||||
|
||||
component.ngOnChanges(mockSimpleChanges);
|
||||
fixture.detectChanges();
|
||||
fixture.detectChanges();
|
||||
component.ngOnChanges(mockSimpleChanges);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getFileName()).toEqual('testFileName.jpg');
|
||||
expect(getFileNameWithoutExtension()).toBe('testFileName.');
|
||||
expect(getExtension()).toBe('jpg');
|
||||
expect(getFileName()).toEqual('fakeFileName.jpeg');
|
||||
});
|
||||
|
||||
it('should set fileName providing fileName input', () => {
|
||||
component.fileName = 'testFileName.jpg';
|
||||
spyOn(viewUtilService, 'getFilenameFromUrl').and.returnValue('fakeFileName.jpeg');
|
||||
const mockSimpleChanges = { urlFile: { currentValue: 'https://fakefile.url/fakeFileName.jpeg' } } as unknown as SimpleChanges;
|
||||
|
||||
component.ngOnChanges(mockSimpleChanges);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getFileName()).toEqual('testFileName.jpg');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -670,4 +696,67 @@ describe('ViewerComponent', () => {
|
||||
expect(component.downloadFile.emit).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
|
||||
describe('ViewerComponent toolbar separators', () => {
|
||||
let component: ViewerComponent<any>;
|
||||
let fixture: ComponentFixture<ViewerComponent<any>>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MatButtonModule, MatIconModule, MatDialogModule],
|
||||
declarations: [ViewerComponent]
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ViewerComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.showViewer = true;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
const createToolbarTest = (
|
||||
allowRightSidebar: boolean,
|
||||
hideInfoButton: boolean,
|
||||
allowFullScreen: boolean,
|
||||
allowGoBack: boolean,
|
||||
expectedSeparatorCount: number
|
||||
) => {
|
||||
it(`should have correct UI state when [R:${allowRightSidebar}, I:${hideInfoButton}, F:${allowFullScreen}, B:${allowGoBack}]`, () => {
|
||||
component.allowRightSidebar = allowRightSidebar;
|
||||
component.hideInfoButton = hideInfoButton;
|
||||
component.allowFullScreen = allowFullScreen;
|
||||
component.allowGoBack = allowGoBack;
|
||||
fixture.detectChanges();
|
||||
|
||||
const separators = fixture.debugElement.queryAll(
|
||||
// .adf-toolbar-divider is the class used for separators
|
||||
// If your divider uses a different selector, update here
|
||||
By.css('adf-toolbar-divider')
|
||||
);
|
||||
expect(separators.length).toBe(expectedSeparatorCount);
|
||||
});
|
||||
};
|
||||
|
||||
describe('Toolbar state combinations', () => {
|
||||
createToolbarTest(true, false, true, true, 2);
|
||||
createToolbarTest(false, false, true, true, 1);
|
||||
createToolbarTest(true, true, true, true, 1);
|
||||
createToolbarTest(true, false, false, true, 1);
|
||||
createToolbarTest(true, false, true, false, 2);
|
||||
createToolbarTest(false, true, false, true, 0);
|
||||
createToolbarTest(false, true, false, false, 0);
|
||||
});
|
||||
|
||||
it('should not show unnecessary separator when close button is disabled but other controls exist', () => {
|
||||
component.allowGoBack = false;
|
||||
component.allowFullScreen = true;
|
||||
component.allowRightSidebar = true;
|
||||
component.hideInfoButton = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
const separators = fixture.debugElement.queryAll(By.css('adf-toolbar-divider'));
|
||||
expect(separators.length).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -297,6 +297,7 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
||||
private _fileNameWithoutExtension: string;
|
||||
private _fileExtension: string;
|
||||
|
||||
public displayName: string;
|
||||
public downloadPromptTimer: number;
|
||||
public downloadPromptReminderTimer: number;
|
||||
public mimeTypeIconUrl: string;
|
||||
@@ -309,6 +310,7 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
||||
this._fileName = fileName;
|
||||
this._fileExtension = this.viewUtilsService.getFileExtension(this.fileName);
|
||||
this._fileNameWithoutExtension = this.fileName?.replace(new RegExp(`${this.fileExtension}$`), '') || '';
|
||||
this.displayName = this.getDisplayFileName();
|
||||
}
|
||||
|
||||
get fileName(): string {
|
||||
@@ -462,6 +464,24 @@ export class ViewerComponent<T> implements OnDestroy, OnInit, OnChanges {
|
||||
this.clearDownloadPromptTimeouts();
|
||||
}
|
||||
|
||||
getDisplayFileName(): string {
|
||||
const fullName = (this.fileNameWithoutExtension || '') + (this.fileExtension || '');
|
||||
const maxLength = 50;
|
||||
|
||||
if (fullName.length <= maxLength) {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
const amountOfTruncateDots = 5;
|
||||
const availableSpace = maxLength - amountOfTruncateDots;
|
||||
const endLength = 8;
|
||||
const startLength = availableSpace - endLength;
|
||||
|
||||
const start = fullName.substring(0, startLength);
|
||||
const end = fullName.substring(fullName.length - endLength);
|
||||
return start + '.....' + end;
|
||||
}
|
||||
|
||||
private configureAndInitDownloadPrompt() {
|
||||
this.configureDownloadPromptProperties();
|
||||
if (this.enableDownloadPrompt) {
|
||||
|
||||
@@ -15,8 +15,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Input, ComponentRef, OnInit, ViewChild, ViewContainerRef, OnDestroy, OnChanges } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
ComponentRef,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
OnDestroy,
|
||||
OnChanges,
|
||||
EventEmitter,
|
||||
Output,
|
||||
DestroyRef,
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import { ExtensionService } from '../../services/extension.service';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-preview-extension',
|
||||
@@ -43,6 +57,11 @@ export class PreviewExtensionComponent implements OnInit, OnChanges, OnDestroy {
|
||||
@Input()
|
||||
extension: string;
|
||||
|
||||
@Output()
|
||||
contentLoaded = new EventEmitter<void>();
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
private componentRef: ComponentRef<any>;
|
||||
|
||||
constructor(private extensionService: ExtensionService) {}
|
||||
@@ -73,11 +92,15 @@ export class PreviewExtensionComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
private updateInstance() {
|
||||
if (this.componentRef?.instance) {
|
||||
const instance = this.componentRef.instance;
|
||||
this.componentRef.setInput('url', this.url);
|
||||
this.componentRef.setInput('extension', this.extension);
|
||||
this.componentRef.setInput('nodeId', this.nodeId);
|
||||
|
||||
instance.url = this.url;
|
||||
instance.extension = this.extension;
|
||||
instance.nodeId = this.nodeId;
|
||||
if (this.componentRef.instance?.contentLoaded) {
|
||||
this.componentRef.instance.contentLoaded.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
||||
this.contentLoaded.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import { BaseApi } from './base.api';
|
||||
import { buildCollectionParam } from '../../../alfrescoApiClient';
|
||||
import { throwIfNotDefined } from '../../../assert';
|
||||
import { RecordsIncludeQuery, RecordsPagingQuery, RecordsSourceQuery } from './types';
|
||||
import { FilePlanRolePaging, FilePlanRoleParameters } from '../model';
|
||||
|
||||
/**
|
||||
* FilePlansApi service.
|
||||
@@ -158,4 +159,32 @@ export class FilePlansApi extends BaseApi {
|
||||
returnType: FilePlanEntry
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of roles for the specified file plan.
|
||||
* @param filePlanId The identifier of a file plan. You can also use the -filePlan- alias.
|
||||
* @param parameters Optional parameters
|
||||
* @returns Promise<FilePlanEntry>
|
||||
*/
|
||||
getFilePlanRoles(filePlanId: string, parameters?: FilePlanRoleParameters): Promise<FilePlanRolePaging> {
|
||||
throwIfNotDefined(filePlanId, 'filePlanId');
|
||||
const whereConditions: string[] = [];
|
||||
if (parameters?.where) {
|
||||
if (parameters.where.personId) {
|
||||
whereConditions.push(`personId='${parameters.where.personId}'`);
|
||||
}
|
||||
if (parameters.where.capabilityNames) {
|
||||
whereConditions.push(`capabilityName in (${parameters.where.capabilityNames.map((value) => "'" + value + "'").join(', ')})`);
|
||||
}
|
||||
}
|
||||
return this.get({
|
||||
path: '/file-plans/{filePlanId}/roles',
|
||||
pathParams: {
|
||||
filePlanId
|
||||
},
|
||||
queryParams: {
|
||||
where: whereConditions.length ? `(${whereConditions.join(' and ')})` : undefined
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# FilePlanRole
|
||||
|
||||
## Properties
|
||||
| Name | Type |
|
||||
|--------------------|-----------------------------------------------------------|
|
||||
| **displayLabel** | string |
|
||||
| **groupShortName** | string |
|
||||
| **name** | string |
|
||||
| **roleGroupName** | string |
|
||||
| **capabilities** | [**FilePlanRoleCapability[]**](FilePlanRoleCapability.md) |
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# FilePLanRoleCapability
|
||||
|
||||
## Properties
|
||||
| Name | Type |
|
||||
|-----------|-------------------------------------------------------------------|
|
||||
| **group** | [**FilePlanRoleCapabilityGroup**](FilePlanRoleCapabilityGroup.md) |
|
||||
| **index** | number |
|
||||
| **name** | string |
|
||||
| **title** | string |
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# FilePlanRoleCapabilityGroup
|
||||
|
||||
## Properties
|
||||
| Name | Type |
|
||||
|-----------|--------|
|
||||
| **id** | string |
|
||||
| **title** | string |
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# FilePlanRoleEntry
|
||||
|
||||
## Properties
|
||||
| Name | Type |
|
||||
|-----------|-------------------------------------|
|
||||
| **entry** | [**FilePlanRole**](FilePlanRole.md) |
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# FilePLanRolePaging
|
||||
|
||||
## Properties
|
||||
| Name | Type |
|
||||
|----------|---------------------------------------------------------|
|
||||
| **list** | [**FilePlanRolePagingList**](FilePlanRolePagingList.md) |
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# FilePLanRolePagingList
|
||||
|
||||
## Properties
|
||||
| Name | Type |
|
||||
|----------------|-------------------------------------------------------------|
|
||||
| **entries** | [**FilePlanRoleEntry[]**](FilePlanRoleEntry.md) |
|
||||
| **pagination** | [**Pagination**](../../content-rest-api/docs/Pagination.md) |
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# FilePlanRoleParameters
|
||||
|
||||
## Properties
|
||||
| Name | Type |
|
||||
|-----------|-------------------------------------------------------------------|
|
||||
| **where** | [**FilePlanRoleParametersWhere**](FilePlanRoleParametersWhere.md) |
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# FilePlanRoleParametersWhere
|
||||
|
||||
## Properties
|
||||
| Name | Type |
|
||||
|---------------------|----------|
|
||||
| **personId** | string |
|
||||
| **capabilityNames** | string[] |
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
All URIs are relative to *https://localhost/alfresco/api/-default-/public/gs/versions/1*
|
||||
|
||||
Method | HTTP request | Description
|
||||
------------- | ------------- | -------------
|
||||
[**createFilePlanCategories**](FilePlansApi.md#createFilePlanCategories) | **POST** /file-plans/{filePlanId}/categories | Create record categories for a file plan
|
||||
[**getFilePlan**](FilePlansApi.md#getFilePlan) | **GET** /file-plans/{filePlanId} | Get a file plan
|
||||
[**getFilePlanCategories**](FilePlansApi.md#getFilePlanCategories) | **GET** /file-plans/{filePlanId}/categories | List file plans's children
|
||||
[**updateFilePlan**](FilePlansApi.md#updateFilePlan) | **PUT** /file-plans/{filePlanId} | Update a file plan
|
||||
|
||||
| Method | HTTP request | Description |
|
||||
|--------------------------------------------------------------------------|----------------------------------------------|---------------------------------------------------|
|
||||
| [**createFilePlanCategories**](FilePlansApi.md#createFilePlanCategories) | **POST** /file-plans/{filePlanId}/categories | Create record categories for a file plan |
|
||||
| [**getFilePlan**](FilePlansApi.md#getFilePlan) | **GET** /file-plans/{filePlanId} | Get a file plan |
|
||||
| [**getFilePlanCategories**](FilePlansApi.md#getFilePlanCategories) | **GET** /file-plans/{filePlanId}/categories | List file plans's children |
|
||||
| [**updateFilePlan**](FilePlansApi.md#updateFilePlan) | **PUT** /file-plans/{filePlanId} | Update a file plan |
|
||||
| [**getFilePlanRoles**](FilePlansApi.md#getFilePlanRoles) | **GET** /file-plans/{filePlanId}/roles | Gets a list of roles for the specified file plan. |
|
||||
|
||||
<a name="createFilePlanCategories"></a>
|
||||
# **createFilePlanCategories**
|
||||
@@ -402,3 +402,39 @@ parameter are returned in addition to those specified in the **fields** paramete
|
||||
|
||||
[**FilePlanEntry**](FilePlanEntry.md)
|
||||
|
||||
<a name="getFilePlanRoles"></a>
|
||||
# **getFilePlanRoles**
|
||||
> FilePlanEntry getFilePlanRoles(filePlanId, parameters)
|
||||
|
||||
Gets a list of roles for the specified file plan.
|
||||
|
||||
### Example
|
||||
```javascript
|
||||
import FilePlansApi from 'FilePlansApi';
|
||||
import { AlfrescoApi } from '@alfresco/js-api';
|
||||
|
||||
this.alfrescoApi = new AlfrescoApi();
|
||||
this.alfrescoApi.setConfig({
|
||||
hostEcm: 'http://127.0.0.1:8080'
|
||||
});
|
||||
|
||||
let fileplansApi = new FilePlansApi(this.alfrescoApi);
|
||||
const filePlanId = 'some id';
|
||||
fileplansApi.updateFilePlan(filePlanId, {
|
||||
where: {
|
||||
capabilityNames: ['ViewRecords']
|
||||
}
|
||||
}).then((data) => console.log('API called successfully. Returned data: ' + data))
|
||||
.catch((error) => console.log(error));
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|----------------|---------------------------------------------------------|-----------------------------------------------------------------------|
|
||||
| **filePlanId** | **string** | The identifier of a file plan. You can also use the -filePlan- alias. |
|
||||
| **parameters** | [**FilePlanRoleParameters**](FilePlanRoleParameters.md) | Optional parameters. |
|
||||
|
||||
### Return type
|
||||
|
||||
[**FilePlanRolePaging**](FilePlanRolePaging.md)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FilePlanRoleCapability } from './filePlanRoleCapability';
|
||||
|
||||
export class FilePlanRole {
|
||||
displayLabel: string;
|
||||
groupShortName: string;
|
||||
name: string;
|
||||
roleGroupName: string;
|
||||
capabilities: FilePlanRoleCapability[];
|
||||
|
||||
constructor(input?: Partial<FilePlanRole>) {
|
||||
if (input) {
|
||||
Object.assign(this, input);
|
||||
this.capabilities = input.capabilities?.map((capability) => new FilePlanRoleCapability(capability));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FilePlanRoleCapabilityGroup } from './filePlanRoleCapabilityGroup';
|
||||
|
||||
export class FilePlanRoleCapability {
|
||||
group: FilePlanRoleCapabilityGroup;
|
||||
index: number;
|
||||
name: string;
|
||||
title: string;
|
||||
|
||||
constructor(input?: Partial<FilePlanRoleCapability>) {
|
||||
if (input) {
|
||||
Object.assign(this, input);
|
||||
this.group = input.group ? new FilePlanRoleCapabilityGroup(input.group) : undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export class FilePlanRoleCapabilityGroup {
|
||||
id: string;
|
||||
title: string;
|
||||
|
||||
constructor(input?: Partial<FilePlanRoleCapabilityGroup>) {
|
||||
if (input) {
|
||||
Object.assign(this, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FilePlanRole } from './filePlanRole';
|
||||
|
||||
export class FilePlanRoleEntry {
|
||||
entry: FilePlanRole;
|
||||
|
||||
constructor(input?: Partial<FilePlanRoleEntry>) {
|
||||
if (input) {
|
||||
Object.assign(this, input);
|
||||
this.entry = input.entry ? new FilePlanRole(input.entry) : undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FilePlanRolePagingList } from './filePlanRolePagingList';
|
||||
|
||||
export class FilePlanRolePaging {
|
||||
list: FilePlanRolePagingList;
|
||||
|
||||
constructor(input: Partial<FilePlanRolePaging>) {
|
||||
if (input) {
|
||||
Object.assign(this, input);
|
||||
this.list = input.list ? new FilePlanRolePagingList(input.list) : undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Pagination } from '../../content-rest-api';
|
||||
import { FilePlanRoleEntry } from './filePlanRoleEntry';
|
||||
|
||||
export class FilePlanRolePagingList {
|
||||
entries: FilePlanRoleEntry[];
|
||||
pagination: Pagination;
|
||||
|
||||
constructor(input: Partial<FilePlanRolePagingList>) {
|
||||
if (input) {
|
||||
Object.assign(this, input);
|
||||
this.pagination = input.pagination ? new Pagination(input.pagination) : undefined;
|
||||
this.entries = input?.entries.map((entry) => new FilePlanRoleEntry(entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FilePlanRoleParametersWhere } from './filePlanRoleParametersWhere';
|
||||
|
||||
export interface FilePlanRoleParameters {
|
||||
where?: FilePlanRoleParametersWhere;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export interface FilePlanRoleParametersWhere {
|
||||
personId?: string;
|
||||
capabilityNames?: string[];
|
||||
}
|
||||
@@ -19,6 +19,14 @@ export * from './filePlan';
|
||||
export * from './filePlanBodyUpdate';
|
||||
export * from './filePlanComponentBodyUpdate';
|
||||
export * from './filePlanEntry';
|
||||
export * from './filePlanRole';
|
||||
export * from './filePlanRoleCapability';
|
||||
export * from './filePlanRoleCapabilityGroup';
|
||||
export * from './filePlanRoleEntry';
|
||||
export * from './filePlanRolePaging';
|
||||
export * from './filePlanRolePagingList';
|
||||
export * from './filePlanRoleParameters';
|
||||
export * from './filePlanRoleParametersWhere';
|
||||
export * from './rMNodeBodyCreate';
|
||||
export * from './rMNodeBodyCreateWithRelativePath';
|
||||
export * from './rMSite';
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { EcmAuthMock, FilePlansMock } from '../mockObjects';
|
||||
import { AlfrescoApi, FilePlanRolePaging, FilePlansApi } from '../../src';
|
||||
|
||||
describe('FilePlansApi', () => {
|
||||
let filePlansApiMock: FilePlansMock;
|
||||
let filePlansApi: FilePlansApi;
|
||||
|
||||
beforeEach(async () => {
|
||||
const hostEcm = 'https://127.0.0.1:8080';
|
||||
const authResponseMock = new EcmAuthMock(hostEcm);
|
||||
authResponseMock.get201Response();
|
||||
filePlansApiMock = new FilePlansMock(hostEcm);
|
||||
const alfrescoApi = new AlfrescoApi({
|
||||
hostEcm
|
||||
});
|
||||
filePlansApi = new FilePlansApi(alfrescoApi);
|
||||
await alfrescoApi.login('admin', 'admin');
|
||||
});
|
||||
|
||||
describe('getFilePlanRoles', () => {
|
||||
const filePlanId = 'filePlanId123';
|
||||
|
||||
let expectedRolePaging: FilePlanRolePaging;
|
||||
|
||||
beforeEach(() => {
|
||||
expectedRolePaging = {
|
||||
list: {
|
||||
pagination: {
|
||||
count: 2,
|
||||
hasMoreItems: false,
|
||||
totalItems: 2,
|
||||
skipCount: 0,
|
||||
maxItems: 100
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
entry: {
|
||||
displayLabel: 'Role One',
|
||||
groupShortName: 'group short name 1',
|
||||
name: 'role1',
|
||||
roleGroupName: 'role group name 1',
|
||||
capabilities: [
|
||||
{
|
||||
index: 0,
|
||||
name: 'capability1',
|
||||
title: 'Capability One',
|
||||
group: {
|
||||
id: 'group1',
|
||||
title: 'Group One'
|
||||
}
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
name: 'capability2',
|
||||
title: 'Capability Two',
|
||||
group: {
|
||||
id: 'group2',
|
||||
title: 'Group Two'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
entry: {
|
||||
displayLabel: 'Role Two',
|
||||
groupShortName: 'group short name 2',
|
||||
name: 'role2',
|
||||
roleGroupName: 'role group name 2',
|
||||
capabilities: [
|
||||
{
|
||||
index: 0,
|
||||
name: 'capability3',
|
||||
title: 'Capability Three',
|
||||
group: {
|
||||
id: 'group3',
|
||||
title: 'Group Three'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('should get file plan roles', (done) => {
|
||||
filePlansApiMock.get200FilePlanRoles(filePlanId);
|
||||
|
||||
filePlansApi.getFilePlanRoles(filePlanId).then((rolePaging) => {
|
||||
expect(rolePaging).toEqual(expectedRolePaging);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get file plan roles with filtering by capability names', (done) => {
|
||||
filePlansApiMock.get200FilePlanRolesWithFilteringByCapabilityNames(filePlanId);
|
||||
|
||||
filePlansApi
|
||||
.getFilePlanRoles(filePlanId, {
|
||||
where: {
|
||||
capabilityNames: ['capability1', 'capability2']
|
||||
}
|
||||
})
|
||||
.then((rolePaging) => {
|
||||
expect(rolePaging).toEqual(expectedRolePaging);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get file plan roles with filtering by person id', (done) => {
|
||||
filePlansApiMock.get200FilePlanRolesWithFilteringByPersonId(filePlanId);
|
||||
|
||||
filePlansApi
|
||||
.getFilePlanRoles(filePlanId, {
|
||||
where: {
|
||||
personId: 'someUser'
|
||||
}
|
||||
})
|
||||
.then((rolePaging) => {
|
||||
expect(rolePaging).toEqual(expectedRolePaging);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get file plan roles with filtering by capability names', (done) => {
|
||||
filePlansApiMock.get200FilePlanRolesWithFilteringByPersonIdAndCapabilityNames(filePlanId);
|
||||
|
||||
filePlansApi
|
||||
.getFilePlanRoles(filePlanId, {
|
||||
where: {
|
||||
personId: 'someUser',
|
||||
capabilityNames: ['capability1', 'capability2']
|
||||
}
|
||||
})
|
||||
.then((rolePaging) => {
|
||||
expect(rolePaging).toEqual(expectedRolePaging);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,117 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BaseMock } from '../base.mock';
|
||||
import nock from 'nock';
|
||||
import { FilePlanRolePaging } from '@alfresco/js-api';
|
||||
|
||||
export class FilePlansMock extends BaseMock {
|
||||
get200FilePlanRoles(filePlanId: string): void {
|
||||
this.nock200FilePlanRoles(filePlanId).query({}).reply(200, this.mockFilePlanRolePaging());
|
||||
}
|
||||
|
||||
get200FilePlanRolesWithFilteringByCapabilityNames(filePlanId: string): void {
|
||||
this.nock200FilePlanRoles(filePlanId)
|
||||
.query({
|
||||
where: "(capabilityName in ('capability1', 'capability2'))"
|
||||
})
|
||||
.reply(200, this.mockFilePlanRolePaging());
|
||||
}
|
||||
|
||||
get200FilePlanRolesWithFilteringByPersonId(filePlanId: string): void {
|
||||
this.nock200FilePlanRoles(filePlanId)
|
||||
.query({
|
||||
where: "(personId='someUser')"
|
||||
})
|
||||
.reply(200, this.mockFilePlanRolePaging());
|
||||
}
|
||||
|
||||
get200FilePlanRolesWithFilteringByPersonIdAndCapabilityNames(filePlanId: string): void {
|
||||
this.nock200FilePlanRoles(filePlanId)
|
||||
.query({
|
||||
where: "(personId='someUser' and capabilityName in ('capability1', 'capability2'))"
|
||||
})
|
||||
.reply(200, this.mockFilePlanRolePaging());
|
||||
}
|
||||
|
||||
private nock200FilePlanRoles(filePlanId: string): nock.Interceptor {
|
||||
return nock(this.host, { encodedQueryParams: true }).get(`/alfresco/api/-default-/public/gs/versions/1/file-plans/${filePlanId}/roles`);
|
||||
}
|
||||
|
||||
private mockFilePlanRolePaging(): FilePlanRolePaging {
|
||||
return {
|
||||
list: {
|
||||
pagination: {
|
||||
count: 2,
|
||||
hasMoreItems: false,
|
||||
totalItems: 2,
|
||||
skipCount: 0,
|
||||
maxItems: 100
|
||||
},
|
||||
entries: [
|
||||
{
|
||||
entry: {
|
||||
displayLabel: 'Role One',
|
||||
groupShortName: 'group short name 1',
|
||||
name: 'role1',
|
||||
roleGroupName: 'role group name 1',
|
||||
capabilities: [
|
||||
{
|
||||
index: 0,
|
||||
name: 'capability1',
|
||||
title: 'Capability One',
|
||||
group: {
|
||||
id: 'group1',
|
||||
title: 'Group One'
|
||||
}
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
name: 'capability2',
|
||||
title: 'Capability Two',
|
||||
group: {
|
||||
id: 'group2',
|
||||
title: 'Group Two'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
entry: {
|
||||
displayLabel: 'Role Two',
|
||||
groupShortName: 'group short name 2',
|
||||
name: 'role2',
|
||||
roleGroupName: 'role group name 2',
|
||||
capabilities: [
|
||||
{
|
||||
index: 0,
|
||||
name: 'capability3',
|
||||
title: 'Capability Three',
|
||||
group: {
|
||||
id: 'group3',
|
||||
title: 'Group Three'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ export * from './content-services/version.mock';
|
||||
export * from './content-services/webscript.mock';
|
||||
|
||||
export * from './goverance-services/authority-clearance.mock';
|
||||
export * from './goverance-services/file-plans.mock';
|
||||
export * from './goverance-services/gs-sites.mock';
|
||||
export * from './goverance-services/node-security-marks.mock';
|
||||
export * from './goverance-services/security-groups.mock';
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
&-container {
|
||||
display: flex;
|
||||
|
||||
@@ -670,17 +670,41 @@ describe('FormCloudComponent', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
const formValues: any[] = [];
|
||||
const formValues: TaskVariableCloud[] = [
|
||||
{
|
||||
name: 'var1',
|
||||
value: 'value1',
|
||||
id: 'var1',
|
||||
type: 'string',
|
||||
hasValue: () => true
|
||||
}
|
||||
];
|
||||
|
||||
const change = new SimpleChange(null, formValues, false);
|
||||
formComponent.data = formValues;
|
||||
formComponent.ngOnChanges({ data: change });
|
||||
});
|
||||
|
||||
it('should not change form if custom form values is empty array', () => {
|
||||
const formModel = new FormModel({
|
||||
id: 'id',
|
||||
taskId: 'task-id',
|
||||
fields: [{ id: 'field1' }, { id: 'field2' }]
|
||||
});
|
||||
formComponent.form = formModel;
|
||||
|
||||
const formValues: TaskVariableCloud[] = [];
|
||||
const change = new SimpleChange(null, formValues, false);
|
||||
formComponent.ngOnChanges({ data: change });
|
||||
|
||||
expect(formComponent.form).toEqual(formModel);
|
||||
});
|
||||
|
||||
it('should save task form and raise corresponding event', () => {
|
||||
spyOn(formCloudService, 'saveTaskForm').and.callFake(
|
||||
() =>
|
||||
new Observable((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
@@ -773,7 +797,7 @@ describe('FormCloudComponent', () => {
|
||||
spyOn(formCloudService, 'completeTaskForm').and.callFake(
|
||||
() =>
|
||||
new Observable((observer) => {
|
||||
observer.next();
|
||||
observer.next(undefined);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user