[ACS-3742] Layout changes for workspace (#2980)

* Layout changes for workspace sidemenu

* added header and search layout changes

* implemented review comments and removed process related code

* Added expand and collapse functionality

* Modified the paths

* linting fixes

* use standard material settings icon

* use only specific modules needed for page layout

* use standard "menu" icon for now

* use standard avatar icon for now

* cleanup user profile menu item

* cleanup About component layout

* remove hardcoded settings route

* deprecate "headerImagePath"

* deprecate "headerTextColor" customisation

* deprecate "headerColor" customisation

* proper toggle of the side menu

* proper sidebar header implementation

* user profile basic cleanup

* minor fixes

* cleanup buttons

* remove old app layout and use ADF one

* remove old header component

* cleanup old layout module

* fix unit tests

* cleanup unit tests

* cleanup header actions module

* deprecate unused main-action component

* cleanup styles

* restore removed method

* cleanup search results toolbar

* restore expand menu functionality

* cleanup code, back buttons for about and profile

* restore original code

* proper collapse button

* remove unused i18n key

* styles cleanup

* cleanup sidebar

* cleanup user profile

* add safety checks for focus after close

* layout fixes

* update view profile unit tests

* code cleanup after reviews

* cleanup header actions

* fix menu population, user info

* improved upload and create actions

* remove useless tests

* fix folder rules tests

* search button workaround

* e2e: remove wait

* add create/upload tooltips

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* e2e fix

* try fix e2e

* update e2e extension configs

* try fix e2e

* try fix e2e

* fix eslint config

* try fix e2e

* move search button to extensions

* move upload and create to extensions

* remove header actions as no longer needed

* cleanup

* e2e fixes and cleanup for unwanted files

* linting fixes

* linting fixes

* added button type to support text buttons

* linting fixes

* added more unit tests to achieve code coverage requirement

* fixing code covergae for aca-content

* fixed code coverage for aca-shared

* linting fixes

* linting fixes

* cleanup

* version fix

---------

Co-authored-by: SheenaMalhotra182 <sheena.malhotra@globallogic.com>
Co-authored-by: Denys Vuika <denys.vuika@gmail.com>
Co-authored-by: SheenaMalhotra182 <sheena.malhotra@contractors.onbase.com>
This commit is contained in:
Yasa-Nataliya 2023-04-20 16:48:24 +05:30 committed by GitHub
parent d042b80386
commit 6fac964d94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
140 changed files with 1663 additions and 2177 deletions

View File

@ -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": {

View File

@ -0,0 +1,4 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M18 9C18 4.02944 13.9706 0 9 0C4.02944 0 0 4.02944 0 9C0 13.9706 4.02944 18 9 18H18V9Z" fill="#2A7DE2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.9984 16.6856V9.05664C17.9984 5.06228 15.3963 1.67568 11.7948 0.499512C9.56758 3.98205 9.97569 8.66281 13.0191 11.7062L17.9984 16.6856Z" fill="#0055B9"/>
</svg>

After

Width:  |  Height:  |  Size: 463 B

View File

@ -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.

View File

@ -89,28 +89,6 @@ Alfresco コンテンツアプリケーションの左上隅に表示される
}
```
### ヘッダーの背景色
"headerColor" キーの色コードを指定することにより、ヘッダーの背景色を変更できます:
```json
{
"headerColor": "#ffffff"
}
```
### ヘッダーの背景画像
ヘッダーの背景画像を変更するには、対応するリソースへのパスを指定します:
```json
{
"application": {
"headerImagePath": "assets/images/mastHead-bg-shapesPattern.svg"
}
}
```
### 制限されたコンテンツ
"files.excluded" パスにあるルールのリストを設定または拡張することで、ユーザーが特定の種類のファイルやフォルダをアップロードできないように制限することができます。

View File

@ -14,6 +14,10 @@
],
"createDefaultProgram": true
},
"plugins": [
"rxjs",
"unicorn"
],
"rules": {
}
}

View File

@ -196,12 +196,12 @@
"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": [
"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": 100,
@ -210,19 +210,13 @@
"route": "favorite/libraries"
},
{
"id": "app.navbar.libraries.files",
"id": "app.navbar.recentFiles",
"order": 200,
"title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP",
"route": "libraries"
}
]
}
]
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.secondary",
"items": [
{
"id": "app.navbar.shared",
"order": 100,
@ -234,14 +228,6 @@
"visible": "repository.isQuickShareEnabled"
}
},
{
"id": "app.navbar.recentFiles",
"order": 200,
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.favorites",
"order": 300,

View File

@ -196,12 +196,12 @@
"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": [
"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": 100,
@ -210,19 +210,13 @@
"route": "favorite/libraries"
},
{
"id": "app.navbar.libraries.files",
"id": "app.navbar.recentFiles",
"order": 200,
"title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP",
"route": "libraries"
}
]
}
]
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.secondary",
"items": [
{
"id": "app.navbar.shared",
"order": 100,
@ -234,14 +228,6 @@
"visible": "repository.isQuickShareEnabled"
}
},
{
"id": "app.navbar.recentFiles",
"order": 200,
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.favorites",
"order": 300,

View File

@ -223,12 +223,12 @@
"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": [
"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": 100,
@ -237,19 +237,13 @@
"route": "favorite/libraries"
},
{
"id": "app.navbar.libraries.files",
"id": "app.navbar.recentFiles",
"order": 200,
"title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP",
"route": "libraries"
}
]
}
]
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.secondary",
"items": [
{
"id": "app.navbar.shared",
"order": 100,
@ -261,14 +255,6 @@
"visible": "repository.isQuickShareEnabled"
}
},
{
"id": "app.navbar.recentFiles",
"order": 200,
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.favorites",
"order": 300,

View File

@ -196,12 +196,12 @@
"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": [
"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": 100,
@ -210,19 +210,13 @@
"route": "favorite/libraries"
},
{
"id": "app.navbar.libraries.files",
"id": "app.navbar.recentFiles",
"order": 200,
"title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP",
"route": "libraries"
}
]
}
]
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.secondary",
"items": [
{
"id": "app.navbar.shared",
"order": 100,
@ -234,14 +228,6 @@
"visible": "repository.isQuickShareEnabled"
}
},
{
"id": "app.navbar.recentFiles",
"order": 200,
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.favorites",
"order": 300,

View File

@ -196,12 +196,12 @@
"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": [
"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": 100,
@ -210,19 +210,13 @@
"route": "favorite/libraries"
},
{
"id": "app.navbar.libraries.files",
"id": "app.navbar.recentFiles",
"order": 200,
"title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP",
"route": "libraries"
}
]
}
]
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.secondary",
"items": [
{
"id": "app.navbar.shared",
"order": 100,
@ -234,14 +228,6 @@
"visible": "repository.isQuickShareEnabled"
}
},
{
"id": "app.navbar.recentFiles",
"order": 200,
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.favorites",
"order": 300,

View File

@ -196,12 +196,12 @@
"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": [
"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": 100,
@ -210,19 +210,13 @@
"route": "favorite/libraries"
},
{
"id": "app.navbar.libraries.files",
"id": "app.navbar.recentFiles",
"order": 200,
"title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP",
"route": "libraries"
}
]
}
]
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.secondary",
"items": [
{
"id": "app.navbar.shared",
"order": 100,
@ -234,14 +228,6 @@
"visible": "repository.isQuickShareEnabled"
}
},
{
"id": "app.navbar.recentFiles",
"order": 200,
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.favorites",
"order": 300,

View File

@ -196,12 +196,12 @@
"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": [
"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": 100,
@ -210,19 +210,13 @@
"route": "favorite/libraries"
},
{
"id": "app.navbar.libraries.files",
"id": "app.navbar.recentFiles",
"order": 200,
"title": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.LIBRARIES.MENU.MY_LIBRARIES.SIDENAV_LINK.TOOLTIP",
"route": "libraries"
}
]
}
]
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.secondary",
"items": [
{
"id": "app.navbar.shared",
"order": 100,
@ -234,14 +228,6 @@
"visible": "repository.isQuickShareEnabled"
}
},
{
"id": "app.navbar.recentFiles",
"order": 200,
"icon": "schedule",
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.favorites",
"order": 300,

View File

@ -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();

View File

@ -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('*');

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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();
});

View File

@ -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,

View File

@ -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');
});
});

View File

@ -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();

View File

@ -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}`);

