Compare commits

..
41 Commits
Author SHA1 Message Date
Amedeo Lepore cf62196fc4 Release 6.5.2 (#9094) 2023-11-16 13:25:14 +01:00
Amedeo Lepore 22d3179a55 Revert "[AAE-18105] Fix release workflow: release-npm step doesn't publish al…" (#9092)
* Revert "[AAE-18105] Fix release workflow: release-npm step doesn't publish all the  packages (#9091)"

This reverts commit 17323b0abb.

* Fix release workflow: publish always all the libs until we don't handle partial release
2023-11-15 16:46:25 +00:00
Amedeo Lepore 17323b0abb [AAE-18105] Fix release workflow: release-npm step doesn't publish all the packages (#9091) 2023-11-15 16:56:14 +01:00
MichalKinas 81787d5202 [MNT-23166] Add resize flag to document list with option to disable blur (#9090)
* [MNT-23166] Add resize flag to document list with option to disable blur

* [MNT-23166] Missing docs and CR fixes

* [MNT-23166] Lint fixes

* [MNT-23166] Lint fixes

* [MNT-23166] Lint fixes
2023-11-15 14:51:38 +01:00
Amedeo Lepore e5ca7d2069 [AAE-18057] Fix token is not refreshed after silent-refresh is called. Get another token from the auth server. (#9089) 2023-11-15 11:28:05 +00:00
AleksanderSklorz 6787ef4582 [ACS-6225] Removed extra gray area around share link dialog (#9086) 2023-11-14 12:45:13 +01:00
AleksanderSklorz 6988c1f458 [ACS-6067] viewer thumbnails not refresh on file change (#9075)
* ACS-6067 Update thumbnails when file is changed

* ACS-6067 Added unit tests

* ACS-6067 Removed redundant line
2023-11-14 12:44:48 +01:00
MichalKinas 15fdbc7e29 [ACS-4794] ES query migration changes (#8773)
* [ACS-4794] ES query migration changes

* [ACS-4974] Remove * from path as it causes exception

* [ACS-4974] Apply PATH workarounds for PNAME and ANAME

* [ACS-4974] Add custom query to autocomplete options filter

* [ACS-4974] Correct username
2023-11-14 08:23:55 +01:00
Amedeo Lepore e2c116c25a Release 6.5.1 (#9082) 2023-11-13 10:19:15 +01:00
Amedeo Lepore f2df3c4143 [AAE-17909][AAE-17964] fix silent-refresh url is not set with the value - fix background image set to undefined (#9080)
* [AAE-17909] fix silent-refresh url is not set with the value from the app.config.json

* [AAE-17964] fix backgroundImage is undefined, set a default value
2023-11-10 14:19:59 +00:00
Wiktor Danielewski 168bb0b6ca [AAE-17258] Update storybook for datatable and datacolumn (#9052)
* [AAE-17258] Datatable storybook - add boolean type

* [AAE-17258] Datatable storybook - Repair location column

* [AAE-17258] Update location column - storybook

* [AAE-17258] Add boolean column and update data mapping - storybook

* [AAE-17258] Add some comments

* [AAE-17258] Storybook - add image column

* [AAE-17258] Add missing props for DataColumn

* [AAE-17258] Update storybook over the amount column type

* [AAE-17258] Add number column to the Storybook

* [AAE-17258] Storybook simplify json column

* [AAE-17258] Stroybook DataColum refactor

* [AAE-17258] Storybook DataColumn refactor

* [AAE-17258] Update DataColumn with date type

* [AAE-17258] Update Datatable over timeAgo column - Storybook

* [AAE-17258] Small changes

* [AAE-17258] Storybook - simplify DataColumn stories and allow for row updates
2023-11-09 14:17:08 +01:00
Tomasz Gnyp c0194029c7 [AAE-17865] Remove few already covered e2es from ADF (#9078) 2023-11-09 04:44:43 -05:00
Maurizio Vitale 625cf2b85a [ADF-5561] Remove unused dep (#9064) 2023-11-09 04:32:41 -05:00
dependabot[bot] 622cf8bdee build(deps): bump apollo-angular from 4.2.1 to 5.0.2 (#9041)
Bumps [apollo-angular](https://github.com/kamilkisiela/apollo-angular/tree/HEAD/packages/apollo-angular) from 4.2.1 to 5.0.2.
- [Release notes](https://github.com/kamilkisiela/apollo-angular/releases)
- [Changelog](https://github.com/kamilkisiela/apollo-angular/blob/master/packages/apollo-angular/CHANGELOG.md)
- [Commits](https://github.com/kamilkisiela/apollo-angular/commits/apollo-angular@5.0.2/packages/apollo-angular)

---
updated-dependencies:
- dependency-name: apollo-angular
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-09 04:25:30 -05:00
Denys Vuika f0a11fdab0 [ACS-6140] migrate tests to harness (#9071)
* migrate aspect list tests to harness

* [ci:force] categories management

* [ci:force] fix keyboard handling

* [ci:force] fix memory leak

* migrate document list

* migrate new version uploader dialog

* migrate folder dialog

* bug fixes for keyboard, remove fake unit tests

* [ci:force] migrate and cleanup notification tests

* migrate app details cloud

* migrate app list cloud

* migrate group cloud component

* [ci:force] cleanup code based on reviews

* [ci:force] migrate people cloud

* [ci:force] migrate process list cloud

* [ci:force] migrate start process cloud

* [ci:force] task form cloud

* [ci:force] service task list cloud

* [ci:force] task list cloud

* [ci:force] process attachment list and apps list

* [ci:force] code review changes

* [ci:force] app list bug fixes and code cleanup

* [ci:force] fix incorrect/missing typings, fix tests

* [ci:force] code cleanup
2023-11-09 04:24:56 -05:00
Robert Duda 479cc8b545 Release 6.5.0 (#9076) 2023-11-08 15:54:57 +01:00
Davide Cerbo 54fa5d8864 Update init-aae-env.ts (#9073) 2023-11-08 10:01:09 +00:00
Alfresco Buildandtomgny 0891a60f4d [ci:force][auto-commit] Update dependencies JS:7.2.0 (#9069)
Co-authored-by: tomgny <tomgny@users.noreply.github.com>
2023-11-07 15:54:34 +01:00
Amedeo Lepore a01a1b9e9a [AAE-17804] Fix login redirection, add redirectUri from the app.config (#9066)
* [AAE-17804] Fix login redirection, add redirectUri from the app.config

* [AAE-17804] Updated unit tests
2023-11-07 14:34:18 +00:00
Wojciech Duda 34c82f4a49 [AAE-17807] fix for header background color (#9067)
* [AAE-17807] fix for header background color

* [AAE-17807] added unit tests
2023-11-07 13:14:54 +00:00
Michał Fidor 41a788d974 [AAE-17475] Fix process for call activities (#9068) 2023-11-07 13:45:09 +01:00
Alfresco Buildandmauriziovitale 00c05315a2 [ci:force][auto-commit] Update dependencies JS:7.2.0-1490 (#9057)
Co-authored-by: mauriziovitale <mauriziovitale@users.noreply.github.com>
2023-11-07 13:16:37 +01:00
Denys Vuika 10361b9065 fix broken expression code in people cloud (#9065) 2023-11-06 16:43:23 +00:00
08da9ae2c3 [AAE-12501] move auth in ADF (#8689)
* remove unneeded JS-API dep
move auth in the right place

* [AAE-12501] Replace alfresco api client with AdfHttpClient

* [AAE-12501] Restore get username methods

* [AAE-12501] Get username with authentication service

* [AAE-12501] Create a request options interface with the needed props, remove the import from js-api, return the body from request

* add emitters

* [AAE-12501] Replace Math.random() to fix hospot security issue, fix lint issues

* [AAE-12501] Comment temporary setCsrfToken because is not possible to import app config service from core due to circular dependencies

* [AAE-12501] Get disableCsrf from app config serviice when app configuration is loaded

* [AAE-12501] Remove wrong character

* Pass down the requestUrl for request interception
bring back check from js-api
fixing isLogin issues part1
some fix around emit
Narrow access for methods
fix sso username issue
Switch to dynamic service injection
add emitters
move auth inside ADF

* clean

* fix unit test

* fix lint

* Fix exports

* Fix process-services unit tests

* Fix core unit tests

Fix core unit tests

Fix core unit tests

Fix core unit tests

Fix core unit tests

Fix core unit tests

Fix core unit tests

* Fix content-services unit tests: getEcmUsername from authentication service

Fix content-services unit tests: alfresco api service has been replaced by authentication service

* Fix circular dependecies issue importing AppConfigService outside the api entrypoint dir

* Import AuthModule even in not only canary mode to let the e2es run

* Fix authentication unit tests

* Fix unit test '[ECM] should return a ticket undefined after logout'

* Remove AlfrescoApiService is not used anymore

* Fix unit test '[BPM] should return an BPM ticket after the login done': add Basic suffix to basicAuth

* Fix unit tests core

* Fix login errors with the BASIC authentication

* Fix missing onLogin event

* Temporary skip unit tests to check e2es

* Fix login component doesn't add the authorization header

* Fix prefix is undefined

* Fix image is not showed by the alfresco file viewer because alf_ticket is not added to the content url query params, pass ticketEcm to the alfrescoApi configuration used by alfrescoApiClient.ts getAlfTicket()

* Fix C280012: set app prefix before calling content api

* Revert "Fix image is not showed by the alfresco file viewer because alf_ticket is not added to the content url query params, pass ticketEcm to the alfrescoApi configuration used by alfrescoApiClient.ts getAlfTicket()"

This reverts commit afbf086b98d72835aab8b15d4af433efeaac2d3b.

* try to change adf core autoamtion service init

* go back

* grant type password login

* fix

* remove automatic login in reset try

* fix not silent login

* lint happy

* fix

* Update alfresco-api-v2-loader.service.ts

* fixint

* Revert "Temporary skip unit tests to check e2es"

This reverts commit a0adc7e58a001a54442c82952761bff891caa5cd.

* fix modules

* fix app config stream in storing service
fix app config stream for sub property

* fix identity test to use the real service

* fix unit

* fix unit

* fix unit

* remove test that are probably have never been green

* fix

* fix PC

* fix localstorage

* fix

* fix

* fix

* fix

* fix storybook
move e2e in content for versioning
fix lint

* fix

* fix size

* enable log

* some fix for usernames

* remove log

* fix rebase

* [AAE-12502] Restore isKerberosEnabled into authentication service

* subject onLogin

* fix unit

* Fix lint issue

* fix

* Update error message

* Revert change did by https://github.com/Alfresco/alfresco-ng2-components/pull/8689/commits/b79c5d37d69b2d76b33e5561eab2bf5b80c81b9e\#diff-ad85723e21276e05e577bab652c6ab0d243bd0ad54d4cc70ef6e60dc5e635c33L38

* Refresh the browser to wait for the user to click process cloud page

* Remove e2e, the application list is already tested by the app-list-cloud.component.spec.ts https://github.com/Alfresco/alfresco-ng2-components/blob/dev-eromano-AAE-12501-2/lib/process-services-cloud/src/lib/app/components/app-list-cloud.component.spec.ts\#L147

* [12502] Add getUsername method to the AuthenticationService

* [12501] restore mutlipart/form-data header needed by angular http-client to to fix 415 unsupported media type

* Revert "[12501] restore mutlipart/form-data header needed by angular http-client to to fix 415 unsupported media type"

This reverts commit d8c584b94f649b57859d74157ec0861f2ebddebb.

* [12501] fix unsupported upload file on admin-apa, append json content type only calling alfresco api

* [12501] fix unsupported upload file on admin-apa

[12501] fix unsupported upload file on admin-apa

* Revert "[12501] fix unsupported upload file on admin-apa"

This reverts commit 53cda21d795588d87244c78c5a5347afd04ea2b1.

* Improve getHeaders

* Revert change

* Set application/json content type if request body is not a FormData

* Logout by the authenticationService

* Update returned error message

* Fix lint issues after rebasing

* [12502] Add basic template with data-automation-ad selector to check when is attached to the Dom

* Fix issues after rebase

---------

Co-authored-by: Amedeo Lepore <amedeo.lepore@hyland.com>
Co-authored-by: Andras Popovics <popovics@ndras.hu>
2023-11-06 14:25:27 +01:00
Bartosz Sekula 057e0bcd7c [AAE-17746] Remove secret from required prop from app.config.schema.json (#9063) 2023-11-06 13:17:14 +00:00
DominikIwanek bac7cc98e1 [ACS-6210] - ACA column alinement shifted when we have very long file/folder name (#9060) 2023-11-06 06:32:59 -05:00
Bartosz Sekula 7c127eb957 [AAE-17669] Custom theme should use default font (#9062) 2023-11-06 12:31:14 +01:00
Denys Vuika fe8f4a5e74 [ACS-6251] remove dead code and imports from insights (#9059)
* remove dead code and imports from insights

* [ci:force] base class to reduce code duplications

* [ci:force] reduce code by introducing base class

* [ci:force] fix import paths

* [ci:force] fix types

* [ci:force] remove pdf from insights unit tests

* [ci:force] improve test performance

* remove obsolete mock file

* remove deleted export
2023-11-06 06:30:49 -05:00
Michał Fidor adf5a5e008 [AAE-17476] update default app by missing process (#9061) 2023-11-06 10:38:38 +01:00
Wojciech Duda a29f63cd9b [AAE-17551] added backgroundImage property for header (#9058)
* [AAE-17551] added backgroundImage property for header

* [AAE-17551] added test for background image

* [AAE-17551] removed some material selectors

* [AAE-17551] rebasing

* [AAE-17551] fixed unit test
2023-11-04 15:06:11 +01:00
SheenaMalhotra182 94fb61541c [ACS-5311] Notification History Bug Fix (#9011)
* [ACS-5311] implemented read state for notifications and showing only unread notifications in history menu

* [ACS-5311] linting fixes

* [ACS-5311] linting fixes

* [ACS-5311] fixed code smell

* [ACS-5311] addressed review comments

* [ACS-5311] addressed review comments

* [ACS-5311] updated unit tests

* [ACS-5311] addressed review comments and optimized unit tests

* [ACS-5311] linting fix

* [ACS-5311] addressed review comments

* [ACS-5311] fixed typos

* [ACS-5311] moved NOTIFICATION_STORAGE to notification.model.ts to reuse across repos

* [ACS-5311] addressed review comments
2023-11-03 14:41:40 +00:00
dependabot[bot] 3687cc58e0 build(deps): bump trim-newlines and meow (#9055)
Bumps [trim-newlines](https://github.com/sindresorhus/trim-newlines) and [meow](https://github.com/sindresorhus/meow). These dependencies needed to be updated together.

Updates `trim-newlines` from 1.0.0 to 3.0.1
- [Release notes](https://github.com/sindresorhus/trim-newlines/releases)
- [Commits](https://github.com/sindresorhus/trim-newlines/commits)

Updates `meow` from 3.7.0 to 9.0.0
- [Release notes](https://github.com/sindresorhus/meow/releases)
- [Commits](https://github.com/sindresorhus/meow/compare/v3.7.0...v9.0.0)

---
updated-dependencies:
- dependency-name: trim-newlines
  dependency-type: indirect
- dependency-name: meow
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-03 06:06:28 -04:00
Denys Vuika 93fd0bec6c [ACS-6140] reduce access to internal material classes (#9053)
* cleanup login (demo shell)

* cleanup e2e from useless calls

* [ci:force] cleanup e2e from useless calls

* [ci:force] cleanup e2e from useless calls

* [ci:force] improved uploader selectors

* [ci:force] remove useless selectors when automation id provided

* [ci:force] improved tests and selectors

* [ci:force] improved tests and selectors

* [ci:force] improved tests and selectors

* [ci:force] improved tests and selectors

* [ci:force] improved tests and selectors

* [ci:force] improved tests and selectors

* [ci:force] switch edit task filter to angular harness

* [ci:force] switch edit process filter to angular harness

* [ci:force] switch search chip list to angular harness

* [ci:force] switch search panel to angular harness

* [ci:force] switch search radio to angular harness

* [ci:force] switch search text to angular harness

* [ci:force] search logical filter

* [ci:force] search form component

* [ci:force] search filter container

* [ci:force] fix viewer test

* [ci:force] search facet chip harness

* [ci:force] search facet chip harness

* [ci:force] dropdown breadcrumb

* [ci:force] search check list

* [ci:force] folder dialog

* [ci:force] search filter component

* [ci:force] json cell

* [ci:force] amount widget

* [ci:force] checkbox widget

* [ci:force] multiline-text widget

* [ci:force] number widget

* [ci:force] text widget

* [ci:force] card view array item

* add permission dialog

* permission container component

* permission list component

* card view components

* search widget chip

* search facet chip

* edit service task filter

* card view components

* sites dropdown

* share dialog

* header component

* datetime widget

* remove comments
2023-11-03 06:05:34 -04:00
Tomasz Gnyp 9278d9296f [AAE-16965] Improve data table date column (#9038)
* [AAE-16965] Improve Date data table column type

* [AAE-16965] Date unit tests

* update docs

* cleanup cells after implement inject

* bring back removed constructors

* remove empty constructors

* replace constructor token injection by inject function

* [AAE-16965] Use other variable for template

* implement suggestions

* update demo shell module

* fix unit test

* fix timeAgo problem

* add some more unit tests

* fake change in extensions

* [AAE-16965] fix for backward compatibility
2023-11-03 10:31:13 +01:00
Bartosz Sekula 85ddcdf22c Fix missing primary scss variable (#9056)
* Fix missing primary scss variable

* remove test var
2023-11-02 15:47:52 +00:00
Alfresco Buildandmauriziovitale 0b677e7189 [ci:force][auto-commit] Update dependencies JS:7.2.0-1481 (#9028)
Co-authored-by: mauriziovitale <mauriziovitale@users.noreply.github.com>
2023-11-02 14:29:45 +00:00
Eugenio Romano 0b56a4858f [AAE-16579] upgrade nrwl dep solve critical webpack loader-utils issue in develop (#9030)
* upgrade nrwl dep

* fix

* downgrade eslint plugin
2023-11-02 14:11:06 +01:00
tomasz hanaj 15f82c812c [AAE-15296] added design tokens to InfoDrawerComponent (#9051)
* [AAE-15296] added design tokens to InfoDrawerComponent

* [AAE-15296] added access to theme to component variables
2023-11-02 13:10:05 +01:00
Bartosz Sekula 54e95bc5f7 [AAE-16970] Custom colors are not calculating correctly in default UI (#9054) 2023-11-02 11:15:30 +01:00
Wiktor Danielewski 81f0df3da1 [AAE-16995] Code refactor of LocationCellComponent (#9033)
* [AAE-16995] Migrate to standalone

* [AAE-16995] Update Datatable module

* [AAE-16995] Enable hyperlink click

* [AAE-16995] Fix test mistake

* [AAE-16995] Refactor DatatableCell

* [AAE-16995] Refactor LocationCellComponent

* [AAE-16995] Update doc about location cell

* [AAE-16995] Clarify the purpose of location cell

* [AAE-16995] Remove unnecessary check

* [AAE-16995] Align to remarks
2023-10-31 16:51:07 +01:00
Denys Vuika 5d72597d7d [ACS-6245] remove mat-card and internal styling from demo shell (#9050)
* remove mat-card from properties demo

* remove mat-card from demo shell viewer (versions)

* cleanup host settings component in demo shell

* cleanup cloud settings
2023-10-31 10:38:59 -04:00
407 changed files with 15978 additions and 12285 deletions
+188
View File
@@ -0,0 +1,188 @@
module.exports = {
root: true,
ignorePatterns: [
'projects/**/*',
'**/node_modules/**/*',
'lib/cli/node_modules/**/*',
'**/node_modules',
'**/docker',
'**/assets',
'**/scripts',
'**/docs'
],
plugins: ['@nrwl/nx'],
overrides: [
{
files: ['*.ts'],
parserOptions: {
project: ['tsconfig.json', 'e2e/tsconfig.e2e.json'],
createDefaultProgram: true
},
extends: [
'plugin:@nrwl/nx/typescript',
'plugin:@nrwl/nx/angular',
'plugin:@cspell/recommended',
'plugin:@angular-eslint/ng-cli-compat',
'plugin:@angular-eslint/ng-cli-compat--formatting-add-on',
'plugin:@angular-eslint/template/process-inline-templates',
'plugin:jsdoc/recommended-typescript-error'
],
plugins: [
'eslint-plugin-unicorn',
'eslint-plugin-rxjs',
'prettier',
'ban',
'license-header',
'@cspell',
'eslint-plugin-import',
'@angular-eslint/eslint-plugin',
'@typescript-eslint',
'jsdoc'
],
rules: {
// Uncomment this to enable prettier checks as part of the ESLint
// 'prettier/prettier': 'error',
'ban/ban': [
'error',
{ name: 'eval', message: 'Calls to eval is not allowed.' },
{ name: 'fdescribe', message: 'Calls to fdescribe is not allowed' },
{ name: 'fit', message: 'Calls to fit is not allowed' },
{ name: 'xit', message: 'Calls to xit is not allowed' },
{ name: 'xdescribe', message: 'Calls to xdescribe is not allowed' },
{ name: ['test', 'only'], message: 'Calls to test.only is not allowed' },
{ name: ['describe', 'only'], message: 'Calls to describe.only is not allowed' }
],
'@angular-eslint/component-selector': [
'error',
{
type: 'element',
prefix: ['adf', 'app'],
style: 'kebab-case'
}
],
'@angular-eslint/directive-selector': [
'error',
{
type: ['element', 'attribute'],
prefix: ['adf', 'app'],
style: 'kebab-case'
}
],
'@angular-eslint/no-host-metadata-property': 'off',
'@angular-eslint/no-input-prefix': 'error',
'@typescript-eslint/consistent-type-definitions': 'error',
'@typescript-eslint/dot-notation': 'off',
'@typescript-eslint/explicit-member-accessibility': [
'off',
{
accessibility: 'explicit'
}
],
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/prefer-optional-chain': 'warn',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/no-var-requires': 'error',
'@typescript-eslint/naming-convention': [
'error',
{
selector: [
'classProperty',
'objectLiteralProperty',
'typeProperty',
'classMethod',
'objectLiteralMethod',
'typeMethod',
'accessor',
'enumMember'
],
format: null,
modifiers: ['requiresQuotes']
}
],
'@typescript-eslint/member-ordering': 'off',
'prefer-arrow/prefer-arrow-functions': 'off',
'prefer-promise-reject-errors': 'error',
'brace-style': 'off',
'@typescript-eslint/brace-style': 'error',
'comma-dangle': 'error',
'default-case': 'error',
'import/order': 'off',
'max-len': [
'error',
{
code: 240
}
],
'no-bitwise': 'off',
'no-console': [
'error',
{
allow: [
'warn',
'dir',
'timeLog',
'assert',
'clear',
'count',
'countReset',
'group',
'groupEnd',
'table',
'dirxml',
'error',
'groupCollapsed',
'Console',
'profile',
'profileEnd',
'timeStamp',
'context'
]
}
],
'no-duplicate-imports': 'error',
'no-multiple-empty-lines': 'error',
'no-redeclare': 'error',
'no-return-await': 'error',
'rxjs/no-create': 'error',
'rxjs/no-subject-unsubscribe': 'error',
'rxjs/no-subject-value': 'error',
'rxjs/no-unsafe-takeuntil': 'error',
'unicorn/filename-case': 'error',
'@typescript-eslint/no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTernary: true
}
],
'license-header/header': [
'error',
[
'/*!',
' * @license',
' * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.',
' *',
' * Licensed under the Apache License, Version 2.0 (the "License");',
' * you may not use this file except in compliance with the License.',
' * You may obtain a copy of the License at',
' *',
' * http://www.apache.org/licenses/LICENSE-2.0',
' *',
' * Unless required by applicable law or agreed to in writing, software',
' * distributed under the License is distributed on an "AS IS" BASIS,',
' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.',
' * See the License for the specific language governing permissions and',
' * limitations under the License.',
' */'
]
]
}
},
{
files: ['*.html'],
extends: ['plugin:@angular-eslint/template/recommended'],
rules: {}
}
]
};
+3 -2
View File
@@ -60,8 +60,9 @@ runs:
echo "Setting up CI flags for Push develop patch"
else
echo "Setting up CI flags for Push on develop branch"
base=$(git describe --tags $(git rev-list --tags --max-count=1))
echo "NX_CALCULATION_FLAGS=--base=$base --head=$HEAD_HASH" >> $GITHUB_ENV
# base=$(git describe --tags $(git rev-list --tags --max-count=1))
# we publish always all the libs until we don't handle partial release
echo "NX_CALCULATION_FLAGS=--all" >> $GITHUB_ENV
fi
echo "BREAK_ACTION=true" >> $GITHUB_ENV
+1 -1
View File
@@ -153,7 +153,7 @@ runs:
echo $PROXY_HOST_BPM
echo "GIT_HASH=$GIT_HASH" >> $GITHUB_ENV
- name: run test
- name: run test
id: e2e_run
if: ${{ steps.determine-affected.outputs.isAffected == 'true' }}
env:
-9
View File
@@ -392,15 +392,6 @@ jobs:
check-cs-env: "true"
check-ps-cloud-env: "true"
deps: "testing"
- description: "Process Cloud: People"
test-id: "process-services-cloud"
folder: "process-services-cloud/people"
provider: "ALL"
auth: "OAUTH"
apa-proxy: true
check-cs-env: "true"
check-ps-cloud-env: "true"
deps: "testing"
- description: "Process Cloud: Process"
test-id: "process-services-cloud"
folder: "process-services-cloud/process"
+1 -1
View File
@@ -10,7 +10,7 @@
"name": "e2e",
"program": "${workspaceFolder}/node_modules/protractor/bin/protractor",
"args": [
"`${workspaceFolder}/.vscode/closest-config-finder.sh ${file} e2e/protractor.conf.js`",
"./e2e/protractor.conf.js",
"--specs=${file}"
],
"envFile": "${workspaceFolder}/.env",
+3 -4
View File
@@ -1019,11 +1019,10 @@
"prefix": "adf",
"architect": {
"build": {
"builder": "@nrwl/workspace:run-commands",
"builder": "nx:run-commands",
"options": {
"commands": [
"cd lib/cli && npm i && npm run dist"
],
"command":
"cd lib/cli && npm i && npm run dist",
"stylePreprocessorOptions": {
"includePaths": [
"lib", "lib/core/src/lib"
+2 -1
View File
@@ -141,7 +141,8 @@
"webscript",
"Whitespaces",
"xdescribe",
"xsrf"
"xsrf",
"BPMECM"
],
"dictionaries": [
"html",
+1 -1
View File
@@ -25,7 +25,7 @@ const fs = require("fs");
const os = require("os");
const cp = require("child_process");
const isWindows = os.platform() === "win32";
const { output } = require("@nrwl/workspace");
const output = require('nx/src/utils/output').output;
/**
* Paths to files being patched
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "Alfresco-ADF-Angular-Demo",
"description": "Demo shell for Alfresco Angular components",
"version": "6.4.0",
"version": "6.5.2",
"author": "Hyland Software, Inc. and its affiliates",
"repository": {
"type": "git",
+3 -3
View File
@@ -18,11 +18,11 @@
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import {
AuthenticationService,
AlfrescoApiService,
PageTitleService
} from '@alfresco/adf-core';
import { Router } from '@angular/router';
import { MatDialog } from '@angular/material/dialog';
import { AdfHttpClient } from '@alfresco/adf-core/api';
@Component({
selector: 'app-root',
@@ -33,7 +33,7 @@ import { MatDialog } from '@angular/material/dialog';
export class AppComponent implements OnInit {
constructor(private pageTitleService: PageTitleService,
private alfrescoApiService: AlfrescoApiService,
private adfHttpClient: AdfHttpClient,
private authenticationService: AuthenticationService,
private router: Router,
private dialogRef: MatDialog) {
@@ -43,7 +43,7 @@ export class AppComponent implements OnInit {
ngOnInit() {
this.pageTitleService.setTitle('title');
this.alfrescoApiService.getInstance().on('error', (error) => {
this.adfHttpClient.on('error', (error) => {
if (error.status === 401) {
if (!this.authenticationService.isLoggedIn()) {
this.dialogRef.closeAll();
+1 -1
View File
@@ -74,7 +74,7 @@ import { UserInfoComponent } from './components/app-layout/user-info/user-info.c
environment.e2e ? NoopAnimationsModule : BrowserAnimationsModule,
ReactiveFormsModule,
RouterModule.forRoot(appRoutes, { useHash: true, relativeLinkResolution: 'legacy' }),
...(environment.oidc ? [AuthModule.forRoot({ useHash: true })] : []),
AuthModule.forRoot({ useHash: true }),
FormsModule,
HttpClientModule,
MaterialModule,
@@ -17,7 +17,13 @@
import { EcmUserModel, PeopleContentService } from '@alfresco/adf-content-services';
import { BpmUserModel, PeopleProcessService } from '@alfresco/adf-process-services';
import { AuthenticationService, IdentityUserModel, IdentityUserService, UserInfoMode } from '@alfresco/adf-core';
import {
AuthenticationService,
BasicAlfrescoAuthService,
IdentityUserModel,
IdentityUserService,
UserInfoMode
} from '@alfresco/adf-core';
import { Component, OnInit, Input } from '@angular/core';
import { MenuPositionX, MenuPositionY } from '@angular/material/menu';
import { Observable, of } from 'rxjs';
@@ -46,6 +52,7 @@ export class UserInfoComponent implements OnInit {
constructor(private peopleContentService: PeopleContentService,
private peopleProcessService: PeopleProcessService,
private identityUserService: IdentityUserService,
private basicAlfrescoAuthService: BasicAlfrescoAuthService,
private authService: AuthenticationService) {
}
@@ -77,7 +84,7 @@ export class UserInfoComponent implements OnInit {
}
get isLoggedIn(): boolean {
if (this.authService.isKerberosEnabled()) {
if (this.basicAlfrescoAuthService.isKerberosEnabled()) {
return true;
}
return this.authService.isLoggedIn();
@@ -96,15 +103,15 @@ export class UserInfoComponent implements OnInit {
}
private isAllLoggedIn() {
return (this.authService.isEcmLoggedIn() && this.authService.isBpmLoggedIn()) || (this.authService.isALLProvider() && this.authService.isKerberosEnabled());
return (this.authService.isEcmLoggedIn() && this.authService.isBpmLoggedIn()) || (this.authService.isALLProvider() && this.basicAlfrescoAuthService.isKerberosEnabled());
}
private isBpmLoggedIn() {
return this.authService.isBpmLoggedIn() || (this.authService.isECMProvider() && this.authService.isKerberosEnabled());
return this.authService.isBpmLoggedIn() || (this.authService.isECMProvider() && this.basicAlfrescoAuthService.isKerberosEnabled());
}
private isEcmLoggedIn() {
return this.authService.isEcmLoggedIn() || (this.authService.isECMProvider() && this.authService.isKerberosEnabled());
return this.authService.isEcmLoggedIn() || (this.authService.isECMProvider() && this.basicAlfrescoAuthService.isKerberosEnabled());
}
}
@@ -1,17 +1,15 @@
<div class="app-main-content">
<h1>CardView Component</h1>
<mat-card class="app-card-view">
<adf-card-view
[properties]="properties"
[editable]="isEditable"
[displayClearAction]="showClearDateAction"
[displayNoneOption]="showNoneOption"
[displayLabelForChips]="showLabelForChips">
</adf-card-view>
</mat-card>
<adf-card-view
[properties]="properties"
[editable]="isEditable"
[displayClearAction]="showClearDateAction"
[displayNoneOption]="showNoneOption"
[displayLabelForChips]="showLabelForChips">
</adf-card-view>
<div class="app-console" #console>
<div class="app-console">
<h3>Changes log:</h3>
<p *ngFor="let log of logs">{{ log }}</p>
</div>
@@ -2,7 +2,7 @@
padding: 0 15px;
}
.app-card-view {
adf-card-view {
width: 30%;
display: inline-block;
}
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, OnInit, ElementRef, ViewChild, OnDestroy } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import {
CardViewTextItemModel,
CardViewDateItemModel,
@@ -39,9 +39,6 @@ import { takeUntil } from 'rxjs/operators';
styleUrls: ['./card-view.component.scss']
})
export class CardViewComponent implements OnInit, OnDestroy {
@ViewChild('console', { static: true }) console: ElementRef;
isEditable = true;
properties: any;
logs: string[];
@@ -51,8 +48,7 @@ export class CardViewComponent implements OnInit, OnDestroy {
private onDestroy$ = new Subject<boolean>();
constructor(private cardViewUpdateService: CardViewUpdateService,
private decimalNumberPipe: DecimalNumberPipe) {
constructor(private cardViewUpdateService: CardViewUpdateService, private decimalNumberPipe: DecimalNumberPipe) {
this.logs = [];
this.createCard();
}
@@ -62,9 +58,7 @@ export class CardViewComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.cardViewUpdateService.itemUpdated$
.pipe(takeUntil(this.onDestroy$))
.subscribe(this.onItemChange.bind(this));
this.cardViewUpdateService.itemUpdated$.pipe(takeUntil(this.onDestroy$)).subscribe(this.onItemChange.bind(this));
}
ngOnDestroy() {
@@ -192,20 +186,29 @@ export class CardViewComponent implements OnInit, OnDestroy {
}),
new CardViewKeyValuePairsItemModel({
label: 'CardView Key-Value Pairs Item',
value: [{ name: 'hey', value: 'you' }, { name: 'hey', value: 'you' }],
value: [
{ name: 'hey', value: 'you' },
{ name: 'hey', value: 'you' }
],
key: 'key-value-pairs',
editable: this.isEditable
}),
new CardViewKeyValuePairsItemModel({
label: 'CardView Key-Value Pairs Item',
value: [{ name: 'hey', value: 'you' }, { name: 'hey', value: 'you' }],
value: [
{ name: 'hey', value: 'you' },
{ name: 'hey', value: 'you' }
],
key: 'key-value-pairs',
editable: false
}),
new CardViewSelectItemModel({
label: 'CardView Select Item',
value: 'one',
options$: of([{ key: 'one', label: 'One' }, { key: 'two', label: 'Two' }]),
options$: of([
{ key: 'one', label: 'One' },
{ key: 'two', label: 'Two' }
]),
key: 'select',
editable: this.isEditable
}),
@@ -253,7 +256,6 @@ export class CardViewComponent implements OnInit, OnDestroy {
}
this.logs.push(`[${notification.target.label}] - ${value}`);
this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight;
}
toggleEditable() {
@@ -16,7 +16,8 @@
<mat-slide-toggle [checked]="processDetailsRedirection" (change)="toggleProcessDetailsRedirection()" data-automation-id="processDetailsRedirection">
Display process details on process click
</mat-slide-toggle>
<mat-form-field data-automation-id="selectionMode">
<mat-form-field data-automation-id="selectionMode" class="adf-cloud-settings-selection-mode">
<mat-label>Selection Mode</mat-label>
<mat-select [(ngModel)]="selectionMode" (selectionChange)="onSelectionModeChange()">
<mat-option *ngFor="let option of selectionModeOptions" [value]="option.value">
@@ -24,32 +25,29 @@
</mat-option>
</mat-select>
</mat-form-field>
<mat-card *ngIf="actionMenu || contextMenu">
<mat-card-header>
<mat-card-title>Add Action</mat-card-title>
</mat-card-header>
<mat-card-content>
<form class="app-cloud-settings-form" [formGroup]="actionMenuForm">
<mat-form-field>
<input matInput formControlName="key" placeholder="Key">
</mat-form-field>
<mat-form-field>
<input matInput formControlName="title" placeholder="Title">
</mat-form-field>
<mat-form-field>
<input matInput formControlName="icon" placeholder="Icon">
</mat-form-field>
<mat-checkbox formControlName="visible">Visible</mat-checkbox>
<mat-checkbox formControlName="disabled">Disable</mat-checkbox>
<button mat-raised-button (click)="addAction()">Add</button>
</form>
<div *ngIf="actions.length > 0">
<mat-chip-list>
<mat-chip *ngFor="let action of actions" [removable]="true">
{{action.title}}
<mat-icon matChipRemove (click)="removeAction(action)">cancel</mat-icon>
</mat-chip>
</mat-chip-list>
</div>
</mat-card-content>
</mat-card>
<div class="app-cloud-actions" *ngIf="actionMenu || contextMenu">
<h2>Add Action</h2>
<form class="app-cloud-settings-form" [formGroup]="actionMenuForm">
<mat-form-field class="app-cloud-settings-form-input">
<input matInput formControlName="key" placeholder="Key">
</mat-form-field>
<mat-form-field class="app-cloud-settings-form-input">
<input matInput formControlName="title" placeholder="Title">
</mat-form-field>
<mat-form-field class="app-cloud-settings-form-input">
<input matInput formControlName="icon" placeholder="Icon">
</mat-form-field>
<mat-checkbox formControlName="visible">Visible</mat-checkbox>
<mat-checkbox formControlName="disabled">Disable</mat-checkbox>
<button mat-raised-button (click)="addAction()">Add</button>
</form>
<div *ngIf="actions.length > 0">
<mat-chip-list>
<mat-chip *ngFor="let action of actions" [removable]="true">
{{action.title}}
<mat-icon matChipRemove (click)="removeAction(action)">cancel</mat-icon>
</mat-chip>
</mat-chip-list>
</div>
</div>
@@ -4,7 +4,11 @@ app-cloud-settings {
display: flex;
flex: 1;
mat-form-field {
.app-cloud-actions {
background-color: white;
}
.adf-cloud-settings-selection-mode {
max-width: 200px;
}
@@ -13,13 +17,9 @@ app-cloud-settings {
place-content: center space-around;
align-items: center;
mat-form-field {
.app-cloud-settings-form-input {
flex: 1 1 100%;
max-width: 23%;
}
mat-form-field, mat-checkbox {
margin-right: 20px;
}
}
}
@@ -110,14 +110,10 @@
</adf-info-drawer-tab>
<adf-info-drawer-tab label="Versions">
<mat-card>
<mat-card-content>
<adf-version-manager [node]="node"
(uploadError)="onUploadError($event)"
(viewVersion)="onViewVersion($event)">
</adf-version-manager>
</mat-card-content>
</mat-card>
<adf-version-manager [node]="node"
(uploadError)="onUploadError($event)"
(viewVersion)="onViewVersion($event)">
</adf-version-manager>
</adf-info-drawer-tab>
</adf-info-drawer>
</ng-template>
@@ -1,4 +1,4 @@
<a mat-fab class="app-setting-button" data-automation-id="settings" href="" routerLink="/settings">
<a class="app-setting-button" data-automation-id="settings" href="" routerLink="/settings">
<mat-icon>settings</mat-icon>
</a>
@@ -1,6 +1,7 @@
.app-setting-button.mat-fab {
.app-setting-button {
position: absolute;
right: 10px;
top: 10px;
z-index: 1;
color: white;
}
@@ -1,120 +1,106 @@
<div class="adf-setting-container">
<mat-card class="adf-setting-card">
<form id="host-form" [formGroup]="form" (submit)="onSubmit(form.value)" (keydown)="keyDownFunction($event)">
<mat-form-field *ngIf="showSelectProviders">
<mat-select id="adf-provider-selector" [formControl]="providersControl">
<mat-option *ngFor="let provider of providers" [value]="provider">
{{ provider }}
</mat-option>
</mat-select>
<form id="host-form" [formGroup]="form" (submit)="onSubmit(form.value)" (keydown)="keyDownFunction($event)">
<mat-form-field *ngIf="showSelectProviders">
<mat-select id="adf-provider-selector" [formControl]="providersControl">
<mat-option *ngFor="let provider of providers" [value]="provider">
{{ provider }}
</mat-option>
</mat-select>
</mat-form-field>
<div class="adf-authentication-type">
<div>Authentication type:</div>
<mat-radio-group formControlName="authType" class="adf-authentication-radio-group">
<mat-radio-button value="BASIC" class="adf-authentication-radio-button">Basic Authentication</mat-radio-button>
<mat-radio-button value="OAUTH" class="adf-authentication-radio-button">SSO</mat-radio-button>
</mat-radio-group>
</div>
<mat-form-field *ngIf="isALL() || isECM()" class="adf-full-width">
<mat-label>Content Services URL</mat-label>
<input matInput [formControl]="ecmHost" data-automation-id="ecmHost" type="text" id="ecmHost" [placeholder]="PLACEHOLDER_URL">
<mat-error *ngIf="ecmHost.hasError('pattern')">{{ ERR_INVALID_URL }}</mat-error>
<mat-error *ngIf="ecmHost.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<mat-form-field *ngIf="isALL() || isBPM()" class="adf-full-width">
<mat-label>Process Services URL</mat-label>
<input matInput [formControl]="bpmHost" data-automation-id="bpmHost" type="text" id="bpmHost" [placeholder]="PLACEHOLDER_URL">
<mat-error *ngIf="bpmHost.hasError('pattern')">{{ ERR_INVALID_URL }}</mat-error>
<mat-error *ngIf="bpmHost.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<mat-form-field *ngIf="isOAUTH()" class="adf-full-width">
<mat-label>Identity Host</mat-label>
<input matInput name="identityHost" id="identityHost" formControlName="identityHost" [placeholder]="PLACEHOLDER_URL">
<mat-error *ngIf="identityHost.hasError('pattern')">{{ ERR_INVALID_URL }}</mat-error>
<mat-error *ngIf="identityHost.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<div *ngIf="isOAUTH()" formGroupName="oauthConfig">
<mat-form-field class="adf-full-width">
<mat-label>Auth Host</mat-label>
<input matInput name="host" id="oauthHost" formControlName="host" [placeholder]="PLACEHOLDER_URL">
<mat-error *ngIf="host.hasError('pattern')">{{ ERR_INVALID_URL }}</mat-error>
<mat-error *ngIf="host.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<div class="adf-authentication-type">
<div>Authentication type :</div>
<mat-radio-group formControlName="authType" >
<mat-radio-button value="BASIC">Basic Authentication</mat-radio-button>
<mat-radio-button value="OAUTH">SSO</mat-radio-button>
</mat-radio-group>
</div>
<mat-form-field class="adf-full-width">
<mat-label>Client ID</mat-label>
<input matInput name="clientId" id="clientId" formControlName="clientId">
<mat-error *ngIf="clientId.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<ng-container *ngIf="isALL() || isECM()">
<mat-card-content>
<mat-form-field class="adf-full-width">
<mat-label>Content Services URL</mat-label>
<input matInput [formControl]="ecmHost" data-automation-id="ecmHost" type="text" id="ecmHost" [placeholder]="PLACEHOLDER_URL">
<mat-error *ngIf="ecmHost.hasError('pattern')">{{ ERR_INVALID_URL }}</mat-error>
<mat-error *ngIf="ecmHost.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
</mat-card-content>
<mat-form-field class="adf-full-width">
<mat-label>Scope Id</mat-label>
<input matInput name="Scope" formControlName="scope">
<mat-error *ngIf="scope.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<mat-form-field class="adf-full-width">
<mat-label>Secret</mat-label>
<input matInput name="Secret" formControlName="secret">
<mat-error *ngIf="secret.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<mat-label>Silent Login</mat-label>
<mat-slide-toggle class="adf-full-width" name="silentLogin" formControlName="silentLogin">
</mat-slide-toggle>
<mat-label>Implicit Flow</mat-label>
<mat-slide-toggle class="adf-full-width" name="implicitFlow" formControlName="implicitFlow">
</mat-slide-toggle>
<ng-container *ngIf="isOAUTH">
<mat-label>Code Flow</mat-label>
<mat-slide-toggle class="adf-full-width" name="codeFlow" formControlName="codeFlow">
</mat-slide-toggle>
</ng-container>
<ng-container *ngIf="isALL() || isBPM()">
<mat-card-content>
<mat-form-field class="adf-full-width">
<mat-label>Process Services URL</mat-label>
<input matInput [formControl]="bpmHost" data-automation-id="bpmHost" type="text" id="bpmHost" [placeholder]="PLACEHOLDER_URL">
<mat-error *ngIf="bpmHost.hasError('pattern')">{{ ERR_INVALID_URL }}</mat-error>
<mat-error *ngIf="bpmHost.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
</mat-card-content>
</ng-container>
<mat-form-field class="adf-full-width">
<mat-label>Redirect URI</mat-label>
<input matInput name="redirectUri" formControlName="redirectUri">
<mat-error *ngIf="redirectUri.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<ng-container *ngIf="isOAUTH()">
<mat-card-content>
<mat-form-field class="adf-full-width">
<mat-label>Identity Host</mat-label>
<input matInput name="identityHost" id="identityHost" formControlName="identityHost" [placeholder]="PLACEHOLDER_URL">
<mat-error *ngIf="identityHost.hasError('pattern')">{{ ERR_INVALID_URL }}</mat-error>
<mat-error *ngIf="identityHost.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
</mat-card-content>
</ng-container>
<mat-form-field class="adf-full-width">
<mat-label>Redirect URI Logout</mat-label>
<input id="logout-url" matInput name="redirectUriLogout" formControlName="redirectUriLogout">
</mat-form-field>
<ng-container *ngIf="isOAUTH()">
<div formGroupName="oauthConfig">
<mat-form-field class="adf-full-width">
<mat-label>Auth Host</mat-label>
<input matInput name="host" id="oauthHost" formControlName="host" [placeholder]="PLACEHOLDER_URL">
<mat-error *ngIf="host.hasError('pattern')">{{ ERR_INVALID_URL }}</mat-error>
<mat-error *ngIf="host.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<mat-form-field class="adf-full-width">
<mat-label>Public urls silent Login</mat-label>
<input id="public-url" matInput name="publicUrls" formControlName="publicUrls">
</mat-form-field>
</div>
<mat-form-field class="adf-full-width">
<mat-label>Client ID</mat-label>
<input matInput name="clientId" id="clientId" formControlName="clientId">
<mat-error *ngIf="clientId.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<mat-form-field class="adf-full-width">
<mat-label>Scope Id</mat-label>
<input matInput name="Scope" formControlName="scope">
<mat-error *ngIf="scope.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<mat-form-field class="adf-full-width">
<mat-label>Secret</mat-label>
<input matInput name="Secret" formControlName="secret">
<mat-error *ngIf="secret.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<mat-label>Silent Login</mat-label>
<mat-slide-toggle class="adf-full-width" name="silentLogin" formControlName="silentLogin">
</mat-slide-toggle>
<mat-label>Implicit Flow</mat-label>
<mat-slide-toggle class="adf-full-width" name="implicitFlow" formControlName="implicitFlow">
</mat-slide-toggle>
<ng-container *ngIf="supportsCodeFlow">
<mat-label>Code Flow</mat-label>
<mat-slide-toggle class="adf-full-width" name="codeFlow" formControlName="codeFlow">
</mat-slide-toggle>
</ng-container>
<mat-form-field class="adf-full-width">
<mat-label>Redirect URI</mat-label>
<input matInput name="redirectUri" formControlName="redirectUri">
<mat-error *ngIf="redirectUri.hasError('required')">{{ ERR_REQUIRED }}</mat-error>
</mat-form-field>
<mat-form-field class="adf-full-width">
<mat-label>Redirect URI Logout</mat-label>
<input id="logout-url" matInput name="redirectUriLogout" formControlName="redirectUriLogout">
</mat-form-field>
<mat-form-field class="adf-full-width">
<mat-label>Public urls silent Login</mat-label>
<input id="public-url" matInput name="publicUrls" formControlName="publicUrls">
</mat-form-field>
</div>
</ng-container>
<mat-card-actions align="end">
<button mat-button (click)="onCancel()">Back</button>
<button type="submit" class="adf-login-button" mat-button
color="primary" data-automation-id="settings-apply-button"
[disabled]="!form.valid">Apply</button>
</mat-card-actions>
</form>
</mat-card>
<div class="adf-host-settings-actions">
<button mat-button (click)="onCancel()">Back</button>
<button type="submit"
mat-button
color="primary"
data-automation-id="settings-apply-button"
[disabled]="!form.valid">Apply</button>
</div>
</form>
</div>
@@ -3,11 +3,26 @@
min-height: 100%;
align-items: center;
.adf-host-settings-actions {
text-align: end;
}
.adf-authentication-type {
margin-bottom: 20px;
margin-top: 10px;
}
.adf-authentication-radio-group {
display: flex;
flex-direction: column;
margin: 15px 0;
align-items: flex-start;
}
.adf-authentication-radio-button {
margin: 5px;
}
.adf-setting-container {
width: 800px;
display: table;
@@ -65,7 +65,7 @@ export class HostSettingsComponent implements OnInit {
private storageService: StorageService,
private alfrescoApiService: AlfrescoApiService,
private appConfig: AppConfigService,
private auth: AuthenticationService
private authenticationService: AuthenticationService
) {}
ngOnInit() {
@@ -191,8 +191,8 @@ export class HostSettingsComponent implements OnInit {
this.storageService.setItem(AppConfigValues.AUTHTYPE, values.authType);
this.alfrescoApiService.reset();
this.auth.reset();
this.alfrescoApiService.getInstance().invalidateSession();
this.authenticationService.reset();
this.authenticationService.logout();
this.success.emit(true);
}
@@ -235,10 +235,6 @@ export class HostSettingsComponent implements OnInit {
return this.form.get('authType').value === 'OAUTH';
}
get supportsCodeFlow(): boolean {
return this.auth.supportCodeFlow;
}
get providersControl(): UntypedFormControl {
return this.form.get('providersControl') as UntypedFormControl;
}
@@ -19,7 +19,7 @@ import { NgModule } from '@angular/core';
import { TaskListDemoComponent } from './task-list-demo.component';
import { Routes, RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { CoreModule } from '@alfresco/adf-core';
import { CoreModule, LocalizedDatePipe } from '@alfresco/adf-core';
import { ProcessModule } from '@alfresco/adf-process-services';
const routes: Routes = [
@@ -38,7 +38,8 @@ const routes: Routes = [
CommonModule,
RouterModule.forChild(routes),
CoreModule,
ProcessModule.forChild()
ProcessModule.forChild(),
LocalizedDatePipe
],
declarations: [TaskListDemoComponent]
})
@@ -60,6 +60,7 @@ Displays the documents from a repository.
| ---- | ---- | ------------- | ----------- |
| additionalSorting | [`DataSorting`](../../../lib/core/src/lib/datatable/data/data-sorting.model.ts) | | Defines default sorting. The format is an array of strings `[key direction, otherKey otherDirection]` i.e. `['name desc', 'nodeType asc']` or `['name asc']`. Set this value if you want a base rule to be added to the sorting apart from the one driven by the header. |
| allowDropFiles | `boolean` | false | When true, this enables you to drop files directly into subfolders shown as items in the list or into another file to trigger updating it's version. When false, the dropped file will be added to the current folder (ie, the one containing all the items shown in the list). See the [Upload directive](../../core/directives/upload.directive.md) for further details about how the file drop is handled. |
| blurOnResize | `boolean` | true | Toggles blur when columns of the list are being resized. |
| columnsPresetKey | `string` | | Key of columns preset set in extension.json|
| contentActions | `boolean` | false | Toggles content actions for each row |
| contentActionsPosition | `string` | "right" | Position of the content actions dropdown menu. Can be set to "left" or "right". |
@@ -71,6 +72,7 @@ Displays the documents from a repository.
| headerFilters | `boolean` | false | Toggles the header filters mode. |
| imageResolver | `any \| null` | null | Custom function to choose image file paths to show. See the [Image Resolver Model](image-resolver.model.md) page for more information. |
| includeFields | `string[]` | | Include additional information about the node in the server request. For example: association, isLink, isLocked and others. |
| isResizingEnabled | `boolean` | false | Toggles column resizing for document list. |
| loading | `boolean` | false | Toggles the loading state and animated spinners for the component. Used in combination with `navigate=false` to perform custom navigation and loading state indication. |
| locationFormat | `string` | "/" | The default route for all the location-based columns (if declared). |
| maxColumnsVisible | `number` | | Limit of possible visible columns, including "$thumbnail" column if provided |
@@ -63,6 +63,7 @@ Defines column properties for DataTable, Tasklist, Document List and other compo
| order | `number` | | Sets position of column. |
| currencyConfig | `CurrencyConfig` | [Default currency config](#default-currency-config) | Currency configuration to customize the formatting and display of currency values within the component. |
| decimalConfig | `DecimalConfig` | [Default decimal config](#default-decimal-config) | Decimal configuration to customize the formatting and display of decimal values within the component. |
| dateConfig | `DateConfig` | [Default date config](#default-date-config) | Date configuration to customize the formatting and localization of date values within the component. |
## Properties configuration
@@ -72,8 +73,10 @@ The `type` input allows us to specify the type of hosted values for a given colu
- `text` - The given values are represented as a strings (default option).
- `boolean` - The column expects true / false (boolean values) and in addition accepts two strings - 'false' and 'true'. Other values are not recognized by the column, and the cell remains empty.
- `date` - This column is responsible for displaying dates. It expects date represented by a string, number or Date object. This type comes with [`dateConfig`](#default-date-config),
- `amount` - This column is responsible for displaying currencies. It expects numerals represented by a string or a number. This type comes with [`currencyConfig`](#default-currency-config),
- `number` - This column is responsible for displaying numbers (integers and decimals). It expects numerals represented by a string or a number. This type comes with [`decimalConfig`](#default-decimal-config)
- `location` - This column displays a clickable location link pointing to the parent path of the node. **Note:** This type is strongly related to the document list component ([document-list.component.md](../../content-services/components/document-list.component.md)).
### `currencyConfig` Input
@@ -119,6 +122,28 @@ These properties offer flexibility in customizing how decimal values are present
For more details on the possible use cases of the above properties, see the [official Angular documents](https://angular.io/api/common/DecimalPipe).
### `dateConfig` Input
The `dateConfig` input allows you to configure date formatting and localization for a component. It accepts an object of type `DateConfig` with optional properties for specifying the format of displayed date, tooltip and locale.
#### Properties
- `format` (optional): A string specifying the date format ([pre-defined formats](https://angular.io/api/common/DatePipe#pre-defined-format-options)).
- `tooltipFormat` (optional): A string specifying the date format for tooltips.
- `locale` (optional): A string indicating the locale or region-specific formatting to use for the currency.
#### Default date config
By default, the `dateConfig` object is not required. If not provided, the component will use the following default values:
- `format`: "medium"
- `tooltipFormat`: "medium"
- `locale`: undefined
These properties offer flexibility in customizing how date values are presented within the component.
For more details on the possible use cases of the above properties, see the [official Angular documents](https://angular.io/api/common/DatePipe).
## Details
### Conditional visibility
@@ -423,6 +423,7 @@ Learm more about styling your datatable: [Customizing the component's styles](#c
| actionsPosition | `string` | "right" | Position of the actions dropdown menu. Can be "left" or "right". |
| actionsVisibleOnHover | `boolean` | false | Toggles whether the actions dropdown should only be visible if the row is hovered over or the dropdown menu is open. |
| allowFiltering | `boolean` | false | Flag that indicate if the datatable allow the use [facet widget](../../../lib/content-services/src/lib/search/models/facet-widget.interface.ts) search for filtering. |
| blurOnResize | `boolean` | true | Toggles blur when columns of the datatable are being resized. |
| columns | `any[]` | \[] | The columns that the datatable will show. |
| contextMenu | `boolean` | false | Toggles custom context menu for the component. |
| data | [`DataTableAdapter`](../../../lib/core/src/lib/datatable/data/datatable-adapter.ts) | | Data source for the table |
+3
View File
@@ -41,3 +41,6 @@ The pages linked below contain the licenses for all third party dependencies of
- [ADF 6.2.0](license-info-6.2.0.md)
- [ADF 6.3.0](license-info-6.3.0.md)
- [ADF 6.4.0](license-info-6.4.0.md)
- [ADF 6.5.0](license-info-6.5.0.md)
- [ADF 6.5.1](license-info-6.5.1.md)
- [ADF 6.5.2](license-info-6.5.2.md)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+3
View File
@@ -9,6 +9,9 @@ The first **General Availability** release was v2.0.0.
## General Availability
- [6.5.2](RelNote-6.5.2.md)
- [6.5.1](RelNote-6.5.1.md)
- [6.5.0](RelNote-6.5.0.md)
- [6.4.0](RelNote-6.4.0.md)
- [6.3.0](RelNote-6.3.0.md)
- [6.2.0](RelNote-6.2.0.md)
+71
View File
@@ -0,0 +1,71 @@
---
Title: Release notes v6.5.0
---
# Alfresco Application Development Framework (ADF) version 6.5.0 Release Note
This document provides information on the Alfresco Application Development Framework **v6.5.0**.
You can find release artifacts on [GitHub](https://github.com/Alfresco/alfresco-ng2-components/releases/tag/6.5.0).
## Contents
- [New Package Versions](#new-package-versions)
- [Features](#features)
- [Changelog](#changelog)
- [See Also](#see-also)
## New Package Versions
| Name | Version |
|--------------------------------|---------|
| @alfresco/js-api | 7.2.0 |
| @alfresco/adf-content-services | 6.5.0 |
| @alfresco/adf-process-services | 6.5.0 |
| @alfresco/adf-core | 6.5.0 |
| @alfresco/adf-insights | 6.5.0 |
| @alfresco/adf-extensions | 6.5.0 |
| @alfresco/adf-testing | 6.5.0 |
| @alfresco/adf-cli | 6.5.0 |
## Features
The suggested stack is:
| Name | Version |
|------------|---------|
| Node | 18.x |
| npm | 8.x |
| Angular | 14.x |
| Typescript | 4.7 |
For a complete list of changes, supported browsers and new feature please refer to the official documentation
## Changelog
- [54fa5d886](https://github.com/Alfresco/alfresco-ng2-components/commit/54fa5d886) Update init-aae-env.ts (#9073)
- [a01a1b9e9](https://github.com/Alfresco/alfresco-ng2-components/commit/a01a1b9e9) [AAE-17804] Fix login redirection, add redirectUri from the app.config (#9066)
- [34c82f4a4](https://github.com/Alfresco/alfresco-ng2-components/commit/34c82f4a4) [AAE-17807] fix for header background color (#9067)
- [41a788d97](https://github.com/Alfresco/alfresco-ng2-components/commit/41a788d97) [AAE-17475] Fix process for call activities (#9068)
- [10361b906](https://github.com/Alfresco/alfresco-ng2-components/commit/10361b906) fix broken expression code in people cloud (#9065)
- [08da9ae2c](https://github.com/Alfresco/alfresco-ng2-components/commit/08da9ae2c) [AAE-12501] move auth in ADF (#8689)
- [057e0bcd7](https://github.com/Alfresco/alfresco-ng2-components/commit/057e0bcd7) [AAE-17746] Remove secret from required prop from app.config.schema.json (#9063)
- [bac7cc98e](https://github.com/Alfresco/alfresco-ng2-components/commit/bac7cc98e) [ACS-6210] - ACA column alinement shifted when we have very long file/folder name (#9060)
- [7c127eb95](https://github.com/Alfresco/alfresco-ng2-components/commit/7c127eb95) [AAE-17669] Custom theme should use default font (#9062)
- [fe8f4a5e7](https://github.com/Alfresco/alfresco-ng2-components/commit/fe8f4a5e7) [ACS-6251] remove dead code and imports from insights (#9059)
- [adf5a5e00](https://github.com/Alfresco/alfresco-ng2-components/commit/adf5a5e00) [AAE-17476] update default app by missing process (#9061)
- [a29f63cd9](https://github.com/Alfresco/alfresco-ng2-components/commit/a29f63cd9) [AAE-17551] added backgroundImage property for header (#9058)
- [94fb61541](https://github.com/Alfresco/alfresco-ng2-components/commit/94fb61541) [ACS-5311] Notification History Bug Fix (#9011)
- [93fd0bec6](https://github.com/Alfresco/alfresco-ng2-components/commit/93fd0bec6) [ACS-6140] reduce access to internal material classes (#9053)
- [9278d9296](https://github.com/Alfresco/alfresco-ng2-components/commit/9278d9296) [AAE-16965] Improve data table date column (#9038)
- [85ddcdf22](https://github.com/Alfresco/alfresco-ng2-components/commit/85ddcdf22) Fix missing primary scss variable (#9056)
- [0b56a4858](https://github.com/Alfresco/alfresco-ng2-components/commit/0b56a4858) [AAE-16579] upgrade nrwl dep solve critical webpack loader-utils issue in develop (#9030)
- [15f82c812](https://github.com/Alfresco/alfresco-ng2-components/commit/15f82c812) [AAE-15296] added design tokens to InfoDrawerComponent (#9051)
- [54e95bc5f](https://github.com/Alfresco/alfresco-ng2-components/commit/54e95bc5f) [AAE-16970] Custom colors are not calculating correctly in default UI (#9054)
- [81f0df3da](https://github.com/Alfresco/alfresco-ng2-components/commit/81f0df3da) [AAE-16995] Code refactor of LocationCellComponent (#9033)
- [5d72597d7](https://github.com/Alfresco/alfresco-ng2-components/commit/5d72597d7) [ACS-6245] remove mat-card and internal styling from demo shell (#9050)
## See Also
- [Issue Tracker](https://github.com/Alfresco/alfresco-ng2-components/issues/new)
- [Discussion forum](http://gitter.im/Alfresco/alfresco-ng2-components)
+27
View File
@@ -0,0 +1,27 @@
---
Title: Release notes v6.5.1
---
# Alfresco Application Development Framework (ADF) version 6.5.1 Release Note
This document provides information on the Alfresco Application Development Framework **v6.5.1**.
You can find release artifacts on [GitHub](https://github.com/Alfresco/alfresco-ng2-components/releases/tag/6.5.1).
## Contents
- [Changelog](#changelog)
- [See Also](#see-also)
## Changelog
- [f2df3c414](git@github.com:Alfresco/alfresco-ng2-components/commit/f2df3c414) [AAE-17909][AAE-17964] fix silent-refresh url is not set with the value - fix background image set to undefined (#9080)
- [168bb0b6c](git@github.com:Alfresco/alfresco-ng2-components/commit/168bb0b6c) [AAE-17258] Update storybook for datatable and datacolumn (#9052)
- [c0194029c](git@github.com:Alfresco/alfresco-ng2-components/commit/c0194029c) [AAE-17865] Remove few already covered e2es from ADF (#9078)
- [625cf2b85](git@github.com:Alfresco/alfresco-ng2-components/commit/625cf2b85) [ADF-5561] Remove unused dep (#9064)
- [f0a11fdab](git@github.com:Alfresco/alfresco-ng2-components/commit/f0a11fdab) [ACS-6140] migrate tests to harness (#9071)
## See Also
- [Issue Tracker](https://github.com/Alfresco/alfresco-ng2-components/issues/new)
- [Discussion forum](http://gitter.im/Alfresco/alfresco-ng2-components)
+29
View File
@@ -0,0 +1,29 @@
---
Title: Release notes v6.5.2
---
# Alfresco Application Development Framework (ADF) version 6.5.2 Release Note
This document provides information on the Alfresco Application Development Framework **v6.5.2**.
You can find release artifacts on [GitHub](https://github.com/Alfresco/alfresco-ng2-components/releases/tag/6.5.2).
## Contents
- [Changelog](#changelog)
- [See Also](#see-also)
## Changelog
- [22d3179a5](git@github.com:Alfresco/alfresco-ng2-components/commit/22d3179a5) Revert &#34;[AAE-18105] Fix release workflow: release-npm step doesn&#39;t publish al…&#34; (#9092)
- [17323b0ab](git@github.com:Alfresco/alfresco-ng2-components/commit/17323b0ab) [AAE-18105] Fix release workflow: release-npm step doesn&#39;t publish all the packages (#9091)
- [81787d520](git@github.com:Alfresco/alfresco-ng2-components/commit/81787d520) [MNT-23166] Add resize flag to document list with option to disable blur (#9090)
- [e5ca7d206](git@github.com:Alfresco/alfresco-ng2-components/commit/e5ca7d206) [AAE-18057] Fix token is not refreshed after silent-refresh is called. Get another token from the auth server. (#9089)
- [6787ef458](git@github.com:Alfresco/alfresco-ng2-components/commit/6787ef458) [ACS-6225] Removed extra gray area around share link dialog (#9086)
- [6988c1f45](git@github.com:Alfresco/alfresco-ng2-components/commit/6988c1f45) [ACS-6067] viewer thumbnails not refresh on file change (#9075)
- [15fdbc7e2](git@github.com:Alfresco/alfresco-ng2-components/commit/15fdbc7e2) [ACS-4794] ES query migration changes (#8773)
## See Also
- [Issue Tracker](https://github.com/Alfresco/alfresco-ng2-components/issues/new)
- [Discussion forum](http://gitter.im/Alfresco/alfresco-ng2-components)
+3
View File
@@ -38,3 +38,6 @@ The pages linked below contain the audit for all third party dependencies of ADF
- [ADF 6.2.0](audit-info-6.2.0.md)
- [ADF 6.3.0](audit-info-6.3.0.md)
- [ADF 6.4.0](audit-info-6.4.0.md)
- [ADF 6.5.0](audit-info-6.5.0.md)
- [ADF 6.5.1](audit-info-6.5.1.md)
- [ADF 6.5.2](audit-info-6.5.2.md)
+52
View File
@@ -0,0 +1,52 @@
---
Title: Audit info, alfresco-ng2-components 6.5.0
---
# Audit information for alfresco-ng2-components 6.5.0
This page lists the security audit of the dependencies this project depends on.
## Risks
- Critical risk: 0
- High risk: 17
- Moderate risk: 12
- Low risk: 0
Dependencies analyzed:
## Libraries
| Severity | Module | Vulnerable versions |
| --- | --- | --- |
|high | @mdx-js/mdx | &#34;&lt;=1.6.22&#34; |
|moderate | @storybook/builder-webpack4 | &#34;*&#34; |
|high | @storybook/core-server | &#34;&lt;=7.0.0-rc.11&#34; |
|high | @storybook/csf-tools | &#34;6.5.0-alpha.1 - 6.5.17-alpha.0&#34; |
|moderate | @storybook/manager-webpack4 | &#34;*&#34; |
|high | @storybook/mdx1-csf | &#34;*&#34; |
|moderate | autoprefixer | &#34;1.0.20131222 - 9.8.8&#34; |
|high | chokidar | &#34;1.0.0-rc1 - 2.1.8&#34; |
|high | cpy | &#34;7.0.0 - 8.1.2&#34; |
|moderate | css-loader | &#34;0.15.0 - 4.3.0&#34; |
|high | fast-glob | &#34;&lt;=2.2.7&#34; |
|high | glob-parent | &#34;&lt;5.1.2&#34; |
|high | globby | &#34;8.0.0 - 9.2.0&#34; |
|moderate | icss-utils | &#34;&lt;=4.1.1&#34; |
|high | meow | &#34;3.4.0 - 5.0.0&#34; |
|moderate | postcss | &#34;&lt;8.4.31&#34; |
|moderate | postcss-flexbugs-fixes | &#34;&lt;=4.2.1&#34; |
|moderate | postcss-modules-extract-imports | &#34;&lt;=2.0.0&#34; |
|moderate | postcss-modules-local-by-default | &#34;&lt;=4.0.0-rc.4&#34; |
|moderate | postcss-modules-scope | &#34;&lt;=2.2.0&#34; |
|moderate | postcss-modules-values | &#34;&lt;=4.0.0-rc.5&#34; |
|high | remark-mdx | &#34;&lt;=1.6.22&#34; |
|high | remark-parse | &#34;&lt;=8.0.3&#34; |
|moderate | semver | &#34;7.0.0 - 7.5.1&#34; |
|high | trim | &#34;&lt;0.0.3&#34; |
|high | trim-newlines | &#34;&lt;3.0.1&#34; |
|high | watchpack | &#34;1.7.2 - 1.7.5&#34; |
|high | watchpack-chokidar2 | &#34;*&#34; |
|high | webpack | &#34;4.44.0 - 4.47.0&#34; |
+52
View File
@@ -0,0 +1,52 @@
---
Title: Audit info, alfresco-ng2-components 6.5.1
---
# Audit information for alfresco-ng2-components 6.5.1
This page lists the security audit of the dependencies this project depends on.
## Risks
- Critical risk: 0
- High risk: 17
- Moderate risk: 12
- Low risk: 0
Dependencies analyzed:
## Libraries
| Severity | Module | Vulnerable versions |
| --- | --- | --- |
|high | @mdx-js/mdx | &#34;&lt;=1.6.22&#34; |
|moderate | @storybook/builder-webpack4 | &#34;*&#34; |
|high | @storybook/core-server | &#34;&lt;=7.0.0-rc.11&#34; |
|high | @storybook/csf-tools | &#34;6.5.0-alpha.1 - 6.5.17-alpha.0&#34; |
|moderate | @storybook/manager-webpack4 | &#34;*&#34; |
|high | @storybook/mdx1-csf | &#34;*&#34; |
|moderate | autoprefixer | &#34;1.0.20131222 - 9.8.8&#34; |
|high | chokidar | &#34;1.0.0-rc1 - 2.1.8&#34; |
|high | cpy | &#34;7.0.0 - 8.1.2&#34; |
|moderate | css-loader | &#34;0.15.0 - 4.3.0&#34; |
|high | fast-glob | &#34;&lt;=2.2.7&#34; |
|high | glob-parent | &#34;&lt;5.1.2&#34; |
|high | globby | &#34;8.0.0 - 9.2.0&#34; |
|moderate | icss-utils | &#34;&lt;=4.1.1&#34; |
|high | meow | &#34;3.4.0 - 5.0.0&#34; |
|moderate | postcss | &#34;&lt;8.4.31&#34; |
|moderate | postcss-flexbugs-fixes | &#34;&lt;=4.2.1&#34; |
|moderate | postcss-modules-extract-imports | &#34;&lt;=2.0.0&#34; |
|moderate | postcss-modules-local-by-default | &#34;&lt;=4.0.0-rc.4&#34; |
|moderate | postcss-modules-scope | &#34;&lt;=2.2.0&#34; |
|moderate | postcss-modules-values | &#34;&lt;=4.0.0-rc.5&#34; |
|high | remark-mdx | &#34;&lt;=1.6.22&#34; |
|high | remark-parse | &#34;&lt;=8.0.3&#34; |
|moderate | semver | &#34;7.0.0 - 7.5.1&#34; |
|high | trim | &#34;&lt;0.0.3&#34; |
|high | trim-newlines | &#34;&lt;3.0.1&#34; |
|high | watchpack | &#34;1.7.2 - 1.7.5&#34; |
|high | watchpack-chokidar2 | &#34;*&#34; |
|high | webpack | &#34;4.44.0 - 4.47.0&#34; |
+52
View File
@@ -0,0 +1,52 @@
---
Title: Audit info, alfresco-ng2-components 6.5.2
---
# Audit information for alfresco-ng2-components 6.5.2
This page lists the security audit of the dependencies this project depends on.
## Risks
- Critical risk: 0
- High risk: 17
- Moderate risk: 12
- Low risk: 0
Dependencies analyzed:
## Libraries
| Severity | Module | Vulnerable versions |
| --- | --- | --- |
|high | @mdx-js/mdx | &#34;&lt;=1.6.22&#34; |
|moderate | @storybook/builder-webpack4 | &#34;*&#34; |
|high | @storybook/core-server | &#34;&lt;=7.0.0-rc.11&#34; |
|high | @storybook/csf-tools | &#34;6.5.0-alpha.1 - 6.5.17-alpha.0&#34; |
|moderate | @storybook/manager-webpack4 | &#34;*&#34; |
|high | @storybook/mdx1-csf | &#34;*&#34; |
|moderate | autoprefixer | &#34;1.0.20131222 - 9.8.8&#34; |
|high | chokidar | &#34;1.0.0-rc1 - 2.1.8&#34; |
|high | cpy | &#34;7.0.0 - 8.1.2&#34; |
|moderate | css-loader | &#34;0.15.0 - 4.3.0&#34; |
|high | fast-glob | &#34;&lt;=2.2.7&#34; |
|high | glob-parent | &#34;&lt;5.1.2&#34; |
|high | globby | &#34;8.0.0 - 9.2.0&#34; |
|moderate | icss-utils | &#34;&lt;=4.1.1&#34; |
|high | meow | &#34;3.4.0 - 5.0.0&#34; |
|moderate | postcss | &#34;&lt;8.4.31&#34; |
|moderate | postcss-flexbugs-fixes | &#34;&lt;=4.2.1&#34; |
|moderate | postcss-modules-extract-imports | &#34;&lt;=2.0.0&#34; |
|moderate | postcss-modules-local-by-default | &#34;&lt;=4.0.0-rc.4&#34; |
|moderate | postcss-modules-scope | &#34;&lt;=2.2.0&#34; |
|moderate | postcss-modules-values | &#34;&lt;=4.0.0-rc.5&#34; |
|high | remark-mdx | &#34;&lt;=1.6.22&#34; |
|high | remark-parse | &#34;&lt;=8.0.3&#34; |
|moderate | semver | &#34;7.0.0 - 7.5.1&#34; |
|high | trim | &#34;&lt;0.0.3&#34; |
|high | trim-newlines | &#34;&lt;3.0.1&#34; |
|high | watchpack | &#34;1.7.2 - 1.7.5&#34; |
|high | watchpack-chokidar2 | &#34;*&#34; |
|high | webpack | &#34;4.44.0 - 4.47.0&#34; |
@@ -21,7 +21,7 @@ import { ContentServicesPage } from '../../core/pages/content-services.page';
import { FileModel } from '../../models/ACS/file.model';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
import { VersionManagePage } from '../pages/version-manager.page';
import { MetadataViewPage } from '../pages/metadata-view.page';
import { MetadataViewPage } from '../../core/pages/metadata-view.page';
describe('Content Services Viewer', () => {
const acsUser = new UserModel();
@@ -0,0 +1,94 @@
/*!
* @license
* Copyright © 2005-2023 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 { browser } from 'protractor';
import { createApiService, FileBrowserUtil, LoginPage, UploadActions, UserModel, UsersActions, ViewerPage } from '@alfresco/adf-testing';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { FileModel } from '../../models/ACS/file.model';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
import { VersionManagePage } from '../pages/version-manager.page';
describe('Viewer', () => {
const navigationBarPage = new NavigationBarPage();
const viewerPage = new ViewerPage();
const loginPage = new LoginPage();
const contentServicesPage = new ContentServicesPage();
const apiService = createApiService();
const uploadActions = new UploadActions(apiService);
const usersActions = new UsersActions(apiService);
const versionManagePage = new VersionManagePage();
const acsUser = new UserModel();
let txtFileUploaded;
const txtFileInfo = new FileModel({
name: browser.params.resources.Files.ADF_DOCUMENTS.TXT.file_name,
location: browser.params.resources.Files.ADF_DOCUMENTS.TXT.file_path
});
const fileModelVersionTwo = new FileModel({
name: browser.params.resources.Files.ADF_DOCUMENTS.TXT.file_name,
location: browser.params.resources.Files.ADF_DOCUMENTS.TXT.file_location
});
beforeAll(async () => {
await apiService.loginWithProfile('admin');
await usersActions.createUser(acsUser);
await apiService.login(acsUser.username, acsUser.password);
txtFileUploaded = await uploadActions.uploadFile(txtFileInfo.location, txtFileInfo.name, '-my-');
await loginPage.login(acsUser.username, acsUser.password);
});
afterAll(async () => {
await apiService.loginWithProfile('admin');
await uploadActions.deleteFileOrFolder(txtFileUploaded.entry.id);
await navigationBarPage.clickLogoutButton();
});
beforeEach(async () => {
await contentServicesPage.goToDocumentList();
await contentServicesPage.doubleClickRow(txtFileUploaded.entry.name);
await viewerPage.waitTillContentLoaded();
});
afterEach(async () => {
await viewerPage.clickCloseButton();
});
it('[C362242] Should the Viewer be able to view a previous version of a file', async () => {
await contentServicesPage.versionManagerContent(txtFileInfo.name);
await versionManagePage.showNewVersionButton.click();
await versionManagePage.uploadNewVersionFile(fileModelVersionTwo.location);
await versionManagePage.closeVersionDialog();
await contentServicesPage.doubleClickRow(txtFileUploaded.entry.name);
await viewerPage.waitTillContentLoaded();
await viewerPage.clickInfoButton();
await viewerPage.clickOnTab('Versions');
await versionManagePage.viewFileVersion('1.0');
await viewerPage.expectUrlToContain('1.0');
});
it('[C362265] Should the Viewer be able to download a previous version of a file', async () => {
await viewerPage.clickDownloadButton();
await FileBrowserUtil.isFileDownloaded(txtFileInfo.name);
});
});
@@ -31,7 +31,7 @@ import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
import { FolderModel } from '../../models/ACS/folder.model';
import { browser } from 'protractor';
import { FileModel } from '../../models/ACS/file.model';
import { UploadDialogPage } from '../../core/pages/dialog/upload-dialog.page';
import { UploadDialogPage } from '../pages/upload-dialog.page';
describe('Document List - Pagination', () => {
const pagination = {
@@ -19,21 +19,19 @@ import { by, browser, ElementFinder, $, $$ } from 'protractor';
import { BrowserVisibility, BrowserActions } from '@alfresco/adf-testing';
export class UploadDialogPage {
closeButton = $('footer[class*="upload-dialog__actions"] button[id="adf-upload-dialog-close"]');
closeButton = $('#adf-upload-dialog-close');
dialog = $('div[id="upload-dialog"]');
minimizedDialog = $('div[class*="upload-dialog--minimized"]');
uploadedStatusIcon = 'mat-icon[class*="status--done"]';
uploadedStatusIcon = '.adf-file-uploading-row__status--done';
cancelledStatusIcon = 'div[class*="status--cancelled"]';
errorStatusIcon = 'div[class*="status--error"] mat-icon';
rowByRowName = by.xpath('ancestor::adf-file-uploading-list-row');
title = $('span[class*="upload-dialog__title"]');
minimizeButton = $('mat-icon[title="Minimize"]');
maximizeButton = $('mat-icon[title="Maximize"]');
toggleMinimizeButton = $(`[data-automation-id='adf-upload-dialog__toggle-minimize']`);
async clickOnCloseButton(): Promise<void> {
await this.checkCloseButtonIsDisplayed();
await BrowserActions.clickExecuteScript('footer[class*="upload-dialog__actions"] button[id="adf-upload-dialog-close"]');
await BrowserActions.click(this.closeButton);
}
async checkCloseButtonIsDisplayed(): Promise<void> {
@@ -107,11 +105,11 @@ export class UploadDialogPage {
}
async minimizeUploadDialog(): Promise<void> {
await BrowserActions.click(this.minimizeButton);
await BrowserActions.click(this.toggleMinimizeButton);
}
async maximizeUploadDialog(): Promise<void> {
await BrowserActions.click(this.maximizeButton);
await BrowserActions.click(this.toggleMinimizeButton);
}
async displayTooltip(): Promise<void> {
@@ -18,7 +18,7 @@
import { browser } from 'protractor';
import { createApiService, LoginPage, UploadActions, UserModel, UsersActions } from '@alfresco/adf-testing';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { UploadDialogPage } from '../../core/pages/dialog/upload-dialog.page';
import { UploadDialogPage } from '../pages/upload-dialog.page';
import { UploadTogglesPage } from '../../core/pages/dialog/upload-toggles.page';
import { FileModel } from '../../models/ACS/file.model';
@@ -24,7 +24,7 @@ import { createApiService,
UsersActions
} from '@alfresco/adf-testing';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { UploadDialogPage } from '../../core/pages/dialog/upload-dialog.page';
import { UploadDialogPage } from '../pages/upload-dialog.page';
import { UploadTogglesPage } from '../../core/pages/dialog/upload-toggles.page';
import { FileModel } from '../../models/ACS/file.model';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
@@ -17,11 +17,11 @@
import { createApiService, LoginPage, UploadActions, UserModel, UsersActions } from '@alfresco/adf-testing';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { UploadDialogPage } from '../../core/pages/dialog/upload-dialog.page';
import { UploadDialogPage } from '../pages/upload-dialog.page';
import { UploadTogglesPage } from '../../core/pages/dialog/upload-toggles.page';
import { FileModel } from '../../models/ACS/file.model';
import { browser } from 'protractor';
import { VersionManagePage } from '../../core/pages/version-manager.page';
import { VersionManagePage } from '../pages/version-manager.page';
describe('Upload component', () => {
@@ -19,7 +19,7 @@ import { browser, by, element } from 'protractor';
import { createApiService, DropActions, LoginPage, StringUtil, UploadActions, UserModel, UsersActions } from '@alfresco/adf-testing';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { UploadDialogPage } from '../../core/pages/dialog/upload-dialog.page';
import { UploadDialogPage } from '../pages/upload-dialog.page';
import { UploadTogglesPage } from '../../core/pages/dialog/upload-toggles.page';
import { FileModel } from '../../models/ACS/file.model';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
@@ -139,7 +139,6 @@ describe('Upload component', () => {
it('[C260172] Should be possible to enable versioning', async () => {
await uploadToggles.enableVersioning();
await uploadToggles.checkVersioningToggleIsEnabled();
await contentServicesPage.uploadFile(pdfFileModel.location);
await contentServicesPage.checkContentIsDisplayed(pdfFileModel.name);
@@ -164,7 +163,6 @@ describe('Upload component', () => {
await contentServicesPage.goToDocumentList();
await uploadToggles.enableMaxSize();
await uploadToggles.checkMaxSizeToggleIsEnabled();
await uploadToggles.addMaxSize('400');
await contentServicesPage.uploadFile(fileWithSpecificSize.location);
@@ -190,7 +188,6 @@ describe('Upload component', () => {
it('[C272796] Should be possible to set max size to 0', async () => {
await contentServicesPage.goToDocumentList();
await uploadToggles.enableMaxSize();
await uploadToggles.checkMaxSizeToggleIsEnabled();
await uploadToggles.addMaxSize('0');
await contentServicesPage.uploadFile(fileWithSpecificSize.location);
// await expect(await contentServicesPage.getErrorMessage()).toEqual('File ' + fileWithSpecificSize.name + ' is larger than the allowed file size');
@@ -207,7 +204,6 @@ describe('Upload component', () => {
it('[C272797] Should be possible to set max size to 1', async () => {
await uploadToggles.enableMaxSize();
await uploadToggles.checkMaxSizeToggleIsEnabled();
await browser.sleep(1000);
await uploadToggles.addMaxSize('1');
await uploadToggles.disableMaxSize();
@@ -18,7 +18,7 @@
import { browser } from 'protractor';
import { createApiService, LoginPage, SnackbarPage, StringUtil, UserModel, UsersActions } from '@alfresco/adf-testing';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { UploadDialogPage } from '../../core/pages/dialog/upload-dialog.page';
import { UploadDialogPage } from '../pages/upload-dialog.page';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
import { FileModel } from '../../models/ACS/file.model';
import CONSTANTS = require('../../util/constants');
@@ -28,9 +28,9 @@ import { createApiService,
import { browser, by, element } from 'protractor';
import { FileModel } from '../../models/ACS/file.model';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { UploadDialogPage } from '../../core/pages/dialog/upload-dialog.page';
import { UploadDialogPage } from '../pages/upload-dialog.page';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
import { VersionManagePage } from '../../core/pages/version-manager.page';
import { VersionManagePage } from '../pages/version-manager.page';
describe('Version component actions', () => {
@@ -26,8 +26,8 @@ import {
UsersActions
} from '@alfresco/adf-testing';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
import { VersionManagePage } from '../../core/pages/version-manager.page';
import { UploadDialogPage } from '../../core/pages/dialog/upload-dialog.page';
import { VersionManagePage } from '../pages/version-manager.page';
import { UploadDialogPage } from '../pages/upload-dialog.page';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { FileModel } from '../../models/ACS/file.model';
import CONSTANTS = require('../../util/constants');
@@ -24,7 +24,7 @@ import { createApiService,
UsersActions, ViewerPage
} from '@alfresco/adf-testing';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { VersionManagePage } from '../../core/pages/version-manager.page';
import { VersionManagePage } from '../pages/version-manager.page';
import { FileModel } from '../../models/ACS/file.model';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
@@ -18,7 +18,7 @@
import { browser } from 'protractor';
import { createApiService, LoginPage, UploadActions, UserModel, UsersActions } from '@alfresco/adf-testing';
import { ContentServicesPage } from '../../core/pages/content-services.page';
import { VersionManagePage } from '../../core/pages/version-manager.page';
import { VersionManagePage } from '../pages/version-manager.page';
import { FileModel } from '../../models/ACS/file.model';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
+3 -17
View File
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { $, browser } from 'protractor';
import { $ } from 'protractor';
import { BrowserActions, BrowserVisibility, TogglePage } from '@alfresco/adf-testing';
export class UploadTogglesPage {
@@ -25,16 +25,14 @@ export class UploadTogglesPage {
extensionFilterToggle = $('#adf-extension-filter-upload-switch');
maxSizeToggle = $('#adf-max-size-filter-upload-switch');
versioningToggle = $('#adf-version-upload-switch');
extensionAcceptedField = $('input[data-automation-id="accepted-files-type"]');
maxSizeField = $('input[data-automation-id="max-files-size"]');
extensionAcceptedField = $('[data-automation-id="accepted-files-type"]');
maxSizeField = $('[data-automation-id="max-files-size"]');
async enableMultipleFileUpload(): Promise<void> {
await browser.executeScript('arguments[0].scrollIntoView()', this.multipleFileUploadToggle);
await this.togglePage.enableToggle(this.multipleFileUploadToggle);
}
async disableMultipleFileUpload(): Promise<void> {
await browser.executeScript('arguments[0].scrollIntoView()', this.multipleFileUploadToggle);
await this.togglePage.disableToggle(this.multipleFileUploadToggle);
}
@@ -42,23 +40,11 @@ export class UploadTogglesPage {
await this.togglePage.enableToggle(this.uploadFolderToggle);
}
async checkMaxSizeToggleIsEnabled(): Promise<void> {
const enabledToggle = $('mat-slide-toggle[id="adf-max-size-filter-upload-switch"][class*="mat-checked"]');
await BrowserVisibility.waitUntilElementIsVisible(enabledToggle);
}
async checkVersioningToggleIsEnabled(): Promise<void> {
const enabledToggle = $('mat-slide-toggle[id="adf-version-upload-switch"][class*="mat-checked"]');
await BrowserVisibility.waitUntilElementIsVisible(enabledToggle);
}
async enableExtensionFilter(): Promise<void> {
await browser.executeScript('arguments[0].scrollIntoView()', this.extensionFilterToggle);
await this.togglePage.enableToggle(this.extensionFilterToggle);
}
async disableExtensionFilter(): Promise<void> {
await browser.executeScript('arguments[0].scrollIntoView()', this.extensionFilterToggle);
await this.togglePage.disableToggle(this.extensionFilterToggle);
}
+2 -2
View File
@@ -46,9 +46,9 @@ export class MetadataViewPage {
resetMetadataButton = $(`[data-automation-id='reset-metadata']`);
private getMetadataGroupLocator = async (groupName: string): Promise<ElementFinder> =>
$(`mat-expansion-panel[data-automation-id="adf-metadata-group-${groupName}"]`);
$(`[data-automation-id="adf-metadata-group-${groupName}"]`);
private getExpandedMetadataGroupLocator = async (groupName: string): Promise<ElementFinder> =>
$(`mat-expansion-panel[data-automation-id="adf-metadata-group-${groupName}"] > mat-expansion-panel-header`);
$(`[data-automation-id="adf-metadata-group-${groupName}"] > mat-expansion-panel-header`);
async getTitle(): Promise<string> {
return BrowserActions.getText(this.title);
@@ -151,18 +151,6 @@ describe('Process list cloud', () => {
await processList.getDataTable().waitTillContentLoaded();
}
it('[C290069] Should display processes ordered by name when Name is selected from sort dropdown', async () => {
await setFilter({ status: PROCESS_STATUS.RUNNING });
await setFilter({ sort: 'Name' });
await setFilter({ order: SORT_DIRECTION.ASC });
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.ASC, 'Process Name')).toBe(true);
await setFilter({ order: SORT_DIRECTION.DESC});
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.DESC, 'Process Name')).toBe(true);
});
it('[C291783] Should display processes ordered by id when Id is selected from sort dropdown', async () => {
await setFilter({ status: PROCESS_STATUS.RUNNING });
await setFilter({ sort: 'Id'});
@@ -185,39 +173,6 @@ describe('Process list cloud', () => {
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.DESC, 'Status')).toBe(true);
});
it('[C305054] Should display processes ordered by started by when Started By is selected from sort dropdown', async () => {
await setFilter({ status: PROCESS_STATUS.ALL });
await setFilter({ sort: 'Started by' });
await setFilter({ order: SORT_DIRECTION.ASC });
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.ASC, 'Started by')).toBe(true);
await setFilter({ order: SORT_DIRECTION.DESC});
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.DESC, 'Started by')).toBe(true);
});
it('[C305054] Should display processes ordered by processdefinitionid date when ProcessDefinitionId is selected from sort dropdown', async () => {
await setFilter({ status: PROCESS_STATUS.ALL });
await setFilter({ sort: 'ProcessDefinitionId' });
await setFilter({ order: SORT_DIRECTION.ASC });
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.ASC, 'Process Definition Id')).toBe(true);
await setFilter({ order: SORT_DIRECTION.DESC});
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.DESC, 'Process Definition Id')).toBe(true);
});
it('[C305054] Should display processes ordered by processdefinitionkey date when ProcessDefinitionKey is selected from sort dropdown', async () => {
await setFilter({ status: PROCESS_STATUS.ALL });
await setFilter({ sort: 'ProcessDefinitionKey' });
await setFilter({ order: SORT_DIRECTION.ASC });
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.ASC, 'Process Definition Key')).toBe(true);
await setFilter({ order: SORT_DIRECTION.DESC});
await expect(await processList.getDataTable().checkListIsSorted(SORT_DIRECTION.DESC, 'Process Definition Key')).toBe(true);
});
it('[C305054] Should display processes ordered by last modified date when Last Modified is selected from sort dropdown', async () => {
await setFilter({ status: PROCESS_STATUS.ALL });
await setFilter({ sort: 'Last Modified' });
@@ -1,178 +0,0 @@
/*!
* @license
* Copyright © 2005-2023 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 { browser } from 'protractor';
import { createApiService,
AppListCloudPage,
ContentNodeSelectorDialogPage,
GroupIdentityService,
IdentityService,
LoginPage,
QueryService,
ProcessCloudWidgetPage,
ProcessDefinitionsService,
ProcessInstancesService,
StringUtil,
TaskFormCloudComponent,
TasksService,
UploadActions,
ViewerPage
} from '@alfresco/adf-testing';
import { ProcessCloudDemoPage } from './../pages/process-cloud-demo.page';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
import { TasksCloudDemoPage } from './../pages/tasks-cloud-demo.page';
import CONSTANTS = require('../../util/constants');
describe('Process Task - Attach content file', () => {
const loginSSOPage = new LoginPage();
const navigationBarPage = new NavigationBarPage();
const appListCloudComponent = new AppListCloudPage();
const processCloudDemoPage = new ProcessCloudDemoPage();
const editProcessFilter = processCloudDemoPage.editProcessFilterCloudComponent();
const processList = processCloudDemoPage.processListCloudComponent();
const tasksCloudDemoPage = new TasksCloudDemoPage();
const taskFilter = tasksCloudDemoPage.taskFilterCloudComponent;
const taskList = tasksCloudDemoPage.taskListCloudComponent();
const taskFormCloudComponent = new TaskFormCloudComponent();
const processCloudWidget = new ProcessCloudWidgetPage();
const contentNodeSelectorDialog = new ContentNodeSelectorDialogPage();
const apiService = createApiService();
const uploadActions = new UploadActions(apiService);
const processDefinitionService = new ProcessDefinitionsService(apiService);
const processInstancesService = new ProcessInstancesService(apiService);
const identityService = new IdentityService(apiService);
const groupIdentityService = new GroupIdentityService(apiService);
const queryService = new QueryService(apiService);
const tasksService = new TasksService(apiService);
const viewerPage = new ViewerPage();
const simpleApp = browser.params.resources.ACTIVITI_CLOUD_APPS.SIMPLE_APP.name;
const processDefinitionName = browser.params.resources.ACTIVITI_CLOUD_APPS.SIMPLE_APP.processes.uploadSingleMultipleFiles;
const uploadWidgetId = browser.params.resources.ACTIVITI_CLOUD_APPS.SIMPLE_APP.forms.uploadSingleMultiple.widgets.contentMultipleAttachFileId;
const taskName = browser.params.resources.ACTIVITI_CLOUD_APPS.SIMPLE_APP.tasks.uploadSingleMultipleFiles;
const folderName = StringUtil.generateRandomString(5);
let uploadedFolder: any;
let processInstance: any;
let testUser: any;
let groupInfo: any;
const pdfFileOne = {
name: browser.params.resources.Files.ADF_DOCUMENTS.PNG.file_name,
location: browser.params.resources.Files.ADF_DOCUMENTS.PNG.file_path
};
const pdfFileTwo = {
name: browser.params.resources.Files.ADF_DOCUMENTS.PNG_B.file_name,
location: browser.params.resources.Files.ADF_DOCUMENTS.PNG_B.file_path
};
beforeAll(async () => {
await apiService.loginWithProfile('identityAdmin');
testUser = await identityService.createIdentityUserWithRole([identityService.ROLES.ACTIVITI_USER]);
groupInfo = await groupIdentityService.getGroupInfoByGroupName('hr');
await identityService.addUserToGroup(testUser.idIdentityService, groupInfo.id);
await apiService.login(testUser.username, testUser.password);
const processDefinition = await processDefinitionService.getProcessDefinitionByName(processDefinitionName, simpleApp);
processInstance = await processInstancesService.createProcessInstance(processDefinition.entry.key, simpleApp, { name: 'upload process' });
const task = await queryService.getProcessInstanceTasks(processInstance.entry.id, simpleApp);
await tasksService.claimTask(task.list.entries[0].entry.id, simpleApp);
await apiService.login(testUser.username, testUser.password);
uploadedFolder = await uploadActions.createFolder(folderName, '-my-');
await uploadActions.uploadFile(pdfFileOne.location, pdfFileOne.name, uploadedFolder.entry.id);
await uploadActions.uploadFile(pdfFileTwo.location, pdfFileTwo.name, uploadedFolder.entry.id);
await loginSSOPage.login(testUser.username, testUser.password);
await navigationBarPage.navigateToProcessServicesCloudPage();
await appListCloudComponent.checkApsContainer();
});
afterAll(async () => {
await uploadActions.deleteFileOrFolder(uploadedFolder.entry.id);
await apiService.loginWithProfile('identityAdmin');
await identityService.deleteIdentityUser(testUser.idIdentityService);
});
it('[C311290] Should be able to attach multiple files when widget allows multiple files to be attached from content', async () => {
await appListCloudComponent.checkAppIsDisplayed(simpleApp);
await appListCloudComponent.goToApp(simpleApp);
await processCloudDemoPage.processFilterCloudComponent.clickOnProcessFilters();
await processCloudDemoPage.processFilterCloudComponent.clickRunningProcessesFilter();
await editProcessFilter.openFilter();
await editProcessFilter.setProcessName('upload process');
await editProcessFilter.closeFilter();
await expect(await processCloudDemoPage.processFilterCloudComponent.getActiveFilterName()).toBe(CONSTANTS.PROCESS_FILTERS.RUNNING);
await processList.checkContentIsDisplayedById(processInstance.entry.id);
await processList.selectRowById(processInstance.entry.id);
await taskList.checkTaskListIsLoaded();
await taskList.selectRow(taskName);
await taskFormCloudComponent.formFields().checkFormIsDisplayed();
await taskFormCloudComponent.formFields().checkWidgetIsVisible(uploadWidgetId);
const contentUploadFileWidget = processCloudWidget.attachFileWidgetCloud(uploadWidgetId);
await contentUploadFileWidget.clickAttachContentFile(uploadWidgetId);
await contentNodeSelectorDialog.attachFileFromContentNode(folderName, pdfFileOne.name);
await viewAttachedFile(contentUploadFileWidget, pdfFileOne.name);
await taskFormCloudComponent.formFields().checkWidgetIsVisible(uploadWidgetId);
await contentUploadFileWidget.clickAttachContentFile(uploadWidgetId);
await contentNodeSelectorDialog.attachFileFromContentNode(folderName, pdfFileTwo.name);
await viewAttachedFile(contentUploadFileWidget, pdfFileTwo.name);
await taskFormCloudComponent.clickCompleteButton();
await expect(await taskFilter.getActiveFilterName()).toBe('My Tasks');
await taskList.checkContentIsNotDisplayedByName(taskName);
await taskFilter.clickTaskFilter('completed-tasks');
await taskList.getDataTable().waitTillContentLoaded();
await taskList.checkContentIsDisplayedByName(taskName);
await processCloudDemoPage.processFilterCloudComponent.clickOnProcessFilters();
await processCloudDemoPage.processFilterCloudComponent.clickCompletedProcessesFilter();
await editProcessFilter.openFilter();
await editProcessFilter.setProcessName('upload process');
await editProcessFilter.closeFilter();
await expect(await processCloudDemoPage.processFilterCloudComponent.getActiveFilterName()).toBe(CONSTANTS.PROCESS_FILTERS.COMPLETED);
await processList.checkContentIsDisplayedById(processInstance.entry.id);
});
async function viewAttachedFile(contentUploadWidget: any, fileName: string): Promise<void> {
await contentUploadWidget.checkFileIsAttached(fileName);
await contentUploadWidget.viewFile(fileName);
await viewerPage.checkToolbarIsDisplayed();
await viewerPage.checkInfoButtonIsDisplayed();
await viewerPage.checkDownloadButtonIsDisplayed();
await viewerPage.checkFileThumbnailIsDisplayed();
await viewerPage.checkFileNameIsDisplayed(fileName);
await viewerPage.clickCloseButton();
}
});
@@ -1,79 +0,0 @@
/*!
* @license
* Copyright © 2005-2023 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 { createApiService, Application, AppListCloudPage, IdentityService, LocalStorageUtil, LoginPage } from '@alfresco/adf-testing';
import { browser } from 'protractor';
import { NavigationBarPage } from '../../core/pages/navigation-bar.page';
describe('Applications list', () => {
const simpleApp = browser.params.resources.ACTIVITI_CLOUD_APPS.SIMPLE_APP.name;
const loginSSOPage = new LoginPage();
const navigationBarPage = new NavigationBarPage();
const appListCloudPage = new AppListCloudPage();
const apiService = createApiService();
const applicationsService = new Application(apiService);
const identityService = new IdentityService(apiService);
let testUser;
const appNames = [];
beforeAll(async () => {
await apiService.loginWithProfile('identityAdmin');
testUser = await identityService.createIdentityUserWithRole( [identityService.ROLES.ACTIVITI_USER, identityService.ROLES.ACTIVITI_DEVOPS]);
await loginSSOPage.login(testUser.username, testUser.password);
await apiService.login(testUser.username, testUser.password);
const applications = await applicationsService.getApplicationsByStatus('RUNNING');
applications.list.entries.forEach(app => {
appNames.push(app.entry.name.toLowerCase());
});
await LocalStorageUtil.setConfigField('alfresco-deployed-apps', '[]');
await LocalStorageUtil.apiReset();
});
afterAll(async () => {
await apiService.loginWithProfile('identityAdmin');
await identityService.deleteIdentityUser(testUser.idIdentityService);
});
it('[C310373] Should all the app with running state be displayed on dashboard when alfresco-deployed-apps is not used in config file', async () => {
await navigationBarPage.navigateToProcessServicesCloudPage();
await appListCloudPage.checkApsContainer();
const list = await appListCloudPage.getNameOfTheApplications();
await expect(JSON.stringify(list)).toEqual(JSON.stringify(appNames));
});
it('[C289910] Should the app be displayed on dashboard when is deployed on APS', async () => {
await browser.refresh();
await navigationBarPage.navigateToProcessServicesCloudPage();
await appListCloudPage.checkApsContainer();
await appListCloudPage.checkAppIsDisplayed(simpleApp);
await appListCloudPage.checkAppIsDisplayed(browser.params.resources.ACTIVITI_CLOUD_APPS.CANDIDATE_BASE_APP.name);
await appListCloudPage.checkAppIsDisplayed(browser.params.resources.ACTIVITI_CLOUD_APPS.SUB_PROCESS_APP.name);
await expect(await appListCloudPage.countAllApps()).toEqual(3);
});
});
@@ -73,7 +73,7 @@ export class TaskDetailsPage {
}
async checkDueDatePickerButtonIsNotDisplayed(): Promise<void> {
const dueDatePickerButton = $('mat-datetimepicker-toggle[data-automation-id="datepickertoggle-dueDate"]');
const dueDatePickerButton = $('[data-automation-id="datepickertoggle-dueDate"]');
await BrowserVisibility.waitUntilElementIsNotVisible(dueDatePickerButton);
}
+1 -1
View File
@@ -285,7 +285,7 @@ exports.config = {
// @ts-ignore
if (browser.params.testConfig.appConfig.authType === 'OAUTH') {
Logger.info(`Configure demo shell OAUTH`);
// @ts-ignore
await LocalStorageUtil.setStorageItem('identityHost', browser.params.testConfig.appConfig.identityHost);
// @ts-ignore
Binary file not shown.
@@ -270,7 +270,7 @@ describe('Search Number Range Filter', () => {
for (const currentResult of results) {
const currentSize = await BrowserActions.getAttribute(currentResult, 'title');
if (currentSize && currentSize.trim() !== '') {
await expect(currentSize === '0').toBe(true);
await expect((currentSize === '0' || currentSize === '1')).toBe(true);
}
}
});
+1 -2
View File
@@ -19,7 +19,6 @@ import { ElementFinder, protractor, $ } from 'protractor';
import { BrowserVisibility, BrowserActions, TestElement } from '@alfresco/adf-testing';
export class SearchBarPage {
searchIcon = $(`button[class*='adf-search-button']`);
searchBar = $(`adf-search-control input`);
searchBarExpanded: TestElement = TestElement.byCss(`adf-search-control mat-form-field[class*="mat-focused"] input`);
@@ -29,7 +28,7 @@ export class SearchBarPage {
highlightName = `.adf-highlight`;
searchBarPage = $(`mat-list[id='autocomplete-search-result-list']`);
getRowByRowName = (name: string): ElementFinder => $(`mat-list-item[data-automation-id='autocomplete_for_${name}']`);
getRowByRowName = (name: string): ElementFinder => $(`[data-automation-id='autocomplete_for_${name}']`);
async clickOnSearchIcon(): Promise<void> {
await BrowserActions.click(this.searchIcon);
+27 -19
View File
@@ -15,29 +15,38 @@
* limitations under the License.
*/
import { BrowserVisibility, DateRangeFilterPage, NumberRangeFilterPage, SearchCategoriesPage, SearchCheckListPage, SearchRadioPage, SearchSliderPage, SearchTextPage } from '@alfresco/adf-testing';
import {
BrowserVisibility,
DateRangeFilterPage,
NumberRangeFilterPage,
SearchCategoriesPage,
SearchCheckListPage,
SearchRadioPage,
SearchSliderPage,
SearchTextPage
} from '@alfresco/adf-testing';
import { $, by } from 'protractor';
export class SearchFiltersPage {
searchCategoriesPage: SearchCategoriesPage = new SearchCategoriesPage();
searchFilters = $('adf-search-filter');
fileTypeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-SEARCH.FACET_FIELDS.TYPE"]');
creatorFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-SEARCH.FILTER.PEOPLE"]');
fileSizeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-SEARCH.FACET_FIELDS.SIZE"]');
nameFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Name"]');
checkListFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Check List"]');
createdDateRangeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Created Date (range)"]');
typeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Type"]');
sizeRangeFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Content Size (range)"]');
sizeSliderFilter = $('mat-expansion-panel[data-automation-id="expansion-panel-Content Size"]');
facetQueriesDefaultGroup = $('mat-expansion-panel[data-automation-id="expansion-panel-SEARCH.FACET_QUERIES.MY_FACET_QUERIES"],' +
'mat-expansion-panel[data-automation-id="expansion-panel-My facet queries"]');
facetQueriesTypeGroup = $('mat-expansion-panel[data-automation-id="expansion-panel-Type facet queries"]');
facetQueriesSizeGroup = $('mat-expansion-panel[data-automation-id="expansion-panel-Size facet queries"]');
facetIntervalsByCreated = $('mat-expansion-panel[data-automation-id="expansion-panel-The Created"]');
facetIntervalsByModified = $('mat-expansion-panel[data-automation-id="expansion-panel-TheModified"]');
fileTypeFilter = $('[data-automation-id="expansion-panel-SEARCH.FACET_FIELDS.TYPE"]');
creatorFilter = $('[data-automation-id="expansion-panel-SEARCH.FILTER.PEOPLE"]');
fileSizeFilter = $('[data-automation-id="expansion-panel-SEARCH.FACET_FIELDS.SIZE"]');
nameFilter = $('[data-automation-id="expansion-panel-Name"]');
checkListFilter = $('[data-automation-id="expansion-panel-Check List"]');
createdDateRangeFilter = $('[data-automation-id="expansion-panel-Created Date (range)"]');
typeFilter = $('[data-automation-id="expansion-panel-Type"]');
sizeRangeFilter = $('[data-automation-id="expansion-panel-Content Size (range)"]');
sizeSliderFilter = $('[data-automation-id="expansion-panel-Content Size"]');
facetQueriesDefaultGroup = $(
'[data-automation-id="expansion-panel-SEARCH.FACET_QUERIES.MY_FACET_QUERIES"],' + '[data-automation-id="expansion-panel-My facet queries"]'
);
facetQueriesTypeGroup = $('[data-automation-id="expansion-panel-Type facet queries"]');
facetQueriesSizeGroup = $('[data-automation-id="expansion-panel-Size facet queries"]');
facetIntervalsByCreated = $('[data-automation-id="expansion-panel-The Created"]');
facetIntervalsByModified = $('[data-automation-id="expansion-panel-TheModified"]');
async checkSearchFiltersIsDisplayed(): Promise<void> {
await BrowserVisibility.waitUntilElementIsVisible(this.searchFilters);
@@ -72,7 +81,7 @@ export class SearchFiltersPage {
}
async checkCustomFacetFieldLabelIsDisplayed(fieldLabel: string): Promise<void> {
await BrowserVisibility.waitUntilElementIsVisible($(`mat-expansion-panel[data-automation-id="expansion-panel-${fieldLabel}"]`));
await BrowserVisibility.waitUntilElementIsVisible($(`[data-automation-id="expansion-panel-${fieldLabel}"]`));
}
sizeSliderFilterPage(): SearchSliderPage {
@@ -234,5 +243,4 @@ export class SearchFiltersPage {
async checkFileTypeFacetLabelIsNotDisplayed(fileType: string | RegExp): Promise<void> {
await BrowserVisibility.waitUntilElementIsNotVisible(this.fileTypeFilter.element(by.cssContainingText('.adf-facet-label', fileType)));
}
}
+4 -4
View File
@@ -9,14 +9,14 @@ const HOST = process.env.URL_HOST_ADF;
const LOG = process.env.E2E_LOG_LEVEL;
const HOST_ECM = process.env.PROXY_HOST_ECM || HOST || 'ecm';
const HOST_BPM = process.env.PROXY_HOST_BPM || HOST || 'bpm';
const HOST_ECM = process.env.PROXY_HOST_ECM || process.env.PROXY_HOST_ADF || HOST || 'ecm';
const HOST_BPM = process.env.PROXY_HOST_BPM || process.env.PROXY_HOST_ADF || HOST || 'bpm';
const HOST_SSO = process.env.HOST_SSO || process.env.PROXY_HOST_ADF || HOST || 'oauth';
const IDENTITY_HOST = process.env.IDENTITY_HOST || process.env.HOST_SSO + '/auth/admin/realms/alfresco';
const PROVIDER = process.env.PROVIDER ? process.env.PROVIDER : 'ALL';
const AUTH_TYPE = process.env.AUTH_TYPE ? process.env.AUTH_TYPE : 'BASIC';
const HOST_SSO = process.env.HOST_SSO || process.env.PROXY_HOST_ADF || HOST || 'oauth';
const IDENTITY_HOST = process.env.IDENTITY_HOST || process.env.HOST_SSO + '/auth/admin/realms/alfresco';
const OAUTH_CLIENT_ID = process.env.OAUTH_CLIENDID || 'alfresco';
const IDENTITY_ADMIN_EMAIL = process.env.IDENTITY_ADMIN_EMAIL || "defaultadmin";
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@alfresco/adf-cli",
"version": "6.4.0",
"version": "6.5.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@alfresco/adf-cli",
"version": "6.4.0",
"version": "6.5.2",
"license": "Apache-2.0",
"dependencies": {
"@alfresco/js-api": ">=7.1.0-1372",
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@alfresco/adf-cli",
"description": "Alfresco ADF cli and utils",
"version": "6.4.0",
"version": "6.5.2",
"author": "Hyland Software, Inc. and its affiliates",
"bin": {
"adf-cli": "./bin/adf-cli",
@@ -20,7 +20,7 @@
"dist": "rm -rf ../../dist/libs/cli && npm run build && cp -R ./bin ../../dist/libs/cli && cp -R ./resources ../../dist/libs/cli && cp -R ./templates ../../dist/libs/cli && cp ./package.json ../../dist/libs/cli"
},
"dependencies": {
"@alfresco/js-api": ">=7.1.0",
"@alfresco/js-api": ">=7.2.0",
"commander": "^6.2.1",
"ejs": "^3.1.9",
"license-checker": "^25.0.1",
+1
View File
@@ -568,6 +568,7 @@ async function deployWithPayload(currentAbsentApp: any, projectRelease: any, env
security: currentAbsentApp.security,
infrastructure: currentAbsentApp.infrastructure,
variables: currentAbsentApp.variables,
enableLocalDevelopment: currentAbsentApp.enableLocalDevelopment,
environmentId: envId
};
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@alfresco/adf-content-services",
"description": "Alfresco ADF content services",
"version": "6.4.0",
"version": "6.5.2",
"author": "Hyland Software, Inc. and its affiliates",
"repository": {
"type": "git",
@@ -21,9 +21,9 @@
"@angular/platform-browser": ">=14.1.3",
"@angular/platform-browser-dynamic": ">=14.1.3",
"@angular/router": ">=14.1.3",
"@alfresco/js-api": ">=7.1.0",
"@alfresco/js-api": ">=7.2.0",
"@ngx-translate/core": ">=14.0.0",
"@alfresco/adf-core": ">=6.4.0"
"@alfresco/adf-core": ">=6.5.2"
},
"keywords": [
"content-services",
@@ -8,7 +8,7 @@
(click)="onCheckBoxClick($event)"
(change)="onChange($event, aspect?.entry?.id)">
<p class="adf-aspect-list-element-title">{{getTitle(aspect)}}</p>
</mat-checkbox>
</mat-checkbox>
</mat-panel-title>
<mat-panel-description [id]="'aspect-list-'+colIndex+'-title'"
[matTooltip]="getTitle(aspect)">
@@ -39,6 +39,6 @@
<ng-template #loading>
<div class="adf-aspect-list-spinner">
<mat-spinner id="adf-aspect-spinner"></mat-spinner>
<mat-progress-spinner mode="indeterminate" id="adf-aspect-spinner"></mat-progress-spinner>
</div>
</ng-template>
@@ -24,86 +24,96 @@ import { AspectListService } from './services/aspect-list.service';
import { of } from 'rxjs';
import { AspectEntry } from '@alfresco/js-api';
import { delay } from 'rxjs/operators';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatExpansionPanelHarness } from '@angular/material/expansion/testing';
import { MatTableHarness } from '@angular/material/table/testing';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
const aspectListMock: AspectEntry[] = [{
entry: {
parentId: 'frs:aspectZero',
id: 'frs:AspectOne',
description: 'First Aspect with random description',
title: 'FirstAspect',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:propA'
},
{
id: 'channelUsername',
title: 'The authenticated channel username',
dataType: 'd:propB'
}
]
const aspectListMock: AspectEntry[] = [
{
entry: {
parentId: 'frs:aspectZero',
id: 'frs:AspectOne',
description: 'First Aspect with random description',
title: 'FirstAspect',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:propA'
},
{
id: 'channelUsername',
title: 'The authenticated channel username',
dataType: 'd:propB'
}
]
}
},
{
entry: {
parentId: 'frs:AspectZer',
id: 'frs:SecondAspect',
description: 'Second Aspect description',
title: 'SecondAspect',
properties: [
{
id: 'assetId',
title: 'Published Asset Id',
dataType: 'd:text'
},
{
id: 'assetUrl',
title: 'Published Asset URL',
dataType: 'd:text'
}
]
}
}
},
{
entry: {
parentId: 'frs:AspectZer',
id: 'frs:SecondAspect',
description: 'Second Aspect description',
title: 'SecondAspect',
properties: [
{
id: 'assetId',
title: 'Published Asset Id',
dataType: 'd:text'
},
{
id: 'assetUrl',
title: 'Published Asset URL',
dataType: 'd:text'
}
]
}
}];
];
const customAspectListMock: AspectEntry[] = [{
entry: {
parentId: 'cst:parentAspect',
id: 'cst:customAspect',
description: 'Custom Aspect with random description',
title: 'CustomAspect',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:propA'
},
{
id: 'channelUsername',
title: 'The authenticated channel username',
dataType: 'd:propB'
}
]
const customAspectListMock: AspectEntry[] = [
{
entry: {
parentId: 'cst:parentAspect',
id: 'cst:customAspect',
description: 'Custom Aspect with random description',
title: 'CustomAspect',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:propA'
},
{
id: 'channelUsername',
title: 'The authenticated channel username',
dataType: 'd:propB'
}
]
}
},
{
entry: {
parentId: 'cst:commonaspect',
id: 'cst:nonamedAspect',
description: '',
title: '',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:propA'
}
]
}
}
},
{
entry: {
parentId: 'cst:commonaspect',
id: 'cst:nonamedAspect',
description: '',
title: '',
properties: [
{
id: 'channelPassword',
title: 'The authenticated channel password',
dataType: 'd:propA'
}
]
}
}];
];
describe('AspectListComponent', () => {
let loader: HarnessLoader;
let component: AspectListComponent;
let fixture: ComponentFixture<AspectListComponent>;
let aspectListService: AspectListService;
@@ -111,36 +121,31 @@ describe('AspectListComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule],
providers: [AspectListService]
});
});
describe('Loading', () => {
beforeEach(() => {
fixture = TestBed.createComponent(AspectListComponent);
component = fixture.componentInstance;
nodeService = TestBed.inject(NodesApiService);
aspectListService = TestBed.inject(AspectListService);
loader = TestbedHarnessEnvironment.loader(fixture);
});
it('should show the loading spinner when result is loading', () => {
it('should show the loading spinner when result is loading', async () => {
const delayResult = of(null).pipe(delay(0));
spyOn(nodeService, 'getNode').and.returnValue(delayResult);
spyOn(aspectListService, 'getAspects').and.returnValue(delayResult);
fixture.detectChanges();
const spinner = fixture.nativeElement.querySelector('#adf-aspect-spinner');
expect(spinner).toBeDefined();
expect(spinner).not.toBeNull();
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(true);
});
});
describe('When passing a node id', () => {
beforeEach(() => {
fixture = TestBed.createComponent(AspectListComponent);
component = fixture.componentInstance;
@@ -152,6 +157,7 @@ describe('AspectListComponent', () => {
spyOn(nodeService, 'getNode').and.returnValue(of({ id: 'fake-node-id', aspectNames: ['frs:AspectOne'] } as any));
component.nodeId = 'fake-node-id';
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
afterEach(() => {
@@ -167,106 +173,80 @@ describe('AspectListComponent', () => {
expect(component.hasEqualAspect).toBe(false);
});
it('should show all the aspects', () => {
const firstElement = fixture.nativeElement.querySelector('#aspect-list-FirstAspect');
const secondElement = fixture.nativeElement.querySelector('#aspect-list-SecondAspect');
expect(firstElement).not.toBeNull();
expect(firstElement).toBeDefined();
expect(secondElement).not.toBeNull();
expect(secondElement).toBeDefined();
it('should show all the aspects', async () => {
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-FirstAspect' }))).toBe(true);
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-SecondAspect' }))).toBe(true);
});
it('should show aspect id when name or title is not set', () => {
const noNameAspect: HTMLElement = fixture.nativeElement.querySelector('#aspect-list-cst-nonamedAspect .adf-aspect-list-element-title');
const noNameAspect = fixture.nativeElement.querySelector('#aspect-list-cst-nonamedAspect .adf-aspect-list-element-title');
expect(noNameAspect).toBeDefined();
expect(noNameAspect).not.toBeNull();
expect(noNameAspect.innerText).toBe('cst:nonamedAspect');
});
it('should show the details when a row is clicked', () => {
const firstElement = fixture.nativeElement.querySelector('#aspect-list-FirstAspect');
firstElement.click();
fixture.detectChanges();
const firstElementDesc = fixture.nativeElement.querySelector('#aspect-list-0-description');
expect(firstElementDesc).not.toBeNull();
expect(firstElementDesc).toBeDefined();
it('should show the details when a row is clicked', async () => {
const panel = await loader.getHarness(MatExpansionPanelHarness);
await panel.expand();
expect(await panel.getDescription()).not.toBeNull();
const firstElementPropertyTable = fixture.nativeElement.querySelector('#aspect-list-0-properties-table');
expect(firstElementPropertyTable).not.toBeNull();
expect(firstElementPropertyTable).toBeDefined();
const nameProperties = fixture.nativeElement.querySelectorAll('#aspect-list-0-properties-table tbody .mat-column-name');
expect(nameProperties[0]).not.toBeNull();
expect(nameProperties[0]).toBeDefined();
expect(nameProperties[0].innerText).toBe('channelPassword');
expect(nameProperties[1]).not.toBeNull();
expect(nameProperties[1]).toBeDefined();
expect(nameProperties[1].innerText).toBe('channelUsername');
const table = await panel.getHarness(MatTableHarness);
const [row1, row2] = await table.getRows();
const [r1c1, r1c2, r1c3] = await row1.getCells();
expect(await r1c1.getText()).toBe('channelPassword');
expect(await r1c2.getText()).toBe('The authenticated channel password');
expect(await r1c3.getText()).toBe('d:propA');
const titleProperties = fixture.nativeElement.querySelectorAll('#aspect-list-0-properties-table tbody .mat-column-title');
expect(titleProperties[0]).not.toBeNull();
expect(titleProperties[0]).toBeDefined();
expect(titleProperties[0].innerText).toBe('The authenticated channel password');
expect(titleProperties[1]).not.toBeNull();
expect(titleProperties[1]).toBeDefined();
expect(titleProperties[1].innerText).toBe('The authenticated channel username');
const dataTypeProperties = fixture.nativeElement.querySelectorAll('#aspect-list-0-properties-table tbody .mat-column-dataType');
expect(dataTypeProperties[0]).not.toBeNull();
expect(dataTypeProperties[0]).toBeDefined();
expect(dataTypeProperties[0].innerText).toBe('d:propA');
expect(dataTypeProperties[1]).not.toBeNull();
expect(dataTypeProperties[1]).toBeDefined();
expect(dataTypeProperties[1].innerText).toBe('d:propB');
const [r2c1, r2c2, r2c3] = await row2.getCells();
expect(await r2c1.getText()).toBe('channelUsername');
expect(await r2c2.getText()).toBe('The authenticated channel username');
expect(await r2c3.getText()).toBe('d:propB');
});
it('should show as checked the node properties', () => {
const firstAspectCheckbox: HTMLInputElement = fixture.nativeElement.querySelector('#aspect-list-0-check-input');
expect(firstAspectCheckbox).toBeDefined();
expect(firstAspectCheckbox).not.toBeNull();
expect(firstAspectCheckbox.checked).toBeTruthy();
it('should show as checked the node properties', async () => {
const panel = await loader.getHarness(MatExpansionPanelHarness);
await panel.expand();
const checkbox = await panel.getHarness(MatCheckboxHarness);
expect(await checkbox.isChecked()).toBe(true);
});
it('should remove aspects unchecked', (done) => {
const secondElement = fixture.nativeElement.querySelector('#aspect-list-1-check-input');
expect(secondElement).toBeDefined();
expect(secondElement).not.toBeNull();
expect(secondElement.checked).toBeFalsy();
secondElement.click();
fixture.detectChanges();
it('should remove aspects unchecked', async () => {
const panel = await loader.getAllHarnesses(MatExpansionPanelHarness);
await panel[1].expand();
const checkbox = await panel[1].getHarness(MatCheckboxHarness);
expect(await checkbox.isChecked()).toBe(false);
await checkbox.toggle();
expect(component.nodeAspects.length).toBe(2);
expect(component.nodeAspects[1]).toBe('frs:SecondAspect');
component.valueChanged.subscribe((aspects) => {
expect(aspects.length).toBe(1);
expect(aspects[0]).toBe('frs:AspectOne');
done();
});
secondElement.click();
fixture.detectChanges();
});
it('should reset the properties on reset', (done) => {
const secondElement = fixture.nativeElement.querySelector('#aspect-list-1-check-input');
expect(secondElement).toBeDefined();
expect(secondElement).not.toBeNull();
expect(secondElement.checked).toBeFalsy();
secondElement.click();
fixture.detectChanges();
expect(component.nodeAspects.length).toBe(2);
component.valueChanged.subscribe((aspects) => {
expect(aspects.length).toBe(1);
done();
});
component.reset();
});
await checkbox.toggle();
it('should clear all the properties on clear', (done) => {
expect(component.nodeAspects.length).toBe(1);
component.valueChanged.subscribe((aspects) => {
expect(aspects.length).toBe(0);
done();
});
expect(component.nodeAspects[0]).toBe('frs:AspectOne');
});
it('should reset the properties on reset', async () => {
const panel = await loader.getAllHarnesses(MatExpansionPanelHarness);
await panel[1].expand();
const checkbox = await panel[1].getHarness(MatCheckboxHarness);
expect(await checkbox.isChecked()).toBe(false);
await checkbox.toggle();
expect(component.nodeAspects.length).toBe(2);
component.reset();
expect(component.nodeAspects.length).toBe(1);
});
it('should clear all the properties on clear', async () => {
expect(component.nodeAspects.length).toBe(1);
component.clear();
expect(component.nodeAspects.length).toBe(0);
});
});
@@ -277,21 +257,16 @@ describe('AspectListComponent', () => {
aspectListService = TestBed.inject(AspectListService);
spyOn(aspectListService, 'getAspects').and.returnValue(of(aspectListMock));
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
afterEach(() => {
fixture.destroy();
});
it('should show all the aspects', () => {
const firstElement = fixture.nativeElement.querySelector('#aspect-list-FirstAspect');
const secondElement = fixture.nativeElement.querySelector('#aspect-list-SecondAspect');
expect(firstElement).not.toBeNull();
expect(firstElement).toBeDefined();
expect(secondElement).not.toBeNull();
expect(secondElement).toBeDefined();
it('should show all the aspects', async () => {
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-FirstAspect' }))).toBe(true);
expect(await loader.hasHarness(MatExpansionPanelHarness.with({ selector: '#aspect-list-SecondAspect' }))).toBe(true);
});
});
});
@@ -26,7 +26,6 @@ import { of } from 'rxjs';
import { TranslateModule } from '@ngx-translate/core';
describe('DropdownBreadcrumb', () => {
let component: DropdownBreadcrumbComponent;
let fixture: ComponentFixture<DropdownBreadcrumbComponent>;
let documentList: DocumentListComponent;
@@ -34,10 +33,7 @@ describe('DropdownBreadcrumb', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [{ provide: DocumentListService, useValue: documentListService }]
});
@@ -64,7 +60,7 @@ describe('DropdownBreadcrumb', () => {
};
const clickOnTheFirstOption = () => {
const option: any = document.querySelector('[id^="mat-option"]');
const option: any = document.querySelector(`[data-automation-class="dropdown-breadcrumb-path-option"]`);
option.click();
};
@@ -75,7 +71,6 @@ describe('DropdownBreadcrumb', () => {
triggerComponentChange(fakeNodeWithCreatePermissionInstance);
fixture.whenStable().then(() => {
openSelect();
const currentFolder = fixture.debugElement.query(By.css('[data-automation-id="current-folder"]'));
@@ -99,7 +94,6 @@ describe('DropdownBreadcrumb', () => {
triggerComponentChange(fakeNodeWithCreatePermissionInstance);
fixture.whenStable().then(() => {
openSelect();
const path = fixture.debugElement.query(By.css('[data-automation-id="dropdown-breadcrumb-path"]'));
@@ -110,7 +104,6 @@ describe('DropdownBreadcrumb', () => {
});
});
it('should update document list when clicking on an option', async () => {
component.target = documentList;
const fakeNodeWithCreatePermissionInstance = JSON.parse(JSON.stringify(fakeNodeWithCreatePermission));
@@ -71,7 +71,8 @@
[value]="category">
{{ category.name }}
</mat-list-option>
<p *ngIf="!existingCategories?.length && !existingCategoriesLoading">
<p *ngIf="!existingCategories?.length && !existingCategoriesLoading"
data-automation-id="no-categories-message">
{{ 'CATEGORIES_MANAGEMENT.NO_EXISTING_CATEGORIES' | translate }}
</p>
</mat-selection-list>
@@ -16,7 +16,6 @@
*/
import { Category, CategoryPaging, ResultNode, ResultSetPaging } from '@alfresco/js-api';
import { DebugElement } from '@angular/core';
import { ComponentFixture, discardPeriodicTasks, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
import { Validators } from '@angular/forms';
import { MatError } from '@angular/material/form-field';
@@ -28,8 +27,12 @@ import { ContentTestingModule } from '../../testing/content.testing.module';
import { CategoriesManagementMode } from './categories-management-mode';
import { CategoryService } from '../services/category.service';
import { CategoriesManagementComponent } from './categories-management.component';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
describe('CategoriesManagementComponent', () => {
let loader: HarnessLoader;
let component: CategoriesManagementComponent;
let fixture: ComponentFixture<CategoriesManagementComponent>;
let categoryService: CategoryService;
@@ -38,18 +41,15 @@ describe('CategoriesManagementComponent', () => {
const category2 = new Category({ id: 'test2', name: 'testCat2' });
const category3 = new Category({ id: 'test3', name: 'testCat3' });
const category4 = new Category({ id: 'test4', name: 'testCat4' });
const resultCat1 = new ResultNode({ id: 'test', name: 'testCat', path: { name: 'general/categories' }});
const resultCat2 = new ResultNode({ id: 'test2', name: 'testCat2', path: { name: 'general/categories' }});
const categoryPagingResponse: CategoryPaging = { list: { pagination: {}, entries: [ { entry: category1 }, { entry: category2 }]}};
const categorySearchResponse: ResultSetPaging = { list: { pagination: {}, entries: [ { entry: resultCat1 }, { entry: resultCat2 }]}};
const resultCat1 = new ResultNode({ id: 'test', name: 'testCat', path: { name: 'general/categories' } });
const resultCat2 = new ResultNode({ id: 'test2', name: 'testCat2', path: { name: 'general/categories' } });
const categoryPagingResponse: CategoryPaging = { list: { pagination: {}, entries: [{ entry: category1 }, { entry: category2 }] } };
const categorySearchResponse: ResultSetPaging = { list: { pagination: {}, entries: [{ entry: resultCat1 }, { entry: resultCat2 }] } };
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [CategoriesManagementComponent],
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule],
providers: [
{
provide: CategoryService,
@@ -65,6 +65,7 @@ describe('CategoriesManagementComponent', () => {
fixture = TestBed.createComponent(CategoriesManagementComponent);
component = fixture.componentInstance;
categoryService = TestBed.inject(CategoryService);
loader = TestbedHarnessEnvironment.loader(fixture);
});
/**
@@ -138,7 +139,9 @@ describe('CategoriesManagementComponent', () => {
* @returns list of native elements
*/
function getRemoveCategoryButtons(): HTMLButtonElement[] {
return fixture.debugElement.queryAll(By.css(`[data-automation-id="categories-remove-category-button"]`)).map((debugElem) => debugElem.nativeElement);
return fixture.debugElement
.queryAll(By.css(`[data-automation-id="categories-remove-category-button"]`))
.map((debugElem) => debugElem.nativeElement);
}
/**
@@ -261,39 +264,28 @@ describe('CategoriesManagementComponent', () => {
});
describe('Spinner', () => {
/**
* Get the spinner element
*
* @returns debug element
*/
function getSpinner(): DebugElement {
return fixture.debugElement.query(By.css(`.mat-progress-spinner`));
}
it('should not be displayed when existing categories stopped loading', async () => {
component.categoryNameControlVisible = true;
fixture.detectChanges();
it('should be displayed with correct diameter when existing categories are loading', fakeAsync(() => {
typeCategory('Category 1', 0);
const categoryControlInput = getCategoryControlInput();
categoryControlInput.value = 'Category 1';
categoryControlInput.dispatchEvent(new InputEvent('input'));
const spinner = getSpinner();
expect(spinner).toBeTruthy();
expect(spinner.componentInstance.diameter).toBe(50);
fixture.detectChanges();
await fixture.whenStable();
discardPeriodicTasks();
flush();
}));
it('should not be displayed when existing categories stopped loading', fakeAsync(() => {
typeCategory('Category 1');
const spinner = getSpinner();
expect(spinner).toBeFalsy();
}));
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(false);
});
});
it('should display correct message when there are no existing categories', fakeAsync(() => {
spyOn(categoryService, 'getSubcategories').and.returnValue(of({list: { pagination: {}, entries: []}}));
spyOn(categoryService, 'getSubcategories').and.returnValue(of({ list: { pagination: {}, entries: [] } }));
typeCategory('test');
const noExistingCategoriesMsg = fixture.debugElement.query(By.css('mat-selection-list p'))?.nativeElement.textContent.trim();
const noExistingCategoriesMsg = fixture.debugElement
.query(By.css(`[data-automation-id="no-categories-message"]`))
?.nativeElement.textContent.trim();
expect(noExistingCategoriesMsg).toBe('CATEGORIES_MANAGEMENT.NO_EXISTING_CATEGORIES');
}));
});
@@ -328,7 +320,9 @@ describe('CategoriesManagementComponent', () => {
it('should have correct remove category title', () => {
const removeButtons = getRemoveCategoryButtons();
const isTitleCorrect = removeButtons.every((removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.UNASSIGN_CATEGORY');
const isTitleCorrect = removeButtons.every(
(removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.UNASSIGN_CATEGORY'
);
expect(isTitleCorrect).toBeTrue();
});
@@ -434,7 +428,9 @@ describe('CategoriesManagementComponent', () => {
it('should have correct remove category title', () => {
const removeButtons = getRemoveCategoryButtons();
const isTitleCorrect = removeButtons.every((removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.DELETE_CATEGORY');
const isTitleCorrect = removeButtons.every(
(removeBtn) => removeBtn.attributes.getNamedItem('title').textContent === 'CATEGORIES_MANAGEMENT.DELETE_CATEGORY'
);
expect(isTitleCorrect).toBeTrue();
});
@@ -21,16 +21,11 @@ import { AppConfigService, AuthenticationService, StorageService, CoreTestingMod
import { Node, PermissionsInfo } from '@alfresco/js-api';
import { TranslateModule } from '@ngx-translate/core';
declare let jasmine: any;
describe('ContentService', () => {
let contentService: ContentService;
let authService: AuthenticationService;
let storage: StorageService;
let node: any;
const nodeId = 'fake-node-id';
beforeEach(() => {
TestBed.configureTestingModule({
@@ -44,14 +39,6 @@ describe('ContentService', () => {
storage = TestBed.inject(StorageService);
storage.clear();
node = {
entry: {
id: nodeId
}
};
jasmine.Ajax.install();
const appConfig: AppConfigService = TestBed.inject(AppConfigService);
appConfig.config = {
ecmHost: 'http://localhost:9876/ecm',
@@ -59,24 +46,6 @@ describe('ContentService', () => {
};
});
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should return a valid content URL', (done) => {
authService.login('fake-username', 'fake-password').subscribe(() => {
expect(contentService.getContentUrl(node)).toContain('/ecm/alfresco/api/' +
'-default-/public/alfresco/versions/1/nodes/fake-node-id/content?attachment=false&alf_ticket=fake-post-ticket');
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 201,
contentType: 'application/json',
responseText: JSON.stringify({ entry: { id: 'fake-post-ticket', userId: 'admin' } })
});
});
describe('AllowableOperations', () => {
it('should hasAllowableOperations be false if allowableOperation is not present in the node', () => {
@@ -18,16 +18,27 @@
import { Injectable } from '@angular/core';
import { from, Observable, throwError, Subject } from 'rxjs';
import { catchError, map, switchMap, filter, take } from 'rxjs/operators';
import { RepositoryInfo, SystemPropertiesRepresentation } from '@alfresco/js-api';
import {
RepositoryInfo,
SystemPropertiesRepresentation,
DiscoveryApi,
AboutApi,
SystemPropertiesApi
} from '@alfresco/js-api';
import { BpmProductVersionModel, AuthenticationService } from '@alfresco/adf-core';
import { ApiClientsService } from '@alfresco/adf-core/api';
import { AlfrescoApiService, BpmProductVersionModel, AuthenticationService } from '@alfresco/adf-core';
@Injectable({
providedIn: 'root'
})
export class DiscoveryApiService {
private _discoveryApi: DiscoveryApi;
get discoveryApi(): DiscoveryApi {
this._discoveryApi = this._discoveryApi ?? new DiscoveryApi(this.alfrescoApiService.getInstance());
return this._discoveryApi;
}
/**
* Gets product information for Content Services.
*/
@@ -35,15 +46,17 @@ export class DiscoveryApiService {
constructor(
private authenticationService: AuthenticationService,
private apiClientsService: ApiClientsService
private alfrescoApiService: AlfrescoApiService
) {
this.authenticationService.onLogin
.pipe(
this.authenticationService.onLogin.subscribe(() => {
this.alfrescoApiService.alfrescoApiInitialized.pipe(
filter(() => this.authenticationService.isEcmLoggedIn()),
take(1),
switchMap(() => this.getEcmProductInfo())
)
.subscribe((info) => this.ecmProductInfo$.next(info));
.subscribe((info) => this.ecmProductInfo$.next(info));
});
}
@@ -53,9 +66,8 @@ export class DiscoveryApiService {
* @returns ProductVersionModel containing product details
*/
getEcmProductInfo(): Observable<RepositoryInfo> {
const discoveryApi = this.apiClientsService.get('DiscoveryClient.discovery');
return from(discoveryApi.getRepositoryInformation())
return from(this.discoveryApi.getRepositoryInformation())
.pipe(
map((res) => res.entry.repository),
catchError((err) => throwError(err))
@@ -68,7 +80,7 @@ export class DiscoveryApiService {
* @returns ProductVersionModel containing product details
*/
getBpmProductInfo(): Observable<BpmProductVersionModel> {
const aboutApi = this.apiClientsService.get('ActivitiClient.about');
const aboutApi = new AboutApi(this.alfrescoApiService.getInstance());
return from(aboutApi.getAppVersion())
.pipe(
@@ -78,7 +90,7 @@ export class DiscoveryApiService {
}
getBPMSystemProperties(): Observable<SystemPropertiesRepresentation> {
const systemPropertiesApi = this.apiClientsService.get('ActivitiClient.system-properties');
const systemPropertiesApi = new SystemPropertiesApi(this.alfrescoApiService.getInstance());
return from(systemPropertiesApi.getProperties())
.pipe(
@@ -25,7 +25,6 @@ import {
import {
AlfrescoApiService,
AlfrescoApiServiceMock,
AuthenticationService,
CoreTestingModule
} from '@alfresco/adf-core';
import { PeopleContentQueryRequestModel, PeopleContentService } from './people-content.service';
@@ -34,7 +33,6 @@ import { TestBed } from '@angular/core/testing';
describe('PeopleContentService', () => {
let peopleContentService: PeopleContentService;
let authenticationService: AuthenticationService;
beforeEach(() => {
TestBed.configureTestingModule({
@@ -47,7 +45,6 @@ describe('PeopleContentService', () => {
]
});
authenticationService = TestBed.inject(AuthenticationService);
peopleContentService = TestBed.inject(PeopleContentService);
});
@@ -130,17 +127,6 @@ describe('PeopleContentService', () => {
expect(getCurrentPersonSpy.calls.count()).toEqual(1);
});
it('should reset the admin cache upon logout', async () => {
spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(Promise.resolve({ entry: fakeEcmAdminUser } as any));
const user = await peopleContentService.getCurrentUserInfo().toPromise();
expect(user.id).toEqual('fake-id');
expect(peopleContentService.isCurrentUserAdmin()).toBe(true);
authenticationService.onLogout.next(true);
expect(peopleContentService.isCurrentUserAdmin()).toBe(false);
});
it('should not change current user on every getPerson call', async () => {
const getCurrentPersonSpy = spyOn(peopleContentService.peopleApi, 'getPerson').and.returnValue(Promise.resolve({entry: fakeEcmAdminUser} as any));
await peopleContentService.getCurrentUserInfo().toPromise();
@@ -607,7 +607,7 @@ describe('ContentMetadataComponent', () => {
it('should hide metadata fields if displayDefaultProperties is set to false', () => {
component.displayDefaultProperties = false;
fixture.detectChanges();
const metadataContainer = fixture.debugElement.query(By.css('mat-expansion-panel[data-automation-id="adf-metadata-group-properties"]'));
const metadataContainer = fixture.debugElement.query(By.css('[data-automation-id="adf-metadata-group-properties"]'));
fixture.detectChanges();
expect(metadataContainer).toBeNull();
});
@@ -615,7 +615,7 @@ describe('ContentMetadataComponent', () => {
it('should display metadata fields if displayDefaultProperties is set to true', () => {
component.displayDefaultProperties = true;
fixture.detectChanges();
const metadataContainer = fixture.debugElement.query(By.css('mat-expansion-panel[data-automation-id="adf-metadata-group-properties"]'));
const metadataContainer = fixture.debugElement.query(By.css('[data-automation-id="adf-metadata-group-properties"]'));
fixture.detectChanges();
expect(metadataContainer).toBeDefined();
});
@@ -24,7 +24,6 @@ import { By } from '@angular/platform-browser';
import { FileModel } from '../common/models/file.model';
import { FileUploadEvent } from '../common/events/file.event';
import { UploadService } from '../common/services/upload.service';
import { of } from 'rxjs';
import { ContentTestingModule } from '../testing/content.testing.module';
import { DocumentListService } from '../document-list/services/document-list.service';
@@ -58,12 +57,7 @@ describe('ContentNodeSelectorComponent', () => {
};
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule,
MatDialogModule,
UploadModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule, MatDialogModule, UploadModule],
providers: [
{ provide: MAT_DIALOG_DATA, useValue: data },
{
@@ -118,6 +112,8 @@ describe('ContentNodeSelectorComponent', () => {
fixture.destroy();
});
const getTabInfoButton = () => fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]'));
const enableLocalUpload = () => {
component.data.showLocalUploadButton = true;
component.hasAllowableOperations = true;
@@ -125,15 +121,16 @@ describe('ContentNodeSelectorComponent', () => {
component.isLoading = false;
};
const getTabLabel = (idx: number) => fixture.debugElement.queryAll(By.css('.mat-tab-label'))[idx];
const selectTabByIndex = (tabIndex: number) => {
const uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[tabIndex];
const uploadFromLocalTab = getTabLabel(tabIndex);
const attributes = uploadFromLocalTab.nativeNode.attributes as NamedNodeMap;
const tabPositionInSet = Number(attributes.getNamedItem('aria-posinset').value) - 1;
component.onTabSelectionChange(tabPositionInSet);
};
describe('Data injecting with the "Material dialog way"', () => {
it('should show the INJECTED title', () => {
const titleElement = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-title"]'));
expect(titleElement).not.toBeNull();
@@ -149,101 +146,105 @@ describe('ContentNodeSelectorComponent', () => {
it('should pass through the injected currentFolderId to the documentList', () => {
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
expect(documentList).not.toBeNull('Document list should be shown');
expect(documentList).not.toBeNull();
expect(documentList.componentInstance.currentFolderId).toBe('cat-girl-nuku-nuku');
});
it('should pass through the injected rowFilter to the documentList', () => {
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
expect(documentList).not.toBeNull('Document list should be shown');
expect(documentList.componentInstance.rowFilter({
node: {
entry: new Node({
name: 'impossible-name',
id: 'name'
})
}
}))
.toBe(data.rowFilter({
expect(documentList).not.toBeNull();
expect(
documentList.componentInstance.rowFilter({
node: {
entry: new Node({
name: 'impossible-name',
id: 'name'
})
}
}));
})
).toBe(
data.rowFilter({
node: {
entry: new Node({
name: 'impossible-name',
id: 'name'
})
}
})
);
});
it('should pass through the injected imageResolver to the documentList', () => {
const documentList = fixture.debugElement.query(By.directive(DocumentListComponent));
expect(documentList).not.toBeNull('Document list should be shown');
expect(documentList).not.toBeNull();
expect(documentList.componentInstance.imageResolver).toBe(data.imageResolver);
});
});
});
describe('Cancel button', () => {
const getCancelButton = () => fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-cancel"]'));
it('should not be shown if dialogRef is NOT injected', () => {
const closeButton = fixture.debugElement.query(By.css('[content-node-selector-actions-cancel]'));
expect(closeButton).toBeNull();
});
it('should close the dialog', () => {
let cancelButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-cancel"]'));
let cancelButton = getCancelButton();
cancelButton.triggerEventHandler('click', {});
expect(dialog.close).toHaveBeenCalled();
fixture.detectChanges();
cancelButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-cancel"]'));
cancelButton = getCancelButton();
expect(cancelButton).not.toBeNull();
});
});
describe('Action button for the chosen node', () => {
const getActionButton = () =>
fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'))?.nativeElement as HTMLButtonElement;
it('should be disabled by default', () => {
fixture.detectChanges();
const actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'));
expect(actionButton.nativeElement.disabled).toBeTruthy();
const actionButton = getActionButton();
expect(actionButton.disabled).toBeTruthy();
});
it('should be enabled when a node is chosen', () => {
component.onSelect([new Node({ id: 'fake' })]);
fixture.detectChanges();
const actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'));
expect(actionButton.nativeElement.disabled).toBeFalsy();
const actionButton = getActionButton();
expect(actionButton.disabled).toBeFalsy();
});
it('should be disabled when no node chosen', () => {
component.onSelect([new Node({ id: 'fake' })]);
fixture.detectChanges();
const actionButtonWithNodeSelected = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'));
expect(actionButtonWithNodeSelected.nativeElement.disabled).toBe(false);
const actionButtonWithNodeSelected = getActionButton();
expect(actionButtonWithNodeSelected.disabled).toBe(false);
component.onSelect([]);
fixture.detectChanges();
const actionButtonWithoutNodeSelected = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'));
expect(actionButtonWithoutNodeSelected.nativeElement.disabled).toBe(true);
const actionButtonWithoutNodeSelected = getActionButton();
expect(actionButtonWithoutNodeSelected.disabled).toBe(true);
});
it('should close the dialog when action button is clicked', async () => {
it('should close the dialog when action button is clicked', () => {
component.onSelect([new Node({ id: 'fake' })]);
fixture.detectChanges();
const actionButton = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-actions-choose"]'));
await actionButton.nativeElement.click();
const actionButton = getActionButton();
actionButton.click();
expect(dialog.close).toHaveBeenCalled();
});
});
describe('Title', () => {
it('should be updated when a site is chosen', () => {
const fakeSiteTitle = 'My fake site';
const contentNodePanel = fixture.debugElement.query(By.directive(ContentNodeSelectorPanelComponent));
@@ -253,17 +254,18 @@ describe('ContentNodeSelectorComponent', () => {
const titleElement = fixture.debugElement.query(By.css('[data-automation-id="content-node-selector-title"]'));
expect(titleElement).not.toBeNull();
expect(titleElement.nativeElement.innerText).toBe('NODE_SELECTOR.CHOOSE_ITEM');
});
});
});
});
describe('Upload button', () => {
const getUploadButton = () => fixture.debugElement.query(By.css('adf-upload-button button'))?.nativeElement as HTMLButtonElement;
it('Should not be able to upload a file whilst a search is still running', () => {
enableLocalUpload();
fixture.detectChanges();
let infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]'));
let uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1];
let infoMatIcon = getTabInfoButton();
let uploadFromLocalTab = getTabLabel(1);
expect(uploadFromLocalTab.nativeElement.getAttribute('aria-disabled')).toBe('false');
expect(infoMatIcon).toBeFalsy();
@@ -271,8 +273,8 @@ describe('ContentNodeSelectorComponent', () => {
component.showingSearch = true;
fixture.detectChanges();
uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1];
infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]'));
uploadFromLocalTab = getTabLabel(1);
infoMatIcon = getTabInfoButton();
expect(uploadFromLocalTab.nativeElement.getAttribute('aria-disabled')).toBe('true');
expect(infoMatIcon).toBeTruthy();
@@ -281,8 +283,8 @@ describe('ContentNodeSelectorComponent', () => {
component.showingSearch = false;
fixture.detectChanges();
uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1];
infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]'));
uploadFromLocalTab = getTabLabel(1);
infoMatIcon = getTabInfoButton();
expect(uploadFromLocalTab.nativeElement.getAttribute('aria-disabled')).toBe('false');
expect(infoMatIcon).toBeFalsy();
@@ -305,10 +307,10 @@ describe('ContentNodeSelectorComponent', () => {
component.hasAllowableOperations = true;
fixture.detectChanges();
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));
const adfUploadButton = getUploadButton();
expect(adfUploadButton).not.toBeNull();
expect(adfUploadButton.nativeElement.disabled).toBe(true);
expect(adfUploadButton.disabled).toBe(true);
});
it('should be able to enable UploadButton if showingSearch set to false', () => {
@@ -317,10 +319,10 @@ describe('ContentNodeSelectorComponent', () => {
component.hasAllowableOperations = true;
fixture.detectChanges();
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));
const adfUploadButton = getUploadButton();
expect(adfUploadButton).not.toBeNull();
expect(adfUploadButton.nativeElement.disabled).toBe(false);
expect(adfUploadButton.disabled).toBe(false);
});
it('should be able to show warning message while searching', () => {
@@ -330,7 +332,7 @@ describe('ContentNodeSelectorComponent', () => {
selectTabByIndex(1);
fixture.detectChanges();
const infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]'));
const infoMatIcon = getTabInfoButton();
const iconTooltipMessage = infoMatIcon.attributes['ng-reflect-message'];
const expectedMessage = 'NODE_SELECTOR.UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE';
@@ -354,10 +356,10 @@ describe('ContentNodeSelectorComponent', () => {
selectTabByIndex(1);
fixture.detectChanges();
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));
const adfUploadButton = getUploadButton();
expect(adfUploadButton).not.toBeNull();
expect(adfUploadButton.nativeElement.disabled).toBe(true);
expect(adfUploadButton.disabled).toBe(true);
});
it('should be able to enable UploadButton if user has allowable operations', () => {
@@ -365,10 +367,10 @@ describe('ContentNodeSelectorComponent', () => {
component.hasAllowableOperations = true;
fixture.detectChanges();
const adfUploadButton = fixture.debugElement.query(By.css('adf-upload-button button'));
const adfUploadButton = getUploadButton();
expect(adfUploadButton).not.toBeNull();
expect(adfUploadButton.nativeElement.disabled).toBe(false);
expect(adfUploadButton.disabled).toBe(false);
});
it('should not be able to show warning message if user has allowable operations', () => {
@@ -388,7 +390,7 @@ describe('ContentNodeSelectorComponent', () => {
selectTabByIndex(1);
fixture.detectChanges();
const infoMatIcon = fixture.debugElement.query(By.css('[data-automation-id="adf-content-node-selector-disabled-tab-info-icon"]'));
const infoMatIcon = getTabInfoButton();
const iconTooltipMessage = infoMatIcon.attributes['ng-reflect-message'];
const expectedMessage = 'NODE_SELECTOR.UPLOAD_BUTTON_PERMISSION_WARNING_MESSAGE';
@@ -424,11 +426,11 @@ describe('ContentNodeSelectorComponent', () => {
});
it('should tabs be headless when local upload is not enabled', () => {
component.data.showLocalUploadButton = false;
fixture.detectChanges();
const tabGroup = fixture.debugElement.queryAll(By.css('.adf-content-node-selector-headless-tabs'))[0];
component.data.showLocalUploadButton = false;
fixture.detectChanges();
const tabGroup = fixture.debugElement.queryAll(By.css('.adf-content-node-selector-headless-tabs'))[0];
expect(tabGroup).not.toBe(undefined);
expect(tabGroup).not.toBe(undefined);
});
it('should tabs show headers when local upload is enabled', () => {
@@ -441,12 +443,14 @@ describe('ContentNodeSelectorComponent', () => {
});
describe('Drag and drop area', () => {
const getEmptyList = () => fixture.nativeElement.querySelector('[data-automation-id="adf-empty-list"]');
it('should uploadStarted be false by default', () => {
expect(component.uploadStarted).toBe(false);
});
it('should uploadStarted become true when the first upload gets started', () => {
const fileUploadEvent = new FileUploadEvent(new FileModel({ name: 'fake-name', size: 100 } as File));
const fileUploadEvent = new FileUploadEvent(new FileModel({ name: 'fake-name', size: 100 } as File));
uploadService.fileUploadStarting.next(fileUploadEvent);
expect(component.uploadStarted).toBe(true);
@@ -454,12 +458,13 @@ describe('ContentNodeSelectorComponent', () => {
it('should show drag and drop area with the empty list template when no upload has started', async () => {
enableLocalUpload();
const uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1];
const uploadFromLocalTab = getTabLabel(1);
uploadFromLocalTab.nativeElement.click();
fixture.detectChanges();
await fixture.whenRenderingDone();
const emptyListTemplate = fixture.nativeElement.querySelector('[data-automation-id="adf-empty-list"]');
const emptyListTemplate = getEmptyList();
const dragAndDropArea = fixture.debugElement.query(By.css('.adf-upload-drag-area'));
expect(emptyListTemplate).not.toBeNull();
@@ -468,19 +473,21 @@ describe('ContentNodeSelectorComponent', () => {
it('should not show the empty list template when an upload has started', async () => {
enableLocalUpload();
const uploadFromLocalTab = fixture.debugElement.queryAll(By.css('.mat-tab-label'))[1];
const uploadFromLocalTab = getTabLabel(1);
uploadFromLocalTab.nativeElement.click();
component.uploadStarted = true;
fixture.detectChanges();
await fixture.whenRenderingDone();
const emptyListTemplate = fixture.nativeElement.querySelector('[data-automation-id="adf-empty-list"]');
const emptyListTemplate = getEmptyList();
expect(emptyListTemplate).toBeNull();
});
});
describe('Selected nodes counter', () => {
const getNodeCounter = () => fixture.debugElement.nativeElement.querySelector('adf-node-counter');
it('should getSelectedCount return 0 by default', () => {
expect(component.getSelectedCount()).toBe(0);
});
@@ -494,19 +501,19 @@ describe('ContentNodeSelectorComponent', () => {
it('should show the counter depending on the action', () => {
component.action = NodeAction.ATTACH;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('adf-node-counter')).not.toBe(null);
expect(getNodeCounter()).not.toBe(null);
component.action = NodeAction.CHOOSE;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('adf-node-counter')).not.toBe(null);
expect(getNodeCounter()).not.toBe(null);
component.action = NodeAction.COPY;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('adf-node-counter')).toBe(null);
expect(getNodeCounter()).toBe(null);
component.action = NodeAction.MOVE;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('adf-node-counter')).toBe(null);
expect(getNodeCounter()).toBe(null);
});
});
});
@@ -15,9 +15,9 @@
* limitations under the License.
*/
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { Component, Inject, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { TranslationService, NotificationService} from '@alfresco/adf-core';
import { TranslationService, NotificationService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api';
import { AllowableOperationsEnum } from '../common/models/allowable-operations.enum';
import { ContentService } from '../common/services/content.service';
@@ -26,6 +26,8 @@ import { ContentNodeSelectorComponentData } from './content-node-selector.compon
import { NodeEntryEvent } from '../document-list/components/node.event';
import { NodeAction } from '../document-list/models/node-action.enum';
import { OverlayContainer } from '@angular/cdk/overlay';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'adf-content-node-selector',
@@ -33,7 +35,9 @@ import { OverlayContainer } from '@angular/cdk/overlay';
styleUrls: ['./content-node-selector.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class ContentNodeSelectorComponent implements OnInit {
export class ContentNodeSelectorComponent implements OnInit, OnDestroy {
private onDestroy$ = new Subject<void>();
title: string;
action: NodeAction;
buttonActionName: string;
@@ -48,13 +52,15 @@ export class ContentNodeSelectorComponent implements OnInit {
emptyFolderImageUrl: string = './assets/images/empty_doc_lib.svg';
breadcrumbFolderNode: Node;
constructor(private translation: TranslationService,
private contentService: ContentService,
private notificationService: NotificationService,
private uploadService: UploadService,
private dialog: MatDialogRef<ContentNodeSelectorComponent>,
private overlayContainer: OverlayContainer,
@Inject(MAT_DIALOG_DATA) public data: ContentNodeSelectorComponentData) {
constructor(
private translation: TranslationService,
private contentService: ContentService,
private notificationService: NotificationService,
private uploadService: UploadService,
private dialog: MatDialogRef<ContentNodeSelectorComponent>,
private overlayContainer: OverlayContainer,
@Inject(MAT_DIALOG_DATA) public data: ContentNodeSelectorComponentData
) {
this.action = data.actionName ?? NodeAction.CHOOSE;
this.buttonActionName = `NODE_SELECTOR.${this.action}`;
this.title = data.title;
@@ -62,28 +68,41 @@ export class ContentNodeSelectorComponent implements OnInit {
}
ngOnInit() {
this.dialog.keydownEvents().subscribe(event => {
// Esc
if (event.keyCode === 27) {
event.preventDefault();
event.stopImmediatePropagation();
this.dialog
.keydownEvents()
.pipe(takeUntil(this.onDestroy$))
.subscribe((event) => {
if (event?.key === 'Escape') {
event.preventDefault();
event.stopImmediatePropagation();
this.close();
}
});
this.dialog
.backdropClick()
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
this.close();
}
});
});
this.dialog.backdropClick().subscribe(() => {
this.close();
});
this.dialog
.afterOpened()
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => {
this.overlayContainer.getContainerElement().setAttribute('role', 'main');
});
this.dialog.afterOpened().subscribe(() => {
this.overlayContainer.getContainerElement().setAttribute('role', 'main');
});
this.uploadService.fileUploadStarting.subscribe(() => {
this.uploadService.fileUploadStarting.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
this.uploadStarted = true;
});
}
ngOnDestroy() {
this.onDestroy$.next();
this.onDestroy$.complete();
}
close() {
this.dialog.close();
this.overlayContainer.getContainerElement().setAttribute('role', 'region');
@@ -179,16 +198,17 @@ export class ContentNodeSelectorComponent implements OnInit {
}
getWarningMessage(): string {
return this.showingSearch ? 'NODE_SELECTOR.UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE' :
(this.hasNoPermissionToUpload() ? 'NODE_SELECTOR.UPLOAD_BUTTON_PERMISSION_WARNING_MESSAGE' : '');
if (this.showingSearch) {
return 'NODE_SELECTOR.UPLOAD_BUTTON_SEARCH_WARNING_MESSAGE';
}
return this.hasNoPermissionToUpload() ? 'NODE_SELECTOR.UPLOAD_BUTTON_PERMISSION_WARNING_MESSAGE' : '';
}
hasNoPermissionToUpload(): boolean {
return (!this.hasAllowableOperations && !this.showingSearch) && !this.isLoading;
return !this.hasAllowableOperations && !this.showingSearch && !this.isLoading;
}
hasUploadError(): boolean {
return this.showingSearch || this.hasNoPermissionToUpload();
}
}
@@ -7,8 +7,6 @@
&__dialog-content {
display: flex;
flex-direction: column;
padding: 24px;
background-color: var(--theme-grey-text-background-color);
}
&__dialog-container {
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { TestBed, fakeAsync, ComponentFixture, tick } from '@angular/core/testing';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
import { of } from 'rxjs';
import { NotificationService, AppConfigService } from '@alfresco/adf-core';
@@ -28,8 +28,12 @@ import { TranslateModule } from '@ngx-translate/core';
import { format, endOfDay } from 'date-fns';
import { By } from '@angular/platform-browser';
import { NodeEntry } from '@alfresco/js-api';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing';
describe('ShareDialogComponent', () => {
let loader: HarnessLoader;
let node: NodeEntry;
let matDialog: MatDialog;
const notificationServiceMock = {
@@ -45,8 +49,6 @@ describe('ShareDialogComponent', () => {
const shareToggleId = '[data-automation-id="adf-share-toggle"]';
const expireToggle = '[data-automation-id="adf-expire-toggle"]';
const getShareToggleLinkedClasses = (): DOMTokenList => fixture.nativeElement.querySelector(shareToggleId).classList;
const fillInDatepickerInput = (value: string) => {
const input = fixture.debugElement.query(By.css('.adf-share-link__input')).nativeElement;
input.value = value;
@@ -55,10 +57,6 @@ describe('ShareDialogComponent', () => {
fixture.detectChanges();
};
const clickExpireToggleButton = () => fixture.nativeElement.querySelector(`${expireToggle} label`).dispatchEvent(new MouseEvent('click'));
const clickShareToggleButton = () => fixture.nativeElement.querySelector(`${shareToggleId} label`).dispatchEvent(new MouseEvent('click'));
beforeEach(() => {
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), ContentTestingModule],
@@ -99,6 +97,7 @@ describe('ShareDialogComponent', () => {
};
spyOn(nodesApiService, 'updateNode').and.returnValue(of(null));
loader = TestbedHarnessEnvironment.loader(fixture);
});
afterEach(() => {
@@ -133,7 +132,7 @@ describe('ShareDialogComponent', () => {
});
});
it(`should toggle share action when property 'sharedId' does not exists`, () => {
it(`should toggle share action when property 'sharedId' does not exists`, async () => {
spyOn(sharedLinksApiService, 'createSharedLinks').and.returnValue(
of({
entry: { id: 'sharedId', sharedId: 'sharedId' }
@@ -151,7 +150,9 @@ describe('ShareDialogComponent', () => {
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalled();
expect(renditionService.getNodeRendition).toHaveBeenCalled();
expect(fixture.nativeElement.querySelector('input[formcontrolname="sharedUrl"]').value).toBe('some-url/sharedId');
expect(getShareToggleLinkedClasses()).toContain('mat-checked');
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId }));
expect(await toggle.isChecked()).toBe(true);
});
it(`should not toggle share action when file has 'sharedId' property`, async () => {
@@ -176,10 +177,12 @@ describe('ShareDialogComponent', () => {
expect(sharedLinksApiService.createSharedLinks).not.toHaveBeenCalled();
expect(fixture.nativeElement.querySelector('input[formcontrolname="sharedUrl"]').value).toBe('some-url/sharedId');
expect(getShareToggleLinkedClasses()).toContain('mat-checked');
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId }));
expect(await toggle.isChecked()).toBe(true);
});
it('should open a confirmation dialog when unshare button is triggered', () => {
it('should open a confirmation dialog when unshare button is triggered', async () => {
spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any);
spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough();
@@ -192,14 +195,13 @@ describe('ShareDialogComponent', () => {
fixture.detectChanges();
clickShareToggleButton();
fixture.detectChanges();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId }));
await toggle.toggle();
expect(matDialog.open).toHaveBeenCalled();
});
it('should unshare file when confirmation dialog returns true', fakeAsync(() => {
it('should unshare file when confirmation dialog returns true', async () => {
spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(true) } as any);
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of({}));
node.entry.properties['qshare:sharedId'] = 'sharedId';
@@ -211,14 +213,13 @@ describe('ShareDialogComponent', () => {
fixture.detectChanges();
clickShareToggleButton();
fixture.detectChanges();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId }));
await toggle.toggle();
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled();
}));
});
it('should not unshare file when confirmation dialog returns false', fakeAsync(() => {
it('should not unshare file when confirmation dialog returns false', async () => {
spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any);
spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough();
node.entry.properties['qshare:sharedId'] = 'sharedId';
@@ -230,14 +231,13 @@ describe('ShareDialogComponent', () => {
fixture.detectChanges();
clickShareToggleButton();
fixture.detectChanges();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId }));
await toggle.toggle();
expect(sharedLinksApiService.deleteSharedLink).not.toHaveBeenCalled();
}));
});
it('should not allow unshare when node has no update permission', () => {
it('should not allow unshare when node has no update permission', async () => {
node.entry.properties['qshare:sharedId'] = 'sharedId';
node.entry.allowableOperations = [];
@@ -248,7 +248,8 @@ describe('ShareDialogComponent', () => {
fixture.detectChanges();
expect(getShareToggleLinkedClasses()).toContain('mat-disabled');
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId }));
expect(await toggle.isChecked()).toBe(true);
});
it('should delete the current link generated with expiry date and generate a new link without expiry date when toggle is unchecked', async () => {
@@ -266,9 +267,9 @@ describe('ShareDialogComponent', () => {
fixture.detectChanges();
component.form.controls['time'].setValue(new Date());
fixture.detectChanges();
clickExpireToggleButton();
fixture.detectChanges();
await fixture.whenStable();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle }));
await toggle.toggle();
expect(sharedLinksApiService.deleteSharedLink).toHaveBeenCalled();
expect(sharedLinksApiService.createSharedLinks).toHaveBeenCalledWith('nodeId', undefined);
@@ -286,7 +287,9 @@ describe('ShareDialogComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
expect(fixture.nativeElement.querySelector('.mat-slide-toggle[data-automation-id="adf-expire-toggle"]').classList).toContain('mat-disabled');
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: `[data-automation-id="adf-expire-toggle"]` }));
expect(await toggle.isDisabled()).toBe(true);
expect(fixture.nativeElement.querySelector('[data-automation-id="adf-slide-toggle-checked"]').style.display).toEqual('none');
});
@@ -303,18 +306,19 @@ describe('ShareDialogComponent', () => {
};
});
it('should update node with input date and end of day time when type is `date`', fakeAsync(() => {
it('should update node with input date and end of day time when type is `date`', async () => {
const dateTimePickerType = 'date';
const date = new Date('2525-01-01');
spyOn(appConfigService, 'get').and.callFake(() => dateTimePickerType as any);
fixture.detectChanges();
clickExpireToggleButton();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle }));
await toggle.toggle();
fixture.componentInstance.time.setValue(date);
component.onTimeChanged();
fixture.detectChanges();
tick(500);
const expiryDate = format(endOfDay(date as Date), `yyyy-MM-dd'T'HH:mm:ss.SSSxx`);
@@ -323,11 +327,14 @@ describe('ShareDialogComponent', () => {
nodeId: 'nodeId',
expiresAt: expiryDate
});
}));
});
it('should not update node when provided date is less than minDate', () => {
it('should not update node when provided date is less than minDate', async () => {
fixture.detectChanges();
clickExpireToggleButton();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle }));
await toggle.toggle();
fillInDatepickerInput('01.01.2010');
expect(component.form.invalid).toBeTrue();
@@ -335,9 +342,12 @@ describe('ShareDialogComponent', () => {
expect(sharedLinksApiService.createSharedLinks).not.toHaveBeenCalled();
});
it('should not accept alphabets in the datepicker input', () => {
it('should not accept alphabets in the datepicker input', async () => {
fixture.detectChanges();
clickExpireToggleButton();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle }));
await toggle.toggle();
fillInDatepickerInput('test');
expect(component.form.invalid).toBeTrue();
@@ -346,7 +356,10 @@ describe('ShareDialogComponent', () => {
it('should show an error if provided date is invalid', async () => {
fixture.detectChanges();
clickExpireToggleButton();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle }));
await toggle.toggle();
fillInDatepickerInput('incorrect');
fixture.detectChanges();
@@ -358,9 +371,12 @@ describe('ShareDialogComponent', () => {
expect(component.time.hasError('invalidDate')).toBeTrue();
});
it('should not show an error when provided date is valid', () => {
it('should not show an error when provided date is valid', async () => {
fixture.detectChanges();
clickExpireToggleButton();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: expireToggle }));
await toggle.toggle();
fillInDatepickerInput('12.12.2525');
const error = fixture.debugElement.query(By.css('[data-automation-id="adf-share-link-input-warning"]'));
@@ -1,4 +1,4 @@
<h2 mat-dialog-title>
<h2 data-automation-id="adf-folder-dialog-title" mat-dialog-title>
{{ (editing ? editTitle : createTitle) | translate }}
</h2>
@@ -35,13 +35,8 @@ describe('FolderDialogComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
providers: [
{ provide: MatDialogRef, useValue: dialogRef }
]
imports: [TranslateModule.forRoot(), ContentTestingModule],
providers: [{ provide: MatDialogRef, useValue: dialogRef }]
});
dialogRef.close.calls.reset();
fixture = TestBed.createComponent(FolderDialogComponent);
@@ -53,8 +48,9 @@ describe('FolderDialogComponent', () => {
fixture.destroy();
});
describe('Edit', () => {
const getTitle = () => fixture.debugElement.query(By.css('[data-automation-id="adf-folder-dialog-title"]'));
describe('Edit', () => {
beforeEach(() => {
component.data = {
folder: {
@@ -76,8 +72,8 @@ describe('FolderDialogComponent', () => {
});
it('should have the proper title', () => {
const title = fixture.debugElement.query(By.css('[mat-dialog-title]'));
expect(title === null).toBe(false);
const title = getTitle();
expect(title).not.toBeNull();
expect(title.nativeElement.innerText.trim()).toBe('CORE.FOLDER_DIALOG.EDIT_FOLDER_TITLE');
});
@@ -100,16 +96,13 @@ describe('FolderDialogComponent', () => {
component.submit();
expect(nodesApi.updateNode).toHaveBeenCalledWith(
'node-id',
{
name: 'folder-name-update',
properties: {
'cm:title': 'folder-title-update',
'cm:description': 'folder-description-update'
}
expect(nodesApi.updateNode).toHaveBeenCalledWith('node-id', {
name: 'folder-name-update',
properties: {
'cm:title': 'folder-title-update',
'cm:description': 'folder-description-update'
}
);
});
});
it('should call dialog to close with form data when submit is successfully', () => {
@@ -174,10 +167,10 @@ describe('FolderDialogComponent', () => {
});
it('should have the proper title', () => {
const title = fixture.debugElement.query(By.css('[mat-dialog-title]'));
expect(title === null).toBe(false);
const title = getTitle();
expect(title).not.toBeNull();
expect(title.nativeElement.innerText.trim()).toBe('CORE.FOLDER_DIALOG.CREATE_FOLDER_TITLE');
});
});
it('should init form with empty inputs', () => {
expect(component.name).toBe('');
@@ -201,17 +194,14 @@ describe('FolderDialogComponent', () => {
component.submit();
expect(nodesApi.createFolder).toHaveBeenCalledWith(
'parentNodeId',
{
name: 'folder-name-update',
properties: {
'cm:title': 'folder-title-update',
'cm:description': 'folder-description-update'
},
nodeType: 'cm:folder'
}
);
expect(nodesApi.createFolder).toHaveBeenCalledWith('parentNodeId', {
name: 'folder-name-update',
properties: {
'cm:title': 'folder-title-update',
'cm:description': 'folder-description-update'
},
nodeType: 'cm:folder'
});
});
it('should submit updated values if form is valid (with custom nodeType)', () => {
@@ -224,17 +214,14 @@ describe('FolderDialogComponent', () => {
component.submit();
expect(nodesApi.createFolder).toHaveBeenCalledWith(
'parentNodeId',
{
name: 'folder-name-update',
properties: {
'cm:title': 'folder-title-update',
'cm:description': 'folder-description-update'
},
nodeType: 'cm:sushi'
}
);
expect(nodesApi.createFolder).toHaveBeenCalledWith('parentNodeId', {
name: 'folder-name-update',
properties: {
'cm:title': 'folder-title-update',
'cm:description': 'folder-description-update'
},
nodeType: 'cm:sushi'
});
});
it('should call dialog to close with form data when submit is successfully', () => {
@@ -315,5 +302,5 @@ describe('FolderDialogComponent', () => {
component.submit();
});
});
});
});
});
@@ -18,8 +18,7 @@
import { Component, ViewChild } from '@angular/core';
import { LibraryFavoriteDirective } from './library-favorite.directive';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { AlfrescoApiServiceMock, CoreModule, AlfrescoApiService } from '@alfresco/adf-core';
import { CoreTestingModule } from '@alfresco/adf-core';
import { LibraryEntity } from '../interfaces/library-entity.interface';
@Component({
@@ -40,10 +39,7 @@ describe('LibraryFavoriteDirective', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), CoreModule.forRoot()],
providers: [
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
],
imports: [CoreTestingModule],
declarations: [TestComponent, LibraryFavoriteDirective]
});
fixture = TestBed.createComponent(TestComponent);
@@ -16,6 +16,8 @@
[rowMenuCacheEnabled]="false"
[stickyHeader]="stickyHeader"
[allowFiltering]="allowFiltering"
[isResizingEnabled]="isResizingEnabled"
[blurOnResize]="blurOnResize"
(showRowContextMenu)="onShowRowContextMenu($event)"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(executeRowAction)="onExecuteRowAction($event)"
@@ -18,7 +18,6 @@
import { CUSTOM_ELEMENTS_SCHEMA, SimpleChange, QueryList, Component, ViewChild, SimpleChanges } from '@angular/core';
import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import {
AlfrescoApiService,
DataColumnListComponent,
DataColumnComponent,
DataColumn,
@@ -27,7 +26,8 @@ import {
ObjectDataTableAdapter,
ShowHeaderMode,
ThumbnailService,
AppConfigService
AppConfigService,
AuthenticationService
} from '@alfresco/adf-core';
import { ContentService } from '../../common/services/content.service';
import { Subject, of, throwError } from 'rxjs';
@@ -62,15 +62,18 @@ import { domSanitizerMock } from '../../testing/dom-sanitizer-mock';
import { MatDialog } from '@angular/material/dialog';
import { FileAutoDownloadComponent } from './file-auto-download/file-auto-download.component';
import { ShareDataTableAdapter } from '../data/share-datatable-adapter';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
const mockDialog = {
open: jasmine.createSpy('open')
};
describe('DocumentList', () => {
let loader: HarnessLoader;
let documentList: DocumentListComponent;
let documentListService: DocumentListService;
let apiService: AlfrescoApiService;
let customResourcesService: CustomResourcesService;
let thumbnailService: ThumbnailService;
let contentService: ContentService;
@@ -82,6 +85,7 @@ describe('DocumentList', () => {
let spyFavorite: any;
let spyFolder: any;
let spyFolderNode: any;
let authenticationService: AuthenticationService;
beforeEach(() => {
TestBed.configureTestingModule({
@@ -99,11 +103,11 @@ describe('DocumentList', () => {
documentList = fixture.componentInstance;
documentListService = TestBed.inject(DocumentListService);
apiService = TestBed.inject(AlfrescoApiService);
customResourcesService = TestBed.inject(CustomResourcesService);
thumbnailService = TestBed.inject(ThumbnailService);
contentService = TestBed.inject(ContentService);
appConfigService = TestBed.inject(AppConfigService);
authenticationService = TestBed.inject(AuthenticationService);
spyFolder = spyOn(documentListService, 'getFolder').and.returnValue(of({ list: {} }));
spyFolderNode = spyOn(documentListService, 'getFolderNode').and.returnValue(of(new NodeEntry({ entry: new Node() })));
@@ -116,6 +120,8 @@ describe('DocumentList', () => {
spyFavorite = spyOn(customResourcesService.favoritesApi, 'listFavorites').and.returnValue(
Promise.resolve(new FavoritePaging({ list: new FavoritePagingList({ entries: [] }) }))
);
loader = TestbedHarnessEnvironment.loader(fixture);
});
afterEach(() => {
@@ -219,7 +225,7 @@ describe('DocumentList', () => {
it('should show the header when there are no records in the table but filter is active', () => {
documentList.data = new ShareDataTableAdapter(thumbnailService, contentService, []);
documentList.filterValue = { $thumbnail: 'TYPE:"cm:folder"' };
documentList.filterValue = { $thumbnail: 'TYPE:"cm:folder"' };
fixture.detectChanges();
@@ -611,7 +617,7 @@ describe('DocumentList', () => {
title: 'FileAction'
});
spyOn(apiService.getInstance(), 'getEcmUsername').and.returnValue('lockOwner');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('lockOwner');
documentList.actions = [documentMenu];
@@ -642,7 +648,7 @@ describe('DocumentList', () => {
title: 'FileAction'
});
spyOn(apiService.getInstance(), 'getEcmUsername').and.returnValue('jerryTheKillerCow');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('jerryTheKillerCow');
documentList.actions = [documentMenu];
@@ -1075,10 +1081,11 @@ describe('DocumentList', () => {
expect(fixture.debugElement.query(By.css('.adf-no-permission__template'))).not.toBeNull();
});
it('should display loading template when data is loading', () => {
it('should display loading template when data is loading', async () => {
documentList.loading = true;
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('mat-progress-spinner'))).not.toBeNull();
expect(await loader.hasHarness(MatProgressSpinnerHarness)).toBe(true);
});
it('should empty folder NOT show the pagination', () => {
@@ -1406,14 +1413,16 @@ describe('DocumentList', () => {
expect(documentList.reload).toHaveBeenCalled();
});
it('should not show loading state if pagination is updated with merge setting as true', fakeAsync (() => {
it('should not show loading state if pagination is updated with merge setting as true', fakeAsync(() => {
spyFolderNode = spyOn(documentListService, 'loadFolderByNodeId').and.callFake(() =>
of(new DocumentLoaderNode(null, {
list: {
pagination: {},
entries: mockPreselectedNodes
}
}))
of(
new DocumentLoaderNode(null, {
list: {
pagination: {},
entries: mockPreselectedNodes
}
})
)
);
fixture.detectChanges();
const fakeDatatableRows = [
@@ -323,6 +323,14 @@ export class DocumentListComponent extends DataTableSchema implements OnInit, On
@Input()
maxColumnsVisible?: number;
/** Enables column resizing for datatable */
@Input()
isResizingEnabled = false;
/** Enables blur when resizing datatable columns */
@Input()
blurOnResize = true;
/** Emitted when the user clicks a list node */
@Output()
nodeClick = new EventEmitter<NodeEntityEvent>();
@@ -98,7 +98,7 @@ export class CustomResourcesService {
getRecentFiles(personId: string, pagination: PaginationModel, filters?: string[]): Observable<ResultSetPaging> {
const defaultFilter = [
'TYPE:"content"',
'-PNAME:"0/wiki"',
'-PATH:"//cm:wiki/*"',
'-TYPE:"app:filelink"',
'-TYPE:"cm:thumbnail"',
'-TYPE:"cm:failedThumbnail"',
@@ -17,7 +17,7 @@
import { TestBed } from '@angular/core/testing';
import { LockService } from './lock.service';
import { CoreTestingModule, AlfrescoApiService } from '@alfresco/adf-core';
import { CoreTestingModule, AuthenticationService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api';
import { TranslateModule } from '@ngx-translate/core';
import { addDays, subDays } from 'date-fns';
@@ -25,7 +25,7 @@ import { addDays, subDays } from 'date-fns';
describe('PeopleProcessService', () => {
let service: LockService;
let apiService: AlfrescoApiService;
let authenticationService: AuthenticationService;
const fakeNodeUnlocked: Node = { name: 'unlocked', isLocked: false, isFile: true } as Node;
const fakeFolderNode: Node = { name: 'unlocked', isLocked: false, isFile: false, isFolder: true } as Node;
@@ -39,7 +39,7 @@ describe('PeopleProcessService', () => {
]
});
service = TestBed.inject(LockService);
apiService = TestBed.inject(AlfrescoApiService);
authenticationService = TestBed.inject(AuthenticationService);
});
it('should return false when no lock is configured', () => {
@@ -145,22 +145,22 @@ describe('PeopleProcessService', () => {
} as Node;
it('should return false when the user is the lock owner', () => {
spyOn(apiService.getInstance(), 'getEcmUsername').and.returnValue('lock-owner-user');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('lock-owner-user');
expect(service.isLocked(nodeOwnerAllowedLock)).toBeFalsy();
});
it('should return true when the user is not the lock owner', () => {
spyOn(apiService.getInstance(), 'getEcmUsername').and.returnValue('banana-user');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('banana-user');
expect(service.isLocked(nodeOwnerAllowedLock)).toBeTruthy();
});
it('should return false when the user is not the lock owner but the lock is expired', () => {
spyOn(apiService.getInstance(), 'getEcmUsername').and.returnValue('banana-user');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('banana-user');
expect(service.isLocked(nodeOwnerAllowedLockWithExpiredDate)).toBeFalsy();
});
it('should return true when is not the lock owner and the expiration date is valid', () => {
spyOn(apiService.getInstance(), 'getEcmUsername').and.returnValue('banana-user');
spyOn(authenticationService, 'getEcmUsername').and.returnValue('banana-user');
expect(service.isLocked(nodeOwnerAllowedLockWithActiveExpiration)).toBeTruthy();
});
});
@@ -1,4 +1,4 @@
<h1 mat-dialog-title>{{ title | translate }}</h1>
<h1 mat-dialog-title data-automation-id="new-version-uploader-dialog-title">{{ title | translate }}</h1>
<section mat-dialog-content *ngIf="!data.showVersionsOnly">
<adf-version-comparison id="adf-version-comparison" [newFileVersion]="data.file" [node]="data.node"></adf-version-comparison>
<adf-version-upload
@@ -28,13 +28,13 @@ import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog
describe('NewVersionUploaderDialog', () => {
let component: NewVersionUploaderDialogComponent;
let fixture: ComponentFixture<NewVersionUploaderDialogComponent>;
let nativeElement;
let nativeElement: HTMLElement;
const cssSelectors = {
adfVersionUploadButton: '#adf-version-upload-button',
adfVersionComparison: '#adf-version-comparison',
adfVersionList: '.adf-version-list',
matDialogTitle: '.mat-dialog-title'
title: '[data-automation-id="new-version-uploader-dialog-title"]'
};
const mockDialogRef = {
@@ -45,10 +45,7 @@ describe('NewVersionUploaderDialog', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule],
declarations: [
NewVersionUploaderDialogComponent,
VersionListComponent,
@@ -59,7 +56,8 @@ describe('NewVersionUploaderDialog', () => {
providers: [
{ provide: MAT_DIALOG_DATA, useValue: { node: mockNode, showVersionsOnly, file: mockFile } },
{
provide: MatDialogRef, useValue: mockDialogRef
provide: MatDialogRef,
useValue: mockDialogRef
}
]
});
@@ -72,12 +70,7 @@ describe('NewVersionUploaderDialog', () => {
fixture.destroy();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('Upload New Version', () => {
const expectedUploadNewVersionTitle = 'ADF-NEW-VERSION-UPLOADER.DIALOG_UPLOAD.TITLE';
it('should display adf version upload button if showVersionsOnly is passed as false from parent component', () => {
@@ -104,7 +97,7 @@ describe('NewVersionUploaderDialog', () => {
it('should show default title if title is not provided from parent component', () => {
component.data.showVersionsOnly = false;
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
expect(matDialogTitle.innerHTML).toEqual(expectedUploadNewVersionTitle);
});
@@ -112,7 +105,7 @@ describe('NewVersionUploaderDialog', () => {
component.data.showVersionsOnly = false;
component.data.title = '';
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
expect(matDialogTitle.innerHTML).toEqual(expectedUploadNewVersionTitle);
});
@@ -120,7 +113,7 @@ describe('NewVersionUploaderDialog', () => {
component.data.showVersionsOnly = false;
component.data.title = 'TEST_TITLE';
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
expect(matDialogTitle.innerHTML).toEqual('TEST_TITLE');
});
@@ -150,11 +143,9 @@ describe('NewVersionUploaderDialog', () => {
component.handleCancel();
expect(mockDialogRef.close).toHaveBeenCalled();
});
});
describe('Manage Versions', () => {
const expectedManageVersionsTitle = 'ADF-NEW-VERSION-UPLOADER.DIALOG_LIST.TITLE';
it('should display adf version list if showVersionsOnly is passed as true from parent component', () => {
@@ -182,7 +173,7 @@ describe('NewVersionUploaderDialog', () => {
component.data.showVersionsOnly = true;
component.data.title = undefined;
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
expect(matDialogTitle.innerHTML).toEqual(expectedManageVersionsTitle);
});
@@ -190,7 +181,7 @@ describe('NewVersionUploaderDialog', () => {
component.data.showVersionsOnly = true;
component.data.title = '';
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
expect(matDialogTitle.innerHTML).toEqual(expectedManageVersionsTitle);
});
@@ -198,10 +189,8 @@ describe('NewVersionUploaderDialog', () => {
component.data.showVersionsOnly = true;
component.data.title = 'TEST_TITLE';
fixture.detectChanges();
const matDialogTitle = nativeElement.querySelector(cssSelectors.matDialogTitle);
const matDialogTitle = nativeElement.querySelector(cssSelectors.title);
expect(matDialogTitle.innerHTML).toEqual('TEST_TITLE');
});
});
});
@@ -26,9 +26,12 @@ import { ContentTestingModule } from '../../../testing/content.testing.module';
import { AddPermissionDialogComponent } from './add-permission-dialog.component';
import { AddPermissionDialogData } from './add-permission-dialog-data.interface';
import { fakeAuthorityResults } from '../../../mock/add-permission.component.mock';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatSelectHarness } from '@angular/material/select/testing';
describe('AddPermissionDialog', () => {
let loader: HarnessLoader;
let fixture: ComponentFixture<AddPermissionDialogComponent>;
let component: AddPermissionDialogComponent;
let element: HTMLElement;
@@ -53,7 +56,7 @@ describe('AddPermissionDialog', () => {
role: 'Consumer'
}
],
confirm: new Subject<PermissionElement[]> ()
confirm: new Subject<PermissionElement[]>()
};
const dialogRef = {
close: jasmine.createSpy('close')
@@ -61,10 +64,7 @@ describe('AddPermissionDialog', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
imports: [TranslateModule.forRoot(), ContentTestingModule],
providers: [
{ provide: MatDialogRef, useValue: dialogRef },
{ provide: MAT_DIALOG_DATA, useValue: data }
@@ -74,12 +74,15 @@ describe('AddPermissionDialog', () => {
component = fixture.componentInstance;
element = fixture.nativeElement;
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
afterEach(() => {
fixture.destroy();
});
const getConfirmButton = () => element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
it('should show the INJECTED title', () => {
const titleElement = fixture.debugElement.query(By.css('#add-permission-dialog-title'));
expect(titleElement).not.toBeNull();
@@ -94,27 +97,31 @@ describe('AddPermissionDialog', () => {
});
it('should disable the confirm button when no selection is applied', () => {
const confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
const confirmButton = getConfirmButton();
expect(confirmButton.disabled).toBeTruthy();
});
it('should enable the button when a selection is done', async () => {
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance;
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(
By.directive(AddPermissionPanelComponent)
).componentInstance;
addPermissionPanelComponent.select.emit(fakeAuthorityResults);
let confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
let confirmButton = getConfirmButton();
expect(confirmButton.disabled).toBeTruthy();
fixture.detectChanges();
await fixture.whenStable();
confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
confirmButton = getConfirmButton();
expect(confirmButton.disabled).toBe(false);
});
it('should update the role after selection', async () => {
spyOn(component, 'onMemberUpdate').and.callThrough();
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance;
let confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(
By.directive(AddPermissionPanelComponent)
).componentInstance;
let confirmButton = getConfirmButton();
expect(confirmButton.disabled).toBe(true);
addPermissionPanelComponent.select.emit([fakeAuthorityResults[0]]);
@@ -127,17 +134,12 @@ describe('AddPermissionDialog', () => {
fixture.detectChanges();
await fixture.whenStable();
const selectBox = fixture.debugElement.query(By.css(('[id="adf-select-role-permission"] .mat-select-trigger')));
selectBox.nativeElement.dispatchEvent(new Event('click'));
fixture.detectChanges();
const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` }));
await select.open();
const options = fixture.debugElement.queryAll(By.css('mat-option'));
expect(options).not.toBeNull();
const options = await select.getOptions();
expect(options.length).toBe(2);
options[0].triggerEventHandler('click', {});
fixture.detectChanges();
await fixture.whenStable();
await options[0].click();
expect(component.onMemberUpdate).toHaveBeenCalled();
@@ -147,7 +149,7 @@ describe('AddPermissionDialog', () => {
currentSelection = selection;
});
confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
confirmButton = getConfirmButton();
expect(confirmButton.disabled).toBe(false);
confirmButton.click();
@@ -156,8 +158,10 @@ describe('AddPermissionDialog', () => {
it('should update all the user role on header column update', async () => {
spyOn(component, 'onBulkUpdate').and.callThrough();
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance;
let confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(
By.directive(AddPermissionPanelComponent)
).componentInstance;
let confirmButton = getConfirmButton();
expect(confirmButton.disabled).toBe(true);
addPermissionPanelComponent.select.emit(fakeAuthorityResults);
@@ -170,19 +174,12 @@ describe('AddPermissionDialog', () => {
fixture.detectChanges();
await fixture.whenStable();
const selectBox = fixture.debugElement.query(By.css(('[id="adf-bulk-select-role-permission"] .mat-select-trigger')));
selectBox.nativeElement.dispatchEvent(new Event('click'));
const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-bulk-select-role-permission` }));
await select.open();
fixture.detectChanges();
await fixture.whenStable();
const options = fixture.debugElement.queryAll(By.css('mat-option'));
expect(options).not.toBeNull();
const options = await select.getOptions();
expect(options.length).toBe(2);
options[0].triggerEventHandler('click', {});
fixture.detectChanges();
await fixture.whenStable();
await options[0].click();
expect(component.onBulkUpdate).toHaveBeenCalled();
@@ -190,7 +187,7 @@ describe('AddPermissionDialog', () => {
expect(selection.length).toBe(3);
});
confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
confirmButton = getConfirmButton();
expect(confirmButton.disabled).toBe(false);
confirmButton.click();
});
@@ -198,8 +195,10 @@ describe('AddPermissionDialog', () => {
it('should delete the user after selection', async () => {
spyOn(component, 'onMemberUpdate').and.callThrough();
spyOn(component, 'onMemberDelete').and.callThrough();
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance;
let confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(
By.directive(AddPermissionPanelComponent)
).componentInstance;
let confirmButton = getConfirmButton();
expect(confirmButton.disabled).toBe(true);
addPermissionPanelComponent.select.emit(fakeAuthorityResults);
@@ -212,22 +211,16 @@ describe('AddPermissionDialog', () => {
fixture.detectChanges();
await fixture.whenStable();
const selectBox = fixture.debugElement.query(By.css(('[id="adf-select-role-permission"] .mat-select-trigger')));
selectBox.nativeElement.dispatchEvent(new Event('click'));
const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` }));
await select.open();
fixture.detectChanges();
await fixture.whenStable();
const options = fixture.debugElement.queryAll(By.css('mat-option'));
expect(options).not.toBeNull();
const options = await select.getOptions();
expect(options.length).toBe(2);
options[0].triggerEventHandler('click', {});
fixture.detectChanges();
await fixture.whenStable();
await options[0].click();
expect(component.onMemberUpdate).toHaveBeenCalled();
confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
confirmButton = getConfirmButton();
expect(confirmButton.disabled).toBe(true);
const deleteButton = element.querySelectorAll('[data-automation-id="adf-delete-permission-button"]') as any;
deleteButton[1].click();
@@ -246,7 +239,9 @@ describe('AddPermissionDialog', () => {
});
it('should stream the confirmed selection on the confirm subject', async () => {
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(By.directive(AddPermissionPanelComponent)).componentInstance;
const addPermissionPanelComponent: AddPermissionPanelComponent = fixture.debugElement.query(
By.directive(AddPermissionPanelComponent)
).componentInstance;
addPermissionPanelComponent.select.emit(fakeAuthorityResults);
fixture.detectChanges();
@@ -255,7 +250,7 @@ describe('AddPermissionDialog', () => {
let authorityResult = fixture.debugElement.query(By.css('[data-automation-id="datatable-row-0"]'));
expect(authorityResult).toBeNull();
const confirmButton = element.querySelector<HTMLButtonElement>('[data-automation-id="add-permission-dialog-confirm-button"]');
const confirmButton = getConfirmButton();
confirmButton.click();
fixture.detectChanges();
@@ -54,7 +54,7 @@ export class SearchPermissionConfigurationService implements SearchConfiguration
if (this.queryProvider?.query) {
query = this.queryProvider.query.replace(new RegExp(/\${([^}]+)}/g), searchTerm);
} else {
query = `(email:*${searchTerm}* OR firstName:*${searchTerm}* OR lastName:*${searchTerm}* OR displayName:*${searchTerm}* OR authorityName:*${searchTerm}* OR authorityDisplayName:*${searchTerm}*) AND ANAME:("0/APP.DEFAULT")`;
query = `(userName:*${searchTerm}* OR email:*${searchTerm}* OR firstName:*${searchTerm}* OR lastName:*${searchTerm}* OR authorityName:*${searchTerm}* OR authorityDisplayName:*${searchTerm}*) AND PATH:"//cm:APP.DEFAULT/*"`;
}
return query;
}
@@ -16,23 +16,23 @@
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core';
import { PermissionContainerComponent } from './permission-container.component';
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatSelectHarness } from '@angular/material/select/testing';
import { MatButtonHarness } from '@angular/material/button/testing';
describe('PermissionContainerComponent', () => {
let loader: HarnessLoader;
let fixture: ComponentFixture<PermissionContainerComponent>;
let component: PermissionContainerComponent;
let element: HTMLElement;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
]
imports: [TranslateModule.forRoot(), ContentTestingModule]
});
fixture = TestBed.createComponent(PermissionContainerComponent);
component = fixture.componentInstance;
@@ -60,6 +60,7 @@ describe('PermissionContainerComponent', () => {
];
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
afterEach(() => {
@@ -72,26 +73,24 @@ describe('PermissionContainerComponent', () => {
expect(element.querySelector('#adf-select-role-permission').textContent).toContain('consumer');
});
it('should emit update event on role change', () => {
it('should emit update event on role change', async () => {
spyOn(component.update, 'emit');
const selectBox = fixture.debugElement.query(By.css(('[id="adf-select-role-permission"] .mat-select-trigger')));
selectBox.triggerEventHandler('click', null);
fixture.detectChanges();
const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` }));
await select.open();
const options = fixture.debugElement.queryAll(By.css('mat-option'));
expect(options).not.toBeNull();
const options = await select.getOptions();
expect(options.length).toBe(2);
options[0].triggerEventHandler('click', {});
fixture.detectChanges();
await options[0].click();
expect(component.update.emit).toHaveBeenCalledWith({ role: 'Test', permission: component.permissions[0] });
});
it('should delete update event on row delete', () => {
it('should delete update event on row delete', async () => {
spyOn(component.delete, 'emit');
const deleteButton: HTMLButtonElement = element.querySelector('[data-automation-id="adf-delete-permission-button-GROUP_EVERYONE"]');
deleteButton.click();
fixture.detectChanges();
const deleteButton = await loader.getHarness(
MatButtonHarness.with({ selector: `[data-automation-id="adf-delete-permission-button-GROUP_EVERYONE"]` })
);
await deleteButton.click();
expect(component.delete.emit).toHaveBeenCalledWith(component.permissions[0]);
});
});
@@ -16,7 +16,6 @@
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core';
import { of, throwError } from 'rxjs';
import { SearchService } from '../../../search/services/search.service';
@@ -36,8 +35,13 @@ import {
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { Node } from '@alfresco/js-api';
import { NodesApiService } from '../../../common/services/nodes-api.service';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing';
import { MatSelectHarness } from '@angular/material/select/testing';
describe('PermissionListComponent', () => {
let loader: HarnessLoader;
let fixture: ComponentFixture<PermissionListComponent>;
let component: PermissionListComponent;
let element: HTMLElement;
@@ -64,6 +68,7 @@ describe('PermissionListComponent', () => {
searchQuerySpy = spyOn(searchApiService, 'searchByQueryBody').and.returnValue(of(fakeEmptyResponse));
component.nodeId = 'fake-node-id';
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
afterEach(() => {
@@ -117,7 +122,9 @@ describe('PermissionListComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined();
const toggle = await loader.getHarness(MatSlideToggleHarness);
expect(await toggle.isChecked()).toBe(true);
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON'
);
@@ -127,10 +134,11 @@ describe('PermissionListComponent', () => {
it('should toggle the inherited button', async () => {
getNodeSpy.and.returnValue(of(fakeNodeInheritedOnly));
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined();
const toggle = await loader.getHarness(MatSlideToggleHarness);
expect(await toggle.isChecked()).toBe(true);
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON'
);
@@ -138,12 +146,8 @@ describe('PermissionListComponent', () => {
spyOn(nodeService, 'updateNode').and.returnValue(of(fakeLocalPermission));
const slider = fixture.debugElement.query(By.css('mat-slide-toggle'));
slider.triggerEventHandler('change', { source: { checked: false } });
await toggle.uncheck();
fixture.detectChanges();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBe(null);
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.OFF'
);
@@ -157,7 +161,9 @@ describe('PermissionListComponent', () => {
fixture.detectChanges();
await fixture.whenStable();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined();
const toggle = await loader.getHarness(MatSlideToggleHarness);
expect(await toggle.isChecked()).toBe(true);
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON'
);
@@ -165,13 +171,8 @@ describe('PermissionListComponent', () => {
spyOn(nodeService, 'updateNode').and.returnValue(of(fakeLocalPermission));
const slider = fixture.debugElement.query(By.css('mat-slide-toggle'));
slider.triggerEventHandler('change', { source: { checked: false } });
await toggle.uncheck();
fixture.detectChanges();
await fixture.whenStable();
expect(element.querySelector('.adf-inherit-container .mat-checked')).toBeDefined();
expect(element.querySelector('.adf-inherit-container h3').textContent.trim()).toBe(
'PERMISSION_MANAGER.LABELS.INHERITED-PERMISSIONS PERMISSION_MANAGER.LABELS.ON'
);
@@ -206,17 +207,16 @@ describe('PermissionListComponent', () => {
expect(element.querySelector('adf-user-name-column').textContent).toContain('GROUP_EVERYONE');
expect(element.querySelector('#adf-select-role-permission').textContent).toContain('Contributor');
const selectBox = fixture.debugElement.query(By.css('[id="adf-select-role-permission"] .mat-select-trigger'));
selectBox.triggerEventHandler('click', null);
fixture.detectChanges();
const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` }));
await select.open();
const options = fixture.debugElement.queryAll(By.css('mat-option'));
expect(options).not.toBeNull();
const options = await select.getOptions();
expect(options.length).toBe(4);
expect(options[0].nativeElement.innerText).toContain('ADF.ROLES.SITECOLLABORATOR');
expect(options[1].nativeElement.innerText).toContain('ADF.ROLES.SITECONSUMER');
expect(options[2].nativeElement.innerText).toContain('ADF.ROLES.SITECONTRIBUTOR');
expect(options[3].nativeElement.innerText).toContain('ADF.ROLES.SITEMANAGER');
expect(await options[0].getText()).toContain('ADF.ROLES.SITECOLLABORATOR');
expect(await options[1].getText()).toContain('ADF.ROLES.SITECONSUMER');
expect(await options[2].getText()).toContain('ADF.ROLES.SITECONTRIBUTOR');
expect(await options[3].getText()).toContain('ADF.ROLES.SITEMANAGER');
});
it('should show readonly member for site manager to toggle the inherit permission', async () => {
@@ -247,14 +247,12 @@ describe('PermissionListComponent', () => {
expect(element.querySelector('adf-user-name-column').textContent).toContain('GROUP_EVERYONE');
expect(element.querySelector('#adf-select-role-permission').textContent).toContain('Contributor');
const selectBox = fixture.debugElement.query(By.css('[id="adf-select-role-permission"] .mat-select-trigger'));
selectBox.triggerEventHandler('click', null);
fixture.detectChanges();
const options = fixture.debugElement.queryAll(By.css('mat-option'));
expect(options).not.toBeNull();
const select = await loader.getHarness(MatSelectHarness.with({ ancestor: `#adf-select-role-permission` }));
await select.open();
const options = await select.getOptions();
expect(options.length).toBe(5);
options[3].triggerEventHandler('click', {});
fixture.detectChanges();
await options[3].click();
expect(nodeService.updateNode).toHaveBeenCalledWith('f472543f-7218-403d-917b-7a5861257244', {
permissions: { locallySet: [{ accessStatus: 'ALLOWED', name: 'Editor', authorityId: 'GROUP_EVERYONE' }] }
});
@@ -22,35 +22,33 @@ import { UserIconColumnComponent } from './user-icon-column.component';
import { NodeEntry } from '@alfresco/js-api';
describe('UserIconColumnComponent', () => {
let fixture: ComponentFixture<UserIconColumnComponent>;
let component: UserIconColumnComponent;
let element: HTMLElement;
const person = {
const person = {
firstName: 'fake',
lastName: 'user',
email: 'fake@test.com'
};
const group = {
const group = {
id: 'fake-id',
displayName: 'fake authority'
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
]
imports: [TranslateModule.forRoot(), ContentTestingModule]
});
fixture = TestBed.createComponent(UserIconColumnComponent);
fixture = TestBed.createComponent(UserIconColumnComponent);
component = fixture.componentInstance;
element = fixture.nativeElement;
fixture.detectChanges();
});
describe('person initial', () => {
const getInitials = () => element.querySelector('[data-automation-id="user-initials-image"]')?.textContent;
it('should render person value from context', () => {
component.context = {
row: {
@@ -61,7 +59,7 @@ describe('UserIconColumnComponent', () => {
};
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('fu');
expect(getInitials()).toContain('fu');
});
it('should render person value from node', () => {
@@ -69,8 +67,8 @@ describe('UserIconColumnComponent', () => {
entry: {
nodeType: 'cm:person',
properties: {
'cm:firstName': 'Fake',
'cm:lastName': 'User',
'cm:firstName': 'Fake',
'cm:lastName': 'User',
'cm:email': 'fake-user@test.com',
'cm:userName': 'fake-user'
}
@@ -78,11 +76,13 @@ describe('UserIconColumnComponent', () => {
} as NodeEntry;
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[data-automation-id="user-initials-image"]').textContent).toContain('FU');
expect(getInitials()).toContain('FU');
});
});
describe('group initial', () => {
const getGroupIcon = () => element.querySelector('[id="group-icon"] .adf-group-icon');
it('should render group value from context', () => {
component.context = {
row: {
@@ -93,8 +93,8 @@ describe('UserIconColumnComponent', () => {
};
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[id="group-icon"] mat-icon')).toBeDefined();
expect(element.querySelector('[id="group-icon"] mat-icon').textContent).toContain('people_alt_outline');
expect(getGroupIcon()).toBeDefined();
expect(getGroupIcon().textContent).toContain('people_alt_outline');
});
it('should render person value from node', () => {
@@ -102,14 +102,14 @@ describe('UserIconColumnComponent', () => {
entry: {
nodeType: 'cm:authorityContainer',
properties: {
'cm:authorityName': 'Fake authorityN'
'cm:authorityName': 'Fake authorityN'
}
}
} as NodeEntry;
component.ngOnInit();
fixture.detectChanges();
expect(element.querySelector('[id="group-icon"] mat-icon')).toBeDefined();
expect(element.querySelector('[id="group-icon"] mat-icon').textContent).toContain('people_alt_outline');
expect(getGroupIcon()).toBeDefined();
expect(getGroupIcon().textContent).toContain('people_alt_outline');
});
});
@@ -20,22 +20,24 @@ import { SearchFilterList } from '../../models/search-filter-list.model';
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { sizeOptions, stepOne, stepThree } from '../../../mock';
import { By } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core';
import { HarnessLoader, TestKey } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { MatButtonHarness } from '@angular/material/button/testing';
describe('SearchCheckListComponent', () => {
let loader: HarnessLoader;
let fixture: ComponentFixture<SearchCheckListComponent>;
let component: SearchCheckListComponent;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
]
imports: [TranslateModule.forRoot(), ContentTestingModule]
});
fixture = TestBed.createComponent(SearchCheckListComponent);
component = fixture.componentInstance;
loader = TestbedHarnessEnvironment.loader(fixture);
});
it('should setup options from settings', () => {
@@ -49,7 +51,7 @@ describe('SearchCheckListComponent', () => {
expect(component.options.items).toEqual(options);
});
it('should handle enter key as click on checkboxes', () => {
it('should handle enter key as click on checkboxes', async () => {
component.options = new SearchFilterList<SearchListOption>([
{ name: 'Folder', value: `TYPE:'cm:folder'`, checked: false },
{ name: 'Document', value: `TYPE:'cm:content'`, checked: false }
@@ -58,13 +60,13 @@ describe('SearchCheckListComponent', () => {
component.ngOnInit();
fixture.detectChanges();
const optionElements = fixture.debugElement.queryAll(By.css('mat-checkbox'));
const option = await loader.getHarness(MatCheckboxHarness);
optionElements[0].triggerEventHandler('keydown.enter', {});
expect(component.options.items[0].checked).toBeTruthy();
await (await option.host()).sendKeys(TestKey.ENTER);
expect(await option.isChecked()).toBe(true);
optionElements[0].triggerEventHandler('keydown.enter', {});
expect(component.options.items[0].checked).toBeFalsy();
await (await option.host()).sendKeys(TestKey.ENTER);
expect(await option.isChecked()).toBe(false);
});
it('should setup operator from the settings', () => {
@@ -95,21 +97,13 @@ describe('SearchCheckListComponent', () => {
spyOn(component.context, 'update').and.stub();
component.changeHandler(
{ checked: true } as any,
component.options.items[0]
);
component.changeHandler({ checked: true } as any, component.options.items[0]);
expect(component.context.queryFragments[component.id]).toEqual(`TYPE:'cm:folder'`);
component.changeHandler(
{ checked: true } as any,
component.options.items[1]
);
component.changeHandler({ checked: true } as any, component.options.items[1]);
expect(component.context.queryFragments[component.id]).toEqual(
`TYPE:'cm:folder' OR TYPE:'cm:content'`
);
expect(component.context.queryFragments[component.id]).toEqual(`TYPE:'cm:folder' OR TYPE:'cm:content'`);
});
it('should reset selected boxes', () => {
@@ -147,7 +141,7 @@ describe('SearchCheckListComponent', () => {
});
describe('Pagination', () => {
it('should show 5 items when pageSize not defined', () => {
it('should show 5 items when pageSize not defined', async () => {
component.id = 'checklist';
component.context = {
queryFragments: {
@@ -160,13 +154,14 @@ describe('SearchCheckListComponent', () => {
component.ngOnInit();
fixture.detectChanges();
const optionElements = fixture.debugElement.queryAll(By.css('mat-checkbox'));
expect(optionElements.length).toEqual(5);
const labels = Array.from(optionElements).map(element => element.nativeElement.innerText);
const options = await loader.getAllHarnesses(MatCheckboxHarness);
expect(options.length).toBe(5);
const labels = await Promise.all(options.map((element) => element.getLabelText()));
expect(labels).toEqual(stepOne);
});
it('should show all items when pageSize is high', () => {
it('should show all items when pageSize is high', async () => {
component.id = 'checklist';
component.context = {
queryFragments: {
@@ -178,14 +173,15 @@ describe('SearchCheckListComponent', () => {
component.ngOnInit();
fixture.detectChanges();
const optionElements = fixture.debugElement.queryAll(By.css('mat-checkbox'));
expect(optionElements.length).toEqual(13);
const labels = Array.from(optionElements).map(element => element.nativeElement.innerText);
const options = await loader.getAllHarnesses(MatCheckboxHarness);
expect(options.length).toBe(13);
const labels = await Promise.all(options.map((element) => element.getLabelText()));
expect(labels).toEqual(stepThree);
});
});
it('should able to check/reset the checkbox', () => {
it('should able to check/reset the checkbox', async () => {
component.id = 'checklist';
component.context = {
queryFragments: {
@@ -198,16 +194,15 @@ describe('SearchCheckListComponent', () => {
component.ngOnInit();
fixture.detectChanges();
const optionElements = fixture.debugElement.query(By.css('mat-checkbox'));
optionElements.triggerEventHandler('change', { checked: true });
const option = await loader.getHarness(MatCheckboxHarness);
await option.check();
expect(component.submitValues).toHaveBeenCalled();
const clearAllElement = fixture.debugElement.query(By.css('button[title="SEARCH.FILTER.ACTIONS.CLEAR-ALL"]'));
clearAllElement.triggerEventHandler('click', {} );
fixture.detectChanges();
const clearButton = await loader.getHarness(MatButtonHarness.with({ selector: `[title="SEARCH.FILTER.ACTIONS.CLEAR-ALL"]` }));
await clearButton.click();
const selectedElements = fixture.debugElement.queryAll(By.css('.mat-checkbox-checked'));
expect(selectedElements.length).toBe(0);
const checkedElements = await loader.getAllHarnesses(MatCheckboxHarness.with({ checked: true }));
expect(checkedElements.length).toBe(0);
});
});
@@ -21,15 +21,13 @@ import { By } from '@angular/platform-browser';
import { SearchFacetFiltersService } from '../../services/search-facet-filters.service';
import { ContentTestingModule } from '../../../testing/content.testing.module';
import { TranslateModule } from '@ngx-translate/core';
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatChipHarness, MatChipRemoveHarness } from '@angular/material/chips/testing';
@Component({
selector: 'adf-test-component',
template: `
<adf-search-chip-list
[searchFilter]="searchFilter"
[clearAll]="allowClear">
</adf-search-chip-list>
`
template: ` <adf-search-chip-list [searchFilter]="searchFilter" [clearAll]="allowClear"> </adf-search-chip-list> `
})
class TestComponent {
allowClear = true;
@@ -40,23 +38,22 @@ class TestComponent {
}
describe('SearchChipListComponent', () => {
let loader: HarnessLoader;
let fixture: ComponentFixture<TestComponent>;
let component: TestComponent;
let searchFacetFiltersService: SearchFacetFiltersService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
],
declarations: [
TestComponent
]
imports: [TranslateModule.forRoot(), ContentTestingModule],
declarations: [TestComponent]
});
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
searchFacetFiltersService = TestBed.inject(SearchFacetFiltersService);
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
it('should display clear button only when entries present', () => {
@@ -65,24 +62,26 @@ describe('SearchChipListComponent', () => {
let clearButton = fixture.debugElement.query(By.css(`[data-automation-id="reset-filter"]`));
expect(clearButton).toBeNull();
searchFacetFiltersService.selectedBuckets = [{
bucket: {
count: 1,
label: 'test',
filterQuery: 'query'
},
field: null
}];
searchFacetFiltersService.selectedBuckets = [
{
bucket: {
count: 1,
label: 'test',
filterQuery: 'query'
},
field: null
}
];
fixture.detectChanges();
clearButton = fixture.debugElement.query(By.css(`[data-automation-id="reset-filter"]`));
expect(clearButton).toBeDefined();
});
it('should reflect changes in the search filter', () => {
it('should reflect changes in the search filter', async () => {
const selectedBuckets = searchFacetFiltersService.selectedBuckets;
fixture.detectChanges();
let chips = fixture.debugElement.queryAll(By.css(`[data-automation-id="chip-list-entry"]`));
let chips = await loader.getAllHarnesses(MatChipHarness.with({ selector: '[data-automation-id="chip-list-entry"]' }));
expect(chips.length).toBe(0);
selectedBuckets.push({
@@ -95,7 +94,7 @@ describe('SearchChipListComponent', () => {
});
fixture.detectChanges();
chips = fixture.debugElement.queryAll(By.css(`[data-automation-id="chip-list-entry"]`));
chips = await loader.getAllHarnesses(MatChipHarness.with({ selector: '[data-automation-id="chip-list-entry"]' }));
expect(chips.length).toBe(1);
});
@@ -115,32 +114,30 @@ describe('SearchChipListComponent', () => {
fixture.detectChanges();
const chips = fixture.debugElement.queryAll(By.css(`[data-automation-id="chip-list-entry"] .mat-chip-remove`));
chips[0].nativeElement.click();
const removeButton = await loader.getHarness(MatChipRemoveHarness.with({ ancestor: `[data-automation-id="chip-list-entry"]` }));
await removeButton.click();
await fixture.whenStable();
expect(searchFacetFiltersService.unselectFacetBucket).toHaveBeenCalled();
});
it('should remove items from the search filter on clear button click', () => {
it('should remove items from the search filter on clear button click', async () => {
spyOn(searchFacetFiltersService, 'unselectFacetBucket').and.stub();
const selectedBucket1: any = { field: { id: 1 }, bucket: {label: 'bucket1'} };
const selectedBucket2: any = { field: { id: 2 }, bucket: {label: 'bucket2'} };
const selectedBucket1: any = { field: { id: 1 }, bucket: { label: 'bucket1' } };
const selectedBucket2: any = { field: { id: 2 }, bucket: { label: 'bucket2' } };
searchFacetFiltersService.selectedBuckets = [selectedBucket1, selectedBucket2];
fixture.detectChanges();
const closeButtons = fixture.debugElement.nativeElement.querySelectorAll('.mat-chip-remove');
const closeButtons = await loader.getAllHarnesses(MatChipRemoveHarness);
expect(closeButtons.length).toBe(2);
closeButtons[0].click();
fixture.detectChanges();
await closeButtons[0].click();
expect(searchFacetFiltersService.unselectFacetBucket).toHaveBeenCalledWith(selectedBucket1.field, selectedBucket1.bucket);
});
it('should disable clear mode via input properties', () => {
it('should disable clear mode via input properties', async () => {
spyOn(component.searchFilter, 'unselectFacetBucket').and.callThrough();
component.allowClear = false;
@@ -157,10 +154,10 @@ describe('SearchChipListComponent', () => {
fixture.detectChanges();
const chips = fixture.debugElement.queryAll(By.css(`[data-automation-id="chip-list-entry"] .mat-chip-remove`));
expect(chips.length).toBe(1);
const closeButtons = await loader.getAllHarnesses(MatChipRemoveHarness.with({ ancestor: `[data-automation-id="chip-list-entry"]` }));
expect(closeButtons.length).toBe(1);
const clearButton = fixture.debugElement.query(By.css(`[data-automation-id="reset-filter"]`));
expect(clearButton).toBeNull();
const hasClearButton = await loader.hasHarness(MatChipRemoveHarness.with({ selector: `[data-automation-id="reset-filter"]` }));
expect(hasClearButton).toBe(false);
});
});
@@ -32,10 +32,7 @@ describe('SearchDateRangeComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
TranslateModule.forRoot(),
ContentTestingModule
]
imports: [TranslateModule.forRoot(), ContentTestingModule]
});
fixture = TestBed.createComponent(SearchDateRangeComponent);
component = fixture.componentInstance;
@@ -43,6 +40,9 @@ describe('SearchDateRangeComponent', () => {
afterEach(() => fixture.destroy());
const getFromInput = () => fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]');
const getToInput = () => fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-to-input"]');
it('should setup form elements on init', () => {
fixture.detectChanges();
@@ -74,7 +74,6 @@ describe('SearchDateRangeComponent', () => {
});
it('should reset form', () => {
fixture.detectChanges();
component.form.setValue({ from: fromDate, to: toDate });
@@ -129,10 +128,13 @@ describe('SearchDateRangeComponent', () => {
spyOn(context, 'update').and.stub();
fixture.detectChanges();
component.apply({
from: fromDate,
to: toDate
}, true);
component.apply(
{
from: fromDate,
to: toDate
},
true
);
const startDate = startOfDay(fromDate).toISOString();
const endDate = endOfDay(toDate).toISOString();
@@ -146,7 +148,7 @@ describe('SearchDateRangeComponent', () => {
it('should show date-format error when Invalid found', async () => {
fixture.detectChanges();
const input = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]');
const input = getFromInput();
input.value = '10-f-18';
input.dispatchEvent(new Event('input'));
@@ -159,7 +161,7 @@ describe('SearchDateRangeComponent', () => {
it('should hide date-format error when correcting input', async () => {
fixture.detectChanges();
const input = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]');
const input = getFromInput();
input.value = '10-f-18';
input.dispatchEvent(new Event('input'));
@@ -181,7 +183,7 @@ describe('SearchDateRangeComponent', () => {
component.settings = { field: 'cm:created', maxDate: 'today' };
fixture.detectChanges();
const input = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]');
const input = getFromInput();
input.value = format(addDays(new Date(), 1), 'dd-MM-yyyy');
input.dispatchEvent(new Event('input'));
@@ -194,11 +196,11 @@ describe('SearchDateRangeComponent', () => {
it('should show error for required constraint', async () => {
fixture.detectChanges();
const fromInput = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]');
const fromInput = getFromInput();
fromInput.value = '';
fromInput.dispatchEvent(new Event('input'));
const toInput = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-to-input"]');
const toInput = getToInput();
toInput.value = '';
toInput.dispatchEvent(new Event('input'));
@@ -212,11 +214,11 @@ describe('SearchDateRangeComponent', () => {
it('should show error for incorrect date range', async () => {
fixture.detectChanges();
const fromInput = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]');
const fromInput = getFromInput();
fromInput.value = '11-10-2018';
fromInput.dispatchEvent(new Event('input'));
const toInput = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-to-input"]');
const toInput = getToInput();
toInput.value = '10-10-2018';
toInput.dispatchEvent(new Event('input'));
@@ -230,7 +232,7 @@ describe('SearchDateRangeComponent', () => {
it('should not show date-format error when valid found', async () => {
fixture.detectChanges();
const input = fixture.debugElement.nativeElement.querySelector('[data-automation-id="date-range-from-input"]');
const input = getFromInput();
input.value = '10-10-2018';
input.dispatchEvent(new Event('input'));

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