diff --git a/app/src/app.config.json.tpl b/app/src/app.config.json.tpl index 824efb2f9b..55902f6d1c 100644 --- a/app/src/app.config.json.tpl +++ b/app/src/app.config.json.tpl @@ -32,16 +32,13 @@ }, "locale": "en", "application": { - "name": "Alfresco Content Application", + "name": "Workspace", "version": "4.0.0-A.3", - "logo": "assets/images/alfresco-logo-flower.svg", - "headerImagePath": "assets/images/mastHead-bg-shapesPattern.svg", + "logo": "assets/images/app-logo.svg", "copyright": "APP.COPYRIGHT" }, "viewer.maxRetries": 1, "sharedLinkDateTimePickerType": "datetime", - "headerColor": "#ffffff", - "headerTextColor": "#000000", "customCssPath": "", "webFontPath": "", "pagination": { diff --git a/app/src/assets/images/app-logo.svg b/app/src/assets/images/app-logo.svg new file mode 100644 index 0000000000..5c63fd78e6 --- /dev/null +++ b/app/src/assets/images/app-logo.svg @@ -0,0 +1,4 @@ + + + + diff --git a/docs/configuration/README.md b/docs/configuration/README.md index 2d6dfa1a1f..9f45f47989 100644 --- a/docs/configuration/README.md +++ b/docs/configuration/README.md @@ -89,29 +89,6 @@ The default logo displayed in the top left corner of the Alfresco Content Applic } ``` -### Header Background color - -You can change the header text and background colors by specifying the color code for the "headerTextColor" and "headerColor" keys: - -```json -{ - "headerTextColor": "#000000", - "headerColor": "#ffffff" -} -``` - -### Header background image - -You can change the header background image by specifying the path to the corresponding resource: - -```json -{ - "application": { - "headerImagePath": "assets/images/mastHead-bg-shapesPattern.svg" - } -} -``` - ### Restricted content You can restrict users from uploading certain types of files and folders by setting or extending the list of rules at the "files.excluded" path. diff --git a/docs/ja/getting-started/configuration.md b/docs/ja/getting-started/configuration.md index 5f2d39675d..aa6fd2a280 100644 --- a/docs/ja/getting-started/configuration.md +++ b/docs/ja/getting-started/configuration.md @@ -89,28 +89,6 @@ Alfresco コンテンツアプリケーションの左上隅に表示される } ``` -### ヘッダーの背景色 - -"headerColor" キーの色コードを指定することにより、ヘッダーの背景色を変更できます: - -```json -{ - "headerColor": "#ffffff" -} -``` - -### ヘッダーの背景画像 - -ヘッダーの背景画像を変更するには、対応するリソースへのパスを指定します: - -```json -{ - "application": { - "headerImagePath": "assets/images/mastHead-bg-shapesPattern.svg" - } -} -``` - ### 制限されたコンテンツ "files.excluded" パスにあるルールのリストを設定または拡張することで、ユーザーが特定の種類のファイルやフォルダをアップロードできないように制限することができます。 diff --git a/e2e/.eslintrc.json b/e2e/.eslintrc.json index f342e37266..10afca993b 100644 --- a/e2e/.eslintrc.json +++ b/e2e/.eslintrc.json @@ -14,6 +14,10 @@ ], "createDefaultProgram": true }, + "plugins": [ + "rxjs", + "unicorn" + ], "rules": { } } diff --git a/e2e/resources/extensibility-configs/context-submenus-ext.json b/e2e/resources/extensibility-configs/context-submenus-ext.json index 46ae287934..9c7df193fd 100644 --- a/e2e/resources/extensibility-configs/context-submenus-ext.json +++ b/e2e/resources/extensibility-configs/context-submenus-ext.json @@ -196,43 +196,18 @@ "route": "personal-files" }, { - "id": "app.navbar.libraries.menu", + "id": "app.navbar.libraries.files", "order": 200, - "icon": "library_books", - "title": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.TOOLTIP", - "children": [ - { - "id": "app.navbar.libraries.favorite", - "order": 100, - "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "favorite/libraries" - }, - { - "id": "app.navbar.libraries.files", - "order": 200, - "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "libraries" - } - ] - } - ] - }, - { - "id": "app.navbar.secondary", - "items": [ + "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "libraries" + }, { - "id": "app.navbar.shared", + "id": "app.navbar.libraries.favorite", "order": 100, - "icon": "people", - "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", - "route": "shared", - "rules": { - "visible": "repository.isQuickShareEnabled" - } + "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "favorite/libraries" }, { "id": "app.navbar.recentFiles", @@ -242,6 +217,17 @@ "description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP", "route": "recent-files" }, + { + "id": "app.navbar.shared", + "order": 100, + "icon": "people", + "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", + "route": "shared", + "rules": { + "visible": "repository.isQuickShareEnabled" + } + }, { "id": "app.navbar.favorites", "order": 300, diff --git a/e2e/resources/extensibility-configs/document-presets-ext.json b/e2e/resources/extensibility-configs/document-presets-ext.json index 597df3f3ff..3dcb666764 100644 --- a/e2e/resources/extensibility-configs/document-presets-ext.json +++ b/e2e/resources/extensibility-configs/document-presets-ext.json @@ -196,43 +196,18 @@ "route": "personal-files" }, { - "id": "app.navbar.libraries.menu", + "id": "app.navbar.libraries.files", "order": 200, - "icon": "library_books", - "title": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.TOOLTIP", - "children": [ - { - "id": "app.navbar.libraries.favorite", - "order": 100, - "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "favorite/libraries" - }, - { - "id": "app.navbar.libraries.files", - "order": 200, - "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "libraries" - } - ] - } - ] - }, - { - "id": "app.navbar.secondary", - "items": [ + "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "libraries" + }, { - "id": "app.navbar.shared", + "id": "app.navbar.libraries.favorite", "order": 100, - "icon": "people", - "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", - "route": "shared", - "rules": { - "visible": "repository.isQuickShareEnabled" - } + "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "favorite/libraries" }, { "id": "app.navbar.recentFiles", @@ -242,6 +217,17 @@ "description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP", "route": "recent-files" }, + { + "id": "app.navbar.shared", + "order": 100, + "icon": "people", + "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", + "route": "shared", + "rules": { + "visible": "repository.isQuickShareEnabled" + } + }, { "id": "app.navbar.favorites", "order": 300, diff --git a/e2e/resources/extensibility-configs/header-ext.json b/e2e/resources/extensibility-configs/header-ext.json index 11bc650211..fb9aa267ba 100644 --- a/e2e/resources/extensibility-configs/header-ext.json +++ b/e2e/resources/extensibility-configs/header-ext.json @@ -223,43 +223,18 @@ "route": "personal-files" }, { - "id": "app.navbar.libraries.menu", + "id": "app.navbar.libraries.files", "order": 200, - "icon": "library_books", - "title": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.TOOLTIP", - "children": [ - { - "id": "app.navbar.libraries.favorite", - "order": 100, - "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "favorite/libraries" - }, - { - "id": "app.navbar.libraries.files", - "order": 200, - "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "libraries" - } - ] - } - ] - }, - { - "id": "app.navbar.secondary", - "items": [ + "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "libraries" + }, { - "id": "app.navbar.shared", + "id": "app.navbar.libraries.favorite", "order": 100, - "icon": "people", - "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", - "route": "shared", - "rules": { - "visible": "repository.isQuickShareEnabled" - } + "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "favorite/libraries" }, { "id": "app.navbar.recentFiles", @@ -269,6 +244,17 @@ "description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP", "route": "recent-files" }, + { + "id": "app.navbar.shared", + "order": 100, + "icon": "people", + "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", + "route": "shared", + "rules": { + "visible": "repository.isQuickShareEnabled" + } + }, { "id": "app.navbar.favorites", "order": 300, diff --git a/e2e/resources/extensibility-configs/info-drawer-ext.json b/e2e/resources/extensibility-configs/info-drawer-ext.json index 7438547990..89da3b859a 100644 --- a/e2e/resources/extensibility-configs/info-drawer-ext.json +++ b/e2e/resources/extensibility-configs/info-drawer-ext.json @@ -196,43 +196,18 @@ "route": "personal-files" }, { - "id": "app.navbar.libraries.menu", + "id": "app.navbar.libraries.files", "order": 200, - "icon": "library_books", - "title": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.TOOLTIP", - "children": [ - { - "id": "app.navbar.libraries.favorite", - "order": 100, - "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "favorite/libraries" - }, - { - "id": "app.navbar.libraries.files", - "order": 200, - "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "libraries" - } - ] - } - ] - }, - { - "id": "app.navbar.secondary", - "items": [ + "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "libraries" + }, { - "id": "app.navbar.shared", + "id": "app.navbar.libraries.favorite", "order": 100, - "icon": "people", - "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", - "route": "shared", - "rules": { - "visible": "repository.isQuickShareEnabled" - } + "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "favorite/libraries" }, { "id": "app.navbar.recentFiles", @@ -242,6 +217,17 @@ "description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP", "route": "recent-files" }, + { + "id": "app.navbar.shared", + "order": 100, + "icon": "people", + "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", + "route": "shared", + "rules": { + "visible": "repository.isQuickShareEnabled" + } + }, { "id": "app.navbar.favorites", "order": 300, diff --git a/e2e/resources/extensibility-configs/info-drawer-no-tabs-ext.json b/e2e/resources/extensibility-configs/info-drawer-no-tabs-ext.json index 6a855a06c8..0cd68e1216 100644 --- a/e2e/resources/extensibility-configs/info-drawer-no-tabs-ext.json +++ b/e2e/resources/extensibility-configs/info-drawer-no-tabs-ext.json @@ -196,43 +196,18 @@ "route": "personal-files" }, { - "id": "app.navbar.libraries.menu", + "id": "app.navbar.libraries.files", "order": 200, - "icon": "library_books", - "title": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.TOOLTIP", - "children": [ - { - "id": "app.navbar.libraries.favorite", - "order": 100, - "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "favorite/libraries" - }, - { - "id": "app.navbar.libraries.files", - "order": 200, - "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "libraries" - } - ] - } - ] - }, - { - "id": "app.navbar.secondary", - "items": [ + "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "libraries" + }, { - "id": "app.navbar.shared", + "id": "app.navbar.libraries.favorite", "order": 100, - "icon": "people", - "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", - "route": "shared", - "rules": { - "visible": "repository.isQuickShareEnabled" - } + "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "favorite/libraries" }, { "id": "app.navbar.recentFiles", @@ -242,6 +217,17 @@ "description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP", "route": "recent-files" }, + { + "id": "app.navbar.shared", + "order": 100, + "icon": "people", + "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", + "route": "shared", + "rules": { + "visible": "repository.isQuickShareEnabled" + } + }, { "id": "app.navbar.favorites", "order": 300, diff --git a/e2e/resources/extensibility-configs/metadata-ext.json b/e2e/resources/extensibility-configs/metadata-ext.json index a92dc9b96a..31b94c3ec3 100644 --- a/e2e/resources/extensibility-configs/metadata-ext.json +++ b/e2e/resources/extensibility-configs/metadata-ext.json @@ -196,43 +196,18 @@ "route": "personal-files" }, { - "id": "app.navbar.libraries.menu", + "id": "app.navbar.libraries.files", "order": 200, - "icon": "library_books", - "title": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.TOOLTIP", - "children": [ - { - "id": "app.navbar.libraries.favorite", - "order": 100, - "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "favorite/libraries" - }, - { - "id": "app.navbar.libraries.files", - "order": 200, - "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "libraries" - } - ] - } - ] - }, - { - "id": "app.navbar.secondary", - "items": [ + "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "libraries" + }, { - "id": "app.navbar.shared", + "id": "app.navbar.libraries.favorite", "order": 100, - "icon": "people", - "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", - "route": "shared", - "rules": { - "visible": "repository.isQuickShareEnabled" - } + "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "favorite/libraries" }, { "id": "app.navbar.recentFiles", @@ -242,6 +217,17 @@ "description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP", "route": "recent-files" }, + { + "id": "app.navbar.shared", + "order": 100, + "icon": "people", + "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", + "route": "shared", + "rules": { + "visible": "repository.isQuickShareEnabled" + } + }, { "id": "app.navbar.favorites", "order": 300, diff --git a/e2e/resources/extensibility-configs/viewer-ext.json b/e2e/resources/extensibility-configs/viewer-ext.json index 98ff2ba029..0dc53e075c 100644 --- a/e2e/resources/extensibility-configs/viewer-ext.json +++ b/e2e/resources/extensibility-configs/viewer-ext.json @@ -196,43 +196,18 @@ "route": "personal-files" }, { - "id": "app.navbar.libraries.menu", + "id": "app.navbar.libraries.files", "order": 200, - "icon": "library_books", - "title": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.TOOLTIP", - "children": [ - { - "id": "app.navbar.libraries.favorite", - "order": 100, - "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "favorite/libraries" - }, - { - "id": "app.navbar.libraries.files", - "order": 200, - "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "libraries" - } - ] - } - ] - }, - { - "id": "app.navbar.secondary", - "items": [ + "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "libraries" + }, { - "id": "app.navbar.shared", + "id": "app.navbar.libraries.favorite", "order": 100, - "icon": "people", - "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", - "route": "shared", - "rules": { - "visible": "repository.isQuickShareEnabled" - } + "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "favorite/libraries" }, { "id": "app.navbar.recentFiles", @@ -242,6 +217,17 @@ "description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP", "route": "recent-files" }, + { + "id": "app.navbar.shared", + "order": 100, + "icon": "people", + "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", + "route": "shared", + "rules": { + "visible": "repository.isQuickShareEnabled" + } + }, { "id": "app.navbar.favorites", "order": 300, diff --git a/e2e/suites/actions-available/files-folders/folders-actions.test.ts b/e2e/suites/actions-available/files-folders/folders-actions.test.ts index e3ca5f32cc..312dacbacf 100755 --- a/e2e/suites/actions-available/files-folders/folders-actions.test.ts +++ b/e2e/suites/actions-available/files-folders/folders-actions.test.ts @@ -43,8 +43,8 @@ describe('Folders - available actions : ', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable } = page; - const { searchInput } = page.header; + const { dataTable, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; const searchResultsPage = new SearchResultsPage(); beforeAll(async () => { @@ -150,6 +150,7 @@ describe('Folders - available actions : ', () => { describe('on a folder', () => { beforeAll(async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(random); await searchResultsPage.waitForResults(); @@ -168,6 +169,8 @@ describe('Folders - available actions : ', () => { describe('on multiple selection', () => { it('[C291821] multiple folders', async () => { + await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(random); await searchResultsPage.waitForResults(); @@ -181,6 +184,8 @@ describe('Folders - available actions : ', () => { }); it('[C291822] both files and folders', async () => { + await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(`${testData.file.name} or ${testData.folderFav.name}`); await searchResultsPage.waitForResults(); diff --git a/e2e/suites/actions-available/files-folders/generic.test.ts b/e2e/suites/actions-available/files-folders/generic.test.ts index 4310c174bf..f822895877 100755 --- a/e2e/suites/actions-available/files-folders/generic.test.ts +++ b/e2e/suites/actions-available/files-folders/generic.test.ts @@ -51,7 +51,7 @@ describe('Generic tests : ', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); const { dataTable, toolbar } = page; - const { searchInput } = page.header; + const { searchInput } = page.pageLayoutHeader; const contextMenu = dataTable.menu; beforeAll(async () => { @@ -113,44 +113,8 @@ describe('Generic tests : ', () => { }); describe('Actions are not displayed when no item is selected', () => { - it('[C213120] on Personal Files', async () => { - await page.clickPersonalFilesAndWait(); - expect(await toolbar.isEmpty()).toBe(true, `actions displayed though nothing selected`); - }); - - it('[C280452] on Trash', async () => { - await page.clickTrash(); - expect(await toolbar.isEmpty()).toBe(true, `actions displayed though nothing selected`); - }); - - it('[C280449] on Favorites', async () => { - await page.clickFavorites(); - expect(await toolbar.isEmpty()).toBe(true, `actions displayed though nothing selected`); - }); - - it('[C280447] on Recent Files', async () => { - await userApi.search.waitForNodes(`file-${random}`, { expect: 2 }); - - await page.clickRecentFilesAndWait(); - expect(await toolbar.isEmpty()).toBe(true, `actions displayed though nothing selected`); - }); - - it('[C280445] on Shared Files', async () => { - await page.clickSharedFiles(); - expect(await toolbar.isEmpty()).toBe(true, `actions displayed though nothing selected`); - }); - - it('[C280439] on My Libraries', async () => { - await page.goToMyLibraries(); - expect(await toolbar.isEmpty()).toBe(true, `actions displayed though nothing selected`); - }); - - it('[C280439] on Favorite Libraries', async () => { - await page.goToFavoriteLibraries(); - expect(await toolbar.isEmpty()).toBe(true, `actions displayed though nothing selected`); - }); - it('[C291815] on Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor('*'); diff --git a/e2e/suites/actions-available/files-folders/locked-files-actions.test.ts b/e2e/suites/actions-available/files-folders/locked-files-actions.test.ts index ee5df0a64d..5a7717263d 100755 --- a/e2e/suites/actions-available/files-folders/locked-files-actions.test.ts +++ b/e2e/suites/actions-available/files-folders/locked-files-actions.test.ts @@ -44,8 +44,8 @@ describe('Locked Files - available actions : ', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable } = page; - const { searchInput } = page.header; + const { dataTable, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; const searchResultsPage = new SearchResultsPage(); beforeAll(async () => { @@ -264,6 +264,7 @@ describe('Locked Files - available actions : ', () => { describe('on Search Results : ', () => { beforeEach(async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFiles(); await searchInput.searchFor(random); diff --git a/e2e/suites/actions-available/files-folders/multiple-files-actions.test.ts b/e2e/suites/actions-available/files-folders/multiple-files-actions.test.ts index c24e2153af..08fd019441 100755 --- a/e2e/suites/actions-available/files-folders/multiple-files-actions.test.ts +++ b/e2e/suites/actions-available/files-folders/multiple-files-actions.test.ts @@ -51,8 +51,8 @@ describe('Multiple Files - available actions : ', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable } = page; - const { searchInput } = page.header; + const { dataTable, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; const searchResultsPage = new SearchResultsPage(); beforeAll(async () => { @@ -161,6 +161,7 @@ describe('Multiple Files - available actions : ', () => { describe('on Search Results : ', () => { beforeEach(async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFiles(); await searchInput.searchFor(random); diff --git a/e2e/suites/actions-available/files-folders/office-files-actions.test.ts b/e2e/suites/actions-available/files-folders/office-files-actions.test.ts index a7f2874f02..32e893903e 100755 --- a/e2e/suites/actions-available/files-folders/office-files-actions.test.ts +++ b/e2e/suites/actions-available/files-folders/office-files-actions.test.ts @@ -43,8 +43,8 @@ describe('Office Files - available actions : ', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable } = page; - const { searchInput } = page.header; + const { dataTable, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; const searchResultsPage = new SearchResultsPage(); beforeAll(async () => { @@ -246,6 +246,7 @@ describe('Office Files - available actions : ', () => { describe('on Search Results : ', () => { beforeEach(async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(random); await searchResultsPage.waitForResults(); diff --git a/e2e/suites/actions-available/files-folders/single-file-actions.test.ts b/e2e/suites/actions-available/files-folders/single-file-actions.test.ts index 42a904cd2d..02b64e7158 100755 --- a/e2e/suites/actions-available/files-folders/single-file-actions.test.ts +++ b/e2e/suites/actions-available/files-folders/single-file-actions.test.ts @@ -44,8 +44,8 @@ describe('Files - available actions : ', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable } = page; - const { searchInput } = page.header; + const { dataTable, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; const searchResultsPage = new SearchResultsPage(); beforeAll(async () => { @@ -231,6 +231,7 @@ describe('Files - available actions : ', () => { describe('on Search Results : ', () => { beforeEach(async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); }); diff --git a/e2e/suites/actions-available/libraries/library.test.ts b/e2e/suites/actions-available/libraries/library.test.ts index 63ad74a06e..5f4c1bcfcf 100755 --- a/e2e/suites/actions-available/libraries/library.test.ts +++ b/e2e/suites/actions-available/libraries/library.test.ts @@ -46,7 +46,8 @@ describe('Library actions : ', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); const searchResultsPage = new SearchResultsPage(); - const { searchInput } = searchResultsPage.header; + const { toolbar } = page; + const { searchInput } = searchResultsPage.pageLayoutHeader; beforeAll(async () => { try { @@ -245,6 +246,7 @@ describe('Library actions : ', () => { try { await Utils.pressEscape(); await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); } catch (error) { @@ -253,7 +255,7 @@ describe('Library actions : ', () => { }); it('[C290084] Public library, user is a member, favorite', async () => { - await searchInput.searchFor(testData.publicUserMemberFav.name); + await searchInput.searchForLibrary(testData.publicUserMemberFav.name); await testUtil.checkToolbarActions( testData.publicUserMemberFav.name, @@ -264,7 +266,7 @@ describe('Library actions : ', () => { }); it('[C290085] Private library, user is a member, favorite', async () => { - await searchInput.searchFor(testData.privateUserMemberFav.name); + await searchInput.searchForLibrary(testData.privateUserMemberFav.name); await testUtil.checkToolbarActions( testData.privateUserMemberFav.name, @@ -275,7 +277,7 @@ describe('Library actions : ', () => { }); it('[C290086] Moderated library, user is a member, favorite', async () => { - await searchInput.searchFor(testData.moderatedUserMemberFav.name); + await searchInput.searchForLibrary(testData.moderatedUserMemberFav.name); await testUtil.checkToolbarActions( testData.moderatedUserMemberFav.name, @@ -286,7 +288,7 @@ describe('Library actions : ', () => { }); it('[C291812] Public library, user is a member, not favorite', async () => { - await searchInput.searchFor(testData.publicUserMemberNotFav.name); + await searchInput.searchForLibrary(testData.publicUserMemberNotFav.name); await testUtil.checkToolbarActions( testData.publicUserMemberNotFav.name, @@ -297,7 +299,7 @@ describe('Library actions : ', () => { }); it('[C291813] Private library, user is a member, not favorite', async () => { - await searchInput.searchFor(testData.privateUserMemberNotFav.name); + await searchInput.searchForLibrary(testData.privateUserMemberNotFav.name); await testUtil.checkToolbarActions( testData.privateUserMemberNotFav.name, @@ -308,7 +310,7 @@ describe('Library actions : ', () => { }); it('[C291814] Moderated library, user is a member, not favorite', async () => { - await searchInput.searchFor(testData.moderatedUserMemberNotFav.name); + await searchInput.searchForLibrary(testData.moderatedUserMemberNotFav.name); await testUtil.checkToolbarActions( testData.moderatedUserMemberNotFav.name, @@ -319,7 +321,7 @@ describe('Library actions : ', () => { }); it('[C326680] Public library, user not a member, favorite', async () => { - await searchInput.searchFor(testData.publicNotMemberFav.name); + await searchInput.searchForLibrary(testData.publicNotMemberFav.name); await testUtil.checkToolbarActions( testData.publicNotMemberFav.name, @@ -330,7 +332,7 @@ describe('Library actions : ', () => { }); it('[C326681] Moderated library, user not a member, favorite', async () => { - await searchInput.searchFor(testData.moderatedNotMemberFav.name); + await searchInput.searchForLibrary(testData.moderatedNotMemberFav.name); await testUtil.checkToolbarActions( testData.moderatedNotMemberFav.name, @@ -341,7 +343,7 @@ describe('Library actions : ', () => { }); it('[C326682] Public library, user not a member, not favorite', async () => { - await searchInput.searchFor(testData.publicNotMemberNotFav.name); + await searchInput.searchForLibrary(testData.publicNotMemberNotFav.name); await testUtil.checkToolbarActions( testData.publicNotMemberNotFav.name, @@ -352,7 +354,7 @@ describe('Library actions : ', () => { }); it('[C326683] Moderated library, user not a member, not favorite', async () => { - await searchInput.searchFor(testData.moderatedNotMemberNotFav.name); + await searchInput.searchForLibrary(testData.moderatedNotMemberNotFav.name); await testUtil.checkToolbarActions( testData.moderatedNotMemberNotFav.name, @@ -363,7 +365,7 @@ describe('Library actions : ', () => { }); it('[C326685] Moderated library, user requested to join, favorite', async () => { - await searchInput.searchFor(testData.moderatedRequestedJoinFav.name); + await searchInput.searchForLibrary(testData.moderatedRequestedJoinFav.name); await testUtil.checkToolbarActions( testData.moderatedRequestedJoinFav.name, @@ -374,7 +376,7 @@ describe('Library actions : ', () => { }); it('[C326684] Moderated library, user requested to join, not favorite', async () => { - await searchInput.searchFor(testData.moderatedRequestedJoinNotFav.name); + await searchInput.searchForLibrary(testData.moderatedRequestedJoinNotFav.name); await testUtil.checkToolbarActions( testData.moderatedRequestedJoinNotFav.name, diff --git a/e2e/suites/actions-available/new-menu/new-menu.test.ts b/e2e/suites/actions-available/new-menu/new-menu.test.ts index ac7f4cf639..605f715c16 100755 --- a/e2e/suites/actions-available/new-menu/new-menu.test.ts +++ b/e2e/suites/actions-available/new-menu/new-menu.test.ts @@ -32,7 +32,7 @@ describe('New menu', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable, sidenav } = page; + const { sidenav } = page; const { menu } = sidenav; const adminApiActions = new AdminActions(); @@ -66,11 +66,7 @@ describe('New menu', () => { await page.clickPersonalFiles(); await sidenav.openNewMenu(); - expect(await menu.isUploadFileEnabled()).toBe(true, 'Upload File option not enabled'); - expect(await menu.isUploadFolderEnabled()).toBe(true, 'Upload Folder option not enabled'); - expect(await menu.isCreateFolderEnabled()).toBe(true, 'Create Folder option not enabled'); - expect(await menu.isCreateLibraryEnabled()).toBe(true, 'Create Library option not enabled'); expect(await menu.isCreateFileFromTemplateEnabled()).toBe(true, 'Create file from template is not enabled'); expect(await menu.isCreateFolderFromTemplateEnabled()).toBe(true, 'Create folder from template is not enabled'); @@ -78,32 +74,9 @@ describe('New menu', () => { it('[C280393] Actions in File Libraries - user with enough permissions', async () => { await page.goToMyLibrariesAndWait(); - await dataTable.doubleClickOnRowByName(siteUser); await sidenav.openNewMenu(); - expect(await menu.isUploadFileEnabled()).toBe(true, 'Upload file is not enabled in File Libraries'); - expect(await menu.isUploadFolderEnabled()).toBe(true, 'Upload folder is not enabled in File Libraries'); - - expect(await menu.isCreateFolderEnabled()).toBe(true, 'Create folder is not enabled'); expect(await menu.isCreateLibraryEnabled()).toBe(true, 'Create Library option not enabled'); - - expect(await menu.isCreateFileFromTemplateEnabled()).toBe(true, 'Create file from template is not enabled'); - expect(await menu.isCreateFolderFromTemplateEnabled()).toBe(true, 'Create folder from template is not enabled'); - }); - - it('[C280397] Actions in File Libraries - user without enough permissions', async () => { - await page.goToMyLibrariesAndWait(); - await dataTable.doubleClickOnRowByName(siteAdmin); - await sidenav.openNewMenu(); - - expect(await menu.isUploadFileEnabled()).toBe(false, 'Upload file is not disabled'); - expect(await menu.isUploadFolderEnabled()).toBe(false, 'Upload folder is not disabled'); - - expect(await menu.isCreateFolderEnabled()).toBe(false, 'Create folder is not disabled'); - expect(await menu.isCreateLibraryEnabled()).toBe(true, 'Create Library option not enabled'); - - expect(await menu.isCreateFileFromTemplateEnabled()).toBe(false, 'Create file from template is not disabled'); - expect(await menu.isCreateFolderFromTemplateEnabled()).toBe(false, 'Create folder from template is not disabled'); }); it('[C216342] Enabled actions tooltips', async () => { @@ -112,39 +85,10 @@ describe('New menu', () => { let tooltip: string; - tooltip = await menu.getItemTooltip('Upload File'); - expect(tooltip).toContain('Select files to upload'); - - tooltip = await menu.getItemTooltip('Upload Folder'); - expect(tooltip).toContain('Select folders to upload'); - tooltip = await menu.getItemTooltip('Create Folder'); expect(tooltip).toContain('Create new folder'); - tooltip = await menu.getItemTooltip('Create Library'); - expect(tooltip).toContain('Create a new File Library'); - tooltip = await menu.getItemTooltip('Create file from template'); expect(tooltip).toContain('Create file from template'); }); - - it('[C280398] Disabled actions tooltips', async () => { - await page.goToMyLibrariesAndWait(); - await dataTable.doubleClickOnRowByName(siteAdmin); - await sidenav.openNewMenu(); - - let tooltip: string; - - tooltip = await menu.getItemTooltip('Upload File'); - expect(tooltip).toContain('Files cannot be uploaded whilst viewing the current items'); - - tooltip = await menu.getItemTooltip('Upload Folder'); - expect(tooltip).toContain('Folders cannot be uploaded whilst viewing the current items'); - - tooltip = await menu.getItemTooltip('Create Folder'); - expect(tooltip).toContain('Folders cannot be created whilst viewing the current items'); - - tooltip = await menu.getItemTooltip('Create file from template'); - expect(tooltip).toContain('Files cannot be created whilst viewing the current items'); - }); }); diff --git a/e2e/suites/actions-available/special-permissions/other-permissions.ts b/e2e/suites/actions-available/special-permissions/other-permissions.ts index f923ec71a7..cb126d7f94 100755 --- a/e2e/suites/actions-available/special-permissions/other-permissions.ts +++ b/e2e/suites/actions-available/special-permissions/other-permissions.ts @@ -27,9 +27,9 @@ import * as testData from './test-data-permissions'; import * as testUtil from '../test-util'; const page = new BrowsingPage(); -const { dataTable } = page; +const { dataTable, toolbar } = page; const searchResultsPage = new SearchResultsPage(); -const { searchInput } = searchResultsPage.header; +const { searchInput } = searchResultsPage.pageLayoutHeader; export function collaboratorTests(siteName?: string) { describe('available actions : ', () => { @@ -73,6 +73,7 @@ export function collaboratorTests(siteName?: string) { }); it('on Search Results - [C297653]', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(testData.fileSharedFav.name); @@ -140,6 +141,7 @@ export function collaboratorTests(siteName?: string) { }); it('file opened from Search Results - [C306992]', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(testData.fileDocxSharedFav.name); await searchResultsPage.waitForResults(); @@ -203,6 +205,7 @@ export function filesLockedByCurrentUser(siteName?: string) { }); it('on Search Results - [C297660]', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(testData.fileLockedByUser); await searchResultsPage.waitForResults(); @@ -244,6 +247,7 @@ export function filesLockedByCurrentUser(siteName?: string) { }); it('file opened from Search Results - [C306993]', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(testData.fileLockedByUser); await searchResultsPage.waitForResults(); @@ -268,7 +272,7 @@ export function filesLockedByOtherUser(siteName?: string) { }); it('on File Libraries - [C297664]', async () => { - await page.clickFileLibrariesAndWait(); + await page.goToMyLibrariesAndWait(); await dataTable.doubleClickOnRowByName(siteName); await dataTable.waitForHeader(); @@ -309,6 +313,7 @@ export function filesLockedByOtherUser(siteName?: string) { }); it('on Search Results - [C297667]', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(testData.fileLockedByUser); await searchResultsPage.waitForResults(); @@ -321,7 +326,7 @@ export function filesLockedByOtherUser(siteName?: string) { describe('available actions in the viewer : ', () => { it('file opened from File Libraries - [C297671]', async () => { - await page.clickFileLibrariesAndWait(); + await page.goToMyLibrariesAndWait(); await dataTable.doubleClickOnRowByName(siteName); await dataTable.waitForHeader(); @@ -350,6 +355,7 @@ export function filesLockedByOtherUser(siteName?: string) { }); it('file opened from Search Results - [C306994]', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(testData.fileLockedByUser); await searchResultsPage.waitForResults(); diff --git a/e2e/suites/actions-available/special-permissions/search-results.ts b/e2e/suites/actions-available/special-permissions/search-results.ts index bed7185b37..f5032ad11a 100755 --- a/e2e/suites/actions-available/special-permissions/search-results.ts +++ b/e2e/suites/actions-available/special-permissions/search-results.ts @@ -29,7 +29,7 @@ import * as testUtil from '../test-util'; export function searchResultsTests() { const page = new BrowsingPage(); const searchResultsPage = new SearchResultsPage(); - const { searchInput } = page.header; + const { searchInput, toolbar } = page.pageLayoutHeader; describe('available actions : ', () => { beforeEach(async () => { @@ -43,6 +43,7 @@ export function searchResultsTests() { describe('on a file', () => { beforeEach(async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFiles(); await searchInput.searchFor(testData.random); @@ -137,6 +138,7 @@ export function searchResultsTests() { describe('on a folder', () => { beforeAll(async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFolders(); await searchInput.searchFor(testData.random); @@ -158,6 +160,7 @@ export function searchResultsTests() { describe('of files', () => { beforeAll(async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFiles(); await searchInput.searchFor(testData.random); @@ -209,6 +212,7 @@ export function searchResultsTests() { it('multiple folders - [C291836]', async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFolders(); await searchInput.searchFor(testData.random); @@ -223,6 +227,7 @@ export function searchResultsTests() { it('both files and folders - [C268128]', async () => { await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(`${testData.file.name} or ${testData.folderFav.name}`); diff --git a/e2e/suites/actions-available/special-permissions/viewer.ts b/e2e/suites/actions-available/special-permissions/viewer.ts index 3f3ad01510..56060ddad9 100755 --- a/e2e/suites/actions-available/special-permissions/viewer.ts +++ b/e2e/suites/actions-available/special-permissions/viewer.ts @@ -29,8 +29,8 @@ import * as testUtil from '../test-util'; export function viewerTests(siteName?: string) { const page = new BrowsingPage(); const searchResultsPage = new SearchResultsPage(); - const { dataTable } = page; - const { searchInput } = page.header; + const { dataTable, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; describe('available actions : ', () => { beforeEach(async () => { @@ -227,6 +227,7 @@ export function viewerTests(siteName?: string) { describe('file opened from Search Results', () => { beforeAll(async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFiles(); await searchInput.searchFor(testData.random); diff --git a/e2e/suites/actions-available/test-util.ts b/e2e/suites/actions-available/test-util.ts index 7d1990d534..be788a1a3c 100644 --- a/e2e/suites/actions-available/test-util.ts +++ b/e2e/suites/actions-available/test-util.ts @@ -37,7 +37,9 @@ export async function checkContextMenu(item: string, expectedContextMenu: string await contextMenu.waitForMenuToOpen(); const actualActions = await contextMenu.getMenuItems(); - expect(actualActions).toEqual(expectedContextMenu); + for (const action of expectedContextMenu) { + expect(actualActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } await Utils.pressEscape(); await menu.waitForMenuToClose(); @@ -47,7 +49,9 @@ export async function checkToolbarPrimary(item: string, expectedToolbarPrimary: await dataTable.selectItem(item); const actualPrimaryActions = await toolbar.getButtons(); - expect(actualPrimaryActions).toEqual(expectedToolbarPrimary); + for (const action of expectedToolbarPrimary) { + expect(actualPrimaryActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } } export async function checkToolbarMoreActions(item: string, expectedToolbarMore: string[]): Promise { @@ -55,7 +59,9 @@ export async function checkToolbarMoreActions(item: string, expectedToolbarMore: await toolbar.openMoreMenu(); const actualMoreActions = await toolbar.menu.getMenuItems(); - expect(actualMoreActions).toEqual(expectedToolbarMore); + for (const action of expectedToolbarMore) { + expect(actualMoreActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } await toolbar.closeMoreMenu(); } @@ -64,12 +70,16 @@ export async function checkToolbarActions(item: string, expectedToolbarPrimary: await dataTable.selectItem(item); const actualPrimaryActions = await toolbar.getButtons(); - expect(actualPrimaryActions).toEqual(expectedToolbarPrimary); + for (const action of expectedToolbarPrimary) { + expect(actualPrimaryActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } await toolbar.openMoreMenu(); const actualMoreActions = await toolbar.menu.getMenuItems(); - expect(actualMoreActions).toEqual(expectedToolbarMore); + for (const action of expectedToolbarMore) { + expect(actualMoreActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } await toolbar.closeMoreMenu(); } @@ -80,7 +90,9 @@ export async function checkMultipleSelContextMenu(items: string[], expectedConte await contextMenu.waitForMenuToOpen(); const actualActions = await contextMenu.getMenuItems(); - expect(actualActions).toEqual(expectedContextMenu); + for (const action of expectedContextMenu) { + expect(actualActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } await Utils.pressEscape(); await menu.waitForMenuToClose(); @@ -90,7 +102,9 @@ export async function checkMultipleSelToolbarPrimary(items: string[], expectedTo await dataTable.selectMultipleItems(items); const actualPrimaryActions = await toolbar.getButtons(); - expect(actualPrimaryActions).toEqual(expectedToolbarPrimary); + for (const action of expectedToolbarPrimary) { + expect(actualPrimaryActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } } export async function checkMultipleSelToolbarActions( @@ -101,12 +115,16 @@ export async function checkMultipleSelToolbarActions( await dataTable.selectMultipleItems(items); const actualPrimaryActions = await toolbar.getButtons(); - expect(actualPrimaryActions).toEqual(expectedToolbarPrimary); + for (const action of expectedToolbarPrimary) { + expect(actualPrimaryActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } await toolbar.openMoreMenu(); const actualMoreActions = await toolbar.menu.getMenuItems(); - expect(actualMoreActions).toEqual(expectedToolbarMore); + for (const action of expectedToolbarMore) { + expect(actualMoreActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } await toolbar.closeMoreMenu(); } @@ -118,12 +136,17 @@ export async function checkViewerActions(item: string, expectedToolbarPrimary: s let actualPrimaryActions = await viewerToolbar.getButtons(); actualPrimaryActions = removeClosePreviousNextOldInfo(actualPrimaryActions); - expect(actualPrimaryActions).toEqual(expectedToolbarPrimary); + + for (const action of expectedToolbarPrimary) { + expect(actualPrimaryActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } await viewerToolbar.openMoreMenu(); const actualMoreActions = await viewerToolbar.menu.getMenuItems(); - expect(actualMoreActions).toEqual(expectedToolbarMore); + for (const action of expectedToolbarMore) { + expect(actualMoreActions.includes(action)).toBe(true, `Expected to contain ${action}`); + } await Utils.pressEscape(); await menu.waitForMenuToClose(); diff --git a/e2e/suites/actions/create/create-file-from-template.test.ts b/e2e/suites/actions/create/create-file-from-template.test.ts index c755af41a8..efeebdb9ff 100755 --- a/e2e/suites/actions/create/create-file-from-template.test.ts +++ b/e2e/suites/actions/create/create-file-from-template.test.ts @@ -86,7 +86,7 @@ describe('Create file from template', () => { const page = new BrowsingPage(); const selectTemplateDialog = new SelectTemplateDialog(); const createFromTemplateDialog = new CreateFromTemplateDialog(); - const { sidenav } = page; + const { toolbar } = page; const templates: NodeContentTree = { folders: [ @@ -155,7 +155,7 @@ describe('Create file from template', () => { describe('Select Template dialog', () => { beforeEach(async () => { - await sidenav.openCreateFileFromTemplateDialog(); + await toolbar.openCreateFileFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); }); @@ -235,7 +235,7 @@ describe('Create file from template', () => { describe('Create from template dialog', () => { beforeEach(async () => { try { - await sidenav.openCreateFileFromTemplateDialog(); + await toolbar.openCreateFileFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); await selectTemplateDialog.dataTable.selectItem(template1InRootFolder); await selectTemplateDialog.clickNext(); @@ -308,7 +308,7 @@ describe('Create file from template', () => { try { await page.clickPersonalFilesAndWait(); await page.dataTable.doubleClickOnRowByName(parent); - await sidenav.openCreateFileFromTemplateDialog(); + await toolbar.openCreateFileFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); await selectTemplateDialog.dataTable.selectItem(template1InRootFolder); await selectTemplateDialog.clickNext(); @@ -376,7 +376,7 @@ describe('Create file from template', () => { try { await fileLibrariesPage.goToMyLibrariesAndWait(); await page.dataTable.doubleClickOnRowByName(siteName); - await sidenav.openCreateFileFromTemplateDialog(); + await toolbar.openCreateFileFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); await selectTemplateDialog.dataTable.selectItem(template1InRootFolder); await selectTemplateDialog.clickNext(); diff --git a/e2e/suites/actions/create/create-folder-from-template.test.ts b/e2e/suites/actions/create/create-folder-from-template.test.ts index 3b621a6fd3..f97fd3bc46 100755 --- a/e2e/suites/actions/create/create-folder-from-template.test.ts +++ b/e2e/suites/actions/create/create-folder-from-template.test.ts @@ -112,7 +112,7 @@ describe('Create folder from template', () => { const page = new BrowsingPage(); const selectTemplateDialog = new SelectTemplateDialog(); const createFromTemplateDialog = new CreateFromTemplateDialog(); - const { sidenav } = page; + const { toolbar } = page; beforeAll(async () => { await adminApiActions.createUser({ username }); @@ -153,7 +153,7 @@ describe('Create folder from template', () => { describe('Select Template dialog', () => { beforeEach(async () => { - await sidenav.openCreateFolderFromTemplateDialog(); + await toolbar.openCreateFolderFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); }); @@ -230,7 +230,7 @@ describe('Create folder from template', () => { describe('Create from template dialog', () => { beforeEach(async () => { - await sidenav.openCreateFolderFromTemplateDialog(); + await toolbar.openCreateFolderFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); await selectTemplateDialog.dataTable.selectItem(templateFolder1); await selectTemplateDialog.clickNext(); @@ -299,7 +299,7 @@ describe('Create folder from template', () => { beforeEach(async () => { await page.clickPersonalFilesAndWait(); await page.dataTable.doubleClickOnRowByName(parent); - await sidenav.openCreateFolderFromTemplateDialog(); + await toolbar.openCreateFolderFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); await selectTemplateDialog.dataTable.selectItem(templateFolder1); await selectTemplateDialog.clickNext(); @@ -364,7 +364,7 @@ describe('Create folder from template', () => { beforeEach(async () => { await fileLibrariesPage.goToMyLibrariesAndWait(); await page.dataTable.doubleClickOnRowByName(siteName); - await sidenav.openCreateFolderFromTemplateDialog(); + await toolbar.openCreateFolderFromTemplateDialog(); await selectTemplateDialog.waitForDialogToOpen(); await selectTemplateDialog.dataTable.selectItem(templateFolder1); await selectTemplateDialog.clickNext(); diff --git a/e2e/suites/actions/create/create-folder.test.ts b/e2e/suites/actions/create/create-folder.test.ts index 912a332829..31a5129077 100755 --- a/e2e/suites/actions/create/create-folder.test.ts +++ b/e2e/suites/actions/create/create-folder.test.ts @@ -55,7 +55,7 @@ describe('Create folder', () => { async function openCreateFolderDialog(name: string) { await page.dataTable.doubleClickOnRowByName(name); - await page.sidenav.openCreateFolderDialog(); + await page.toolbar.openCreateFolderDialog(); await createDialog.waitForDialogToOpen(); } diff --git a/e2e/suites/actions/create/create-library.test.ts b/e2e/suites/actions/create/create-library.test.ts index a083d58fe3..874a1f702a 100755 --- a/e2e/suites/actions/create/create-library.test.ts +++ b/e2e/suites/actions/create/create-library.test.ts @@ -88,7 +88,9 @@ describe('Create library', () => { }); it('[C280024] Create Library dialog UI', async () => { - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); expect(await createDialog.getDialogTitle()).toMatch('Create Library'); @@ -104,7 +106,9 @@ describe('Create library', () => { }); it('[C280025] Create a public library', async () => { - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); await createDialog.enterName(site1Name); await BrowserActions.click(createDialog.createButton); @@ -117,7 +121,9 @@ describe('Create library', () => { }); it('[C289880] Create a moderated library', async () => { - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); await createDialog.enterName(site2Name); await BrowserActions.click(createDialog.visibilityModerated); @@ -131,7 +137,9 @@ describe('Create library', () => { }); it('[C289881] Create a private library', async () => { - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); await createDialog.enterName(site3Name); await BrowserActions.click(createDialog.visibilityPrivate); @@ -145,7 +153,9 @@ describe('Create library', () => { }); it('[C289882] Create a library with a given ID and description', async () => { - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); await createDialog.enterName(site4.name); await createDialog.enterLibraryId(site4.id); @@ -162,7 +172,9 @@ describe('Create library', () => { }); it('[C280027] Duplicate library ID', async () => { - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); await createDialog.enterName(duplicateSite.name); await createDialog.enterLibraryId(duplicateSite.id); @@ -172,7 +184,9 @@ describe('Create library', () => { }); it('[C280028] Create library using the ID of a library from the Trashcan', async () => { - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); await createDialog.enterName(siteInTrash.name); await createDialog.enterLibraryId(siteInTrash.id); @@ -182,7 +196,9 @@ describe('Create library', () => { }); it('[C280029] Cancel button', async () => { - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); await createDialog.enterName('test site'); await createDialog.enterDescription('test description'); @@ -194,7 +210,8 @@ describe('Create library', () => { it('[C280026] Library ID cannot contain special characters', async () => { const idWithSpecialChars = ['a*a', 'a"a', 'aa', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a']; - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); await createDialog.enterName('test site'); @@ -206,7 +223,9 @@ describe('Create library', () => { }); it('[C280030] Create 2 libraries with same name but different IDs', async () => { - await page.sidenav.openCreateLibraryDialog(); + await page.goToMyLibrariesAndWait(); + + await page.toolbar.openCreateLibraryDialog(); await createDialog.waitForDialogToOpen(); await createDialog.enterName(duplicateSite.name); await createDialog.enterLibraryId(`${duplicateSite.id}-2`); diff --git a/e2e/suites/actions/delete/restore.test.ts b/e2e/suites/actions/delete/restore.test.ts index 097a53ce57..35c7fcbfd6 100755 --- a/e2e/suites/actions/delete/restore.test.ts +++ b/e2e/suites/actions/delete/restore.test.ts @@ -111,7 +111,7 @@ describe('Restore from Trash', () => { const action = await page.getSnackBarAction(); expect(action).toContain('View'); expect(await dataTable.isItemPresent(site)).toBe(false, `${site} was not removed from list`); - await page.clickFileLibrariesAndWait(); + await page.goToMyLibrariesAndWait(); expect(await page.dataTable.isItemPresent(site)).toBe(true, `${site} not displayed in list`); }); diff --git a/e2e/suites/actions/library/library-actions.test.ts b/e2e/suites/actions/library/library-actions.test.ts index cdaed8542b..588b18afaa 100755 --- a/e2e/suites/actions/library/library-actions.test.ts +++ b/e2e/suites/actions/library/library-actions.test.ts @@ -60,7 +60,7 @@ describe('Library actions', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); const { dataTable, toolbar } = page; - const { searchInput } = page.header; + const { searchInput } = page.pageLayoutHeader; const confirmDialog = new ConfirmDialog(); const adminApiActions = new AdminActions(); @@ -111,9 +111,10 @@ describe('Library actions', () => { }); it('[C306959] from Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(siteSearchPublic1Admin); + await searchInput.searchForLibrary(siteSearchPublic1Admin); await dataTable.waitForBody(); await dataTable.selectItem(siteSearchPublic1Admin); await BrowserActions.click(toolbar.joinButton); @@ -144,9 +145,10 @@ describe('Library actions', () => { }); it('[C306960] from Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(siteSearchModerated1Admin); + await searchInput.searchForLibrary(siteSearchModerated1Admin); await dataTable.waitForBody(); await dataTable.selectItem(siteSearchModerated1Admin); await BrowserActions.click(toolbar.joinButton); @@ -202,9 +204,10 @@ describe('Library actions', () => { }); it('[C306961] from Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(siteSearchPublic2Admin); + await searchInput.searchForLibrary(siteSearchPublic2Admin); await dataTable.waitForBody(); await dataTable.selectItem(siteSearchPublic2Admin); @@ -277,9 +280,10 @@ describe('Library actions', () => { }); it('[C306962] from Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(siteSearchModerated2Admin); + await searchInput.searchForLibrary(siteSearchModerated2Admin); await dataTable.waitForBody(); await dataTable.selectItem(siteSearchModerated2Admin); @@ -312,9 +316,10 @@ describe('Library actions', () => { }); it('[C306963] from Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(siteSearchPublic3Admin); + await searchInput.searchForLibrary(siteSearchPublic3Admin); await dataTable.waitForBody(); await dataTable.selectItem(siteSearchPublic3Admin); @@ -365,9 +370,10 @@ describe('Library actions', () => { }); it('[C306964] from Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(siteSearchPublic4Admin); + await searchInput.searchForLibrary(siteSearchPublic4Admin); await dataTable.waitForBody(); await dataTable.selectItem(siteSearchPublic4Admin); @@ -407,9 +413,10 @@ describe('Library actions', () => { }); it('[C306965] from Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(siteSearchForDelete); + await searchInput.searchForLibrary(siteSearchForDelete); await dataTable.waitForBody(); await dataTable.selectItem(siteSearchForDelete); diff --git a/e2e/suites/actions/share/unshare-file-search-results.test.ts b/e2e/suites/actions/share/unshare-file-search-results.test.ts index 100c19804d..074478049f 100755 --- a/e2e/suites/actions/share/unshare-file-search-results.test.ts +++ b/e2e/suites/actions/share/unshare-file-search-results.test.ts @@ -123,6 +123,7 @@ describe('Unshare a file from Search Results', () => { }); it('[C306995] Unshare dialog UI', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(file1); @@ -143,6 +144,7 @@ describe('Unshare a file from Search Results', () => { }); it('[C306996] Unshare a file', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(file2); @@ -169,6 +171,7 @@ describe('Unshare a file from Search Results', () => { }); it('[C306997] Cancel the Unshare action', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(file3); @@ -192,6 +195,7 @@ describe('Unshare a file from Search Results', () => { }); it('[C306999] Unshare a file from the context menu', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(file4); @@ -219,6 +223,7 @@ describe('Unshare a file from Search Results', () => { }); it('[C306998] Consumer - on Search Results - file shared by other user', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileSite1); @@ -238,6 +243,7 @@ describe('Unshare a file from Search Results', () => { }); it('[C307000] Consumer - on Search Results - file shared by the user', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileSite2); diff --git a/e2e/suites/actions/upload-download/upload-file.test.ts b/e2e/suites/actions/upload-download/upload-file.test.ts index f3c630962a..527b1feca7 100755 --- a/e2e/suites/actions/upload-download/upload-file.test.ts +++ b/e2e/suites/actions/upload-download/upload-file.test.ts @@ -53,9 +53,9 @@ describe('Upload files', () => { beforeEach(async () => { await page.clickPersonalFilesAndWait(); await dataTable.doubleClickOnRowByName(folder1); - await page.sidenav.openNewMenu(); - await page.sidenav.menu.uploadFilesInput.sendKeys(`${__dirname}/upload-file.test.ts`); - await page.sidenav.closeNewMenu(); + await page.toolbar.openUploadMenu(); + await page.toolbar.menu.uploadFilesInput.sendKeys(`${__dirname}/upload-file.test.ts`); + await page.toolbar.closeUploadMenu(); await page.uploadFilesDialog.uploadDialog.isVisible(); }); diff --git a/e2e/suites/actions/upload-download/upload-new-version.test.ts b/e2e/suites/actions/upload-download/upload-new-version.test.ts index 97ea559aa5..eb6639b7f7 100755 --- a/e2e/suites/actions/upload-download/upload-new-version.test.ts +++ b/e2e/suites/actions/upload-download/upload-new-version.test.ts @@ -94,7 +94,7 @@ describe('Upload new version', () => { const searchResultsPage = new SearchResultsPage(); const { dataTable, toolbar } = page; const uploadNewVersionDialog = new UploadNewVersionDialog(); - const { searchInput } = page.header; + const { searchInput } = page.pageLayoutHeader; const adminActions = new AdminActions(); const userActions = new UserActions(); @@ -140,6 +140,7 @@ describe('Upload new version', () => { }); it('[C307003] dialog UI defaults', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(file); @@ -159,6 +160,7 @@ describe('Upload new version', () => { }); it('[C307004] file is updated after uploading a new version - major', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileSearch1); @@ -181,6 +183,7 @@ describe('Upload new version', () => { }); it('[C307005] file is updated after uploading a new version - minor', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileSearch2); @@ -203,6 +206,7 @@ describe('Upload new version', () => { }); it('[C307006] file is not updated when clicking Cancel', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileSearch3); @@ -223,6 +227,7 @@ describe('Upload new version', () => { }); it('[C307007] upload new version fails when new file name already exists', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileSearch4); @@ -246,6 +251,7 @@ describe('Upload new version', () => { }); it('[C307008] file is unlocked after uploading a new version', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileLockedSearch1); @@ -269,6 +275,7 @@ describe('Upload new version', () => { }); it('[C307009] file remains locked after canceling of uploading a new version', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileLockedSearch2); diff --git a/e2e/suites/actions/upload-download/version-actions.test.ts b/e2e/suites/actions/upload-download/version-actions.test.ts index 309f46e7aa..c421368a45 100644 --- a/e2e/suites/actions/upload-download/version-actions.test.ts +++ b/e2e/suites/actions/upload-download/version-actions.test.ts @@ -120,7 +120,7 @@ describe('Version actions', () => { }); it('[C586768] Should be possible to download a previous document version', async () => { - await viewerPage.toolbar.downloadButton.click(); + await viewerPage.toolbar.viewerDownloadButton.click(); expect(await Utils.fileExistsOnOS(filesToUpload[0])).toBe(true, 'File not found in download location'); }); diff --git a/e2e/suites/application/page-titles.test.ts b/e2e/suites/application/page-titles.test.ts index 4fa5a8eff6..08a0d229b2 100755 --- a/e2e/suites/application/page-titles.test.ts +++ b/e2e/suites/application/page-titles.test.ts @@ -40,12 +40,13 @@ const PAGE_TITLES = { describe('Page titles', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); + const { toolbar } = page; const username = `user-${Utils.random()}`; const apis = new RepoClient(username, username); const adminApiActions = new AdminActions(); const file = `file-${Utils.random()}.txt`; let fileId: string; - const { searchInput } = page.header; + const { searchInput } = page.pageLayoutHeader; beforeAll(async () => { await adminApiActions.createUser({ username }); @@ -124,6 +125,7 @@ describe('Page titles', () => { }); it('[C280413] Search Results page', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(file); expect(await browser.getTitle()).toContain(PAGE_TITLES.SEARCH); diff --git a/e2e/suites/extensions/ext-viewer.test.ts b/e2e/suites/extensions/ext-viewer.test.ts index fdd2967329..b714899b31 100755 --- a/e2e/suites/extensions/ext-viewer.test.ts +++ b/e2e/suites/extensions/ext-viewer.test.ts @@ -140,7 +140,7 @@ describe('Extensions - Viewer', () => { await page.dataTable.doubleClickOnRowByName(pdfFile.fileName); expect(await viewer.isViewerOpened()).toBe(true, 'Viewer is not opened'); - await toolbar.openMoreMenu(); + await toolbar.openViewerMoreMenu(); expect(await toolbar.menu.isMenuItemPresent(customSecondaryAction.title)).toBe(true, 'action is not present'); expect(await toolbar.menu.getItemIconText(customSecondaryAction.title)).toEqual(customSecondaryAction.icon); expect(await toolbar.menu.getItemIdAttribute(customSecondaryAction.title)).toEqual(customSecondaryAction.id); @@ -150,7 +150,7 @@ describe('Extensions - Viewer', () => { await page.dataTable.doubleClickOnRowByName(pdfFile.fileName); expect(await viewer.isViewerOpened()).toBe(true, 'Viewer is not opened'); - await toolbar.openMoreMenu(); + await toolbar.openViewerMoreMenu(); expect(await BrowserActions.getAttribute(toolbar.menu.getItemById(moveAction.id), 'title')).toEqual(moveAction.title); }); @@ -158,7 +158,7 @@ describe('Extensions - Viewer', () => { await page.dataTable.doubleClickOnRowByName(pdfFile.fileName); expect(await viewer.isViewerOpened()).toBe(true, 'Viewer is not opened'); - await toolbar.openMoreMenu(); + await toolbar.openViewerMoreMenu(); expect(await toolbar.menu.managePermissionsAction.isPresent()).toBe(false, 'Action is still displayed'); }); }); diff --git a/e2e/suites/info-drawer/library-properties.test.ts b/e2e/suites/info-drawer/library-properties.test.ts index 1b436c0523..7c6bad7c60 100755 --- a/e2e/suites/info-drawer/library-properties.test.ts +++ b/e2e/suites/info-drawer/library-properties.test.ts @@ -85,7 +85,7 @@ describe('Library properties', () => { }); beforeEach(async () => { - await page.clickFileLibrariesAndWait(); + await page.goToMyLibrariesAndWait(); }); afterEach(async () => { diff --git a/e2e/suites/list-views/empty-list.test.ts b/e2e/suites/list-views/empty-list.test.ts index 842dddc6fd..cdcc0a09d2 100755 --- a/e2e/suites/list-views/empty-list.test.ts +++ b/e2e/suites/list-views/empty-list.test.ts @@ -28,8 +28,8 @@ describe('Empty list views', () => { const username = `user-${Utils.random()}`; const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable, pagination } = page; - const { searchInput } = page.header; + const { dataTable, pagination, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; const adminApiActions = new AdminActions(); beforeAll(async () => { @@ -134,6 +134,7 @@ describe('Empty list views', () => { }); it('[C290123] Search results - pagination controls not displayed', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); /* cspell:disable-next-line */ await searchInput.searchFor('qwertyuiop'); @@ -148,10 +149,12 @@ describe('Empty list views', () => { }); it('[C290020] Empty Search results - Libraries', async () => { + await page.goToMyLibraries(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); /* cspell:disable-next-line */ - await searchInput.searchFor('qwertyuiop'); + await searchInput.searchForLibrary('qwertyuiop'); await dataTable.waitForBody(); expect(await dataTable.isEmpty()).toBe(true, 'list is not empty'); @@ -159,6 +162,8 @@ describe('Empty list views', () => { }); it('[C290031] Empty Search results - Files / Folders', async () => { + await page.clickPersonalFiles(); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); /* cspell:disable-next-line */ diff --git a/e2e/suites/list-views/permissions.test.ts b/e2e/suites/list-views/permissions.test.ts index 561ae67f91..b79ed7001b 100755 --- a/e2e/suites/list-views/permissions.test.ts +++ b/e2e/suites/list-views/permissions.test.ts @@ -33,8 +33,8 @@ describe('Special permissions', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable } = page; - const { searchInput } = page.header; + const { dataTable, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; const adminApiActions = new AdminActions(); const userActions = new UserActions(); @@ -101,6 +101,7 @@ describe('Special permissions', () => { }); it('[C290122] on Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileName); @@ -163,6 +164,7 @@ describe('Special permissions', () => { }); it('[C306868] on Search results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileName); diff --git a/e2e/suites/navigation/breadcrumb.test.ts b/e2e/suites/navigation/breadcrumb.test.ts index 6d91d62c13..e0607408fe 100755 --- a/e2e/suites/navigation/breadcrumb.test.ts +++ b/e2e/suites/navigation/breadcrumb.test.ts @@ -136,12 +136,12 @@ describe('Breadcrumb', () => { }); it('[C260967] File Libraries breadcrumb for a folder hierarchy', async () => { - await page.clickFileLibrariesAndWait(); + await page.goToMyLibrariesAndWait(); await page.dataTable.doubleClickOnRowByName(siteName); await page.dataTable.doubleClickOnRowByName(parentFromSite); await page.dataTable.doubleClickOnRowByName(subFolder1FromSite); await page.dataTable.doubleClickOnRowByName(subFolder2FromSite); - const expectedItems = ['Favorite Libraries', siteName, parentFromSite, subFolder1FromSite, subFolder2FromSite]; + const expectedItems = ['My Libraries', siteName, parentFromSite, subFolder1FromSite, subFolder2FromSite]; expect(await breadcrumb.getAllItems()).toEqual(expectedItems); }); diff --git a/e2e/suites/navigation/sidebar.test.ts b/e2e/suites/navigation/sidebar.test.ts index 8b78c98a2a..04b3475f87 100755 --- a/e2e/suites/navigation/sidebar.test.ts +++ b/e2e/suites/navigation/sidebar.test.ts @@ -28,9 +28,9 @@ import { APP_ROUTES, SIDEBAR_LABELS, LoginPage, BrowsingPage, SearchResultsPage, describe('Sidebar', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { sidenav, header } = page; + const { sidenav, toolbar } = page; const searchResultsPage = new SearchResultsPage(); - const { searchInput } = searchResultsPage.header; + const { searchInput } = searchResultsPage.pageLayoutHeader; beforeAll(async () => { await loginPage.loginWithAdmin(); @@ -38,7 +38,12 @@ describe('Sidebar', () => { beforeEach(async () => { await Utils.pressEscape(); - await header.expandSideNav(); + await sidenav.expandSideNav(); + }); + + afterEach(async () => { + await Utils.pressEscape(); + await page.clickPersonalFiles(); }); it('[C217149] has "Personal Files" as default', async () => { @@ -46,31 +51,15 @@ describe('Sidebar', () => { expect(await sidenav.isActive(SIDEBAR_LABELS.PERSONAL_FILES)).toBe(true, 'Default active link'); }); - it('[C217150] File Libraries has correct sub-categories', async () => { - await page.clickFileLibraries(); - expect(await sidenav.isFileLibrariesMenuExpanded()).toBe(true, 'File Libraries not expanded'); - expect(await sidenav.getLink(SIDEBAR_LABELS.MY_LIBRARIES).isPresent()).toBe(true, 'My Libraries link not present'); - expect(await sidenav.getLink(SIDEBAR_LABELS.FAVORITE_LIBRARIES).isPresent()).toBe(true, 'Favorite Libraries link not present'); - }); - - it('[C289900] Favorite Libraries is automatically selected on expanding File Libraries', async () => { - await sidenav.expandFileLibraries(); - expect(await browser.getCurrentUrl()).toContain(APP_ROUTES.FAVORITE_LIBRARIES); - expect(await sidenav.isActive(SIDEBAR_LABELS.FILE_LIBRARIES)).toBe(true, 'File Libraries is not active'); - expect(await sidenav.isActive(SIDEBAR_LABELS.FAVORITE_LIBRARIES)).toBe(true, 'Favorite Libraries link not active'); - }); - it('[C289902] navigate to Favorite Libraries', async () => { await page.goToFavoriteLibraries(); expect(await browser.getCurrentUrl()).toContain(APP_ROUTES.FAVORITE_LIBRARIES); - expect(await sidenav.isActive(SIDEBAR_LABELS.FILE_LIBRARIES)).toBe(true, 'File Libraries link is not active'); expect(await sidenav.isActive(SIDEBAR_LABELS.FAVORITE_LIBRARIES)).toBe(true, 'Favorite Libraries link not active'); }); it('[C289901] navigate to My Libraries', async () => { await page.goToMyLibraries(); expect(await browser.getCurrentUrl()).toContain(APP_ROUTES.MY_LIBRARIES); - expect(await sidenav.isActive(SIDEBAR_LABELS.FILE_LIBRARIES)).toBe(true, 'File Libraries link is not active'); expect(await sidenav.isActive(SIDEBAR_LABELS.MY_LIBRARIES)).toBe(true, 'My Libraries link not active'); }); @@ -107,126 +96,98 @@ describe('Sidebar', () => { it('[C217151] Personal Files tooltip', async () => { await page.clickPersonalFiles(); expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.PERSONAL_FILES)).toContain('View your Personal Files'); - - await header.collapseSideNav(); - expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.PERSONAL_FILES)).toContain('View your Personal Files'); }); it('[C213111] Shared Files tooltip', async () => { await page.clickSharedFiles(); expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.SHARED_FILES)).toContain('View files that have been shared'); - - await header.collapseSideNav(); - expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.SHARED_FILES)).toContain('View files that have been shared'); }); it('[C213167] Recent Files tooltip', async () => { await page.clickRecentFiles(); expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.RECENT_FILES)).toContain('View files you recently edited'); - - await header.collapseSideNav(); - expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.RECENT_FILES)).toContain('View files you recently edited'); }); it('[C217153] Favorites tooltip', async () => { await page.clickFavorites(); expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.FAVORITES)).toContain('View your favorite files and folders'); - - await header.collapseSideNav(); - expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.FAVORITES)).toContain('View your favorite files and folders'); }); it('[C217154] Trash tooltip', async () => { await page.clickTrash(); expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.TRASH)).toContain('View deleted files in the trash'); - - await header.collapseSideNav(); - expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.TRASH)).toContain('View deleted files in the trash'); - }); - - it('[C217152] File Libraries tooltip', async () => { - await page.clickFileLibraries(); - expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.FILE_LIBRARIES)).toContain('File Libraries'); - - await header.collapseSideNav(); - expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.FILE_LIBRARIES)).toContain('File Libraries'); }); it('[C289916] My Libraries tooltip', async () => { await page.goToMyLibraries(); expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.MY_LIBRARIES)).toContain('Access my libraries'); - - await header.collapseSideNav(); - await sidenav.clickLink(SIDEBAR_LABELS.FILE_LIBRARIES); - expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.MY_LIBRARIES)).toContain('Access my libraries'); }); it('[C289917] Favorite Libraries tooltip', async () => { await page.goToFavoriteLibraries(); expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.FAVORITE_LIBRARIES)).toContain('Access my favorite libraries'); - - await header.collapseSideNav(); - await sidenav.clickLink(SIDEBAR_LABELS.FILE_LIBRARIES); - expect(await sidenav.getLinkTooltip(SIDEBAR_LABELS.FAVORITE_LIBRARIES)).toContain('Access my favorite libraries'); }); it('[C269095] default state is expanded', async () => { - expect(await header.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); + expect(await sidenav.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); }); it('[C269096] sidebar toggle', async () => { - await header.collapseSideNav(); - expect(await header.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); + await sidenav.collapseSideNav(); + expect(await sidenav.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); - await header.expandSideNav(); - expect(await header.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); + await sidenav.expandSideNav(); + expect(await sidenav.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); }); it('[C269100] sidebar state is preserved on page refresh', async () => { - expect(await header.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); + expect(await sidenav.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); await page.refresh(); - expect(await header.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); + expect(await sidenav.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); - await header.collapseSideNav(); - expect(await header.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); + await sidenav.collapseSideNav(); + expect(await sidenav.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); await page.refresh(); - expect(await header.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); + expect(await sidenav.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); }); it('[C269102] sidebar state is preserved after logout / login', async () => { - await header.collapseSideNav(); + await sidenav.collapseSideNav(); await page.signOut(); await loginPage.loginWithAdmin(); - expect(await header.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); + expect(await sidenav.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); }); it('[C277223] sidebar is collapsed automatically when Search Results opens', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); /* cspell:disable-next-line */ await searchInput.searchFor('qwertyuiop'); await searchResultsPage.waitForResults(); - expect(await header.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); + expect(await sidenav.isSidenavExpanded()).toBe(false, 'Sidebar not collapsed'); }); it('[C277224] sidenav returns to the default state when navigating away from the Search Results page', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); /* cspell:disable-next-line */ await searchInput.searchFor('qwertyuiop'); await searchResultsPage.waitForResults(); await page.clickFavorites(); - expect(await header.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); + expect(await sidenav.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); }); it('[C277230] sidenav can be expanded when search results page is displayed', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); /* cspell:disable-next-line */ await searchInput.searchFor('qwertyuiop'); await searchResultsPage.waitForResults(); - await header.expandSideNav(); + await sidenav.expandSideNav(); - expect(await header.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); + expect(await sidenav.isSidenavExpanded()).toBe(true, 'Sidebar not expanded'); }); }); diff --git a/e2e/suites/navigation/single-click.test.ts b/e2e/suites/navigation/single-click.test.ts index 74e0b461a3..b048c48a37 100755 --- a/e2e/suites/navigation/single-click.test.ts +++ b/e2e/suites/navigation/single-click.test.ts @@ -46,9 +46,9 @@ describe('Single click on item name', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable, breadcrumb } = page; + const { dataTable, breadcrumb, toolbar } = page; const viewer = new Viewer(); - const { searchInput } = page.header; + const { searchInput } = page.pageLayoutHeader; const adminApiActions = new AdminActions(); const userActions = new UserActions(); @@ -116,7 +116,7 @@ describe('Single click on item name', () => { describe('on File Libraries', () => { beforeEach(async () => { - await page.clickFileLibrariesAndWait(); + await page.goToMyLibrariesAndWait(); }); it('[C284901] Hyperlink appears when mouse over a library', async () => { @@ -206,6 +206,7 @@ describe('Single click on item name', () => { describe('on Search Results', () => { beforeEach(async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); }); diff --git a/e2e/suites/pagination/search-results.ts b/e2e/suites/pagination/search-results.ts index 6329a79024..8853d7859a 100755 --- a/e2e/suites/pagination/search-results.ts +++ b/e2e/suites/pagination/search-results.ts @@ -27,12 +27,13 @@ import { BrowsingPage, LoginPage, Utils } from '@alfresco/aca-testing-shared'; export function searchResultsTests(username: string, random: string) { const page = new BrowsingPage(); const loginPage = new LoginPage(); - const { dataTable, pagination } = page; - const { searchInput } = page.header; + const { dataTable, pagination, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; describe('Pagination controls : ', () => { beforeAll(async () => { await loginPage.loginWith(username); + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFiles(); await searchInput.searchFor(random); diff --git a/e2e/suites/pagination/single-page.test.ts b/e2e/suites/pagination/single-page.test.ts index 578636e875..2385d95896 100755 --- a/e2e/suites/pagination/single-page.test.ts +++ b/e2e/suites/pagination/single-page.test.ts @@ -43,8 +43,8 @@ describe('Pagination on single page', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { pagination } = page; - const { searchInput } = page.header; + const { pagination, toolbar } = page; + const { searchInput } = page.pageLayoutHeader; const searchResultsPage = new SearchResultsPage(); beforeAll(async () => { @@ -115,6 +115,7 @@ describe('Pagination on single page', () => { }); it('[C290124] page selector not displayed on Search results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(file); await searchResultsPage.waitForResults(); diff --git a/e2e/suites/search/search-filters.test.ts b/e2e/suites/search/search-filters.test.ts index d98988ffba..4c735de7b1 100644 --- a/e2e/suites/search/search-filters.test.ts +++ b/e2e/suites/search/search-filters.test.ts @@ -74,8 +74,8 @@ describe('Search filters', () => { const loginPage = new LoginPage(); const page = new SearchResultsPage(); - const { searchInput } = page.header; - const { dataTable, filters } = page; + const { searchInput } = page.pageLayoutHeader; + const { dataTable, filters, toolbar } = page; const sizeFilter = filters.size; const fileTypeFilter = filters.fileType; @@ -107,7 +107,7 @@ describe('Search filters', () => { beforeEach(async () => { await Utils.pressEscape(); await page.clickPersonalFilesAndWait(); - + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(`search-filters-${random}`); await dataTable.waitForBody(); diff --git a/e2e/suites/search/search-input.test.ts b/e2e/suites/search/search-input.test.ts index a02d54f2b1..1c35e196db 100644 --- a/e2e/suites/search/search-input.test.ts +++ b/e2e/suites/search/search-input.test.ts @@ -27,7 +27,8 @@ import { BrowsingPage, LoginPage, Utils } from '@alfresco/aca-testing-shared'; describe('Search input', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { searchInput } = page.header; + const { toolbar } = page; + const { searchInput } = page.pageLayoutHeader; beforeAll(async () => { await loginPage.loginWithAdmin(); @@ -38,11 +39,15 @@ describe('Search input', () => { await page.clickPersonalFiles(); }); - it('[C289847] Search input is displayed in the app header', async () => { + it('[C289847] Search icon is displayed in toolbar and clicking on it displays search input container', async () => { + await toolbar.clickSearchIconButton(); + await searchInput.clickSearchButton(); + expect(await searchInput.isSearchContainerDisplayed()).toBe(true, 'search controls not displayed'); }); it('[C289848] Search options are displayed when clicking in the search input', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); expect(await searchInput.isOptionsAreaDisplayed()).toBe(true, 'Search options not displayed'); expect(await searchInput.isFilesOptionEnabled()).toBe(true, 'Files option not enabled'); @@ -54,6 +59,7 @@ describe('Search input', () => { }); it('[C289849] Search options are correctly enabled / disabled', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.clickFilesOption(); diff --git a/e2e/suites/search/search-results-files-folders.test.ts b/e2e/suites/search/search-results-files-folders.test.ts index c02162a24c..a30cc3fd02 100644 --- a/e2e/suites/search/search-results-files-folders.test.ts +++ b/e2e/suites/search/search-results-files-folders.test.ts @@ -51,8 +51,8 @@ describe('Search results - files and folders', () => { const loginPage = new LoginPage(); const page = new SearchResultsPage(); - const { searchInput } = page.header; - const { dataTable, breadcrumb } = page; + const { searchInput } = page.pageLayoutHeader; + const { dataTable, breadcrumb, toolbar } = page; const adminApiActions = new AdminActions(); beforeAll(async () => { @@ -72,6 +72,7 @@ describe('Search results - files and folders', () => { beforeEach(async () => { await page.refresh(); + await page.clickPersonalFilesAndWait(); }); afterAll(async () => { @@ -83,16 +84,8 @@ describe('Search results - files and folders', () => { ]); }); - it('[C307002] Results page title', async () => { - await searchInput.clickSearchButton(); - await searchInput.checkFilesAndFolders(); - await searchInput.searchFor(random); - await dataTable.waitForBody(); - - expect(await page.breadcrumb.currentItem.getText()).toEqual('Search Results'); - }); - it('[C279183] File information', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(random); @@ -114,6 +107,7 @@ describe('Search results - files and folders', () => { }); it('[C306867] Folder information', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(random); @@ -133,6 +127,7 @@ describe('Search results - files and folders', () => { }); it('[C290029] Search file with special characters', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(fileRussian); @@ -142,6 +137,7 @@ describe('Search results - files and folders', () => { }); it('[C279177] Location column redirect - file in user Home', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(file); diff --git a/e2e/suites/search/search-results-general.test.ts b/e2e/suites/search/search-results-general.test.ts index bb8c42f1cd..1c5580ce79 100644 --- a/e2e/suites/search/search-results-general.test.ts +++ b/e2e/suites/search/search-results-general.test.ts @@ -41,7 +41,7 @@ describe('Search results general', () => { const loginPage = new LoginPage(); const page = new SearchResultsPage(); - const { searchInput } = page.header; + const { searchInput, toolbar } = page.pageLayoutHeader; const dataTable = page.dataTable; const adminApiActions = new AdminActions(); @@ -66,7 +66,13 @@ describe('Search results general', () => { await page.refresh(); }); + afterEach(async () => { + await Utils.pressEscape(); + await page.clickPersonalFiles(); + }); + it('[C290005] Only files are returned when Files option is the only one checked', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFiles(); await searchInput.searchFor(random); @@ -78,6 +84,7 @@ describe('Search results general', () => { }); it('[C290006] Only folders are returned when Folders option is the only one checked', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkOnlyFolders(); await searchInput.searchFor(random); @@ -89,6 +96,7 @@ describe('Search results general', () => { }); it('[C290007] Files and folders are returned when both Files and Folders options are checked', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(random); @@ -100,9 +108,10 @@ describe('Search results general', () => { }); it('[C290008] Only libraries are returned when Libraries option is checked', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(random); + await searchInput.searchForLibrary(random); await page.waitForResults(); expect(await dataTable.isItemPresent(file)).toBe(false, `${file} is displayed`); @@ -111,6 +120,7 @@ describe('Search results general', () => { }); it('[C279162] Results are updated automatically when changing the search term', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(file); await page.waitForResults(); @@ -120,15 +130,17 @@ describe('Search results general', () => { await searchInput.clickSearchButton(); await searchInput.searchFor(folder); + await page.waitForResults(); expect(await dataTable.isItemPresent(file)).toBe(false, `${file} is displayed`); expect(await dataTable.isItemPresent(folder)).toBe(true, `${folder} is not displayed`); }); it('[C279178] Results are returned when accessing an URL containing a search query', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(site); + await searchInput.searchForLibrary(site); await page.waitForResults(); expect(await dataTable.isItemPresent(site)).toBe(true, `${site} not displayed`); diff --git a/e2e/suites/search/search-results-libraries.test.ts b/e2e/suites/search/search-results-libraries.test.ts index 35793828b9..7a03263175 100644 --- a/e2e/suites/search/search-results-libraries.test.ts +++ b/e2e/suites/search/search-results-libraries.test.ts @@ -69,7 +69,7 @@ describe('Search results - libraries', () => { const loginPage = new LoginPage(); const page = new SearchResultsPage(); - const { searchInput } = page.header; + const { searchInput, toolbar } = page.pageLayoutHeader; const dataTable = page.dataTable; const adminApiActions = new AdminActions(); @@ -136,9 +136,10 @@ describe('Search results - libraries', () => { }); it('[C290012] Search library - full name match', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(site1.name); + await searchInput.searchForLibrary(site1.name); await dataTable.waitForBody(); expect(await dataTable.isItemPresent(site1.name)).toBe(true, `${site1.name} not displayed`); @@ -148,9 +149,10 @@ describe('Search results - libraries', () => { }); it('[C290013] Search library - partial name match', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(`lib-${random}`); + await searchInput.searchForLibrary(`lib-${random}`); await dataTable.waitForBody(); expect(await dataTable.isItemPresent(site1.name)).toBe(true, `${site1.name} not displayed`); @@ -160,9 +162,10 @@ describe('Search results - libraries', () => { }); it('[C290014] Search library - description match', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(site4.description); + await searchInput.searchForLibrary(site4.description); await dataTable.waitForBody(); expect(await dataTable.isItemPresent(site1.name)).toBe(false, `${site1.name} displayed`); @@ -172,18 +175,20 @@ describe('Search results - libraries', () => { }); it('[C290015] Results page title', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(random); + await searchInput.searchForLibrary(random); await dataTable.waitForBody(); expect(await page.breadcrumb.currentItem.getText()).toEqual('Libraries found...'); }); it('[C290016] Results page columns', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(site1.name); + await searchInput.searchForLibrary(site1.name); await dataTable.waitForBody(); const expectedColumns = ['Name', 'Description', 'My Role', 'Visibility']; @@ -193,9 +198,10 @@ describe('Search results - libraries', () => { }); it('[C290017] Library visibility is correctly displayed', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(`user-site-${random}`); + await searchInput.searchForLibrary(`user-site-${random}`); await dataTable.waitForBody(); const expectedSitesVisibility = { @@ -212,9 +218,10 @@ describe('Search results - libraries', () => { }); it('[C290018] User role is correctly displayed', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(`admin-${random}-site`); + await searchInput.searchForLibrary(`admin-${random}-site`); await dataTable.waitForBody(); const expectedSitesRoles = { @@ -232,18 +239,20 @@ describe('Search results - libraries', () => { }); it('[C290019] Private sites are not displayed when user is not a member', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(`admin-${random}-site`); + await searchInput.searchForLibrary(`admin-${random}-site`); await dataTable.waitForBody(); expect(await dataTable.isItemPresent(adminPrivate)).toBe(false, `${adminPrivate} is displayed`); }); it('[C290028] Search libraries with special characters', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkLibraries(); - await searchInput.searchFor(siteRussian.name); + await searchInput.searchForLibrary(siteRussian.name); await dataTable.waitForBody(); expect(await dataTable.isItemPresent(siteRussian.name)).toBe(true, `${siteRussian.name} not displayed`); diff --git a/e2e/suites/search/search-sorting.test.ts b/e2e/suites/search/search-sorting.test.ts index 7b690ed0fa..2d9e2e0381 100644 --- a/e2e/suites/search/search-sorting.test.ts +++ b/e2e/suites/search/search-sorting.test.ts @@ -52,8 +52,8 @@ describe('Search sorting', () => { const loginPage = new LoginPage(); const page = new SearchResultsPage(); - const { searchInput } = page.header; - const { dataTable } = page; + const { searchInput } = page.pageLayoutHeader; + const { dataTable, toolbar } = page; const adminApiActions = new AdminActions(); beforeAll(async () => { @@ -74,7 +74,7 @@ describe('Search sorting', () => { beforeEach(async () => { await Utils.pressEscape(); await page.clickPersonalFilesAndWait(); - + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.searchFor(`search sort ${random}`); await dataTable.waitForBody(); diff --git a/e2e/suites/viewer/viewer-actions.test.ts b/e2e/suites/viewer/viewer-actions.test.ts index 8709eb1566..a9e4898762 100755 --- a/e2e/suites/viewer/viewer-actions.test.ts +++ b/e2e/suites/viewer/viewer-actions.test.ts @@ -37,6 +37,7 @@ import { UploadFilesDialog } from '@alfresco/aca-testing-shared'; import { Logger } from '@alfresco/adf-testing'; +import { By, element } from 'protractor'; describe('Viewer actions', () => { const username = `user-${Utils.random()}`; @@ -63,6 +64,8 @@ describe('Viewer actions', () => { const userActions = new UserActions(); const uploadFilesDialog = new UploadFilesDialog(); + const downloadButton = element(By.css(`button[id='app.viewer.download']`)); + const shareButton = element(By.css(`adf-viewer [data-automation-id="share-action-button"]`)); beforeAll(async () => { await adminApiActions.createUser({ username }); @@ -143,7 +146,7 @@ describe('Viewer actions', () => { await dataTable.doubleClickOnRowByName(docxPersonalFiles); await viewer.waitForViewerToOpen(); - await toolbar.downloadButton.click(); + await downloadButton.click(); expect(await Utils.fileExistsOnOS(docxPersonalFiles)).toBe(true, 'File not found in download location'); }); @@ -568,7 +571,7 @@ describe('Viewer actions', () => { await dataTable.doubleClickOnRowByName(docxFavorites); expect(await viewer.isViewerOpened()).toBe(true, 'Viewer is not opened'); - await toolbar.shareButton.click(); + await shareButton.click(); expect(await shareDialog.isDialogOpen()).toBe(true, 'Dialog is not open'); await shareDialog.clickClose(); }); diff --git a/e2e/suites/viewer/viewer-general.test.ts b/e2e/suites/viewer/viewer-general.test.ts index e938040b70..cf05f3597c 100755 --- a/e2e/suites/viewer/viewer-general.test.ts +++ b/e2e/suites/viewer/viewer-general.test.ts @@ -49,9 +49,9 @@ describe('Viewer general', () => { const loginPage = new LoginPage(); const page = new BrowsingPage(); - const { dataTable } = page; + const { dataTable, toolbar } = page; const viewer = new Viewer(); - const { searchInput } = page.header; + const { searchInput } = page.pageLayoutHeader; const adminApiActions = new AdminActions(); const userActions = new UserActions(); @@ -182,6 +182,7 @@ describe('Viewer general', () => { }); it('[C279175] Viewer opens for a file from Search Results', async () => { + await toolbar.clickSearchIconButton(); await searchInput.clickSearchButton(); await searchInput.checkFilesAndFolders(); await searchInput.searchFor(xlsxFile); diff --git a/projects/aca-about/src/lib/about.component.html b/projects/aca-about/src/lib/about.component.html index 5791cb2fc5..d08f642134 100644 --- a/projects/aca-about/src/lib/about.component.html +++ b/projects/aca-about/src/lib/about.component.html @@ -1,4 +1,11 @@ + + +