View File

@ -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);

View File

@ -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<void> {
@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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();
}

View File

@ -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', 'a<a', 'a>a', `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`);

View File

@ -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`);
});

View File

@ -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);

View File

@ -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);

View File

@ -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();
});

View File

@ -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);

View File

@ -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');
});

View File

@ -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);

View File

@ -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');
});
});

View File

@ -85,7 +85,7 @@ describe('Library properties', () => {
});
beforeEach(async () => {
await page.clickFileLibrariesAndWait();
await page.goToMyLibrariesAndWait();
});
afterEach(async () => {

View File

@ -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 */

View File

@ -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);

View File

@ -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);
});

View File

@ -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');
});
});

View File

@ -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();
});

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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);

View File

@ -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`);

View File

@ -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`);

View File

@ -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();

View File

@ -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();
});

View File

@ -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);

View File

@ -1,4 +1,11 @@
<aca-page-layout>
<aca-page-layout-header>
<button mat-icon-button [routerLink]="landingPage">
<mat-icon class="app-profile-icon">arrow_back</mat-icon>
</button>
<h1>{{ 'APP.BROWSE.ABOUT.TITLE' | translate }}</h1>
</aca-page-layout-header>
<aca-page-layout-content [scrollable]="true">
<adf-about>
<adf-about-panel *ngIf="dev" [label]="'ABOUT.SERVER_SETTINGS.TITLE' | translate">

View File

@ -1,4 +0,0 @@
adf-about {
padding: 10px;
width: 100%;
}

View File

@ -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<ExtensionRef[]>;
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 {

View File

@ -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'])]
})

View File

@ -85,19 +85,19 @@
"component": "app.notification-center",
"order": 50
},
{
"id": "app.header.more",
"type": "menu",
"order": 10000,
"icon": "apps",
"title": "APP.ACTIONS.MORE",
"children": [
{
"id": "app.header.user",
"type": "custom",
"component": "app.user",
"order": 100
},
{
"id": "app.header.more",
"type": "menu",
"order": 10000,
"icon": "more_vert",
"title": "APP.ACTIONS.MORE",
"children": [
{
"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"
}
}
],
@ -241,10 +192,18 @@
{
"id": "app.navbar.primary",
"items": [
{
"id": "app.navbar.menu",
"order": 100,
"title": "APP.BROWSE.FILE.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.FILE.SIDENAV_LINK.TOOLTIP",
"rules": {
"visible": "app.isContentServiceEnabled"
},
"children": [
{
"id": "app.navbar.personalFiles",
"order": 100,
"icon": "folder",
"title": "APP.BROWSE.PERSONAL.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.PERSONAL.SIDENAV_LINK.TOOLTIP",
"route": "personal-files",
@ -252,79 +211,181 @@
"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",
"rules": {
"visible": "app.isContentServiceEnabled"
},
"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",
"rules": {
"visible": "app.isContentServiceEnabled"
},
"items": [
{
"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.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": 200,
"icon": "schedule",
"order": 400,
"title": "APP.BROWSE.RECENT.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.RECENT.SIDENAV_LINK.TOOLTIP",
"route": "recent-files"
},
{
"id": "app.navbar.favorites",
"order": 300,
"icon": "star",
"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": 400,
"icon": "delete",
"order": 700,
"title": "APP.BROWSE.TRASHCAN.SIDENAV_LINK.LABEL",
"description": "APP.BROWSE.TRASHCAN.SIDENAV_LINK.TOOLTIP",
"route": "trashcan"
}
]
}
]
}
],
"toolbar": [
{
"id": "app.toolbar.create",
"type": "menu",
"order": 10,
"title": "APP.HEADER.BUTTONS.CREATE",
"description": "APP.HEADER.BUTTONS.CREATE_TOOLTIP",
"data": {
"menuType": "button"
},
"children": [
{
"id": "app.create.folder",
"order": 100,
"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": "app.navigation.folder.canCreate"
}
},
{
"id": "app.create.library",
"order": 200,
"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.create.fileFromTemplate",
"order": 300,
"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.create.folderFromTemplate",
"order": 400,
"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"
}
}
]
},
{
"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",

View File

@ -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,6 +424,12 @@
"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": {

View File

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="768px" height="64px" viewBox="0 0 768 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: sketchtool 63.1 (101010) - https://sketch.com -->
<title>F9486AC0-402C-4076-AD87-A8B3E339A00C</title>
<desc>Created with sketchtool.</desc>
<defs>
<rect id="path-1" x="0" y="0" width="1440" height="1024"></rect>
<linearGradient x1="39.5825108%" y1="4.36333766%" x2="2.76867691%" y2="43.9379266%" id="linearGradient-3">
<stop stop-color="#FB9729" offset="0%"></stop>
<stop stop-color="#FF6B00" offset="100%"></stop>
</linearGradient>
<linearGradient x1="39.5825108%" y1="4.41939366%" x2="2.76867691%" y2="43.9453727%" id="linearGradient-4">
<stop stop-color="#FB9729" offset="0%"></stop>
<stop stop-color="#FF6B00" offset="100%"></stop>
</linearGradient>
<linearGradient x1="39.5825108%" y1="4.41972419%" x2="2.76867691%" y2="43.9454166%" id="linearGradient-5">
<stop stop-color="#FB9729" offset="0%"></stop>
<stop stop-color="#FF6B00" offset="100%"></stop>
</linearGradient>
</defs>
<g id="1.-🎨-Styles-/-Atoms-/-Molecules-/-Compounds" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="08.5-Various-(Light)" transform="translate(-80.000000, -593.000000)">
<g id="Header" transform="translate(80.000000, 550.000000)">
<g id="3.-Layout/Desktop/Header/ADW/MastHead" transform="translate(0.000000, 43.000000)">
<g id="mastHead-bg-shapesPattern">
<g id="bgWallpaper-Pattern">
<g transform="translate(0.000000, -418.000000)" id="standards/bgWallpaper-ColCircles">
<g transform="translate(0.000000, 1.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="Mask"></g>
<g id="interectionsShapes" mask="url(#mask-2)">
<g transform="translate(-5874.000000, -2763.000000)" id="Group-2">
<g transform="translate(0.025102, 0.632890)">
<g id="masthead-v2" transform="translate(0.576046, 0.968258)">
<path d="M6137.3568,3265.15228 C6731.50498,3265.15228 7213.15725,2783.18681 7213.15725,2188.65228 C7213.15725,1594.11774 6731.50498,1112.15228 6137.3568,1112.15228 C5934.86387,1112.15228 5572.13069,1112.15228 5049.15725,1112.15228 C5057.42331,1636.08719 5061.55635,1994.92052 5061.55635,2188.65228 C5061.55635,2783.18681 5543.20862,3265.15228 6137.3568,3265.15228 Z" id="Petal-Blue" stroke="url(#linearGradient-3)" stroke-width="5" transform="translate(6131.157249, 2188.652277) rotate(-193.000000) translate(-6131.157249, -2188.652277) "></path>
<path d="M6047.87926,3281.34542 C6563.7778,3281.34542 6981.9962,2862.95552 6981.9962,2346.84542 C6981.9962,1830.73532 6563.7778,1412.34542 6047.87926,1412.34542 C5872.05476,1412.34542 5557.09374,1412.34542 5102.9962,1412.34542 C5110.17362,1867.16862 5113.76233,2178.66862 5113.76233,2346.84542 C5113.76233,2862.95552 5531.98072,3281.34542 6047.87926,3281.34542 Z" id="Petal-Green" stroke="#8BC34A" stroke-width="10" transform="translate(6042.496196, 2346.845419) rotate(-236.000000) translate(-6042.496196, -2346.845419) "></path>
<path d="M4476.11162,7601 C6211.88094,7601 7619,6193.83097 7619,4458 C7619,2722.16903 6211.88094,1315 4476.11162,1315 C3884.54032,1315 2824.83644,1315 1297,1315 C1321.14883,2844.705 1333.22325,3892.37167 1333.22325,4458 C1333.22325,6193.83097 2740.3423,7601 4476.11162,7601 Z" id="Petal-thin-orange" stroke="url(#linearGradient-4)" stroke-width="2" transform="translate(4458.000000, 4458.000000) rotate(-135.000000) translate(-4458.000000, -4458.000000) "></path>
<path d="M6722.92439,3755.28058 C7108.40685,3755.28058 7420.90213,3442.77534 7420.90213,3057.28058 C7420.90213,2671.78583 7108.40685,2359.28058 6722.92439,2359.28058 C6591.54728,2359.28058 6356.20653,2359.28058 6016.90213,2359.28058 C6022.26515,2698.99872 6024.94665,2931.66538 6024.94665,3057.28058 C6024.94665,3442.77534 6337.44193,3755.28058 6722.92439,3755.28058 Z" id="Petal-orange" stroke="url(#linearGradient-5)" stroke-width="23" transform="translate(6718.902134, 3057.280584) rotate(-57.000000) translate(-6718.902134, -3057.280584) "></path>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -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
});
}
}

View File

@ -22,7 +22,6 @@
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/
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',

View File

@ -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,

View File

@ -1,14 +1,4 @@
<ng-container>
<adf-content-user-info
*ngIf="mode === userInfoMode.CONTENT || mode === userInfoMode.CONTENT_SSO"
[ecmUser]="ecmUser$ | async"
[identityUser]="identityUser$ | async"
[isLoggedIn]="isLoggedIn"
[mode]="mode"
></adf-content-user-info>
<adf-identity-user-info
*ngIf="mode === userInfoMode.SSO"
[identityUser]="identityUser$ | async"
[isLoggedIn]="isLoggedIn"
></adf-identity-user-info>
</ng-container>
<button mat-menu-item [routerLink]="['/profile']" title="{{'APP.TOOLTIPS.MY_PROFILE' | translate}}">
<mat-icon>account_circle</mat-icon>
<span>{{ (displayName$ | async) }}</span>
</button>

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<UserInfoComponent>;
let authServiceStub: Partial<AuthenticationService>;
let peopleContentServiceStub: Partial<PeopleContentService>;
let identityUserServiceStub: Partial<PeopleContentService>;
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)');
});
});

View File

@ -22,21 +22,18 @@
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/
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<EcmUserModel>;
identityUser$: Observable<IdentityUserModel>;
selectedIndex: number;
userInfoMode = UserInfoMode;
displayName$: Observable<string>;
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() {

View File

@ -1,19 +0,0 @@
<adf-layout-header
[logo]="logo$ | async"
[redirectUrl]="landingPage"
[tooltip]="appName$ | async"
[color]="headerColor$ | async"
[title]="appName$ | async"
(clicked)="onToggleSidenav($event)"
[expandedSidenav]="isSidenavExpanded"
>
<div class="adf-toolbar--spacer adf-toolbar-divider"></div>
<aca-search-input *ngIf="isContentServiceEnabled()"></aca-search-input>
<adf-toolbar-divider></adf-toolbar-divider>
<ng-container *ngFor="let actionRef of actions; trackBy: trackByActionId">
<aca-toolbar-action [actionRef]="actionRef"> </aca-toolbar-action>
</ng-container>
</adf-layout-header>

View File

@ -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;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<AppHeaderComponent>;
const actions = [
{ id: 'action-1', type: 'button' },
{ id: 'action-2', type: 'button' }
] as Array<ContentActionRef>;
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();
});
});
});

View File

@ -1,45 +0,0 @@
<adf-upload-drag-area [rootFolderId]="currentFolderId" [disabled]="!canUpload">
<adf-sidenav-layout
#layout
[sidenavMin]="70"
[sidenavMax]="320"
[stepOver]="600"
[hideSidenav]="hideSidenav"
[expandedSidenav]="expandedSidenav"
(expanded)="onExpanded($event)"
>
<adf-sidenav-layout-header>
<ng-template let-isMenuMinimized="isMenuMinimized">
<app-header
*ngIf="!hideSidenav"
role="heading"
aria-level="1"
(toggleClicked)="layout.toggleMenu()"
[data]="{ layout }"
[expandedSidenav]="!isMenuMinimized()">
</app-header>
</ng-template>
</adf-sidenav-layout-header>
<adf-sidenav-layout-navigation>
<ng-template let-isMenuMinimized="isMenuMinimized">
<app-sidenav
[mode]="isMenuMinimized() ? 'collapsed' : 'expanded'"
[attr.data-automation-id]="isMenuMinimized() ? 'collapsed' : 'expanded'"
(swipeleft)="hideMenu($event)"
>
</app-sidenav>
</ng-template>
</adf-sidenav-layout-navigation>
<adf-sidenav-layout-content>
<ng-template>
<router-outlet></router-outlet>
</ng-template>
</adf-sidenav-layout-content>
</adf-sidenav-layout>
<adf-file-uploading-dialog *ngIf="showFileUploadingDialog" position="left"></adf-file-uploading-dialog>
</adf-upload-drag-area>
<router-outlet name="viewer"></router-outlet>

View File

@ -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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<AppLayoutComponent>;
let component: AppLayoutComponent;
let appConfig: AppConfigService;
let userPreference: UserPreferencesService;
let store: Store<AppStore>;
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);
});
});
});

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<boolean> = new Subject<boolean>();
isSmallScreen$: Observable<boolean>;
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<AppStore>,
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<boolean>('sideNav.expandedSidenav', true);
const preserveState = this.appConfigService.get<boolean>('sideNav.preserveState', true);
if (preserveState) {
return this.userPreferenceService.get('expandedSidenav', expand.toString()) === 'true';
}
return expand;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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 {}

View File

@ -1,30 +0,0 @@
<ng-container *ngIf="(mainAction$ | async) as action">
<ng-container [ngSwitch]="action.type">
<ng-container *ngSwitchCase="actionTypes.button">
<button
*ngIf="expanded"
mat-stroked-button
[id]="action.id"
(click)="runAction(action.actions.click)"
[disabled]="action.disabled"
class="app-main-action-button"
data-automation-id="app-main-action-button"
>
{{action.title | translate}}
</button>
<button
*ngIf="expanded === false"
mat-icon-button
[id]="action.id"
(click)="runAction(action.actions.click)"
[disabled]="action.disabled"
data-automation-id="app-main-action-icon"
title="{{ action.title| translate }}"
>
<mat-icon class="main-action-menu-icon">{{action.icon}}</mat-icon>
</button>
</ng-container>
</ng-container>
</ng-container>

View File

@ -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);
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<MainActionComponent>;
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();
});
});
});

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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 {}

View File

@ -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;

View File

@ -1,9 +1,9 @@
<div
class="app-search-container searchMenuTrigger"
<div class="app-search-container searchMenuTrigger"
[matMenuTriggerFor]="searchOptionsMenu"
(menuOpened)="onMenuOpened()"
(menuClosed)="syncInputValues()"
>
<button mat-icon-button class="app-search-button" (click)="searchByOption()" [title]="'SEARCH.BUTTON.TOOLTIP' | translate">
<mat-icon [attr.aria-label]="'SEARCH.BUTTON.ARIA-LABEL' | translate">search</mat-icon>
</button>
@ -20,6 +20,10 @@
<div matSuffix class="app-suffix-search-icon-wrapper">
<mat-icon>arrow_drop_down</mat-icon>
</div>
<button mat-icon-button matSuffix class="app-suffix-search-icon-wrapper app-close-icon" (click)="exitSearch()">
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
</div>

View File

@ -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 {

View File

@ -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<SearchInputComponent>;
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();
});
});
});

View File

@ -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<AppStore>,
private appHookService: AppHookService
private appHookService: AppHookService,
public searchInputService: SearchNavigationService
) {
this.searchOnChange = this.config.get<boolean>('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,8 +147,11 @@ export class SearchInputComponent implements OnInit, OnDestroy {
} else {
this.store.dispatch(new SnackbarErrorAction('APP.BROWSE.SEARCH.EMPTY_SEARCH'));
}
if (this.trigger) {
this.trigger.closeMenu();
}
}
onSearchChange(searchTerm: string) {
if (!this.searchOnChange) {

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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']);
});
});

View File

@ -22,16 +22,33 @@
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/
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']);
}
}

View File

@ -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]

View File

@ -1,6 +1,7 @@
<aca-page-layout>
<aca-page-layout-header>
<adf-breadcrumb root="APP.BROWSE.SEARCH.TITLE"> </adf-breadcrumb>
<aca-search-input></aca-search-input>
<div class="adf-toolbar--spacer adf-toolbar-divider"></div>
<adf-toolbar class="adf-toolbar--inline">
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>

View File

@ -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: {

View File

@ -27,9 +27,6 @@
<mat-panel-title>
<div class="item">
<button
[ngClass]="{
'action-button--active': acaExpansionPanel.hasActiveLinks()
}"
[attr.aria-label]="item.title | translate"
[id]="item.id"
[attr.title]="item.description | translate"

View File

@ -0,0 +1,20 @@
<div class="sidenav-header">
<div class="sidenav-header-title">
<div class="sidenav-header-title-logo"
(click)="toggleNavBar.emit()"
(keypress)="toggleNavBar.emit()">
<img
src="{{ logo$ | async }}"
title="{{'APP.TOOLTIPS.COLLAPSE_NAVIGATION' | translate}}"
alt="{{ 'CORE.HEADER.LOGO_ARIA' | translate }}" />
</div>
<div class="sidenav-header-title-text" [routerLink]="landingPage">
{{ appName$ | async | translate }}
</div>
<ng-container *ngFor="let actionRef of actions; trackBy: trackByActionId">
<aca-toolbar-action [actionRef]="actionRef"></aca-toolbar-action>
</ng-container>
</div>
</div>

View File

@ -22,55 +22,36 @@
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/
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<boolean> = new Subject<boolean>();
@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<boolean>();
appName$: Observable<string>;
headerColor$: Observable<any>;
headerTextColor$: Observable<string>;
logo$: Observable<string>;
landingPage: string;
actions: Array<ContentActionRef> = [];
constructor(public store: Store<AppStore>, private appExtensions: AppExtensionService, private appConfigService: AppConfigService) {
this.headerColor$ = store.select(getHeaderColor);
this.headerTextColor$ = store.select(getHeaderTextColor);
@Output()
toggleNavBar = new EventEmitter();
constructor(public store: Store<AppStore>, 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() {

View File

@ -1,3 +0,0 @@
<app-sidenav
[mode]="data.mode"
></app-sidenav>

View File

@ -1,36 +1,16 @@
<div class="sidenav">
<ng-container [ngSwitch]="mode">
<div class="section action-menu" [ngClass]="'section--' + mode">
<app-main-action [expanded]="mode === 'expanded'"></app-main-action>
<app-create-menu [expanded]="mode === 'expanded'"></app-create-menu>
</div>
<app-sidenav-header (toggleNavBar)="toggleClick()"></app-sidenav-header>
<div class="section-sub-actions">
<div *ngFor="let group of groups; trackBy: trackByGroupId" class="section" [ngClass]="'section--' + mode">
<ng-container *ngSwitchCase="'expanded'">
<div *ngFor="let group of groups; trackBy: trackByGroupId" class="section">
<mat-list-item *ngFor="let item of group.items; trackBy: trackByLinkId">
<ng-container *ngIf="!item.component">
<app-expand-menu [item]="item"></app-expand-menu>
</ng-container>
<ng-container *ngIf="item.component">
<adf-dynamic-component [data]="{ item: item, state: 'expanded' }" [id]="item.component"></adf-dynamic-component>
</ng-container>
</mat-list-item>
</ng-container>
<ng-container *ngSwitchCase="'collapsed'">
<div class="list-item" *ngFor="let item of group.items; trackBy: trackByLinkId">
<ng-container *ngIf="!item.component">
<app-button-menu [item]="item"></app-button-menu>
</ng-container>
<ng-container *ngIf="item.component">
<adf-dynamic-component [data]="{ item: item, state: 'collapsed' }" [id]="item.component"> </adf-dynamic-component>
</ng-container>
</div>
</ng-container>
</div>
</div>
</ng-container>
</div>

View File

@ -1,60 +1,110 @@
.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);
overflow-y: hidden;
background: var(--theme-sidenav-background-color);
.action-menu {
&-header {
padding: 32px 0;
&-title {
display: flex;
flex-direction: column;
justify-content: center;
align-items: stretch;
flex-direction: row;
align-items: center;
height: 32px;
padding: 0 24px;
&-logo {
img {
cursor: pointer;
height: 28px;
vertical-align: middle;
}
}
.section.action-menu {
padding: 8px 14px;
position: sticky;
&-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-sub-actions {
overflow-y: auto;
}
.section {
padding: 8px 6px;
border-bottom: 1px solid var(--theme-divider-color);
}
.section:last-child {
border-bottom: 0;
}
.section--collapsed {
display: flex;
flex-direction: column;
align-items: center;
}
.section-sub-actions {
overflow-y: auto;
.list-item {
padding: 12px 0;
.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;
height: 24px;
border: none;
}
.menu {
&-header:hover {
background: var(--theme-hover-background-color);
}
&-header-title {
display: flex;
flex: 1;
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 {
@ -63,89 +113,17 @@
}
.action-button--active {
color: var(--theme-primary-color) !important;
color: var(--theme-selected-text-color) !important;
background: var(--theme-selected-background-color);
}
.action-button {
color: var(--theme-text-color);
}
.action-panel-header {
color: var(--theme-action-button-text-color);
padding: 0 24px;
.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;
&__label {
font-size: var(--theme-caption-font-size);
}
}
.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);
}
}
[dir='rtl'] .sidenav {
/* stylelint-disable-next-line no-descending-specificity */
.mat-expansion-panel-header {
padding: 0 0 0 8px !important;
}
}

View File

@ -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<SidenavComponent>;
@ -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]
});

View File

@ -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<NavBarGroupRef> = [];
private onDestroy$ = new Subject<boolean>();
constructor(private store: Store<AppStore>, private extensions: AppExtensionService) {}
constructor(private store: Store<AppStore>, 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();

View File

@ -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,

View File

@ -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]

View File

@ -1089,7 +1089,7 @@ export class ContentManagementService {
private focusAfterClose(focusedElementSelector: string): void {
if (focusedElementSelector) {
document.querySelector<HTMLElement>(focusedElementSelector).focus();
document.querySelector<HTMLElement>(focusedElementSelector)?.focus();
}
}
}

View File

@ -700,7 +700,7 @@ export class NodeActionsService {
private focusAfterClose(focusedElementSelector: string): void {
if (focusedElementSelector) {
document.querySelector<HTMLElement>(focusedElementSelector).focus();
document.querySelector<HTMLElement>(focusedElementSelector)?.focus();
}
}
}

View File

@ -164,7 +164,7 @@ export class DownloadEffects {
private focusAfterClose(focusedElementSelector: string): void {
if (focusedElementSelector) {
document.querySelector<HTMLElement>(focusedElementSelector).focus();
document.querySelector<HTMLElement>(focusedElementSelector)?.focus();
}
}
}

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