{{ 'APP.BROWSE.ABOUT.TITLE' | translate }}

+
+ diff --git a/projects/aca-about/src/lib/about.component.scss b/projects/aca-about/src/lib/about.component.scss deleted file mode 100644 index caf329f4a9..0000000000 --- a/projects/aca-about/src/lib/about.component.scss +++ /dev/null @@ -1,4 +0,0 @@ -adf-about { - padding: 10px; - width: 100%; -} diff --git a/projects/aca-about/src/lib/about.component.ts b/projects/aca-about/src/lib/about.component.ts index 0ffe39444e..422a312c39 100644 --- a/projects/aca-about/src/lib/about.component.ts +++ b/projects/aca-about/src/lib/about.component.ts @@ -26,20 +26,27 @@ import { Component, Inject, OnInit, Optional } from '@angular/core'; import { DEV_MODE_TOKEN } from './dev-mode.tokens'; import { Observable } from 'rxjs'; import { AppExtensionService, ExtensionRef } from '@alfresco/adf-extensions'; -import { AuthenticationService, RepositoryInfo } from '@alfresco/adf-core'; +import { AppConfigService, AuthenticationService, RepositoryInfo } from '@alfresco/adf-core'; import { DiscoveryApiService } from '@alfresco/adf-content-services'; import { PACKAGE_JSON } from './package-json.token'; @Component({ selector: 'app-about-page', templateUrl: './about.component.html', - styleUrls: ['./about.component.scss'] + styles: [ + ` + adf-about { + width: 100%; + } + ` + ] }) export class AboutComponent implements OnInit { pkg: any; dev = false; extensions$: Observable; repository: RepositoryInfo = null; + landingPage: string; constructor( @Inject(DEV_MODE_TOKEN) devMode, @@ -48,10 +55,12 @@ export class AboutComponent implements OnInit { public packageJson, private authService: AuthenticationService, private appExtensions: AppExtensionService, - private discovery: DiscoveryApiService + private discovery: DiscoveryApiService, + appConfigService: AppConfigService ) { this.dev = !devMode; this.extensions$ = this.appExtensions.references$; + this.landingPage = appConfigService.get('landingPage', '/personal-files'); } ngOnInit(): void { diff --git a/projects/aca-about/src/lib/aca-about.module.ts b/projects/aca-about/src/lib/aca-about.module.ts index 4182049fc9..7d192b2ace 100644 --- a/projects/aca-about/src/lib/aca-about.module.ts +++ b/projects/aca-about/src/lib/aca-about.module.ts @@ -31,9 +31,10 @@ import { SharedModule, PageLayoutModule } from '@alfresco/aca-shared'; import { ExtensionService, provideExtensionConfig } from '@alfresco/adf-extensions'; import { DEV_MODE_TOKEN } from './dev-mode.tokens'; import { PACKAGE_JSON } from './package-json.token'; +import { RouterModule } from '@angular/router'; @NgModule({ - imports: [CommonModule, CoreModule.forChild(), SharedModule, PageLayoutModule], + imports: [CommonModule, RouterModule, CoreModule.forChild(), SharedModule, PageLayoutModule], declarations: [AboutComponent], providers: [provideExtensionConfig(['about.plugin.json'])] }) diff --git a/projects/aca-content/assets/app.extensions.json b/projects/aca-content/assets/app.extensions.json index 3278f3cc7e..5065c62a31 100644 --- a/projects/aca-content/assets/app.extensions.json +++ b/projects/aca-content/assets/app.extensions.json @@ -85,19 +85,19 @@ "component": "app.notification-center", "order": 50 }, - { - "id": "app.header.user", - "type": "custom", - "component": "app.user", - "order": 100 - }, { "id": "app.header.more", "type": "menu", "order": 10000, - "icon": "more_vert", + "icon": "apps", "title": "APP.ACTIONS.MORE", "children": [ + { + "id": "app.header.user", + "type": "custom", + "component": "app.user", + "order": 100 + }, { "id": "app.languagePicker", "order": 100, @@ -132,44 +132,6 @@ } ], "create": [ - { - "id": "app.create.uploadFile", - "order": 100, - "icon": "file_upload", - "title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FILE", - "description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES", - "description-disabled": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES_NOT_ALLOWED", - "actions": { - "click": "UPLOAD_FILES" - }, - "rules": { - "enabled": "app.navigation.folder.canUpload", - "visible": "app.isContentServiceEnabled" - } - }, - { - "id": "app.create.uploadFolder", - "order": 200, - "icon": "file_upload", - "title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FOLDER", - "description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS", - "description-disabled": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS_NOT_ALLOWED", - "actions": { - "click": "UPLOAD_FOLDER" - }, - "rules": { - "enabled": "app.navigation.folder.canUpload", - "visible": "app.isContentServiceEnabled" - } - }, - { - "id": "app.create.separator.1", - "type": "separator", - "order": 300, - "rules": { - "visible": "app.isContentServiceEnabled" - } - }, { "id": "app.create.folder", "order": 400, @@ -181,8 +143,7 @@ "click": "CREATE_FOLDER" }, "rules": { - "enabled": "app.navigation.folder.canCreate", - "visible": "app.isContentServiceEnabled" + "visible": "app.navigation.folder.canCreate" } }, { @@ -195,15 +156,7 @@ "click": "CREATE_LIBRARY" }, "rules": { - "visible": "app.isContentServiceEnabled" - } - }, - { - "id": "app.create.separator.2", - "type": "separator", - "order": 650, - "rules": { - "visible": "app.isContentServiceEnabled" + "visible": "app.canCreateLibrary" } }, { @@ -217,8 +170,7 @@ "click": "FILE_FROM_TEMPLATE" }, "rules": { - "enabled": "app.navigation.folder.canUpload", - "visible": "app.isContentServiceEnabled" + "visible": "app.navigation.folder.canUpload" } }, { @@ -232,8 +184,7 @@ "click": "FOLDER_FROM_TEMPLATE" }, "rules": { - "enabled": "app.navigation.folder.canUpload", - "visible": "app.isContentServiceEnabled" + "visible": "app.navigation.folder.canUpload" } } ], @@ -242,32 +193,23 @@ "id": "app.navbar.primary", "items": [ { - "id": "app.navbar.personalFiles", + "id": "app.navbar.menu", "order": 100, - "icon": "folder", - "title": "APP.BROWSE.PERSONAL.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.PERSONAL.SIDENAV_LINK.TOOLTIP", - "route": "personal-files", - "rules": { - "visible": "app.isContentServiceEnabled" - } - }, - { - "id": "app.navbar.libraries.menu", - "order": 200, - "icon": "library_books", - "title": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.SIDENAV_LINK.TOOLTIP", + "title": "APP.BROWSE.FILE.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.FILE.SIDENAV_LINK.TOOLTIP", "rules": { "visible": "app.isContentServiceEnabled" }, "children": [ { - "id": "app.navbar.libraries.favorite", + "id": "app.navbar.personalFiles", "order": 100, - "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", - "route": "favorite/libraries" + "title": "APP.BROWSE.PERSONAL.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.PERSONAL.SIDENAV_LINK.TOOLTIP", + "route": "personal-files", + "rules": { + "visible": "app.isContentServiceEnabled" + } }, { "id": "app.navbar.libraries.files", @@ -275,56 +217,175 @@ "title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL", "description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP", "route": "libraries" + }, + { + "id": "app.navbar.libraries.favorite", + "order": 300, + "title": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.LIBRARIES.MENU.FAVORITE_LIBRARIES.SIDENAV_LINK.TOOLTIP", + "route": "favorite/libraries" + }, + { + "id": "app.navbar.recentFiles", + "order": 400, + "title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP", + "route": "recent-files" + }, + { + "id": "app.navbar.favorites", + "order": 500, + "title": "APP.BROWSE.FAVORITES.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.FAVORITES.SIDENAV_LINK.TOOLTIP", + "route": "favorites" + }, + { + "id": "app.navbar.shared", + "order": 600, + "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", + "route": "shared" + }, + { + "id": "app.navbar.trashcan", + "order": 700, + "title": "APP.BROWSE.TRASHCAN.SIDENAV_LINK.LABEL", + "description": "APP.BROWSE.TRASHCAN.SIDENAV_LINK.TOOLTIP", + "route": "trashcan" } ] } ] - }, + } + ], + "toolbar": [ { - "id": "app.navbar.secondary", - "rules": { - "visible": "app.isContentServiceEnabled" + "id": "app.toolbar.create", + "type": "menu", + "order": 10, + "title": "APP.HEADER.BUTTONS.CREATE", + "description": "APP.HEADER.BUTTONS.CREATE_TOOLTIP", + "data": { + "menuType": "button" }, - "items": [ + "children": [ { - "id": "app.navbar.shared", + "id": "app.create.folder", "order": 100, - "icon": "people", - "title": "APP.BROWSE.SHARED.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.SHARED.SIDENAV_LINK.TOOLTIP", - "route": "shared", + "icon": "create_new_folder", + "title": "APP.NEW_MENU.MENU_ITEMS.CREATE_FOLDER", + "description": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER", + "description-disabled": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER_NOT_ALLOWED", + "actions": { + "click": "CREATE_FOLDER" + }, "rules": { - "visible": "repository.isQuickShareEnabled" + "visible": "app.navigation.folder.canCreate" } }, { - "id": "app.navbar.recentFiles", + "id": "app.create.library", "order": 200, - "icon": "schedule", - "title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP", - "route": "recent-files" + "title": "APP.NEW_MENU.MENU_ITEMS.CREATE_LIBRARY", + "description": "APP.NEW_MENU.TOOLTIPS.CREATE_LIBRARY", + "icon": "create_new_folder", + "actions": { + "click": "CREATE_LIBRARY" + }, + "rules": { + "visible": "app.canCreateLibrary" + } }, { - "id": "app.navbar.favorites", + "id": "app.create.fileFromTemplate", "order": 300, - "icon": "star", - "title": "APP.BROWSE.FAVORITES.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.FAVORITES.SIDENAV_LINK.TOOLTIP", - "route": "favorites" + "icon": "description", + "title": "APP.NEW_MENU.MENU_ITEMS.FILE_TEMPLATE", + "description": "APP.NEW_MENU.MENU_ITEMS.FILE_TEMPLATE", + "description-disabled": "APP.NEW_MENU.TOOLTIPS.CREATE_FILE_NOT_ALLOWED", + "actions": { + "click": "FILE_FROM_TEMPLATE" + }, + "rules": { + "visible": "app.navigation.folder.canUpload" + } }, { - "id": "app.navbar.trashcan", + "id": "app.create.folderFromTemplate", "order": 400, - "icon": "delete", - "title": "APP.BROWSE.TRASHCAN.SIDENAV_LINK.LABEL", - "description": "APP.BROWSE.TRASHCAN.SIDENAV_LINK.TOOLTIP", - "route": "trashcan" + "icon": "create_new_folder", + "title": "APP.NEW_MENU.MENU_ITEMS.FOLDER_TEMPLATE", + "description": "APP.NEW_MENU.MENU_ITEMS.FOLDER_TEMPLATE", + "description-disabled": "APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER_NOT_ALLOWED", + "actions": { + "click": "FOLDER_FROM_TEMPLATE" + }, + "rules": { + "visible": "app.navigation.folder.canUpload" + } } ] - } - ], - "toolbar": [ + }, + { + "id": "app.toolbar.upload", + "type": "menu", + "order": 20, + "title": "APP.HEADER.BUTTONS.UPLOAD", + "description": "APP.HEADER.BUTTONS.UPLOAD_TOOLTIP", + "data": { + "menuType": "flat-button", + "color": "primary" + }, + "children": [ + { + "id": "app.create.uploadFile", + "order": 100, + "icon": "file_upload", + "title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FILE", + "description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES", + "actions": { + "click": "UPLOAD_FILES" + }, + "rules": { + "visible": "app.isUploadSupported" + } + }, + { + "id": "app.create.uploadFolder", + "order": 200, + "icon": "file_upload", + "title": "APP.NEW_MENU.MENU_ITEMS.UPLOAD_FOLDER", + "description": "APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS", + "actions": { + "click": "UPLOAD_FOLDER" + }, + "rules": { + "visible": "app.isUploadSupported" + } + } + ] + }, + { + "id": "app.toolbar.search.separator", + "type": "separator", + "order": 89 + }, + { + "id": "app.toolbar.search", + "order": 90, + "title": "SEARCH.BUTTON.TOOLTIP", + "icon": "search", + "type": "button", + "data": { + "buttonType": "icon-button" + }, + "actions": { + "click": "SEARCH" + }, + "rules": { + "visible": "app.isSearchSupported" + } + }, { "id": "app.toolbar.share", "type": "custom", @@ -435,7 +496,7 @@ "type": "menu", "order": 10000, "icon": "more_vert", - "title": "APP.ACTIONS.MORE", + "description": "APP.ACTIONS.MORE", "children": [ { "id": "app.toolbar.toggleLock", diff --git a/projects/aca-content/assets/i18n/en.json b/projects/aca-content/assets/i18n/en.json index 30f9f23213..56f5181fe2 100644 --- a/projects/aca-content/assets/i18n/en.json +++ b/projects/aca-content/assets/i18n/en.json @@ -1,6 +1,7 @@ { "APP": { "COPYRIGHT": "© 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.", + "TITLE": "Workspace", "ABOUT": { "VERSION": "Version:", "PLUGINS": { @@ -102,7 +103,21 @@ "CREATE_LIBRARY": "Create a new File Library" } }, + "HEADER": { + "BUTTONS": { + "CREATE": "Create", + "CREATE_TOOLTIP": "Create content", + "UPLOAD": "Upload", + "UPLOAD_TOOLTIP": "Upload content" + } + }, "BROWSE": { + "FILE": { + "SIDENAV_LINK": { + "LABEL": "Files", + "TOOLTIP": "Files" + } + }, "PERSONAL": { "TITLE": "Personal Files", "SIDENAV_LINK": { @@ -409,7 +424,13 @@ "EXPAND": "Expand", "CLOSE_LIBRARY": "Close Library" } - } + }, + "TOOLTIPS": { + "COLLAPSE_NAVIGATION": "Collapse navigation menu", + "OPTIONS_SETTINGS": "Options and settings", + "MY_PROFILE": "My profile", + "EXPAND_NAVIGATION": "Expand navigation" + } }, "NODE_SELECTOR": { "COPY_ITEM": "Copy '{{ name }}' to...", diff --git a/projects/aca-content/assets/images/mastHead-bg-shapesPattern.svg b/projects/aca-content/assets/images/mastHead-bg-shapesPattern.svg deleted file mode 100644 index d1b4709b1e..0000000000 --- a/projects/aca-content/assets/images/mastHead-bg-shapesPattern.svg +++ /dev/null @@ -1,53 +0,0 @@ - - - - F9486AC0-402C-4076-AD87-A8B3E339A00C - Created with sketchtool. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/projects/aca-content/src/lib/aca-content.module.ts b/projects/aca-content/src/lib/aca-content.module.ts index 84bc43609c..ada701a0e1 100644 --- a/projects/aca-content/src/lib/aca-content.module.ts +++ b/projects/aca-content/src/lib/aca-content.module.ts @@ -42,7 +42,7 @@ import { LibraryStatusColumnComponent, TrashcanNameColumnComponent } from '@alfresco/adf-content-services'; -import { DocumentBasePageService, ExtensionsDataLoaderGuard, RouterExtensionService, SharedModule } from '@alfresco/aca-shared'; +import { DocumentBasePageService, ExtensionsDataLoaderGuard, PageLayoutModule, RouterExtensionService, SharedModule } from '@alfresco/aca-shared'; import * as rules from '@alfresco/aca-shared/rules'; import { FilesComponent } from './components/files/files.component'; @@ -61,11 +61,9 @@ import { AppToolbarModule } from './components/toolbar/toolbar.module'; import { AppCreateMenuModule } from './components/create-menu/create-menu.module'; import { AppSidenavModule } from './components/sidenav/sidenav.module'; import { AppCommonModule } from './components/common/common.module'; -import { AppLayoutModule } from './components/layout/layout.module'; import { AppSearchInputModule } from './components/search/search-input.module'; import { DocumentListCustomComponentsModule } from './components/dl-custom-components/document-list-custom-components.module'; import { AppSearchResultsModule } from './components/search/search-results.module'; -import { AppHeaderModule } from './components/header/header.module'; import { AppNodeVersionModule } from './components/node-version/node-version.module'; import { FavoritesComponent } from './components/favorites/favorites.component'; import { RecentFilesComponent } from './components/recent-files/recent-files.component'; @@ -96,7 +94,6 @@ import { LocationLinkComponent } from './components/common/location-link/locatio import { LogoutComponent } from './components/common/logout/logout.component'; import { ToggleSharedComponent } from './components/common/toggle-shared/toggle-shared.component'; import { CustomNameColumnComponent } from './components/dl-custom-components/name-column/name-column.component'; -import { AppHeaderComponent } from './components/header/header.component'; import { CommentsTabComponent } from './components/info-drawer/comments-tab/comments-tab.component'; import { LibraryMetadataTabComponent } from './components/info-drawer/library-metadata-tab/library-metadata-tab.component'; import { MetadataTabComponent } from './components/info-drawer/metadata-tab/metadata-tab.component'; @@ -113,14 +110,14 @@ import { ViewNodeComponent } from './components/toolbar/view-node/view-node.comp import { CONTENT_ROUTES } from './aca-content.routes'; import { RouterModule } from '@angular/router'; import { UploadFilesDialogComponent } from './components/upload-files-dialog/upload-files-dialog.component'; -import { SidenavWrapperComponent } from './components/sidenav/sidenav-wrapper/sidenav-wrapper.component'; -import { AppLayoutComponent } from './components/layout/app-layout/app-layout.component'; import { AppTrashcanModule } from './components/trashcan/trashcan.module'; import { AppSharedLinkViewModule } from './components/shared-link-view/shared-link-view.module'; import { AcaFolderRulesModule } from '@alfresco/aca-folder-rules'; import { TagsColumnComponent } from './components/dl-custom-components/tags-column/tags-column.component'; -import { ContentManagementService } from './services/content-management.service'; import { UserInfoComponent } from './components/common/user-info/user-info.component'; +import { SidenavComponent } from './components/sidenav/sidenav.component'; +import { ContentManagementService } from './services/content-management.service'; +import { ShellLayoutComponent, SHELL_NAVBAR_MIN_WIDTH } from '@alfresco/adf-core/shell'; registerLocaleData(localeFr); registerLocaleData(localeDe); @@ -153,7 +150,7 @@ registerLocaleData(localeSv); MaterialModule, AppStoreModule, AppCommonModule, - AppLayoutModule, + PageLayoutModule, DirectivesModule, ContextMenuModule, AppInfoDrawerModule, @@ -163,7 +160,6 @@ registerLocaleData(localeSv); DocumentListCustomComponentsModule, AppSearchInputModule, AppSearchResultsModule, - AppHeaderModule, AppNodeVersionModule, HammerModule, ViewProfileModule, @@ -194,7 +190,8 @@ registerLocaleData(localeSv); name: 'app', source: 'assets' } - } + }, + { provide: SHELL_NAVBAR_MIN_WIDTH, useValue: 0 } ] }) export class ContentServiceExtensionModule { @@ -205,9 +202,8 @@ export class ContentServiceExtensionModule { }); extensions.setComponents({ - 'app.layout.main': AppLayoutComponent, - 'app.layout.header': AppHeaderComponent, - 'app.layout.sidenav': SidenavWrapperComponent, + 'app.layout.main': ShellLayoutComponent, + 'app.layout.sidenav': SidenavComponent, 'app.shell.sibling': UploadFilesDialogComponent, 'app.components.tabs.metadata': MetadataTabComponent, 'app.components.tabs.library.metadata': LibraryMetadataTabComponent, @@ -300,7 +296,10 @@ export class ContentServiceExtensionModule { 'repository.isQuickShareEnabled': rules.hasQuickShareEnabled, 'user.isAdmin': rules.isAdmin, 'app.canShowLogout': rules.canShowLogout, - 'app.isContentServiceEnabled': rules.isContentServiceEnabled + 'app.isContentServiceEnabled': rules.isContentServiceEnabled, + 'app.isUploadSupported': rules.isUploadSupported, + 'app.canCreateLibrary': rules.canCreateLibrary, + 'app.isSearchSupported': rules.isSearchSupported }); } } diff --git a/projects/aca-content/src/lib/aca-content.routes.ts b/projects/aca-content/src/lib/aca-content.routes.ts index 8e57378ee7..56cc534813 100644 --- a/projects/aca-content/src/lib/aca-content.routes.ts +++ b/projects/aca-content/src/lib/aca-content.routes.ts @@ -22,7 +22,6 @@ * from Hyland Software. If not, see . */ -import { AppLayoutComponent } from './components/layout/app-layout/app-layout.component'; import { FilesComponent } from './components/files/files.component'; import { LibrariesComponent } from './components/libraries/libraries.component'; import { FavoriteLibrariesComponent } from './components/favorite-libraries/favorite-libraries.component'; @@ -40,6 +39,7 @@ import { ViewProfileRuleGuard } from './components/view-profile/view-profile.gua import { Route } from '@angular/router'; import { SharedLinkViewComponent } from './components/shared-link-view/shared-link-view.component'; import { TrashcanComponent } from './components/trashcan/trashcan.component'; +import { ShellLayoutComponent } from '@alfresco/adf-core/shell'; export const CONTENT_ROUTES: ExtensionRoute[] = [ { @@ -56,7 +56,7 @@ export const CONTENT_ROUTES: ExtensionRoute[] = [ }, { path: 'view', - component: AppLayoutComponent, + component: ShellLayoutComponent, children: [ { path: ':nodeId', diff --git a/projects/aca-content/src/lib/components/common/common.module.ts b/projects/aca-content/src/lib/components/common/common.module.ts index 20c8d2f6de..8d6c784445 100644 --- a/projects/aca-content/src/lib/components/common/common.module.ts +++ b/projects/aca-content/src/lib/components/common/common.module.ts @@ -33,9 +33,10 @@ import { LanguagePickerComponent } from './language-picker/language-picker.compo import { LogoutComponent } from './logout/logout.component'; import { ContentModule } from '@alfresco/adf-content-services'; import { UserInfoComponent } from './user-info/user-info.component'; +import { RouterModule } from '@angular/router'; @NgModule({ - imports: [CommonModule, CoreModule.forChild(), ContentModule.forChild(), ExtensionsModule, GenericErrorModule], + imports: [CommonModule, CoreModule.forChild(), ContentModule.forChild(), ExtensionsModule, GenericErrorModule, RouterModule], declarations: [LocationLinkComponent, ToggleSharedComponent, LanguagePickerComponent, LogoutComponent, UserInfoComponent], exports: [ ExtensionsModule, diff --git a/projects/aca-content/src/lib/components/common/user-info/user-info.component.html b/projects/aca-content/src/lib/components/common/user-info/user-info.component.html index 2b07657e2d..7017c6af68 100644 --- a/projects/aca-content/src/lib/components/common/user-info/user-info.component.html +++ b/projects/aca-content/src/lib/components/common/user-info/user-info.component.html @@ -1,14 +1,4 @@ - - - - \ No newline at end of file + diff --git a/projects/aca-content/src/lib/components/common/user-info/user-info.component.spec.ts b/projects/aca-content/src/lib/components/common/user-info/user-info.component.spec.ts new file mode 100644 index 0000000000..2df6b9ec9e --- /dev/null +++ b/projects/aca-content/src/lib/components/common/user-info/user-info.component.spec.ts @@ -0,0 +1,121 @@ +/*! + * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AuthenticationService } from '@alfresco/adf-core'; +import { PeopleContentService } from '@alfresco/adf-content-services'; +import { UserInfoComponent } from './user-info.component'; +import { AppTestingModule } from '../../../testing/app-testing.module'; +import { of } from 'rxjs'; + +describe('UserInfoComponent', () => { + let component: UserInfoComponent; + let fixture: ComponentFixture; + let authServiceStub: Partial; + let peopleContentServiceStub: Partial; + let identityUserServiceStub: Partial; + + beforeEach(() => { + authServiceStub = { + isOauth: () => true, + isECMProvider: () => true, + isEcmLoggedIn: () => true, + isKerberosEnabled: () => false, + isLoggedIn: () => true + }; + + peopleContentServiceStub = { + getCurrentUserInfo: () => + of({ + firstName: 'John', + email: 'john@example.com', + id: 'johnDoe1', + enabled: true, + company: { + organization: 'ABC Organization', + address1: 'XYZ Road', + address2: 'Ohio', + address3: 'Westlake', + postcode: '44145', + telephone: '456876', + fax: '323984', + email: 'contact.us@abc.com' + }, + isAdmin: () => true + }) + }; + + identityUserServiceStub = { + getCurrentUserInfo: () => + of({ + firstName: 'John', + email: 'john@example.com', + id: 'johnDoe1', + enabled: true, + company: { + organization: 'ABC Organization', + address1: 'XYZ Road', + address2: 'Ohio', + address3: 'Westlake', + postcode: '44145', + telephone: '456876', + fax: '323984', + email: 'contact.us@abc.com' + }, + isAdmin: () => true + }) + }; + + TestBed.configureTestingModule({ + imports: [AppTestingModule], + declarations: [UserInfoComponent], + providers: [ + { provide: AuthenticationService, useValue: authServiceStub }, + { provide: PeopleContentService, useValue: peopleContentServiceStub }, + { provide: identityUserServiceStub, useValue: identityUserServiceStub } + ] + }).compileComponents(); + + fixture = TestBed.createComponent(UserInfoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should check if user is logged in', async () => { + const loggedIn = component.isLoggedIn; + expect(loggedIn).toBeTrue(); + }); + + it('should parse display name without email', async () => { + const model = { firstName: 'John' }; + const displayName = component['parseDisplayName'](model); + expect(displayName).toBe('John'); + }); + + it('should parse display name with email', async () => { + const model = { firstName: 'John', email: 'john@example.com' }; + const displayName = component['parseDisplayName'](model); + expect(displayName).toBe('John (john@example.com)'); + }); +}); diff --git a/projects/aca-content/src/lib/components/common/user-info/user-info.component.ts b/projects/aca-content/src/lib/components/common/user-info/user-info.component.ts index e676590a76..afacbf7097 100644 --- a/projects/aca-content/src/lib/components/common/user-info/user-info.component.ts +++ b/projects/aca-content/src/lib/components/common/user-info/user-info.component.ts @@ -22,21 +22,18 @@ * from Hyland Software. If not, see . */ -import { IdentityUserModel, IdentityUserService, AuthenticationService, UserInfoMode } from '@alfresco/adf-core'; +import { IdentityUserService, AuthenticationService } from '@alfresco/adf-core'; import { Component, OnInit } from '@angular/core'; import { Observable, of } from 'rxjs'; -import { EcmUserModel, PeopleContentService } from '@alfresco/adf-content-services'; +import { PeopleContentService } from '@alfresco/adf-content-services'; +import { map } from 'rxjs/operators'; @Component({ selector: 'app-user-info', templateUrl: './user-info.component.html' }) export class UserInfoComponent implements OnInit { - mode: UserInfoMode; - ecmUser$: Observable; - identityUser$: Observable; - selectedIndex: number; - userInfoMode = UserInfoMode; + displayName$: Observable; constructor( private peopleContentService: PeopleContentService, @@ -51,15 +48,12 @@ export class UserInfoComponent implements OnInit { getUserInfo() { if (this.authService.isOauth()) { this.loadIdentityUserInfo(); - this.mode = UserInfoMode.SSO; if (this.authService.isECMProvider() && this.authService.isEcmLoggedIn()) { - this.mode = UserInfoMode.CONTENT_SSO; this.loadEcmUserInfo(); } } else if (this.isEcmLoggedIn()) { this.loadEcmUserInfo(); - this.mode = UserInfoMode.CONTENT; } } @@ -71,11 +65,21 @@ export class UserInfoComponent implements OnInit { } private loadEcmUserInfo(): void { - this.ecmUser$ = this.peopleContentService.getCurrentUserInfo(); + this.displayName$ = this.peopleContentService.getCurrentUserInfo().pipe(map((model) => this.parseDisplayName(model))); } private loadIdentityUserInfo() { - this.identityUser$ = of(this.identityUserService.getCurrentUserInfo()); + this.displayName$ = of(this.identityUserService.getCurrentUserInfo()).pipe(map((model) => this.parseDisplayName(model))); + } + + private parseDisplayName(model: { firstName?: string; email?: string }): string { + let result = model.firstName; + + if (model.email) { + result = `${model.firstName} (${model.email})`; + } + + return result; } private isEcmLoggedIn() { diff --git a/projects/aca-content/src/lib/components/header/header.component.html b/projects/aca-content/src/lib/components/header/header.component.html deleted file mode 100644 index 6db2b8bf7d..0000000000 --- a/projects/aca-content/src/lib/components/header/header.component.html +++ /dev/null @@ -1,19 +0,0 @@ - -
- - - - - - - - -
diff --git a/projects/aca-content/src/lib/components/header/header.component.scss b/projects/aca-content/src/lib/components/header/header.component.scss deleted file mode 100644 index 6a3cc26423..0000000000 --- a/projects/aca-content/src/lib/components/header/header.component.scss +++ /dev/null @@ -1,21 +0,0 @@ -.app-header { - box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.02), 0 6px 10px 0 rgba(0, 0, 0, 0.014), 0 1px 18px 0 rgba(0, 0, 0, 0.012); - z-index: 2; - - adf-layout-header .mat-toolbar-single-row { - color: var(--theme-header-text-color) !important; - } - - .mat-toolbar { - background-image: var(--header-background-image) !important; - background-repeat: no-repeat !important; - - .aca-current-user { - color: var(--theme-foreground-text-color) !important; - } - - .adf-toolbar-divider div { - background-color: var(--theme-foreground-text-color) !important; - } - } -} diff --git a/projects/aca-content/src/lib/components/header/header.component.spec.ts b/projects/aca-content/src/lib/components/header/header.component.spec.ts deleted file mode 100644 index 02553b2a39..0000000000 --- a/projects/aca-content/src/lib/components/header/header.component.spec.ts +++ /dev/null @@ -1,133 +0,0 @@ -/*! - * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * from Hyland Software. If not, see . - */ - -import { AppHeaderComponent } from './header.component'; -import { AppState } from '@alfresco/aca-shared/store'; -import { of } from 'rxjs'; -import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { ContentActionRef } from '@alfresco/adf-extensions'; -import { Store } from '@ngrx/store'; -import { AppTestingModule } from '../../testing/app-testing.module'; -import { AppExtensionService, SharedToolbarModule } from '@alfresco/aca-shared'; -import { CoreModule, SidenavLayoutComponent } from '@alfresco/adf-core'; -import { AppSearchInputModule } from '../search/search-input.module'; -import { By } from '@angular/platform-browser'; - -describe('AppHeaderComponent', () => { - let component: AppHeaderComponent; - let fixture: ComponentFixture; - - const actions = [ - { id: 'action-1', type: 'button' }, - { id: 'action-2', type: 'button' } - ] as Array; - - const store = { - select: jasmine.createSpy('select'), - dispatch: () => {} - } as any; - - const appExtensionService = { - getHeaderActions: () => of(actions) - } as any; - - const app = { - headerColor: 'some-color', - headerTextColor: 'text-color', - appName: 'name', - logoPath: 'some/path' - } as AppState; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [AppTestingModule, CoreModule.forChild(), AppSearchInputModule, SharedToolbarModule], - declarations: [AppHeaderComponent], - providers: [ - { - provide: AppExtensionService, - useValue: appExtensionService - }, - { - provide: Store, - useValue: store - } - ] - }); - - store.select.and.callFake((memoizeFn) => of(memoizeFn({ app }))); - - fixture = TestBed.createComponent(AppHeaderComponent); - component = fixture.componentInstance; - }); - - it('should set header color, header text color, name and logo', fakeAsync(() => { - component.appName$.subscribe((val) => expect(val).toBe(app.appName)); - component.logo$.subscribe((val) => expect(val).toBe(app.logoPath)); - component.headerColor$.subscribe((val) => expect(val).toBe(app.headerColor)); - component.headerTextColor$.subscribe((val) => expect(val).toBe(app.headerTextColor)); - })); - - it('should get header actions', fakeAsync(() => { - component.ngOnInit(); - tick(); - expect(component.actions).toEqual(actions); - })); - - it('should minimize sidenav on toggle sidenav click', () => { - const layout = TestBed.createComponent(SidenavLayoutComponent); - const mockData: any = { layout: layout.componentInstance, isMenuMinimized: true }; - component.data = mockData; - - const toggleMenuSpy = spyOn(component.data.layout, 'toggleMenu'); - component.onToggleSidenav(true); - - expect(toggleMenuSpy).toHaveBeenCalled(); - expect(component.isSidenavExpanded).toBe(false); - }); - - describe('Search input', () => { - beforeEach(() => { - localStorage.clear(); - }); - - afterEach(() => { - localStorage.clear(); - }); - - it('should search be present when contentService is enabled', () => { - fixture.detectChanges(); - const searchInput = fixture.debugElement.query(By.css('.aca-search-input')); - - expect(searchInput).not.toBeNull(); - }); - - it('should search not be present when contentService is disabled', () => { - localStorage.setItem('contentService', 'false'); - fixture.detectChanges(); - const searchInput = fixture.debugElement.query(By.css('.aca-search-input')); - - expect(searchInput).toBeNull(); - }); - }); -}); diff --git a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.html b/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.html deleted file mode 100644 index 17be622bf0..0000000000 --- a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.scss b/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.scss deleted file mode 100644 index 9f026feab8..0000000000 --- a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.scss +++ /dev/null @@ -1,34 +0,0 @@ -.app-layout { - display: flex; - flex-direction: column; - flex: 1; - height: 100%; - overflow: hidden; - min-height: 0; - - router-outlet[name='viewer'] + * { - width: 100%; - height: 100%; - z-index: 999; - position: absolute; - top: 0; - right: 0; - background-color: white; - } - - adf-file-uploading-dialog { - z-index: 1000; - } -} - -@media screen and (max-width: 599px) { - .adf-app-title { - display: none; - } -} - -@media screen and (max-width: 719px) { - .adf-app-logo { - display: none; - } -} diff --git a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.spec.ts b/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.spec.ts deleted file mode 100644 index de500145b0..0000000000 --- a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.spec.ts +++ /dev/null @@ -1,220 +0,0 @@ -/*! - * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * from Hyland Software. If not, see . - */ - -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { TestBed, ComponentFixture } from '@angular/core/testing'; -import { AppConfigService, UserPreferencesService } from '@alfresco/adf-core'; -import { FileModel, UploadService } from '@alfresco/adf-content-services'; -import { AppLayoutComponent } from './app-layout.component'; -import { AppTestingModule } from '../../../testing/app-testing.module'; -import { Store } from '@ngrx/store'; -import { AppStore, SetSelectedNodesAction, ResetSelectionAction } from '@alfresco/aca-shared/store'; -import { Router, NavigationStart } from '@angular/router'; -import { of, Subject } from 'rxjs'; -import { By } from '@angular/platform-browser'; - -class MockRouter { - private url = 'some-url'; - private subject = new Subject(); - events = this.subject.asObservable(); - routerState = { snapshot: { url: this.url } }; - - navigateByUrl(url: string) { - const navigationStart = new NavigationStart(0, url); - this.subject.next(navigationStart); - } -} - -describe('AppLayoutComponent', () => { - let fixture: ComponentFixture; - let component: AppLayoutComponent; - let appConfig: AppConfigService; - let userPreference: UserPreferencesService; - let store: Store; - let router: Router; - let uploadService: UploadService; - let fakeFileList: FileModel[]; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [AppTestingModule], - providers: [ - Store, - { - provide: Router, - useClass: MockRouter - } - ], - declarations: [AppLayoutComponent], - schemas: [NO_ERRORS_SCHEMA] - }); - - fixture = TestBed.createComponent(AppLayoutComponent); - component = fixture.componentInstance; - appConfig = TestBed.inject(AppConfigService); - store = TestBed.inject(Store); - router = TestBed.inject(Router); - userPreference = TestBed.inject(UserPreferencesService); - - fakeFileList = [new FileModel(new File([], 'fakeFile'))]; - - uploadService = TestBed.inject(UploadService); - }); - - beforeEach(() => { - appConfig.config.languages = []; - appConfig.config.locale = 'en'; - }); - - describe('sidenav state', () => { - it('should get state from configuration', () => { - appConfig.config.sideNav = { - expandedSidenav: false, - preserveState: false - }; - - fixture.detectChanges(); - - expect(component.expandedSidenav).toBe(false); - }); - - it('should resolve state to true is no configuration', () => { - appConfig.config.sidenav = {}; - - fixture.detectChanges(); - - expect(component.expandedSidenav).toBe(true); - }); - - it('should get state from user settings as true', () => { - appConfig.config.sideNav = { - expandedSidenav: false, - preserveState: true - }; - - spyOn(userPreference, 'get').and.callFake((key) => { - if (key === 'expandedSidenav') { - return 'true'; - } - return 'false'; - }); - - fixture.detectChanges(); - - expect(component.expandedSidenav).toBe(true); - }); - - it('should get state from user settings as false', () => { - appConfig.config.sidenav = { - expandedSidenav: false, - preserveState: true - }; - - spyOn(userPreference, 'get').and.callFake((key) => { - if (key === 'expandedSidenav') { - return 'false'; - } - return 'true'; - }); - - fixture.detectChanges(); - - expect(component.expandedSidenav).toBe(false); - }); - }); - - it('should reset selection before navigation', () => { - const selection: any[] = [{ entry: { id: 'nodeId', name: 'name' } }]; - spyOn(store, 'dispatch').and.stub(); - fixture.detectChanges(); - store.dispatch(new SetSelectedNodesAction(selection)); - router.navigateByUrl('somewhere/over/the/rainbow'); - fixture.detectChanges(); - - expect(store.dispatch['calls'].mostRecent().args).toEqual([new ResetSelectionAction()]); - }); - - it('should close menu on mobile screen size', () => { - component.minimizeSidenav = false; - component.layout.container = { - isMobileScreenSize: true, - toggleMenu: () => {} - }; - - spyOn(component.layout.container, 'toggleMenu'); - fixture.detectChanges(); - - component.hideMenu({ preventDefault: () => {} } as any); - - expect(component.layout.container.toggleMenu).toHaveBeenCalled(); - }); - - it('should close menu on mobile screen size also when minimizeSidenav true', () => { - fixture.detectChanges(); - component.minimizeSidenav = true; - component.layout.container = { - isMobileScreenSize: true, - toggleMenu: () => {} - }; - - spyOn(component.layout.container, 'toggleMenu'); - fixture.detectChanges(); - - component.hideMenu({ preventDefault: () => {} } as any); - - expect(component.layout.container.toggleMenu).toHaveBeenCalled(); - }); - - describe('File Uploading Dialog', () => { - it('should the uploading file dialog be visible on the left when the showFileUploadingDialog is true', async () => { - fixture.detectChanges(); - await fixture.whenStable(); - - uploadService.addToQueue(...fakeFileList); - fixture.detectChanges(); - await fixture.whenStable(); - - const fileUploadingDialog = fixture.debugElement.query(By.css('adf-file-uploading-dialog')); - - expect(fileUploadingDialog.attributes['position']).toEqual('left'); - expect(component.showFileUploadingDialog).toEqual(true); - expect(fileUploadingDialog).not.toEqual(null); - }); - - it('should the uploading file dialog not be visible when the showFileUploadingDialog is false', async () => { - spyOn(store, 'select').and.returnValue(of(false)); - fixture.detectChanges(); - await fixture.whenStable(); - - uploadService.addToQueue(...fakeFileList); - fixture.detectChanges(); - await fixture.whenStable(); - - const fileUploadingDialog = fixture.debugElement.query(By.css('adf-file-uploading-dialog')); - - expect(component.showFileUploadingDialog).toEqual(false); - expect(fileUploadingDialog).toEqual(null); - }); - }); -}); diff --git a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.ts b/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.ts deleted file mode 100644 index a4175338de..0000000000 --- a/projects/aca-content/src/lib/components/layout/app-layout/app-layout.component.ts +++ /dev/null @@ -1,176 +0,0 @@ -/*! - * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * from Hyland Software. If not, see . - */ - -import { AppConfigService, SidenavLayoutComponent, UserPreferencesService } from '@alfresco/adf-core'; -import { Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { NavigationEnd, Router, NavigationStart } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { Subject, Observable } from 'rxjs'; -import { filter, takeUntil, map, withLatestFrom, delay } from 'rxjs/operators'; -import { NodePermissionService } from '@alfresco/aca-shared'; -import { BreakpointObserver } from '@angular/cdk/layout'; -import { AppStore, getCurrentFolder, getFileUploadingDialog, ResetSelectionAction } from '@alfresco/aca-shared/store'; -import { Directionality } from '@angular/cdk/bidi'; - -@Component({ - selector: 'app-layout', - templateUrl: './app-layout.component.html', - styleUrls: ['./app-layout.component.scss'], - encapsulation: ViewEncapsulation.None, - host: { class: 'app-layout' } -}) -export class AppLayoutComponent implements OnInit, OnDestroy { - @ViewChild('layout', { static: true }) - layout: SidenavLayoutComponent; - - onDestroy$: Subject = new Subject(); - isSmallScreen$: Observable; - - expandedSidenav: boolean; - currentFolderId: string; - canUpload = false; - - minimizeSidenav = false; - hideSidenav = false; - direction: Directionality; - - showFileUploadingDialog: boolean; - - private minimizeConditions: string[] = ['search']; - private hideConditions: string[] = ['/preview/']; - - constructor( - protected store: Store, - private permission: NodePermissionService, - private router: Router, - private userPreferenceService: UserPreferencesService, - private appConfigService: AppConfigService, - private breakpointObserver: BreakpointObserver - ) {} - - ngOnInit() { - this.isSmallScreen$ = this.breakpointObserver.observe(['(max-width: 600px)']).pipe(map((result) => result.matches)); - - this.hideSidenav = this.hideConditions.some((el) => this.router.routerState.snapshot.url.includes(el)); - - this.minimizeSidenav = this.minimizeConditions.some((el) => this.router.routerState.snapshot.url.includes(el)); - - if (!this.minimizeSidenav) { - this.expandedSidenav = this.getSidenavState(); - } else { - this.expandedSidenav = false; - } - - this.store - .select(getCurrentFolder) - .pipe(takeUntil(this.onDestroy$)) - .subscribe((node) => { - this.currentFolderId = node ? node.id : null; - this.canUpload = node && this.permission.check(node, ['create']); - }); - - this.router.events - .pipe( - withLatestFrom(this.isSmallScreen$), - filter(([event, isSmallScreen]) => isSmallScreen && event instanceof NavigationEnd), - takeUntil(this.onDestroy$) - ) - .subscribe(() => { - this.layout.container.sidenav.close(); - }); - - this.router.events - .pipe( - filter((event) => event instanceof NavigationEnd), - takeUntil(this.onDestroy$) - ) - .subscribe((event: NavigationEnd) => { - this.minimizeSidenav = this.minimizeConditions.some((el) => event.urlAfterRedirects.includes(el)); - this.hideSidenav = this.hideConditions.some((el) => event.urlAfterRedirects.includes(el)); - - this.updateState(); - }); - - this.router.events - .pipe( - filter((event) => event instanceof NavigationStart), - takeUntil(this.onDestroy$) - ) - .subscribe(() => { - this.store.dispatch(new ResetSelectionAction()); - }); - - this.store - .select(getFileUploadingDialog) - .pipe(delay(0), takeUntil(this.onDestroy$)) - .subscribe((fileUploadingDialog: boolean) => { - this.showFileUploadingDialog = fileUploadingDialog; - }); - } - - ngOnDestroy() { - this.onDestroy$.next(true); - this.onDestroy$.complete(); - } - - hideMenu(event: Event) { - if (this.layout.container.isMobileScreenSize) { - event.preventDefault(); - this.layout.container.toggleMenu(); - } - } - - private updateState() { - if (this.minimizeSidenav && !this.layout.isMenuMinimized) { - this.layout.isMenuMinimized = true; - if (!this.layout.container.isMobileScreenSize) { - this.layout.container.toggleMenu(); - } - } - - if (!this.minimizeSidenav) { - if (this.getSidenavState() && this.layout.isMenuMinimized) { - this.layout.isMenuMinimized = false; - this.layout.container.toggleMenu(); - } - } - } - - onExpanded(state: boolean) { - if (!this.minimizeSidenav && this.appConfigService.get('sideNav.preserveState')) { - this.userPreferenceService.set('expandedSidenav', state); - } - } - - private getSidenavState(): boolean { - const expand = this.appConfigService.get('sideNav.expandedSidenav', true); - const preserveState = this.appConfigService.get('sideNav.preserveState', true); - - if (preserveState) { - return this.userPreferenceService.get('expandedSidenav', expand.toString()) === 'true'; - } - - return expand; - } -} diff --git a/projects/aca-content/src/lib/components/layout/layout.module.ts b/projects/aca-content/src/lib/components/layout/layout.module.ts deleted file mode 100644 index 7a5b545c63..0000000000 --- a/projects/aca-content/src/lib/components/layout/layout.module.ts +++ /dev/null @@ -1,52 +0,0 @@ -/*! - * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * from Hyland Software. If not, see . - */ - -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { CoreModule } from '@alfresco/adf-core'; -import { AppLayoutComponent } from './app-layout/app-layout.component'; -import { ContentModule } from '@alfresco/adf-content-services'; -import { RouterModule } from '@angular/router'; -import { AppSidenavModule } from '../sidenav/sidenav.module'; -import { AppCommonModule } from '../common/common.module'; -import { AppHeaderModule } from '../header/header.module'; -import { HttpClientModule } from '@angular/common/http'; -import { PageLayoutModule } from '@alfresco/aca-shared'; - -@NgModule({ - imports: [ - CommonModule, - RouterModule, - CoreModule.forChild(), - ContentModule.forChild(), - AppCommonModule, - AppSidenavModule, - AppHeaderModule, - HttpClientModule, - PageLayoutModule - ], - declarations: [AppLayoutComponent], - exports: [AppLayoutComponent, PageLayoutModule] -}) -export class AppLayoutModule {} diff --git a/projects/aca-content/src/lib/components/main-action/main-action.component.html b/projects/aca-content/src/lib/components/main-action/main-action.component.html deleted file mode 100644 index c8be49da3a..0000000000 --- a/projects/aca-content/src/lib/components/main-action/main-action.component.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - diff --git a/projects/aca-content/src/lib/components/main-action/main-action.component.scss b/projects/aca-content/src/lib/components/main-action/main-action.component.scss deleted file mode 100644 index a46a78fb1a..0000000000 --- a/projects/aca-content/src/lib/components/main-action/main-action.component.scss +++ /dev/null @@ -1,10 +0,0 @@ -.app-main-action-button { - width: 100%; - border-radius: 4px; - background-color: var(--theme-accent-color); - color: var(--theme-accent-color-default-contrast); -} - -.main-action-menu-icon { - color: var(--theme-accent-color); -} diff --git a/projects/aca-content/src/lib/components/main-action/main-action.component.spec.ts b/projects/aca-content/src/lib/components/main-action/main-action.component.spec.ts deleted file mode 100644 index e53a16130a..0000000000 --- a/projects/aca-content/src/lib/components/main-action/main-action.component.spec.ts +++ /dev/null @@ -1,156 +0,0 @@ -/*! - * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * from Hyland Software. If not, see . - */ - -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MainActionComponent } from './main-action.component'; -import { TranslationService, TranslationMock } from '@alfresco/adf-core'; -import { AppExtensionService } from '@alfresco/aca-shared'; -import { of } from 'rxjs'; -import { ACTION_CLICK, ACTION_TITLE, getContentActionRef } from '../../testing/content-action-ref'; -import { AppExtensionServiceMock } from '../../testing/app-extension-service-mock'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { TranslateModule } from '@ngx-translate/core'; - -describe('MainActionComponent', () => { - let mainActionComponent: MainActionComponent; - const buttonQuery = '[data-automation-id="app-main-action-button"]'; - const iconQuery = '[data-automation-id="app-main-action-icon"]'; - - let fixture: ComponentFixture; - let appExtensionService: AppExtensionServiceMock; - - beforeEach(async () => { - TestBed.configureTestingModule({ - imports: [CommonModule, MatButtonModule, TranslateModule.forRoot()], - providers: [ - { provide: TranslationService, useClass: TranslationMock }, - { provide: AppExtensionService, useClass: AppExtensionServiceMock } - ] - }).compileComponents(); - - appExtensionService = TestBed.inject(AppExtensionService); - - fixture = TestBed.createComponent(MainActionComponent); - mainActionComponent = fixture.componentInstance; - }); - - describe('component is in expanded mode', () => { - beforeEach(async () => { - mainActionComponent.expanded = true; - fixture.detectChanges(); - }); - - it('should display button if main action is configured', () => { - const buttonMainAction = fixture.debugElement.nativeElement.querySelector(buttonQuery); - const iconMainAction = fixture.debugElement.nativeElement.querySelector(iconQuery); - - expect(iconMainAction).toBeFalsy(); - expect(buttonMainAction.textContent.trim()).toBe(ACTION_TITLE); - }); - - it('should not display button if main action is not configured', () => { - spyOn(appExtensionService, 'getMainAction').and.returnValue(of(undefined)); - mainActionComponent.ngOnInit(); - fixture.detectChanges(); - - const button = fixture.debugElement.nativeElement.querySelector(buttonQuery); - expect(button).toBeFalsy(); - }); - - it('should call extension action', () => { - const runExtensionActionSpy = spyOn(appExtensionService, 'runActionById'); - - const button = fixture.debugElement.nativeElement.querySelector(buttonQuery); - button.click(); - - expect(runExtensionActionSpy).toHaveBeenCalledWith(ACTION_CLICK); - }); - - it('should not call button if main action is disabled', () => { - const disabledMainActionRef = getContentActionRef(); - disabledMainActionRef.disabled = true; - - spyOn(appExtensionService, 'getMainAction').and.returnValue(of(disabledMainActionRef)); - const runAction = spyOn(mainActionComponent, 'runAction'); - - mainActionComponent.ngOnInit(); - fixture.detectChanges(); - - const button = fixture.debugElement.nativeElement.querySelector(buttonQuery); - button.click(); - - expect(runAction).not.toHaveBeenCalled(); - }); - }); - - describe('component is displayed as icon', () => { - beforeEach(async () => { - mainActionComponent.expanded = false; - fixture.detectChanges(); - }); - - it('should display icon if main action is configured', () => { - const buttonMainAction = fixture.debugElement.nativeElement.querySelector(buttonQuery); - const iconMainAction = fixture.debugElement.nativeElement.querySelector(iconQuery); - - expect(buttonMainAction).toBeFalsy(); - expect(iconMainAction).toBeTruthy(); - }); - - it('should not display icon if main action is not configured', () => { - spyOn(appExtensionService, 'getMainAction').and.returnValue(of(undefined)); - mainActionComponent.ngOnInit(); - fixture.detectChanges(); - - const mainAction = fixture.debugElement.nativeElement.querySelector(iconQuery); - expect(mainAction).toBeFalsy(); - }); - - it('should call extension action', () => { - const runExtensionActionSpy = spyOn(appExtensionService, 'runActionById'); - - const mainAction = fixture.debugElement.nativeElement.querySelector(iconQuery); - mainAction.click(); - - expect(runExtensionActionSpy).toHaveBeenCalledWith(ACTION_CLICK); - }); - - it('should not call icon if main action is disabled', () => { - const disabledMainActionRef = getContentActionRef(); - disabledMainActionRef.disabled = true; - - spyOn(appExtensionService, 'getMainAction').and.returnValue(of(disabledMainActionRef)); - const runAction = spyOn(mainActionComponent, 'runAction'); - - mainActionComponent.ngOnInit(); - fixture.detectChanges(); - - const button = fixture.debugElement.nativeElement.querySelector(iconQuery); - button.click(); - - expect(runAction).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/projects/aca-content/src/lib/components/main-action/main-action.module.ts b/projects/aca-content/src/lib/components/main-action/main-action.module.ts deleted file mode 100644 index 241605011d..0000000000 --- a/projects/aca-content/src/lib/components/main-action/main-action.module.ts +++ /dev/null @@ -1,37 +0,0 @@ -/*! - * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Alfresco Example Content Application - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * from Hyland Software. If not, see . - */ - -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { MatButtonModule } from '@angular/material/button'; -import { TranslateModule } from '@ngx-translate/core'; -import { MainActionComponent } from './main-action.component'; -import { MatIconModule } from '@angular/material/icon'; - -@NgModule({ - imports: [CommonModule, MatButtonModule, MatIconModule, TranslateModule.forChild()], - exports: [MainActionComponent], - declarations: [MainActionComponent] -}) -export class MainActionModule {} diff --git a/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.scss b/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.scss index 46fa1ca03c..658fcede4e 100644 --- a/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.scss +++ b/projects/aca-content/src/lib/components/search/search-input-control/search-input-control.component.scss @@ -22,6 +22,7 @@ $top-margin: 12px; font-size: 16px; padding-left: 15px; box-sizing: border-box; + margin-bottom: 12px !important; .mat-form-field { font-size: 16px; diff --git a/projects/aca-content/src/lib/components/search/search-input/search-input.component.html b/projects/aca-content/src/lib/components/search/search-input/search-input.component.html index b9a0ab48f1..5dcfc4a2a6 100644 --- a/projects/aca-content/src/lib/components/search/search-input/search-input.component.html +++ b/projects/aca-content/src/lib/components/search/search-input/search-input.component.html @@ -1,9 +1,9 @@ -
+ @@ -20,6 +20,10 @@
arrow_drop_down
+ +
diff --git a/projects/aca-content/src/lib/components/search/search-input/search-input.component.scss b/projects/aca-content/src/lib/components/search/search-input/search-input.component.scss index 3aaad8e99d..c2786f9c60 100644 --- a/projects/aca-content/src/lib/components/search/search-input/search-input.component.scss +++ b/projects/aca-content/src/lib/components/search/search-input/search-input.component.scss @@ -1,5 +1,5 @@ $search-width: 594px; -$search-height: 40px; +$search-height: 32px; $search-background: #f5f6f5; $search-border-radius: 4px; $top-margin: 12px; @@ -9,8 +9,26 @@ $top-margin: 12px; width: 100%; max-width: $search-width; height: $search-height + $top-margin; + margin: 0 !important; + + .app-search-button { + width: 32px; + height: 32px; + margin-left: 0; + padding-left: 0; + margin-top: -4px; + } .app-input-form-field { + .app-close-icon { + height: 6px; + + .mat-icon { + font-size: 18px !important; + line-height: 28px; + } + } + .mat-input-element { caret-color: var(--theme-text-color); @@ -52,6 +70,8 @@ mat-checkbox { background-color: $search-background; border-radius: $search-border-radius; height: $search-height; + margin-bottom: 0 !important; + padding-bottom: 26px !important; } .app-search-control { diff --git a/projects/aca-content/src/lib/components/search/search-input/search-input.component.spec.ts b/projects/aca-content/src/lib/components/search/search-input/search-input.component.spec.ts index 193a3a1da2..3d19b9bb0b 100644 --- a/projects/aca-content/src/lib/components/search/search-input/search-input.component.spec.ts +++ b/projects/aca-content/src/lib/components/search/search-input/search-input.component.spec.ts @@ -31,12 +31,14 @@ import { SearchByTermAction, SearchActionTypes, SnackbarErrorAction, SnackbarAct import { AppHookService } from '@alfresco/aca-shared'; import { map } from 'rxjs/operators'; import { SearchQueryBuilderService } from '@alfresco/adf-content-services'; +import { SearchNavigationService } from '../search-navigation.service'; describe('SearchInputComponent', () => { let fixture: ComponentFixture; let component: SearchInputComponent; let actions$: Actions; let appHookService: AppHookService; + let searchInputService: SearchNavigationService; beforeEach(() => { TestBed.configureTestingModule({ @@ -49,12 +51,20 @@ describe('SearchInputComponent', () => { actions$ = TestBed.inject(Actions); fixture = TestBed.createComponent(SearchInputComponent); appHookService = TestBed.inject(AppHookService); + searchInputService = TestBed.inject(SearchNavigationService); component = fixture.componentInstance; - fixture.detectChanges(); }); - it('should change flag on library400Error event', () => { + afterEach(() => { + fixture.destroy(); + }); + + it('should change flag on library400Error event', async () => { + fixture.detectChanges(); + await fixture.whenStable(); + expect(component.has400LibraryError).toBe(false); + appHookService.library400Error.next(); expect(component.has400LibraryError).toBe(true); @@ -64,9 +74,13 @@ describe('SearchInputComponent', () => { expect(component.hasLibraryConstraint()).toBe(false); }); - it('should have library constraint on 400 error received', () => { + it('should have library constraint on 400 error received', async () => { + fixture.detectChanges(); + await fixture.whenStable(); + const libItem = component.searchOptions.find((item) => item.key.toLowerCase().indexOf('libraries') > 0); libItem.value = true; + appHookService.library400Error.next(); expect(component.hasLibraryConstraint()).toBe(true); @@ -192,4 +206,23 @@ describe('SearchInputComponent', () => { expect(component.isContentChecked()).toBe(true); }); }); + + describe('exitSearch()', () => { + it('should exit search on click of close icon', async () => { + spyOn(component, 'exitSearch').and.callThrough(); + spyOn(searchInputService, 'navigateBack').and.callThrough(); + + fixture.detectChanges(); + await fixture.whenStable(); + + const closeIcon = fixture.debugElement.nativeElement.querySelector('.app-close-icon'); + closeIcon.click(); + + fixture.detectChanges(); + await fixture.whenStable(); + + expect(component.exitSearch).toHaveBeenCalled(); + expect(searchInputService.navigateBack).toHaveBeenCalledWith(); + }); + }); }); diff --git a/projects/aca-content/src/lib/components/search/search-input/search-input.component.ts b/projects/aca-content/src/lib/components/search/search-input/search-input.component.ts index a445c5f5db..b732dc55c4 100644 --- a/projects/aca-content/src/lib/components/search/search-input/search-input.component.ts +++ b/projects/aca-content/src/lib/components/search/search-input/search-input.component.ts @@ -33,6 +33,7 @@ import { Store } from '@ngrx/store'; import { Subject } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { SearchInputControlComponent } from '../search-input-control/search-input-control.component'; +import { SearchNavigationService } from '../search-navigation.service'; import { SearchLibrariesQueryBuilderService } from '../search-libraries-results/search-libraries-query-builder.service'; @Component({ @@ -84,7 +85,8 @@ export class SearchInputComponent implements OnInit, OnDestroy { private config: AppConfigService, private router: Router, private store: Store, - private appHookService: AppHookService + private appHookService: AppHookService, + public searchInputService: SearchNavigationService ) { this.searchOnChange = this.config.get('search.aca:triggeredOnChange', true); } @@ -106,6 +108,10 @@ export class SearchInputComponent implements OnInit, OnDestroy { }); } + exitSearch() { + this.searchInputService.navigateBack(); + } + showInputValue() { this.has400LibraryError = false; this.searchedWord = this.getUrlSearchTerm(); @@ -122,7 +128,9 @@ export class SearchInputComponent implements OnInit, OnDestroy { } onMenuOpened() { - this.searchInputControl.searchInput.nativeElement.focus(); + if (this.searchInputControl) { + this.searchInputControl.searchInput?.nativeElement?.focus(); + } } /** @@ -139,7 +147,10 @@ export class SearchInputComponent implements OnInit, OnDestroy { } else { this.store.dispatch(new SnackbarErrorAction('APP.BROWSE.SEARCH.EMPTY_SEARCH')); } - this.trigger.closeMenu(); + + if (this.trigger) { + this.trigger.closeMenu(); + } } onSearchChange(searchTerm: string) { diff --git a/projects/aca-content/src/lib/components/search/search-navigation.service.spec.ts b/projects/aca-content/src/lib/components/search/search-navigation.service.spec.ts new file mode 100644 index 0000000000..60c4590880 --- /dev/null +++ b/projects/aca-content/src/lib/components/search/search-navigation.service.spec.ts @@ -0,0 +1,65 @@ +/*! + * Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Alfresco Example Content Application + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * from Hyland Software. If not, see . + */ + +import { TestBed } from '@angular/core/testing'; +import { CoreModule } from '@alfresco/adf-core'; +import { TranslateModule } from '@ngx-translate/core'; +import { SearchNavigationService } from './search-navigation.service'; +import { Router } from '@angular/router'; + +describe('SearchNavigationService', () => { + let service: SearchNavigationService; + let router: Router; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot(), CoreModule.forRoot()] + }); + service = TestBed.inject(SearchNavigationService); + router = TestBed.inject(Router); + }); + + it('should not navigate to saved route when exitSearch function is called if saved route is null', () => { + const routerNavigate = spyOn(router, 'navigate'); + service.saveRoute(''); + service.navigateBack(); + + expect(routerNavigate).not.toHaveBeenCalledWith([service.previousRoute]); + }); + + it('should navigate to saved route when exitSearch function is called', () => { + const routerNavigate = spyOn(router, 'navigate'); + service.saveRoute('/personal-files'); + service.navigateBack(); + + expect(routerNavigate).toHaveBeenCalledWith([service.previousRoute]); + }); + + it('should navigate to Search when navigateToSearch function is called', () => { + const routerNavigate = spyOn(router, 'navigate'); + service.navigateToSearch(); + + expect(routerNavigate).toHaveBeenCalledWith(['/search']); + }); +}); diff --git a/projects/aca-content/src/lib/components/header/header.module.ts b/projects/aca-content/src/lib/components/search/search-navigation.service.ts similarity index 65% rename from projects/aca-content/src/lib/components/header/header.module.ts rename to projects/aca-content/src/lib/components/search/search-navigation.service.ts index 9089cf9622..412816449a 100644 --- a/projects/aca-content/src/lib/components/header/header.module.ts +++ b/projects/aca-content/src/lib/components/search/search-navigation.service.ts @@ -22,16 +22,33 @@ * from Hyland Software. If not, see . */ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { CoreModule } from '@alfresco/adf-core'; -import { AppHeaderComponent } from './header.component'; -import { AppSearchInputModule } from '../search/search-input.module'; -import { AppToolbarModule } from '../toolbar/toolbar.module'; +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; -@NgModule({ - imports: [CommonModule, CoreModule.forChild(), AppSearchInputModule, AppToolbarModule], - declarations: [AppHeaderComponent], - exports: [AppHeaderComponent] +@Injectable({ + providedIn: 'root' }) -export class AppHeaderModule {} +export class SearchNavigationService { + private _previousRoute = ''; + + get previousRoute(): string { + return this._previousRoute; + } + + constructor(private router: Router) {} + + saveRoute(route: string): void { + this._previousRoute = route; + } + + navigateBack(): void { + if (this.previousRoute) { + this.router.navigate([this.previousRoute]); + } + } + + navigateToSearch(): void { + this.saveRoute(this.router.url); + this.router.navigate(['/search']); + } +} diff --git a/projects/aca-content/src/lib/components/search/search-results.module.ts b/projects/aca-content/src/lib/components/search/search-results.module.ts index c30f767590..daf2cc7352 100644 --- a/projects/aca-content/src/lib/components/search/search-results.module.ts +++ b/projects/aca-content/src/lib/components/search/search-results.module.ts @@ -26,7 +26,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CoreModule } from '@alfresco/adf-core'; import { ContentModule } from '@alfresco/adf-content-services'; -import { LockedByModule } from '@alfresco/aca-shared'; +import { LockedByModule, PageLayoutModule } from '@alfresco/aca-shared'; import { SearchResultsComponent } from './search-results/search-results.component'; import { SearchResultsRowComponent } from './search-results-row/search-results-row.component'; import { SearchLibrariesResultsComponent } from './search-libraries-results/search-libraries-results.component'; @@ -34,10 +34,10 @@ import { AppInfoDrawerModule } from '../info-drawer/info.drawer.module'; import { AppToolbarModule } from '../toolbar/toolbar.module'; import { AppCommonModule } from '../common/common.module'; import { DirectivesModule } from '../../directives/directives.module'; -import { AppLayoutModule } from '../layout/layout.module'; import { ContextMenuModule } from '../context-menu/context-menu.module'; import { SearchActionMenuComponent } from './search-action-menu/search-action-menu.component'; import { DocumentListCustomComponentsModule } from '../dl-custom-components/document-list-custom-components.module'; +import { AppSearchInputModule } from './search-input.module'; @NgModule({ imports: [ @@ -48,10 +48,11 @@ import { DocumentListCustomComponentsModule } from '../dl-custom-components/docu AppInfoDrawerModule, AppToolbarModule, DirectivesModule, - AppLayoutModule, + PageLayoutModule, ContextMenuModule, LockedByModule, - DocumentListCustomComponentsModule + DocumentListCustomComponentsModule, + AppSearchInputModule ], declarations: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent, SearchActionMenuComponent], exports: [SearchResultsComponent, SearchLibrariesResultsComponent, SearchResultsRowComponent, SearchActionMenuComponent] diff --git a/projects/aca-content/src/lib/components/search/search-results/search-results.component.html b/projects/aca-content/src/lib/components/search/search-results/search-results.component.html index 0c652273ec..9cc85a86f0 100644 --- a/projects/aca-content/src/lib/components/search/search-results/search-results.component.html +++ b/projects/aca-content/src/lib/components/search/search-results/search-results.component.html @@ -1,6 +1,7 @@ - + +
diff --git a/projects/aca-content/src/lib/components/search/search-results/search-results.component.spec.ts b/projects/aca-content/src/lib/components/search/search-results/search-results.component.spec.ts index f66379046b..322c3d852e 100644 --- a/projects/aca-content/src/lib/components/search/search-results/search-results.component.spec.ts +++ b/projects/aca-content/src/lib/components/search/search-results/search-results.component.spec.ts @@ -24,7 +24,6 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { SearchResultsComponent } from './search-results.component'; -import { AppTestingModule } from '../../../testing/app-testing.module'; import { AppSearchResultsModule } from '../search-results.module'; import { AppConfigService, CoreModule, TranslationService } from '@alfresco/adf-core'; import { Store } from '@ngrx/store'; @@ -33,7 +32,9 @@ import { Pagination, SearchRequest } from '@alfresco/js-api'; import { SearchQueryBuilderService } from '@alfresco/adf-content-services'; import { ActivatedRoute, Router } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, Subject } from 'rxjs'; +import { AppTestingModule } from '../../../testing/app-testing.module'; +import { AppService } from '@alfresco/aca-shared'; describe('SearchComponent', () => { let component: SearchResultsComponent; @@ -49,8 +50,15 @@ describe('SearchComponent', () => { beforeEach(() => { params = new BehaviorSubject({ q: 'TYPE: "cm:folder" AND %28=cm: name: email OR cm: name: budget%29' }); TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot(), CoreModule.forRoot(), AppTestingModule, AppSearchResultsModule], + imports: [TranslateModule.forRoot(), AppTestingModule, CoreModule.forRoot(), AppSearchResultsModule], providers: [ + { + provide: AppService, + useValue: { + appNavNarMode$: new BehaviorSubject('expanded'), + toggleAppNavBar$: new Subject() + } + }, { provide: ActivatedRoute, useValue: { diff --git a/projects/aca-content/src/lib/components/sidenav/components/expand-menu.component.html b/projects/aca-content/src/lib/components/sidenav/components/expand-menu.component.html index ed51d164f2..c7ad1830c2 100644 --- a/projects/aca-content/src/lib/components/sidenav/components/expand-menu.component.html +++ b/projects/aca-content/src/lib/components/sidenav/components/expand-menu.component.html @@ -27,9 +27,6 @@
diff --git a/projects/aca-content/src/lib/components/header/header.component.ts b/projects/aca-content/src/lib/components/sidenav/components/sidenav-header.component.ts similarity index 55% rename from projects/aca-content/src/lib/components/header/header.component.ts rename to projects/aca-content/src/lib/components/sidenav/components/sidenav-header.component.ts index bc51ceb125..a02dbc0432 100644 --- a/projects/aca-content/src/lib/components/header/header.component.ts +++ b/projects/aca-content/src/lib/components/sidenav/components/sidenav-header.component.ts @@ -22,55 +22,36 @@ * from Hyland Software. If not, see . */ -import { Component, ViewEncapsulation, Output, EventEmitter, OnInit, Input, OnDestroy } from '@angular/core'; +import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { Store } from '@ngrx/store'; import { Observable, Subject } from 'rxjs'; +import { AppStore, getAppName, getLogoPath } from '@alfresco/aca-shared/store'; +import { AppConfigService } from '@alfresco/adf-core'; import { ContentActionRef } from '@alfresco/adf-extensions'; -import { AppStore, getHeaderColor, getAppName, getLogoPath, getHeaderImagePath, getHeaderTextColor } from '@alfresco/aca-shared/store'; import { AppExtensionService } from '@alfresco/aca-shared'; import { takeUntil } from 'rxjs/operators'; -import { AppConfigService, SidenavLayoutComponent } from '@alfresco/adf-core'; -import { isContentServiceEnabled } from '@alfresco/aca-shared/rules'; @Component({ - selector: 'app-header', - templateUrl: './header.component.html', - styleUrls: ['./header.component.scss'], + selector: 'app-sidenav-header', + templateUrl: `./sidenav-header.component.html`, encapsulation: ViewEncapsulation.None, - host: { class: 'app-header' } + host: { class: 'app-sidenav-header' } }) -export class AppHeaderComponent implements OnInit, OnDestroy { - private onDestroy$: Subject = new Subject(); - - @Output() - toggleClicked = new EventEmitter(); - - @Input() expandedSidenav = true; - - @Input() data: { layout?: SidenavLayoutComponent; isMenuMinimized?: boolean } = {}; - - get isSidenavExpanded(): boolean { - return !this.data.isMenuMinimized ?? this.expandedSidenav; - } +export class SidenavHeaderComponent implements OnInit, OnDestroy { + private onDestroy$ = new Subject(); appName$: Observable; - headerColor$: Observable; - headerTextColor$: Observable; logo$: Observable; landingPage: string; - actions: Array = []; - constructor(public store: Store, private appExtensions: AppExtensionService, private appConfigService: AppConfigService) { - this.headerColor$ = store.select(getHeaderColor); - this.headerTextColor$ = store.select(getHeaderTextColor); + @Output() + toggleNavBar = new EventEmitter(); + + constructor(public store: Store, private appConfigService: AppConfigService, private appExtensions: AppExtensionService) { this.appName$ = store.select(getAppName); this.logo$ = store.select(getLogoPath); this.landingPage = this.appConfigService.get('landingPage', '/personal-files'); - - store.select(getHeaderImagePath).subscribe((path) => { - document.body.style.setProperty('--header-background-image', `url('${path}')`); - }); } ngOnInit() { @@ -80,18 +61,6 @@ export class AppHeaderComponent implements OnInit, OnDestroy { .subscribe((actions) => { this.actions = actions; }); - - this.headerTextColor$.subscribe((color) => { - document.documentElement.style.setProperty('--adf-header-text-color', color); - }); - } - - onToggleSidenav(_event: boolean): void { - this.data.layout.toggleMenu(); - } - - isContentServiceEnabled(): boolean { - return isContentServiceEnabled(); } ngOnDestroy() { diff --git a/projects/aca-content/src/lib/components/sidenav/sidenav-wrapper/sidenav-wrapper.component.html b/projects/aca-content/src/lib/components/sidenav/sidenav-wrapper/sidenav-wrapper.component.html deleted file mode 100644 index c52e69d20d..0000000000 --- a/projects/aca-content/src/lib/components/sidenav/sidenav-wrapper/sidenav-wrapper.component.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/projects/aca-content/src/lib/components/sidenav/sidenav.component.html b/projects/aca-content/src/lib/components/sidenav/sidenav.component.html index 2c91866da2..1391a0bb29 100644 --- a/projects/aca-content/src/lib/components/sidenav/sidenav.component.html +++ b/projects/aca-content/src/lib/components/sidenav/sidenav.component.html @@ -1,36 +1,16 @@
- -
- - -
+
-
- +
- - - - -
- - - - - - - -
-
-
diff --git a/projects/aca-content/src/lib/components/sidenav/sidenav.component.scss b/projects/aca-content/src/lib/components/sidenav/sidenav.component.scss index 98a801dff8..6355fd3573 100644 --- a/projects/aca-content/src/lib/components/sidenav/sidenav.component.scss +++ b/projects/aca-content/src/lib/components/sidenav/sidenav.component.scss @@ -1,151 +1,129 @@ -.app-sidenav { - display: flex; - flex: 1; - flex-direction: column; - height: 100%; - overflow-y: hidden; -} - .sidenav { display: flex; flex: 1; flex-direction: column; height: 100%; - background-color: var(--theme-background-color); - - .action-menu { - display: flex; - flex-direction: column; - justify-content: center; - align-items: stretch; - } - - .section.action-menu { - padding: 8px 14px; - position: sticky; - } - - .section-sub-actions { - overflow-y: auto; - } - - .section { - padding: 8px 6px; - border-bottom: 1px solid var(--theme-divider-color); + overflow-y: hidden; + background: var(--theme-sidenav-background-color); + + &-header { + padding: 32px 0; + + &-title { + display: flex; + flex-direction: row; + align-items: center; + height: 32px; + padding: 0 24px; + + &-logo { + img { + cursor: pointer; + height: 28px; + vertical-align: middle; + } + } + + &-text { + flex: 1; + color: var(--theme-selected-text-color); + padding-left: 32px; + letter-spacing: 0.25px; + font-style: normal; + font-weight: 400; + font-size: var(--theme-body-1-font-size); + cursor: pointer; + } + } } .section:last-child { border-bottom: 0; } - .section--collapsed { - display: flex; - flex-direction: column; - align-items: center; - } - - .list-item { - padding: 12px 0; - display: flex; - align-items: center; - height: 24px; - } - - .menu { - display: flex; - flex: 1; - flex-direction: row; - } - - .full-width { - display: flex; - width: 100%; - } - - .action-button--active { - color: var(--theme-primary-color) !important; - } - - .action-button { - color: var(--theme-text-color); - } - - .action-button .action-button__label { - margin: 0 8px !important; - } - - .item { - padding: 12px 0; - flex-direction: row; - display: flex; - align-items: center; - text-decoration: none; - height: 24px; - width: 100%; - user-select: none; - } - - .app-item, - .app-item .item { - display: flex; - flex: 1; - flex-direction: row; - } - - .item:hover .action-button__label { - color: var(--theme-primary-color); - } - - .mat-expansion-panel-header { - padding: 0 8px 0 0 !important; - display: flex; - align-items: center; - font-size: 14px !important; - } - - .mat-expansion-panel { - width: 100%; - background-color: unset; - box-shadow: none !important; - } - - .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled='true']):hover { - background: none !important; - } - - .mat-expansion-indicator { - display: flex; - align-content: center; - } - - .mat-expansion-panel-body { - padding-bottom: 0; - } - - .mat-expansion-panel-header-title { - display: flex; - flex-direction: row; - align-items: center; - } -} - -.aca-menu-panel { - .action-button--active { - color: var(--theme-accent-color) !important; - } - - .action-button { - color: var(--theme-primary-color); - } - - .action-button:hover { - color: var(--theme-accent-color); - } -} + .section-sub-actions { + overflow-y: auto; -[dir='rtl'] .sidenav { - /* stylelint-disable-next-line no-descending-specificity */ - .mat-expansion-panel-header { - padding: 0 0 0 8px !important; + .mat-expansion-panel { + width: 100%; + background-color: unset; + box-shadow: none; + border-radius: 0; + + &-header { + height: 32px; + padding: 0 32px 0 0; + display: flex; + align-items: center; + border: none; + } + + &-header:hover { + background: var(--theme-hover-background-color); + } + + &-header-title { + display: flex; + flex-direction: row; + align-items: center; + } + + &-body { + padding: 0 0 16px; + font-size: var(--theme-body-1-font-size); + + .mat-button { + line-height: 32px; + } + } + + .mat-expansion-indicator { + display: flex; + align-content: center; + } + + .mat-expansion-indicator::after { + transform: rotate(226deg); + } + } + + .item { + flex-direction: row; + display: flex; + align-items: center; + text-decoration: none; + width: 100%; + user-select: none; + + &:hover .action-button__label { + color: var(--theme-selected-text-color); + } + } + + .action-button { + color: var(--theme-action-button-text-color); + height: 32px; + padding: 0 24px; + border-radius: 0; + } + + .full-width { + display: flex; + width: 100%; + } + + .action-button--active { + color: var(--theme-selected-text-color) !important; + background: var(--theme-selected-background-color); + } + + .action-panel-header { + color: var(--theme-action-button-text-color); + padding: 0 24px; + + &__label { + font-size: var(--theme-caption-font-size); + } + } } } diff --git a/projects/aca-content/src/lib/components/sidenav/sidenav.component.spec.ts b/projects/aca-content/src/lib/components/sidenav/sidenav.component.spec.ts index 08207b6de3..97769edebb 100644 --- a/projects/aca-content/src/lib/components/sidenav/sidenav.component.spec.ts +++ b/projects/aca-content/src/lib/components/sidenav/sidenav.component.spec.ts @@ -26,7 +26,8 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { TestBed, ComponentFixture } from '@angular/core/testing'; import { SidenavComponent } from './sidenav.component'; import { AppTestingModule } from '../../testing/app-testing.module'; -import { AppExtensionService } from '@alfresco/aca-shared'; +import { AppExtensionService, AppService } from '@alfresco/aca-shared'; +import { BehaviorSubject, Subject } from 'rxjs'; describe('SidenavComponent', () => { let fixture: ComponentFixture; @@ -37,6 +38,15 @@ describe('SidenavComponent', () => { TestBed.configureTestingModule({ imports: [AppTestingModule], declarations: [SidenavComponent], + providers: [ + { + provide: AppService, + useValue: { + appNavNarMode$: new BehaviorSubject('expanded'), + toggleAppNavBar$: new Subject() + } + } + ], schemas: [NO_ERRORS_SCHEMA] }); diff --git a/projects/aca-content/src/lib/components/sidenav/sidenav.component.ts b/projects/aca-content/src/lib/components/sidenav/sidenav.component.ts index 528b3fc89a..ae1cfa44ec 100755 --- a/projects/aca-content/src/lib/components/sidenav/sidenav.component.ts +++ b/projects/aca-content/src/lib/components/sidenav/sidenav.component.ts @@ -28,7 +28,8 @@ import { Store } from '@ngrx/store'; import { AppStore, getSideNavState } from '@alfresco/aca-shared/store'; import { Subject } from 'rxjs'; import { takeUntil, distinctUntilChanged, debounceTime } from 'rxjs/operators'; -import { AppExtensionService } from '@alfresco/aca-shared'; +import { AppExtensionService, AppService } from '@alfresco/aca-shared'; +import { SidenavLayoutComponent } from '@alfresco/adf-core'; @Component({ selector: 'app-sidenav', @@ -39,12 +40,15 @@ import { AppExtensionService } from '@alfresco/aca-shared'; }) export class SidenavComponent implements OnInit, OnDestroy { @Input() - mode: 'collapsed' | 'expanded' = 'expanded'; + data: { + layout?: SidenavLayoutComponent; + mode?: 'collapsed' | 'expanded'; + } = {}; groups: Array = []; private onDestroy$ = new Subject(); - constructor(private store: Store, private extensions: AppExtensionService) {} + constructor(private store: Store, private extensions: AppExtensionService, private appService: AppService) {} ngOnInit() { this.store @@ -53,6 +57,9 @@ export class SidenavComponent implements OnInit, OnDestroy { .subscribe(() => { this.groups = this.extensions.getApplicationNavigation(this.extensions.navbar); }); + + this.appService.appNavNarMode$.next(this.data.mode); + this.appService.toggleAppNavBar$.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.toggleNavBar()); } trackByGroupId(_: number, obj: NavBarGroupRef): string { @@ -63,6 +70,15 @@ export class SidenavComponent implements OnInit, OnDestroy { return obj.id; } + toggleClick() { + this.toggleNavBar(); + } + + private toggleNavBar() { + this.data.layout.toggleMenu(); + this.appService.appNavNarMode$.next(this.data.layout.isMenuMinimized ? 'collapsed' : 'expanded'); + } + ngOnDestroy() { this.onDestroy$.next(true); this.onDestroy$.complete(); diff --git a/projects/aca-content/src/lib/components/sidenav/sidenav.module.ts b/projects/aca-content/src/lib/components/sidenav/sidenav.module.ts index ee980ee2d1..00b4b9f07f 100644 --- a/projects/aca-content/src/lib/components/sidenav/sidenav.module.ts +++ b/projects/aca-content/src/lib/components/sidenav/sidenav.module.ts @@ -24,11 +24,9 @@ import { NgModule } from '@angular/core'; import { AppCreateMenuModule } from '../create-menu/create-menu.module'; -import { CommonModule } from '@angular/common'; import { CoreModule } from '@alfresco/adf-core'; import { RouterModule } from '@angular/router'; import { ExtensionsModule } from '@alfresco/adf-extensions'; -import { CoreExtensionsModule } from '../../extensions/core.extensions.module'; import { ExpansionPanelDirective } from './directives/expansion-panel.directive'; import { MenuPanelDirective } from './directives/menu-panel.directive'; import { SidenavComponent } from './sidenav.component'; @@ -36,19 +34,11 @@ import { ActiveLinkDirective } from './directives/active-link.directive'; import { ExpandMenuComponent } from './components/expand-menu.component'; import { ButtonMenuComponent } from './components/button-menu.component'; import { ActionDirective } from './directives/action.directive'; -import { MainActionModule } from '../main-action/main-action.module'; -import { SidenavWrapperComponent } from './sidenav-wrapper/sidenav-wrapper.component'; +import { SidenavHeaderComponent } from './components/sidenav-header.component'; +import { SharedToolbarModule } from '@alfresco/aca-shared'; @NgModule({ - imports: [ - CommonModule, - CoreModule.forChild(), - CoreExtensionsModule.forChild(), - ExtensionsModule.forChild(), - RouterModule, - AppCreateMenuModule, - MainActionModule - ], + imports: [CoreModule.forChild(), ExtensionsModule.forChild(), RouterModule, AppCreateMenuModule, SharedToolbarModule], declarations: [ MenuPanelDirective, ExpansionPanelDirective, @@ -57,7 +47,7 @@ import { SidenavWrapperComponent } from './sidenav-wrapper/sidenav-wrapper.compo ExpandMenuComponent, ButtonMenuComponent, SidenavComponent, - SidenavWrapperComponent + SidenavHeaderComponent ], exports: [ MenuPanelDirective, diff --git a/projects/aca-content/src/lib/components/trashcan/trashcan.module.ts b/projects/aca-content/src/lib/components/trashcan/trashcan.module.ts index 99f31f34df..b05786a0b3 100644 --- a/projects/aca-content/src/lib/components/trashcan/trashcan.module.ts +++ b/projects/aca-content/src/lib/components/trashcan/trashcan.module.ts @@ -31,7 +31,8 @@ import { AppCommonModule } from '../common/common.module'; import { AppToolbarModule } from '../toolbar/toolbar.module'; import { DirectivesModule } from '../../directives/directives.module'; import { ContextMenuModule } from '../context-menu/context-menu.module'; -import { AppLayoutModule } from '../layout/layout.module'; +import { AppSearchInputModule } from '../search/search-input.module'; +import { PageLayoutModule } from '@alfresco/aca-shared'; @NgModule({ imports: [ @@ -42,7 +43,8 @@ import { AppLayoutModule } from '../layout/layout.module'; AppCommonModule, AppToolbarModule, ContextMenuModule, - AppLayoutModule + PageLayoutModule, + AppSearchInputModule ], declarations: [TrashcanComponent], exports: [TrashcanComponent] diff --git a/projects/aca-content/src/lib/components/view-profile/view-profile.component.html b/projects/aca-content/src/lib/components/view-profile/view-profile.component.html index 442a4b83eb..b30ed76b2b 100644 --- a/projects/aca-content/src/lib/components/view-profile/view-profile.component.html +++ b/projects/aca-content/src/lib/components/view-profile/view-profile.component.html @@ -139,4 +139,4 @@

{{'APP.EDIT_PROFILE.EMAIL' | tr

- + \ No newline at end of file diff --git a/projects/aca-content/src/lib/components/view-profile/view-profile.component.scss b/projects/aca-content/src/lib/components/view-profile/view-profile.component.scss index 5abffab1b2..2d62438fb3 100644 --- a/projects/aca-content/src/lib/components/view-profile/view-profile.component.scss +++ b/projects/aca-content/src/lib/components/view-profile/view-profile.component.scss @@ -185,4 +185,4 @@ app-view-profile { padding-top: 2rem; padding-left: .5rem; } -} +} \ No newline at end of file diff --git a/projects/aca-content/src/lib/services/content-management.service.ts b/projects/aca-content/src/lib/services/content-management.service.ts index afddb2ce28..7dcb51cfff 100644 --- a/projects/aca-content/src/lib/services/content-management.service.ts +++ b/projects/aca-content/src/lib/services/content-management.service.ts @@ -1089,7 +1089,7 @@ export class ContentManagementService { private focusAfterClose(focusedElementSelector: string): void { if (focusedElementSelector) { - document.querySelector(focusedElementSelector).focus(); + document.querySelector(focusedElementSelector)?.focus(); } } } diff --git a/projects/aca-content/src/lib/services/node-actions.service.ts b/projects/aca-content/src/lib/services/node-actions.service.ts index 55bf0163a9..ee4f54f325 100644 --- a/projects/aca-content/src/lib/services/node-actions.service.ts +++ b/projects/aca-content/src/lib/services/node-actions.service.ts @@ -700,7 +700,7 @@ export class NodeActionsService { private focusAfterClose(focusedElementSelector: string): void { if (focusedElementSelector) { - document.querySelector(focusedElementSelector).focus(); + document.querySelector(focusedElementSelector)?.focus(); } } } diff --git a/projects/aca-content/src/lib/store/effects/download.effects.ts b/projects/aca-content/src/lib/store/effects/download.effects.ts index c5e5d1889d..b500110113 100644 --- a/projects/aca-content/src/lib/store/effects/download.effects.ts +++ b/projects/aca-content/src/lib/store/effects/download.effects.ts @@ -164,7 +164,7 @@ export class DownloadEffects { private focusAfterClose(focusedElementSelector: string): void { if (focusedElementSelector) { - document.querySelector(focusedElementSelector).focus(); + document.querySelector(focusedElementSelector)?.focus(); } } } diff --git a/projects/aca-content/src/lib/store/effects/search.effects.spec.ts b/projects/aca-content/src/lib/store/effects/search.effects.spec.ts index e9168d007f..98dd786c4f 100644 --- a/projects/aca-content/src/lib/store/effects/search.effects.spec.ts +++ b/projects/aca-content/src/lib/store/effects/search.effects.spec.ts @@ -28,7 +28,7 @@ import { SearchEffects } from './search.effects'; import { EffectsModule } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { Router } from '@angular/router'; -import { SearchOptionIds, SearchByTermAction } from '@alfresco/aca-shared/store'; +import { SearchOptionIds, SearchByTermAction, SearchAction } from '@alfresco/aca-shared/store'; describe('SearchEffects', () => { let store: Store; @@ -77,4 +77,15 @@ describe('SearchEffects', () => { expect(router.navigateByUrl).toHaveBeenCalledWith('/search;q=%2528test%2529'); })); }); + + describe('search$', () => { + it('should navigate to search when the toolbar search icon is clicked', fakeAsync(() => { + const routerNavigate = spyOn(router, 'navigate'); + store.dispatch(new SearchAction()); + + tick(); + + expect(routerNavigate).toHaveBeenCalledWith(['/search']); + })); + }); }); diff --git a/projects/aca-content/src/lib/store/effects/search.effects.ts b/projects/aca-content/src/lib/store/effects/search.effects.ts index 92ae940f03..1833f7dacd 100644 --- a/projects/aca-content/src/lib/store/effects/search.effects.ts +++ b/projects/aca-content/src/lib/store/effects/search.effects.ts @@ -25,12 +25,24 @@ import { Actions, ofType, createEffect } from '@ngrx/effects'; import { Injectable } from '@angular/core'; import { map } from 'rxjs/operators'; -import { SearchActionTypes, SearchByTermAction, SearchOptionIds } from '@alfresco/aca-shared/store'; +import { SearchAction, SearchActionTypes, SearchByTermAction, SearchOptionIds } from '@alfresco/aca-shared/store'; import { Router } from '@angular/router'; +import { SearchNavigationService } from '../../components/search/search-navigation.service'; @Injectable() export class SearchEffects { - constructor(private actions$: Actions, private router: Router) {} + constructor(private actions$: Actions, private router: Router, private searchNavigationService: SearchNavigationService) {} + + search$ = createEffect( + () => + this.actions$.pipe( + ofType(SearchActionTypes.Search), + map(() => { + this.searchNavigationService.navigateToSearch(); + }) + ), + { dispatch: false } + ); searchByTerm$ = createEffect( () => diff --git a/projects/aca-content/src/lib/store/initial-state.ts b/projects/aca-content/src/lib/store/initial-state.ts index 32df645222..bde97f5aa0 100644 --- a/projects/aca-content/src/lib/store/initial-state.ts +++ b/projects/aca-content/src/lib/store/initial-state.ts @@ -26,10 +26,7 @@ import { AppState, AppStore } from '@alfresco/aca-shared/store'; export const INITIAL_APP_STATE: AppState = { appName: 'Alfresco Content Application', - headerColor: '#ffffff', - headerTextColor: '#000000', logoPath: 'assets/images/alfresco-logo-white.svg', - headerImagePath: 'assets/images/mastHead-bg-shapesPattern.svg', customCssPath: '', webFontPath: '', sharedUrl: '', diff --git a/projects/aca-content/src/lib/store/reducers/app.reducer.ts b/projects/aca-content/src/lib/store/reducers/app.reducer.ts index f572f8e759..a10b72ae10 100644 --- a/projects/aca-content/src/lib/store/reducers/app.reducer.ts +++ b/projects/aca-content/src/lib/store/reducers/app.reducer.ts @@ -34,7 +34,6 @@ import { SetRepositoryInfoAction, SetInfoDrawerStateAction, SetInfoDrawerMetadataAspectAction, - SetHeaderColorAction, SetCurrentNodeVersionAction, SetFileUploadingDialogAction, SetInfoDrawerPreviewStateAction, @@ -50,12 +49,6 @@ export function appReducer(state: AppState = INITIAL_APP_STATE, action: Action): case AppActionTypes.SetInitialState: newState = Object.assign({}, (action as SetInitialStateAction).payload); break; - case AppActionTypes.SetHeaderColor: - newState = { - ...state, - headerColor: (action as SetHeaderColorAction).color - }; - break; case NodeActionTypes.SetSelection: newState = updateSelectedNodes(state, action as SetSelectedNodesAction); break; diff --git a/projects/aca-content/src/lib/ui/application.scss b/projects/aca-content/src/lib/ui/application.scss index 1b2e6162b1..e8a3070193 100644 --- a/projects/aca-content/src/lib/ui/application.scss +++ b/projects/aca-content/src/lib/ui/application.scss @@ -48,6 +48,6 @@ ng-component { adf-layout-container, aca-search-results, ng-component { - height: 80vh; + height: 100vh; } } diff --git a/projects/aca-content/src/lib/ui/variables/variables.scss b/projects/aca-content/src/lib/ui/variables/variables.scss index 82181de062..7a00c99131 100644 --- a/projects/aca-content/src/lib/ui/variables/variables.scss +++ b/projects/aca-content/src/lib/ui/variables/variables.scss @@ -31,6 +31,11 @@ $datetimepicker-selected-date-background: #2254b2; $datetimepicker-cell-background-color: #fff; $datetimepicker-cell-focus-border-color: #1f74db; $datetimepicker-cell-focus-background-color: rgba(33, 33, 33, 0.12); +$sidenav-background-color: #f8f8f8; +$selected-text-color: #212121; +$selected-background-color: rgba(31, 116, 219, 0.24); +$action-button-text-color: rgba(33, 35, 40, 0.7); +$page-layout-header-background-color: #fff; // CSS Variables $defaults: ( @@ -44,7 +49,6 @@ $defaults: ( --theme-title-color: mat.get-color-from-palette($foreground, text, 0.87), --theme-text-disabled-color: mat.get-color-from-palette($foreground, text, 0.38), --theme-border-color: mat.get-color-from-palette($foreground, text, 0.07), - --header-background-image: url('/assets/images/mastHead-bg-shapesPattern.svg'), --theme-card-background-color: mat.get-color-from-palette($background, card), --theme-foreground-text-color: mat.get-color-from-palette($foreground, text, 0.72), --theme-foreground-text-bold-color: mat.get-color-from-palette($foreground, text, 0.87), @@ -68,7 +72,14 @@ $defaults: ( --theme-datetimepicker-selected-date-background: $datetimepicker-selected-date-background, --theme-datetimepicker-cell-background: $datetimepicker-cell-background-color, --theme-datetimepicker-cell-focus-border: $datetimepicker-cell-focus-border-color, - --theme-datetimepicker-cell-focus-background: $datetimepicker-cell-focus-background-color + --theme-datetimepicker-cell-focus-background: $datetimepicker-cell-focus-background-color, + --theme-sidenav-background-color: $sidenav-background-color, + --theme-selected-text-color: $selected-text-color, + --theme-selected-background-color: $selected-background-color, + --theme-hover-background-color: $grey-text-background, + --theme-action-button-text-color: $action-button-text-color, + --theme-header-border-color: $grey-background, + --theme-page-layout-header-background-color: $page-layout-header-background-color, ); // propagates SCSS variables into the CSS variables scope diff --git a/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.spec.ts b/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.spec.ts index 00b93128c1..14593c8846 100644 --- a/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.spec.ts +++ b/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.spec.ts @@ -28,7 +28,7 @@ import { DebugElement, Predicate } from '@angular/core'; import { CoreTestingModule } from '@alfresco/adf-core'; import { FolderRulesService } from '../services/folder-rules.service'; import { ActivatedRoute } from '@angular/router'; -import { of } from 'rxjs'; +import { BehaviorSubject, of, Subject } from 'rxjs'; import { inheritedRuleSetMock, inheritedRuleSetWithEmptyRulesMock, @@ -43,6 +43,7 @@ import { ActionsService } from '../services/actions.service'; import { FolderRuleSetsService } from '../services/folder-rule-sets.service'; import { ruleMock, ruleSettingsMock } from '../mock/rules.mock'; import { Store } from '@ngrx/store'; +import { AppService } from '@alfresco/aca-shared'; describe('ManageRulesSmartComponent', () => { let fixture: ComponentFixture; @@ -57,6 +58,13 @@ describe('ManageRulesSmartComponent', () => { TestBed.configureTestingModule({ imports: [CoreTestingModule, AcaFolderRulesModule], providers: [ + { + provide: AppService, + useValue: { + appNavNarMode$: new BehaviorSubject('expanded'), + toggleAppNavBar$: new Subject() + } + }, FolderRuleSetsService, FolderRulesService, { provide: Store, useValue: { dispatch: () => {} } }, diff --git a/projects/aca-preview/src/lib/components/preview.component.spec.ts b/projects/aca-preview/src/lib/components/preview.component.spec.ts index 5fa64fb9c0..1186fb01f5 100644 --- a/projects/aca-preview/src/lib/components/preview.component.spec.ts +++ b/projects/aca-preview/src/lib/components/preview.component.spec.ts @@ -58,10 +58,7 @@ class DocumentBasePageServiceMock extends DocumentBasePageService { export const INITIAL_APP_STATE: AppState = { appName: 'Alfresco Content Application', - headerColor: '#ffffff', - headerTextColor: '#000000', logoPath: 'assets/images/alfresco-logo-white.svg', - headerImagePath: 'assets/images/mastHead-bg-shapesPattern.svg', customCssPath: '', webFontPath: '', sharedUrl: '', diff --git a/projects/aca-shared/rules/src/app.rules.ts b/projects/aca-shared/rules/src/app.rules.ts index d4e0ece4b8..b23902d8d6 100644 --- a/projects/aca-shared/rules/src/app.rules.ts +++ b/projects/aca-shared/rules/src/app.rules.ts @@ -90,6 +90,21 @@ export interface AcaRuleContext extends RuleContext { */ export const isContentServiceEnabled = (): boolean => localStorage && localStorage.getItem('contentService') !== 'false'; +/** + * Checks if Search is supported for active view + * JSON ref: `app.isSearchSupported` + */ +export const isSearchSupported = (context: RuleContext): boolean => + [navigation.isNotSearchResults(context) /*, !hasSelection(context)*/].every(Boolean); + +/** + * Checks if upload action is supported for the given context + * JSON ref: `app.isUploadSupported` + * + * @param content Rule execution context + */ +export const isUploadSupported = (context: RuleContext): boolean => + [isContentServiceEnabled(), navigation.isPersonalFiles(context) || navigation.isLibraryContent(context), canUpload(context)].every(Boolean); /** * Checks if user can copy selected node. * JSON ref: `app.canCopyNode` @@ -226,21 +241,35 @@ export const hasSelection = (context: RuleContext): boolean => !context.selectio * JSON ref: `app.navigation.folder.canCreate` */ export function canCreateFolder(context: RuleContext): boolean { - const { currentFolder } = context.navigation; - if (currentFolder) { - return context.permissions.check(currentFolder, ['create']); + if (isContentServiceEnabled() && (navigation.isPersonalFiles(context) || navigation.isLibraryContent(context))) { + const { currentFolder } = context.navigation; + + if (currentFolder) { + return context.permissions.check(currentFolder, ['create']); + } } return false; } +/** + * Checks if user can create a Library + * JSON ref: `app.canCreateLibrary` + * + * @param context Rule execution context + */ +export const canCreateLibrary = (context: RuleContext): boolean => [isContentServiceEnabled(), navigation.isLibraries(context)].every(Boolean); + /** * Checks if user can upload content to current folder. * JSON ref: `app.navigation.folder.canUpload` */ export function canUpload(context: RuleContext): boolean { - const { currentFolder } = context.navigation; - if (currentFolder) { - return context.permissions.check(currentFolder, ['create']); + if (isContentServiceEnabled() && (navigation.isPersonalFiles(context) || navigation.isLibraryContent(context))) { + const { currentFolder } = context.navigation; + + if (currentFolder) { + return context.permissions.check(currentFolder, ['create']); + } } return false; } diff --git a/projects/aca-shared/rules/src/navigation.rules.ts b/projects/aca-shared/rules/src/navigation.rules.ts index 558ba85e0a..35872d5c85 100644 --- a/projects/aca-shared/rules/src/navigation.rules.ts +++ b/projects/aca-shared/rules/src/navigation.rules.ts @@ -105,6 +105,11 @@ export function isLibraries(context: RuleContext): boolean { return url && (url.endsWith('/libraries') || url.startsWith('/search-libraries')); } +export function isLibraryContent(context: RuleContext): boolean { + const { url } = context.navigation; + return url && (url.endsWith('/libraries') || url.includes('/libraries/') || url.startsWith('/search-libraries')); +} + /** * Checks if the activated route is neither **Libraries** nor **Library Search Results**. * JSON ref: `app.navigation.isNotLibraries` diff --git a/projects/aca-shared/src/lib/components/document-base-page/document-base-page.component.ts b/projects/aca-shared/src/lib/components/document-base-page/document-base-page.component.ts index 1e5abbbcd1..440e6e828b 100644 --- a/projects/aca-shared/src/lib/components/document-base-page/document-base-page.component.ts +++ b/projects/aca-shared/src/lib/components/document-base-page/document-base-page.component.ts @@ -67,12 +67,20 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges { nodeResult: NodePaging; showHeader = ShowHeaderMode.Data; filterSorting = 'name-asc'; + createActions: Array = []; protected subscriptions: Subscription[] = []; protected constructor(protected store: Store, protected extensions: AppExtensionService, protected content: DocumentBasePageService) {} ngOnInit() { + this.extensions + .getCreateActions() + .pipe(takeUntil(this.onDestroy$)) + .subscribe((actions) => { + this.createActions = actions; + }); + this.sharedPreviewUrl$ = this.store.select(getSharedUrl); this.infoDrawerOpened$ = this.store.select(isInfoDrawerOpened).pipe(map((infoDrawerState) => !this.isOutletPreviewUrl() && infoDrawerState)); diff --git a/projects/aca-shared/src/lib/components/document-base-page/document-base-page.spec.ts b/projects/aca-shared/src/lib/components/document-base-page/document-base-page.spec.ts index 588978bc38..2ba78fad22 100644 --- a/projects/aca-shared/src/lib/components/document-base-page/document-base-page.spec.ts +++ b/projects/aca-shared/src/lib/components/document-base-page/document-base-page.spec.ts @@ -41,10 +41,7 @@ import { Subscription } from 'rxjs'; export const INITIAL_APP_STATE: AppState = { appName: 'Alfresco Content Application', - headerColor: '#ffffff', - headerTextColor: '#000000', logoPath: 'assets/images/alfresco-logo-white.svg', - headerImagePath: 'assets/images/mastHead-bg-shapesPattern.svg', customCssPath: '', webFontPath: '', sharedUrl: '', diff --git a/projects/aca-shared/src/lib/components/page-layout/page-layout.component.html b/projects/aca-shared/src/lib/components/page-layout/page-layout.component.html index 966402c252..9a22692ece 100644 --- a/projects/aca-shared/src/lib/components/page-layout/page-layout.component.html +++ b/projects/aca-shared/src/lib/components/page-layout/page-layout.component.html @@ -1,3 +1,11 @@ - - - +
+ + +
+ + diff --git a/projects/aca-shared/src/lib/components/page-layout/page-layout.component.scss b/projects/aca-shared/src/lib/components/page-layout/page-layout.component.scss index c537aed39f..d21ed1b7d9 100644 --- a/projects/aca-shared/src/lib/components/page-layout/page-layout.component.scss +++ b/projects/aca-shared/src/lib/components/page-layout/page-layout.component.scss @@ -3,14 +3,25 @@ .aca-page-layout { @include flex-column; + .aca-content-header { + background: var(--theme-page-layout-header-background-color); + height: 96px; + padding: 0 24px; + display: flex; + align-items: center; + } + .aca-page-layout-header { display: flex; align-items: center; - flex: 0 0 65px; - flex-basis: 48px; - background: var(--theme-background-color); - border-bottom: 1px solid var(--theme-border-color, rgba(0, 0, 0, 0.07)); - padding: 0 24px; + flex: auto; + width: 100%; + + .adf-breadcrumb-item { + font-size: 20px; + font-weight: 400; + letter-spacing: 0.15px; + } } .aca-page-layout-content { @@ -32,14 +43,6 @@ overflow: auto !important; } } - - .sidebar { - display: block; - height: 100%; - overflow-y: scroll; - max-width: 350px; - width: 350px; - } } [dir='rtl'] .aca-page-layout { diff --git a/projects/aca-content/src/lib/components/main-action/main-action.component.ts b/projects/aca-shared/src/lib/components/page-layout/page-layout.component.spec.ts similarity index 51% rename from projects/aca-content/src/lib/components/main-action/main-action.component.ts rename to projects/aca-shared/src/lib/components/page-layout/page-layout.component.spec.ts index 8026ae5013..42f684c408 100644 --- a/projects/aca-content/src/lib/components/main-action/main-action.component.ts +++ b/projects/aca-shared/src/lib/components/page-layout/page-layout.component.spec.ts @@ -22,37 +22,36 @@ * from Hyland Software. If not, see . */ -import { AppExtensionService } from '@alfresco/aca-shared'; -import { ContentActionRef, ContentActionType } from '@alfresco/adf-extensions'; -import { Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { Observable, Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; - -@Component({ - selector: 'app-main-action', - templateUrl: './main-action.component.html', - styleUrls: ['./main-action.component.scss'] -}) -export class MainActionComponent implements OnInit, OnDestroy { - @Input() expanded: boolean; - - mainAction$: Observable; - - actionTypes = ContentActionType; - - private onDestroy$ = new Subject(); - - constructor(private extensions: AppExtensionService) {} - - ngOnDestroy(): void { - this.onDestroy$.next(true); - } - - ngOnInit(): void { - this.mainAction$ = this.extensions.getMainAction().pipe(takeUntil(this.onDestroy$)); - } - - runAction(action: string): void { - this.extensions.runActionById(action); - } -} +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PageLayoutComponent } from './page-layout.component'; +import { AppService } from '../../services/app.service'; +import { BehaviorSubject, Subject } from 'rxjs'; + +describe('PageLayoutComponent', () => { + let fixture: ComponentFixture; + let component: PageLayoutComponent; + const appServiceMock = { + toggleAppNavBar$: new Subject(), + appNavNarMode$: new BehaviorSubject<'collapsed' | 'expanded'>('expanded') + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [PageLayoutComponent], + providers: [ + { + provide: AppService, + useValue: appServiceMock + } + ] + }); + fixture = TestBed.createComponent(PageLayoutComponent); + component = fixture.componentInstance; + }); + + it('should toggle the appService toggleAppNavBar$ Subject', () => { + spyOn(appServiceMock.toggleAppNavBar$, 'next'); + component.toggleClick(); + expect(appServiceMock.toggleAppNavBar$.next).toHaveBeenCalled(); + }); +}); diff --git a/projects/aca-shared/src/lib/components/page-layout/page-layout.component.ts b/projects/aca-shared/src/lib/components/page-layout/page-layout.component.ts index eb6559068f..a8ea9c3f5c 100644 --- a/projects/aca-shared/src/lib/components/page-layout/page-layout.component.ts +++ b/projects/aca-shared/src/lib/components/page-layout/page-layout.component.ts @@ -22,17 +22,35 @@ * from Hyland Software. If not, see . */ -import { Component, ViewEncapsulation, ChangeDetectionStrategy, Input } from '@angular/core'; +import { Component, ViewEncapsulation, Input, OnDestroy } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { AppService } from '../../services/app.service'; @Component({ selector: 'aca-page-layout', templateUrl: './page-layout.component.html', styleUrls: ['./page-layout.component.scss'], encapsulation: ViewEncapsulation.None, - host: { class: 'aca-page-layout' }, - changeDetection: ChangeDetectionStrategy.OnPush + host: { class: 'aca-page-layout' } }) -export class PageLayoutComponent { +export class PageLayoutComponent implements OnDestroy { @Input() hasError = false; + + private onDestroy$ = new Subject(); + appNavNarMode$: Observable<'collapsed' | 'expanded'>; + + constructor(private appService: AppService) { + this.appNavNarMode$ = appService.appNavNarMode$.pipe(takeUntil(this.onDestroy$)); + } + + toggleClick() { + this.appService.toggleAppNavBar$.next(); + } + + ngOnDestroy() { + this.onDestroy$.next(true); + this.onDestroy$.complete(); + } } diff --git a/projects/aca-shared/src/lib/components/page-layout/page-layout.module.ts b/projects/aca-shared/src/lib/components/page-layout/page-layout.module.ts index 2766ec0322..dd3b4da295 100644 --- a/projects/aca-shared/src/lib/components/page-layout/page-layout.module.ts +++ b/projects/aca-shared/src/lib/components/page-layout/page-layout.module.ts @@ -28,9 +28,12 @@ import { PageLayoutErrorComponent } from './page-layout-error.component'; import { PageLayoutHeaderComponent } from './page-layout-header.component'; import { PageLayoutComponent } from './page-layout.component'; import { CommonModule } from '@angular/common'; +import { MatIconModule } from '@angular/material/icon'; +import { TranslateModule } from '@ngx-translate/core'; +import { MatButtonModule } from '@angular/material/button'; @NgModule({ - imports: [CommonModule], + imports: [CommonModule, MatIconModule, TranslateModule, MatButtonModule], declarations: [PageLayoutContentComponent, PageLayoutErrorComponent, PageLayoutHeaderComponent, PageLayoutComponent], exports: [PageLayoutContentComponent, PageLayoutErrorComponent, PageLayoutHeaderComponent, PageLayoutComponent] }) diff --git a/projects/aca-shared/src/lib/components/tool-bar/toolbar-action/toolbar-action.component.html b/projects/aca-shared/src/lib/components/tool-bar/toolbar-action/toolbar-action.component.html index 5e38541818..0373201b45 100644 --- a/projects/aca-shared/src/lib/components/tool-bar/toolbar-action/toolbar-action.component.html +++ b/projects/aca-shared/src/lib/components/tool-bar/toolbar-action/toolbar-action.component.html @@ -4,13 +4,13 @@
- + - + diff --git a/projects/aca-shared/src/lib/components/tool-bar/toolbar-action/toolbar-action.component.ts b/projects/aca-shared/src/lib/components/tool-bar/toolbar-action/toolbar-action.component.ts index c9e4b6d805..06e7e46d85 100644 --- a/projects/aca-shared/src/lib/components/tool-bar/toolbar-action/toolbar-action.component.ts +++ b/projects/aca-shared/src/lib/components/tool-bar/toolbar-action/toolbar-action.component.ts @@ -36,6 +36,12 @@ import { ThemePalette } from '@angular/material/core'; host: { class: 'aca-toolbar-action' } }) export class ToolbarActionComponent implements DoCheck { + @Input() + data: { + buttonType?: ToolbarButtonType; + color?: string; + }; + @Input() type: ToolbarButtonType = ToolbarButtonType.ICON_BUTTON; diff --git a/projects/aca-shared/src/lib/components/tool-bar/toolbar-button/toolbar-button.component.html b/projects/aca-shared/src/lib/components/tool-bar/toolbar-button/toolbar-button.component.html index a39c6ebd7b..879dbeacc3 100644 --- a/projects/aca-shared/src/lib/components/tool-bar/toolbar-button/toolbar-button.component.html +++ b/projects/aca-shared/src/lib/components/tool-bar/toolbar-button/toolbar-button.component.html @@ -1,4 +1,4 @@ - + + + + diff --git a/projects/aca-shared/src/lib/components/tool-bar/toolbar-button/toolbar-button.component.ts b/projects/aca-shared/src/lib/components/tool-bar/toolbar-button/toolbar-button.component.ts index f06632870d..925c585aea 100644 --- a/projects/aca-shared/src/lib/components/tool-bar/toolbar-button/toolbar-button.component.ts +++ b/projects/aca-shared/src/lib/components/tool-bar/toolbar-button/toolbar-button.component.ts @@ -29,6 +29,7 @@ import { ThemePalette } from '@angular/material/core'; export enum ToolbarButtonType { ICON_BUTTON = 'icon-button', + FLAT_BUTTON = 'flat-button', MENU_ITEM = 'menu-item' } @@ -39,6 +40,12 @@ export enum ToolbarButtonType { host: { class: 'app-toolbar-button' } }) export class ToolbarButtonComponent { + @Input() + data: { + buttonType?: ToolbarButtonType; + color?: string; + }; + @Input() type: ToolbarButtonType = ToolbarButtonType.ICON_BUTTON; diff --git a/projects/aca-shared/src/lib/components/tool-bar/toolbar-menu/toolbar-menu.component.html b/projects/aca-shared/src/lib/components/tool-bar/toolbar-menu/toolbar-menu.component.html index a89c571f65..adcae5f0f4 100644 --- a/projects/aca-shared/src/lib/components/tool-bar/toolbar-menu/toolbar-menu.component.html +++ b/projects/aca-shared/src/lib/components/tool-bar/toolbar-menu/toolbar-menu.component.html @@ -1,15 +1,49 @@ - + + + + + + + + + + + + + diff --git a/projects/aca-shared/src/lib/components/tool-bar/toolbar-menu/toolbar-menu.component.ts b/projects/aca-shared/src/lib/components/tool-bar/toolbar-menu/toolbar-menu.component.ts index 0657763568..b023cd90e1 100644 --- a/projects/aca-shared/src/lib/components/tool-bar/toolbar-menu/toolbar-menu.component.ts +++ b/projects/aca-shared/src/lib/components/tool-bar/toolbar-menu/toolbar-menu.component.ts @@ -50,6 +50,16 @@ export class ToolbarMenuComponent implements AfterViewInit { @ViewChildren(ToolbarMenuItemComponent) toolbarMenuItems: QueryList; + @Input() + data: { + menuType?: string; + color?: string; + }; + + get type(): string { + return this.data?.menuType || 'default'; + } + @HostListener('document:keydown.Escape') handleKeydownEscape() { this.matTrigger.closeMenu(); diff --git a/projects/aca-shared/src/lib/services/app.service.ts b/projects/aca-shared/src/lib/services/app.service.ts index 2b6b62fc0e..545a108c26 100644 --- a/projects/aca-shared/src/lib/services/app.service.ts +++ b/projects/aca-shared/src/lib/services/app.service.ts @@ -22,9 +22,9 @@ * from Hyland Software. If not, see . */ -import { Inject, Injectable } from '@angular/core'; +import { Inject, Injectable, OnDestroy } from '@angular/core'; import { AuthenticationService, AppConfigService, AlfrescoApiService, PageTitleService, UserPreferencesService } from '@alfresco/adf-core'; -import { Observable, BehaviorSubject } from 'rxjs'; +import { Observable, BehaviorSubject, Subject } from 'rxjs'; import { GroupService, SearchQueryBuilderService, SharedLinksApiService, UploadService, FileUploadErrorEvent } from '@alfresco/adf-content-services'; import { OverlayContainer } from '@angular/cdk/overlay'; import { ActivatedRoute, ActivationEnd, NavigationStart, Router } from '@angular/router'; @@ -53,14 +53,19 @@ import { AcaMobileAppSwitcherService } from './aca-mobile-app-switcher.service'; providedIn: 'root' }) // After moving shell to ADF to core, AppService will implement ShellAppService -export class AppService { +export class AppService implements OnDestroy { private ready: BehaviorSubject; ready$: Observable; pageHeading$: Observable; + appNavNarMode$: Subject<'collapsed' | 'expanded'> = new BehaviorSubject('expanded'); + toggleAppNavBar$ = new Subject(); + hideSidenavConditions = ['/preview/']; - minimizeSidenavConditions = ['search']; + minimizeSidenavConditions = ['search', 'about', 'profile']; + + onDestroy$ = new Subject(); /** * Whether `withCredentials` mode is enabled. @@ -107,6 +112,11 @@ export class AppService { ); } + ngOnDestroy(): void { + this.onDestroy$.next(true); + this.onDestroy$.complete(); + } + init(): void { this.alfrescoApiService.getInstance().on('error', (error: { status: number; response: any }) => { if (error.status === 401 && !this.alfrescoApiService.isExcludedErrorListener(error?.response?.req?.url)) { @@ -200,10 +210,7 @@ export class AppService { const state: AppState = { ...this.initialAppState, appName: this.config.get('application.name'), - headerColor: this.config.get('headerColor'), - headerTextColor: this.config.get('headerTextColor', '#000000'), logoPath: this.config.get('application.logo'), - headerImagePath: this.config.get('application.headerImagePath'), customCssPath: this.config.get('customCssPath'), webFontPath: this.config.get('webFontPath'), sharedUrl: baseShareUrl diff --git a/projects/aca-shared/src/lib/testing/lib-testing-module.ts b/projects/aca-shared/src/lib/testing/lib-testing-module.ts index a120267ba5..43f7d991ce 100644 --- a/projects/aca-shared/src/lib/testing/lib-testing-module.ts +++ b/projects/aca-shared/src/lib/testing/lib-testing-module.ts @@ -42,9 +42,7 @@ import { CommonModule } from '@angular/common'; export const initialState = { app: { appName: 'Alfresco Content Application', - headerColor: '#ffffff', logoPath: 'assets/images/alfresco-logo-white.svg', - headerImagePath: 'assets/images/mastHead-bg-shapesPattern.svg', sharedUrl: '', user: { isAdmin: null, diff --git a/projects/aca-shared/store/src/actions/app-action-types.ts b/projects/aca-shared/store/src/actions/app-action-types.ts index d38b3ffc93..aa0fcbb1ec 100644 --- a/projects/aca-shared/store/src/actions/app-action-types.ts +++ b/projects/aca-shared/store/src/actions/app-action-types.ts @@ -25,7 +25,6 @@ export enum AppActionTypes { SetSettingsParameter = 'SET_SETTINGS_PARAMETER', SetInitialState = 'SET_INITIAL_STATE', - SetHeaderColor = 'SET_HEADER_COLOR', SetCurrentFolder = 'SET_CURRENT_FOLDER', SetCurrentVersion = 'SET_CURRENT_VERSION', SetCurrentUrl = 'SET_CURRENT_URL', diff --git a/projects/aca-shared/store/src/actions/app.actions.ts b/projects/aca-shared/store/src/actions/app.actions.ts index e69e518c83..3cd43a9888 100644 --- a/projects/aca-shared/store/src/actions/app.actions.ts +++ b/projects/aca-shared/store/src/actions/app.actions.ts @@ -39,12 +39,6 @@ export class SetInitialStateAction implements Action { constructor(public payload: AppState) {} } -export class SetHeaderColorAction implements Action { - readonly type = AppActionTypes.SetHeaderColor; - - constructor(public color: string) {} -} - export class SetCurrentFolderAction implements Action { readonly type = AppActionTypes.SetCurrentFolder; diff --git a/projects/aca-shared/store/src/actions/search.actions.ts b/projects/aca-shared/store/src/actions/search.actions.ts index 67c362bfcf..bac13da10f 100644 --- a/projects/aca-shared/store/src/actions/search.actions.ts +++ b/projects/aca-shared/store/src/actions/search.actions.ts @@ -26,9 +26,15 @@ import { Action } from '@ngrx/store'; import { SearchOptionModel } from '../models/search-option.model'; export enum SearchActionTypes { + Search = 'SEARCH', SearchByTerm = 'SEARCH_BY_TERM' } +export class SearchAction implements Action { + readonly type = SearchActionTypes.Search; + constructor() {} +} + export class SearchByTermAction implements Action { readonly type = SearchActionTypes.SearchByTerm; constructor(public payload: string, public searchOptions?: SearchOptionModel[]) {} diff --git a/projects/aca-shared/store/src/selectors/app.selectors.ts b/projects/aca-shared/store/src/selectors/app.selectors.ts index 8e27d23a5c..63fe483660 100644 --- a/projects/aca-shared/store/src/selectors/app.selectors.ts +++ b/projects/aca-shared/store/src/selectors/app.selectors.ts @@ -27,13 +27,10 @@ import { createSelector } from '@ngrx/store'; export const selectApp = (state: AppStore) => state.app; -export const getHeaderColor = createSelector(selectApp, (state) => state.headerColor); -export const getHeaderTextColor = createSelector(selectApp, (state) => state.headerTextColor); export const getAppName = createSelector(selectApp, (state) => state.appName); export const getLogoPath = createSelector(selectApp, (state) => state.logoPath); export const getCustomCssPath = createSelector(selectApp, (state) => state.customCssPath); export const getCustomWebFontPath = createSelector(selectApp, (state) => state.webFontPath); -export const getHeaderImagePath = createSelector(selectApp, (state) => state.headerImagePath); export const getUserProfile = createSelector(selectApp, (state) => state.user); export const getCurrentFolder = createSelector(selectApp, (state) => state.navigation.currentFolder); export const getCurrentVersion = createSelector(selectApp, (state) => state.currentNodeVersion); diff --git a/projects/aca-shared/store/src/states/app.state.ts b/projects/aca-shared/store/src/states/app.state.ts index fdffa7b4d7..bf3a28370b 100644 --- a/projects/aca-shared/store/src/states/app.state.ts +++ b/projects/aca-shared/store/src/states/app.state.ts @@ -30,12 +30,9 @@ export const STORE_INITIAL_APP_DATA = new InjectionToken('STORE_INITIA export interface AppState { appName: string; - headerColor: string; - headerTextColor: string; logoPath: string; customCssPath: string; webFontPath: string; - headerImagePath: string; sharedUrl: string; currentNodeVersion: VersionEntry; selection: SelectionState; diff --git a/projects/aca-testing-shared/src/components/components.ts b/projects/aca-testing-shared/src/components/components.ts index ac18d3fc35..27d85f0ada 100755 --- a/projects/aca-testing-shared/src/components/components.ts +++ b/projects/aca-testing-shared/src/components/components.ts @@ -24,6 +24,7 @@ export * from './login/login'; export * from './header/header'; +export * from './pageLayoutHeader/pageLayoutHeader'; export * from './header/user-info'; export * from './data-table/data-table'; export * from './dialog/confirm-dialog'; diff --git a/projects/aca-testing-shared/src/components/header/header.ts b/projects/aca-testing-shared/src/components/header/header.ts index 1826cbaedc..bd98cd1690 100755 --- a/projects/aca-testing-shared/src/components/header/header.ts +++ b/projects/aca-testing-shared/src/components/header/header.ts @@ -34,7 +34,7 @@ import { BrowserActions } from '@alfresco/adf-testing'; export class Header extends Component { logoLink = this.byCss('.app-menu__title'); moreActions = browser.element(by.id('app.header.more')); - sidenavToggle = this.byCss(`[id='adf-sidebar-toggle-start']`); + sidenavToggle = this.byCss(`.sidenav-header-title-logo`); userInfo = new UserInfo(); menu = new Menu(); @@ -42,7 +42,7 @@ export class Header extends Component { searchInput = new SearchInput(); constructor(ancestor?: string) { - super('adf-layout-header', ancestor); + super('app-sidenav-header', ancestor); } async openMoreMenu(): Promise { diff --git a/projects/aca-testing-shared/src/components/pageLayoutHeader/pageLayoutHeader.ts b/projects/aca-testing-shared/src/components/pageLayoutHeader/pageLayoutHeader.ts new file mode 100644 index 0000000000..98c51b39d7 --- /dev/null +++ b/projects/aca-testing-shared/src/components/pageLayoutHeader/pageLayoutHeader.ts @@ -0,0 +1,76 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { by, browser } from 'protractor'; +import { Component } from '../component'; +import { Menu } from '../menu/menu'; +import { Toolbar } from '../toolbar/toolbar'; +import { SearchInput } from '../search/search-input'; +import { waitElement } from '../../utilities/utils'; +import { BrowserActions } from '@alfresco/adf-testing'; + +export class PageLayoutHeader extends Component { + logoLink = this.byCss('.app-menu__title'); + moreActions = browser.element(by.id('app.header.more')); + sidenavToggle = this.byCss(`.sidenav-header-title-logo`); + + menu = new Menu(); + toolbar = new Toolbar(); + searchInput = new SearchInput(); + + constructor(ancestor?: string) { + super('aca-page-layout', ancestor); + } + + async openMoreMenu(): Promise { + await BrowserActions.click(this.moreActions); + await this.menu.waitForMenuToOpen(); + } + + async closeMoreMenu(): Promise { + await BrowserActions.click(this.moreActions); + await this.menu.waitForMenuToClose(); + } + + async isSidenavExpanded(): Promise { + return browser.isElementPresent(by.css(`[data-automation-id='expanded']`)); + } + + async expandSideNav(): Promise { + const expanded = await this.isSidenavExpanded(); + if (!expanded) { + await BrowserActions.click(this.sidenavToggle); + await waitElement(`[data-automation-id='expanded']`); + } + } + + async collapseSideNav(): Promise { + const expanded = await this.isSidenavExpanded(); + if (expanded) { + await BrowserActions.click(this.sidenavToggle); + await waitElement(`[data-automation-id='collapsed']`); + } + } +} diff --git a/projects/aca-testing-shared/src/components/search/search-input.ts b/projects/aca-testing-shared/src/components/search/search-input.ts index 5abe7715e3..cdd05740c6 100755 --- a/projects/aca-testing-shared/src/components/search/search-input.ts +++ b/projects/aca-testing-shared/src/components/search/search-input.ts @@ -28,7 +28,10 @@ import { waitForPresence, waitElement } from '../../utilities/utils'; import { BrowserActions, BrowserVisibility, TestElement } from '@alfresco/adf-testing'; export class SearchInput extends Component { - searchButton = this.component.element(by.css('.app-search-button')); + get searchButton() { + return browser.element(by.css('.app-search-button')); + } + searchContainer = browser.element(by.css('.app-search-container')); searchControl = browser.element(by.css('.app-search-control')); @@ -58,6 +61,7 @@ export class SearchInput extends Component { async clickSearchButton() { await BrowserActions.click(this.searchButton); + await this.waitForSearchControl(); } @@ -151,28 +155,33 @@ export class SearchInput extends Component { await this.clickLibrariesOption(); } + async searchForLibrary(text: string) { + await BrowserVisibility.waitUntilElementIsClickable(this.searchInput.elementFinder); + await this.searchInput.typeText(text); + } + async searchFor(text: string) { await BrowserVisibility.waitUntilElementIsClickable(this.searchInput.elementFinder); await this.searchInput.typeText(text); await BrowserActions.click(this.searchButton); } - async searchByURL(text: string){ + async searchByURL(text: string) { const query = Buffer.from(text, 'utf-8').toString(); await BrowserActions.getUrl(`#/search;q=${query}`); } async searchUntilResult(text: string, methodType: 'URL' | 'UI', waitPerSearch: number = 2000, timeout: number = 20000) { - const attempts = Math.round(timeout/waitPerSearch); + const attempts = Math.round(timeout / waitPerSearch); let loopCount = 0; let myPromise = new Promise((resolve, reject) => { const check = async () => { - loopCount++; - loopCount >= attempts ? reject('File not found') : methodType === 'UI' ? await this.searchFor(text) : await this.searchByURL(text); - await this.searchResult.isPresent(waitPerSearch) ? resolve('File found') : setTimeout(check, waitPerSearch); - } + loopCount++; + loopCount >= attempts ? reject('File not found') : methodType === 'UI' ? await this.searchFor(text) : await this.searchByURL(text); + (await this.searchResult.isPresent(waitPerSearch)) ? resolve('File found') : setTimeout(check, waitPerSearch); + }; return check(); - }); - return myPromise; + }); + return myPromise; } } diff --git a/projects/aca-testing-shared/src/components/sidenav/sidenav.ts b/projects/aca-testing-shared/src/components/sidenav/sidenav.ts index a4977a2902..91f469a35d 100755 --- a/projects/aca-testing-shared/src/components/sidenav/sidenav.ts +++ b/projects/aca-testing-shared/src/components/sidenav/sidenav.ts @@ -22,16 +22,16 @@ * along with Alfresco. If not, see . */ -import { ElementFinder, by, element, browser } from 'protractor'; +import { ElementFinder, by, element, browser, By } from 'protractor'; import { Logger, BrowserActions } from '@alfresco/adf-testing'; -import { SIDEBAR_LABELS, BROWSER_WAIT_TIMEOUT } from '../../configs'; import { Menu } from '../menu/menu'; import { Component } from '../component'; +import { waitElement } from '../../utilities'; export class Sidenav extends Component { links = this.component.all(by.css('.item')); activeLink = this.byCss('.action-button--active'); - newButton = this.allByCss('[data-automation-id="create-button"]'); + newButton = element(By.css('[id="app.toolbar.create"]')); personalFiles = this.byCss(`[data-automation-id='app.navbar.personalFiles']`); fileLibraries = this.byCss(`[data-automation-id='app.navbar.libraries.menu']`); myLibraries = this.byCss(`[data-automation-id='app.navbar.libraries.files']`, browser); @@ -40,6 +40,7 @@ export class Sidenav extends Component { recentFiles = this.byCss(`[data-automation-id='app.navbar.recentFiles']`); favorites = this.byCss(`[data-automation-id='app.navbar.favorites']`); trash = this.byCss(`[data-automation-id='app.navbar.trashcan']`); + sidenavToggle = this.byCss(`.sidenav-header-title-logo`); menu: Menu = new Menu(); @@ -47,27 +48,33 @@ export class Sidenav extends Component { super('app-sidenav', ancestor); } - private async expandMenu(name: string): Promise { - try { - if (await element(by.cssContainingText('.mat-expanded', name)).isPresent()) { - return Promise.resolve(); - } else { - const link = this.getLink(name); - await BrowserActions.click(link); - await element(by.css('.mat-expansion-panel-body')).isPresent(); - } - } catch (e) { - Logger.error(`---- sidebar navigation catch expandMenu: failed to expand ${name} menu : `, e); + async isSidenavExpanded(): Promise { + return browser.isElementPresent(by.css(`[data-automation-id='expanded']`)); + } + + async expandSideNav(): Promise { + const expanded = await this.isSidenavExpanded(); + if (!expanded) { + await BrowserActions.click(this.sidenavToggle); + await waitElement(`[data-automation-id='expanded']`); + } + } + + async collapseSideNav(): Promise { + const expanded = await this.isSidenavExpanded(); + if (expanded) { + await BrowserActions.click(this.sidenavToggle); + await waitElement(`[data-automation-id='collapsed']`); } } async openNewMenu(): Promise { - await BrowserActions.click(this.newButton.first()); + await BrowserActions.click(this.newButton); await this.menu.waitForMenuToOpen(); } async closeNewMenu(): Promise { - await BrowserActions.click(element(by.css('button[data-automation-id="create-button"] span span'))); + await BrowserActions.click(element(by.css('button[id="app.toolbar.create"] span span'))); await this.menu.waitForMenuToClose(); } @@ -130,11 +137,6 @@ export class Sidenav extends Component { async getLinkTooltip(name: string): Promise { const link = this.getLinkLabel(name); - const condition = () => link.getAttribute('title').then((value) => value && value.length > 0); - - await browser.actions().mouseMove(link).perform(); - await browser.wait(condition, BROWSER_WAIT_TIMEOUT); - return link.getAttribute('title'); } @@ -146,12 +148,4 @@ export class Sidenav extends Component { Logger.error(`---- clickLink catch : sidebar navigation failed to click on - ${name} : `, error); } } - - async isFileLibrariesMenuExpanded(): Promise { - return element(by.cssContainingText('.mat-expanded', SIDEBAR_LABELS.FILE_LIBRARIES)).isPresent(); - } - - async expandFileLibraries(): Promise { - await this.expandMenu(SIDEBAR_LABELS.FILE_LIBRARIES); - } } diff --git a/projects/aca-testing-shared/src/components/toolbar/toolbar.ts b/projects/aca-testing-shared/src/components/toolbar/toolbar.ts index 13e17b6aec..e65d4b2c3c 100755 --- a/projects/aca-testing-shared/src/components/toolbar/toolbar.ts +++ b/projects/aca-testing-shared/src/components/toolbar/toolbar.ts @@ -22,7 +22,7 @@ * along with Alfresco. If not, see . */ -import { ElementFinder, by, browser } from 'protractor'; +import { ElementFinder, by, browser, By, element } from 'protractor'; import { BrowserActions } from '@alfresco/adf-testing'; import { Menu } from '../menu/menu'; import { Component } from '../component'; @@ -32,17 +32,20 @@ export class Toolbar extends Component { menu = new Menu(); buttons = this.allByCss('button'); - shareButton = this.byId('share-action-button'); - viewButton = this.byCss(`.mat-icon-button[title='View']`); - downloadButton = this.byCss(`.mat-icon-button[title='Download']`); - editFolderButton = this.byId('app.toolbar.editFolder'); - viewDetailsButton = this.byCss(`.mat-icon-button[title='View Details']`); - printButton = this.byCss(`.mat-icon-button[title='Print']`); - fullScreenButton = this.byCss(`.mat-icon-button[title='Activate full-screen mode']`); - joinButton = this.byCss(`.mat-icon-button[title='Join']`); - leaveButton = this.byCss(`.mat-icon-button[title='Leave Library']`); - permanentlyDeleteButton = this.byCss(`.mat-icon-button[title='Permanently Delete']`); - restoreButton = this.byCss(`.mat-icon-button[title='Restore']`); + createButton = element(By.css('[id="app.toolbar.create"]')); + uploadButton = element(By.css('[id="app.toolbar.upload"]')); + shareButton = element(By.css('button[data-automation-id="share-action-button"]')); + viewButton = element(By.css(`button[title='View']`)); + downloadButton = element(By.css(`.mat-icon-button[title='Download']`)); + viewDetailsButton = element(By.css(`button[title='View Details']`)); + printButton = element(By.css(`button[title='Print']`)); + fullScreenButton = element(By.css(`button[title='Activate full-screen mode']`)); + joinButton = element(By.css(`button[title='Join']`)); + leaveButton = element(By.css(`button[title='Leave Library']`)); + permanentlyDeleteButton = element(By.css(`button[title='Permanently Delete']`)); + restoreButton = element(By.css(`button[title='Restore']`)); + searchIconButton = element(By.css(`button[title='Search']`)); + viewerDownloadButton = element(By.css('[id="app.viewer.download"]')); constructor(ancestor?: string) { super('.adf-toolbar', ancestor); @@ -72,11 +75,23 @@ export class Toolbar extends Component { return this.component.element(by.id(id)); } - async openMoreMenu(): Promise { - await this.isButtonPresent('More Actions'); + async clickSearchIconButton() { + await BrowserActions.click(this.searchIconButton); + } - const moreMenu = this.getButtonByTitleAttribute('More Actions'); - await BrowserActions.click(moreMenu); + async openViewerMoreMenu(): Promise { + const btnMoreActions = element(By.css('button[id="app.viewer.toolbar.more"]')); + await btnMoreActions.isPresent(); + await BrowserActions.click(btnMoreActions); + + await this.menu.waitForMenuToOpen(); + await browser.sleep(500); + } + + async openMoreMenu(): Promise { + const btnMoreActions = element(By.css('button[id="app.toolbar.more"]')); + await btnMoreActions.isPresent(); + await BrowserActions.click(btnMoreActions); await this.menu.waitForMenuToOpen(); await browser.sleep(500); @@ -98,6 +113,46 @@ export class Toolbar extends Component { return browser.isElementPresent(this.printButton); } + async openCreateFolderDialog(): Promise { + await this.openCreateMenu(); + await BrowserActions.click(this.menu.createFolderAction); + } + + async openCreateLibraryDialog(): Promise { + await this.openCreateMenu(); + await BrowserActions.click(this.menu.createLibraryAction); + } + + async openCreateFileFromTemplateDialog(): Promise { + await this.openCreateMenu(); + await BrowserActions.click(this.menu.createFileFromTemplateAction); + } + + async openCreateFolderFromTemplateDialog(): Promise { + await this.openCreateMenu(); + await BrowserActions.click(this.menu.createFolderFromTemplateAction); + } + + async openCreateMenu(): Promise { + await BrowserActions.click(this.createButton); + await this.menu.waitForMenuToOpen(); + } + + async closeCreateMenu(): Promise { + await BrowserActions.click(element(by.css('button[id="app.toolbar.create"]'))); + await this.menu.waitForMenuToClose(); + } + + async openUploadMenu(): Promise { + await BrowserActions.click(this.uploadButton); + await this.menu.waitForMenuToOpen(); + } + + async closeUploadMenu(): Promise { + await BrowserActions.click(element(by.css('button[id="app.toolbar.upload"]'))); + await this.menu.waitForMenuToClose(); + } + async clickMoreActionsFavorite(): Promise { await this.openMoreMenu(); await this.menu.clickMenuItem('Favorite'); diff --git a/projects/aca-testing-shared/src/configs.ts b/projects/aca-testing-shared/src/configs.ts index 06d7ea3cbb..e57262f6aa 100755 --- a/projects/aca-testing-shared/src/configs.ts +++ b/projects/aca-testing-shared/src/configs.ts @@ -47,7 +47,6 @@ export const APP_ROUTES = { // Sidebar labels export const SIDEBAR_LABELS = { PERSONAL_FILES: 'Personal Files', - FILE_LIBRARIES: 'File Libraries', MY_LIBRARIES: 'My Libraries', FAVORITE_LIBRARIES: 'Favorite Libraries', SHARED_FILES: 'Shared', diff --git a/projects/aca-testing-shared/src/pages/browsing-page.ts b/projects/aca-testing-shared/src/pages/browsing-page.ts index 531c4dcc40..121adc46a8 100755 --- a/projects/aca-testing-shared/src/pages/browsing-page.ts +++ b/projects/aca-testing-shared/src/pages/browsing-page.ts @@ -22,7 +22,7 @@ * along with Alfresco. If not, see . */ -import { Header, DataTable, Pagination, Toolbar, Breadcrumb, Sidenav } from '../components/components'; +import { Header, DataTable, Pagination, Toolbar, Breadcrumb, Sidenav, PageLayoutHeader } from '../components/components'; import { SIDEBAR_LABELS } from './../configs'; import { Page } from './page'; @@ -31,6 +31,7 @@ export class BrowsingPage extends Page { sidenav = new Sidenav(this.appRoot); toolbar = new Toolbar(this.appRoot); breadcrumb = new Breadcrumb(this.appRoot); + pageLayoutHeader = new PageLayoutHeader(this.appRoot); dataTable = new DataTable(this.appRoot); pagination = new Pagination(this.appRoot); @@ -43,19 +44,7 @@ export class BrowsingPage extends Page { await this.dataTable.waitForHeader(); } - async clickFileLibraries(): Promise { - await this.sidenav.clickLink(SIDEBAR_LABELS.FILE_LIBRARIES); - } - - async clickFileLibrariesAndWait(): Promise { - await this.clickFileLibraries(); - await this.dataTable.waitForHeader(); - } - async goToFavoriteLibraries(): Promise { - if (!(await this.sidenav.isFileLibrariesMenuExpanded())) { - await this.sidenav.expandFileLibraries(); - } await this.sidenav.clickLink(SIDEBAR_LABELS.FAVORITE_LIBRARIES); } @@ -65,9 +54,6 @@ export class BrowsingPage extends Page { } async goToMyLibraries(): Promise { - if (!(await this.sidenav.isFileLibrariesMenuExpanded())) { - await this.sidenav.expandFileLibraries(); - } await this.sidenav.clickLink(SIDEBAR_LABELS.MY_LIBRARIES); }