From 09aeeff204a632a9a9ccb0e309062437ca083b2f Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 23 Apr 2018 12:21:41 +0100 Subject: [PATCH 001/179] initial e2e integration (#329) * e2e integration with ci * update travis config * try always build image * build the app in production mode * try to stop previous * stop default postgresql service * try upgrade selenium-webdriver * disable Gecko for webdriver-manager * use stable chrome and latest protractor --- .travis.yml | 13 +- e2e/components/component.ts | 43 + e2e/components/components.ts | 32 + e2e/components/data-table/data-table.ts | 243 ++++++ .../dialog/create-edit-folder-dialog.ts | 108 +++ e2e/components/header/header.ts | 42 + e2e/components/header/user-info.ts | 64 ++ e2e/components/login/login.ts | 105 +++ e2e/components/menu/menu.ts | 106 +++ e2e/components/pagination/pagination.ts | 98 +++ e2e/components/sidenav/sidenav.ts | 82 ++ e2e/components/toolbar/toolbar-actions.ts | 64 ++ e2e/components/toolbar/toolbar-breadcrumb.ts | 82 ++ e2e/components/toolbar/toolbar.ts | 42 + e2e/configs.ts | 78 ++ e2e/pages/browsing-page.ts | 40 + e2e/pages/login-page.ts | 75 ++ e2e/pages/logout-page.ts | 43 + e2e/pages/page.ts | 110 +++ e2e/pages/pages.ts | 28 + e2e/suites/actions/create-folder.test.ts | 278 +++++++ e2e/suites/actions/delete.test.ts | 503 ++++++++++++ e2e/suites/actions/edit-folder.test.ts | 187 +++++ e2e/suites/actions/mark-favorite.test.ts | 419 ++++++++++ e2e/suites/actions/permanently-delete.test.ts | 122 +++ e2e/suites/actions/restore.test.ts | 268 +++++++ .../toolbar-multiple-selection.test.ts | 543 +++++++++++++ .../actions/toolbar-single-selection.test.ts | 752 ++++++++++++++++++ e2e/suites/actions/undo-delete.test.ts | 423 ++++++++++ e2e/suites/actions/upload-file.test.ts | 74 ++ e2e/suites/application/page-titles.test.ts | 128 +++ e2e/suites/authentication/login.test.ts | 237 ++++++ e2e/suites/authentication/logout.test.ts | 82 ++ e2e/suites/list-views/empty-list.test.ts | 108 +++ e2e/suites/list-views/favorites.test.ts | 156 ++++ e2e/suites/list-views/file-libraries.test.ts | 161 ++++ e2e/suites/list-views/permissions.test.ts | 181 +++++ e2e/suites/list-views/personal-files.test.ts | 176 ++++ e2e/suites/list-views/recent-files.test.ts | 141 ++++ e2e/suites/list-views/shared-files.test.ts | 142 ++++ e2e/suites/list-views/tooltips.test.ts | 330 ++++++++ e2e/suites/list-views/trash.test.ts | 169 ++++ e2e/suites/navigation/breadcrumb.test.ts | 244 ++++++ e2e/suites/navigation/sidebar.test.ts | 139 ++++ e2e/suites/pagination/pag-favorites.test.ts | 228 ++++++ .../pagination/pag-personal-files.test.ts | 228 ++++++ .../pagination/pag-recent-files.test.ts | 230 ++++++ .../pagination/pag-shared-files.test.ts | 236 ++++++ e2e/suites/pagination/pag-trash.test.ts | 233 ++++++ e2e/tsconfig.e2e.json | 0 .../apis/favorites/favorites-api.ts | 118 +++ .../apis/nodes/node-body-create.ts | 38 + .../apis/nodes/node-content-tree.ts | 85 ++ .../repo-client/apis/nodes/nodes-api.ts | 182 +++++ .../apis/people/people-api-models.ts | 43 + .../repo-client/apis/people/people-api.ts | 70 ++ e2e/utilities/repo-client/apis/repo-api.ts | 71 ++ .../repo-client/apis/search/search-api.ts | 71 ++ .../apis/shared-links/shared-links-api.ts | 79 ++ .../apis/sites/sites-api-models.ts | 42 + .../repo-client/apis/sites/sites-api.ts | 124 +++ .../repo-client/apis/trashcan/trashcan-api.ts | 76 ++ .../repo-client/repo-client-models.ts | 46 ++ e2e/utilities/repo-client/repo-client.ts | 59 ++ .../reporters/console/console-logger.ts | 79 ++ e2e/utilities/reporters/console/console.ts | 90 +++ .../rest-client/rest-client-models.ts | 63 ++ e2e/utilities/rest-client/rest-client.ts | 89 +++ e2e/utilities/utils.ts | 73 ++ package-lock.json | 509 ++++++++---- package.json | 19 +- protractor.conf.js | 12 +- 72 files changed, 10493 insertions(+), 161 deletions(-) create mode 100755 e2e/components/component.ts create mode 100755 e2e/components/components.ts create mode 100755 e2e/components/data-table/data-table.ts create mode 100755 e2e/components/dialog/create-edit-folder-dialog.ts create mode 100755 e2e/components/header/header.ts create mode 100755 e2e/components/header/user-info.ts create mode 100755 e2e/components/login/login.ts create mode 100755 e2e/components/menu/menu.ts create mode 100755 e2e/components/pagination/pagination.ts create mode 100755 e2e/components/sidenav/sidenav.ts create mode 100755 e2e/components/toolbar/toolbar-actions.ts create mode 100755 e2e/components/toolbar/toolbar-breadcrumb.ts create mode 100755 e2e/components/toolbar/toolbar.ts create mode 100755 e2e/configs.ts create mode 100755 e2e/pages/browsing-page.ts create mode 100755 e2e/pages/login-page.ts create mode 100755 e2e/pages/logout-page.ts create mode 100755 e2e/pages/page.ts create mode 100755 e2e/pages/pages.ts create mode 100755 e2e/suites/actions/create-folder.test.ts create mode 100755 e2e/suites/actions/delete.test.ts create mode 100755 e2e/suites/actions/edit-folder.test.ts create mode 100644 e2e/suites/actions/mark-favorite.test.ts create mode 100755 e2e/suites/actions/permanently-delete.test.ts create mode 100755 e2e/suites/actions/restore.test.ts create mode 100755 e2e/suites/actions/toolbar-multiple-selection.test.ts create mode 100755 e2e/suites/actions/toolbar-single-selection.test.ts create mode 100755 e2e/suites/actions/undo-delete.test.ts create mode 100755 e2e/suites/actions/upload-file.test.ts create mode 100755 e2e/suites/application/page-titles.test.ts create mode 100755 e2e/suites/authentication/login.test.ts create mode 100755 e2e/suites/authentication/logout.test.ts create mode 100755 e2e/suites/list-views/empty-list.test.ts create mode 100755 e2e/suites/list-views/favorites.test.ts create mode 100755 e2e/suites/list-views/file-libraries.test.ts create mode 100755 e2e/suites/list-views/permissions.test.ts create mode 100755 e2e/suites/list-views/personal-files.test.ts create mode 100755 e2e/suites/list-views/recent-files.test.ts create mode 100755 e2e/suites/list-views/shared-files.test.ts create mode 100755 e2e/suites/list-views/tooltips.test.ts create mode 100755 e2e/suites/list-views/trash.test.ts create mode 100755 e2e/suites/navigation/breadcrumb.test.ts create mode 100755 e2e/suites/navigation/sidebar.test.ts create mode 100755 e2e/suites/pagination/pag-favorites.test.ts create mode 100755 e2e/suites/pagination/pag-personal-files.test.ts create mode 100755 e2e/suites/pagination/pag-recent-files.test.ts create mode 100755 e2e/suites/pagination/pag-shared-files.test.ts create mode 100755 e2e/suites/pagination/pag-trash.test.ts mode change 100644 => 100755 e2e/tsconfig.e2e.json create mode 100755 e2e/utilities/repo-client/apis/favorites/favorites-api.ts create mode 100755 e2e/utilities/repo-client/apis/nodes/node-body-create.ts create mode 100755 e2e/utilities/repo-client/apis/nodes/node-content-tree.ts create mode 100755 e2e/utilities/repo-client/apis/nodes/nodes-api.ts create mode 100755 e2e/utilities/repo-client/apis/people/people-api-models.ts create mode 100755 e2e/utilities/repo-client/apis/people/people-api.ts create mode 100755 e2e/utilities/repo-client/apis/repo-api.ts create mode 100755 e2e/utilities/repo-client/apis/search/search-api.ts create mode 100755 e2e/utilities/repo-client/apis/shared-links/shared-links-api.ts create mode 100755 e2e/utilities/repo-client/apis/sites/sites-api-models.ts create mode 100755 e2e/utilities/repo-client/apis/sites/sites-api.ts create mode 100755 e2e/utilities/repo-client/apis/trashcan/trashcan-api.ts create mode 100755 e2e/utilities/repo-client/repo-client-models.ts create mode 100755 e2e/utilities/repo-client/repo-client.ts create mode 100755 e2e/utilities/reporters/console/console-logger.ts create mode 100755 e2e/utilities/reporters/console/console.ts create mode 100755 e2e/utilities/rest-client/rest-client-models.ts create mode 100755 e2e/utilities/rest-client/rest-client.ts create mode 100755 e2e/utilities/utils.ts mode change 100644 => 100755 protractor.conf.js diff --git a/.travis.yml b/.travis.yml index 11e39bebb6..f97f4facde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,24 @@ dist: trusty sudo: required +services: + - docker + +addons: + chrome: stable + language: node_js node_js: - "8" +before_script: + # Disable services enabled by default + - sudo /etc/init.d/postgresql stop + install: - npm install -g npm@latest - npm ci script: - - npm run test:ci + # - docker-compose stop + - npm run build && npm run e2e:docker diff --git a/e2e/components/component.ts b/e2e/components/component.ts new file mode 100755 index 0000000000..134287c0c5 --- /dev/null +++ b/e2e/components/component.ts @@ -0,0 +1,43 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, element, by, ExpectedConditions as EC, browser } from 'protractor'; +import { BROWSER_WAIT_TIMEOUT } from '../configs'; + +export abstract class Component { + component: ElementFinder; + + constructor(selector: string, ancestor?: ElementFinder) { + const locator = by.css(selector); + + this.component = ancestor + ? ancestor.element(locator) + : element(locator); + } + + wait() { + return browser.wait(EC.presenceOf(this.component), BROWSER_WAIT_TIMEOUT); + } +} diff --git a/e2e/components/components.ts b/e2e/components/components.ts new file mode 100755 index 0000000000..604be941d1 --- /dev/null +++ b/e2e/components/components.ts @@ -0,0 +1,32 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +export * from './login/login'; +export * from './header/header'; +export * from './header/user-info'; +export * from './data-table/data-table'; +export * from './pagination/pagination'; +export * from './sidenav/sidenav'; +export * from './toolbar/toolbar'; diff --git a/e2e/components/data-table/data-table.ts b/e2e/components/data-table/data-table.ts new file mode 100755 index 0000000000..1bf8de8167 --- /dev/null +++ b/e2e/components/data-table/data-table.ts @@ -0,0 +1,243 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, ElementArrayFinder, promise, by, browser, ExpectedConditions as EC, protractor } from 'protractor'; +import { BROWSER_WAIT_TIMEOUT } from '../../configs'; +import { Component } from '../component'; +import { Utils } from '../../utilities/utils'; + +export class DataTable extends Component { + private static selectors = { + root: 'adf-datatable', + + head: '.adf-datatable-header', + columnHeader: '.adf-datatable-row .adf-datatable-table-cell-header', + sortedColumnHeader: ` + .adf-data-table__header--sorted-asc, + .adf-data-table__header--sorted-desc + `, + + body: '.adf-datatable-body', + row: '.adf-datatable-row[role]', + selectedRow: '.adf-datatable-row.is-selected', + cell: '.adf-data-table-cell', + locationLink: 'app-location-link', + + selectedIcon: '.mat-icon', + + emptyListContainer: 'div.adf-no-content-container', + emptyFolderDragAndDrop: '.adf-empty-list_template .adf-empty-folder', + + emptyListTitle: '.app-empty-folder__title', + emptyListSubtitle: '.app-empty-folder__subtitle', + emptyListText: '.app-empty-folder__text' + }; + + head: ElementFinder = this.component.element(by.css(DataTable.selectors.head)); + body: ElementFinder = this.component.element(by.css(DataTable.selectors.body)); + cell = by.css(DataTable.selectors.cell); + locationLink = by.css(DataTable.selectors.locationLink); + emptyList: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyListContainer)); + emptyFolderDragAndDrop: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyFolderDragAndDrop)); + emptyListTitle: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyListTitle)); + emptyListSubtitle: ElementFinder = this.component.element(by.css(DataTable.selectors.emptyListSubtitle)); + emptyListText: ElementArrayFinder = this.component.all(by.css(DataTable.selectors.emptyListText)); + + constructor(ancestor?: ElementFinder) { + super(DataTable.selectors.root, ancestor); + } + + // Wait methods (waits for elements) + waitForHeader() { + return browser.wait(EC.presenceOf(this.head), BROWSER_WAIT_TIMEOUT); + } + + waitForEmptyState() { + return browser.wait(EC.presenceOf(this.emptyList), BROWSER_WAIT_TIMEOUT); + } + + // Header/Column methods + getColumnHeaders(): ElementArrayFinder { + const locator = by.css(DataTable.selectors.columnHeader); + return this.head.all(locator); + } + + getNthColumnHeader(nth: number): ElementFinder { + return this.getColumnHeaders().get(nth - 1); + } + + getColumnHeaderByLabel(label: string): ElementFinder { + const locator = by.cssContainingText(DataTable.selectors.columnHeader, label); + return this.head.element(locator); + } + + getSortedColumnHeader(): ElementFinder { + const locator = by.css(DataTable.selectors.sortedColumnHeader); + return this.head.element(locator); + } + + getSortingOrder() { + return this.getSortedColumnHeader().getAttribute('class') + .then(str => { + if (str.includes('asc')) { + return 'asc'; + } else { + if (str.includes('desc')) { + return 'desc'; + } + } + }); + } + + sortByColumn(columnName: string): promise.Promise { + const column = this.getColumnHeaderByLabel(columnName); + const click = browser.actions().mouseMove(column).click(); + + return click.perform(); + } + + // Rows methods + getRows(): ElementArrayFinder { + return this.body.all(by.css(DataTable.selectors.row)); + } + + getSelectedRows(): ElementArrayFinder { + return this.body.all(by.css(DataTable.selectors.selectedRow)); + } + + countSelectedRows(): promise.Promise { + return this.getSelectedRows().count(); + } + + getNthRow(nth: number): ElementFinder { + return this.getRows().get(nth - 1); + } + + getRowName(name: string): ElementFinder { + return this.body.element(by.cssContainingText(`.adf-data-table-cell span`, name)); + } + + getItemNameTooltip(name: string): promise.Promise { + return this.getRowName(name).getAttribute('title'); + } + + countRows(): promise.Promise { + return this.getRows().count(); + } + + hasCheckMarkIcon(itemName: string) { + return this.getRowName(itemName).element(by.xpath(`./ancestor::div[contains(@class, 'adf-datatable-row')]`)) + .element(by.css(DataTable.selectors.selectedIcon)).isPresent(); + } + + // Navigation/selection methods + doubleClickOnItemName(name: string): promise.Promise { + const dblClick = browser.actions() + .mouseMove(this.getRowName(name)) + .click() + .click(); + + return dblClick.perform(); + } + + clickOnItemName(name: string): promise.Promise { + const item = this.getRowName(name); + return Utils.waitUntilElementClickable(item) + .then(() => this.getRowName(name).click()); + } + + selectMultipleItems(names: string[]): promise.Promise { + return this.clearSelection() + .then(() => browser.actions().sendKeys(protractor.Key.COMMAND).perform()) + .then(() => { + names.forEach(name => { + this.clickOnItemName(name); + }); + }) + .then(() => browser.actions().sendKeys(protractor.Key.NULL).perform()); + } + + clearSelection(): promise.Promise { + return this.getSelectedRows().count() + .then(count => { + if (count !== 0) { browser.refresh().then(() => this.waitForHeader()); } + }); + } + + getItemLocation(name: string) { + return this.getRowName(name).element(by.xpath(`./ancestor::div[contains(@class, 'adf-datatable-row')]`)) + .element(this.locationLink); + } + + getItemLocationTooltip(name: string): promise.Promise { + return this.getItemLocation(name).$('a').getAttribute('title'); + } + + clickItemLocation(name: string) { + return this.getItemLocation(name).click(); + } + + // empty state methods + isEmptyList(): promise.Promise { + return this.emptyList.isPresent(); + } + + isEmptyWithDragAndDrop(): promise.Promise { + return this.emptyFolderDragAndDrop.isDisplayed(); + } + + getEmptyDragAndDropText(): promise.Promise { + return this.isEmptyWithDragAndDrop() + .then(() => { + return this.emptyFolderDragAndDrop.getText(); + }); + } + + getEmptyStateTitle(): promise.Promise { + return this.isEmptyList() + .then(() => { + return this.emptyListTitle.getText(); + }); + } + + getEmptyStateSubtitle(): promise.Promise { + return this.isEmptyList() + .then(() => { + return this.emptyListSubtitle.getText(); + }); + } + + getEmptyStateText(): promise.Promise { + return this.isEmptyList() + .then(() => { + return this.emptyListText.getText(); + }); + } + + getCellsContainingName(name: string) { + return this.getRows().all(by.cssContainingText(DataTable.selectors.cell, name)) + .map(cell => cell.getText()); + } +} diff --git a/e2e/components/dialog/create-edit-folder-dialog.ts b/e2e/components/dialog/create-edit-folder-dialog.ts new file mode 100755 index 0000000000..696746e63d --- /dev/null +++ b/e2e/components/dialog/create-edit-folder-dialog.ts @@ -0,0 +1,108 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, by, browser, protractor, ExpectedConditions as EC, promise } from 'protractor'; +import { BROWSER_WAIT_TIMEOUT } from '../../configs'; +import { Component } from '../component'; +import { Utils } from '../../utilities/utils'; + +export class CreateOrEditFolderDialog extends Component { + private static selectors = { + root: 'adf-folder-dialog', + + title: '.mat-dialog-title', + nameInput: 'input[placeholder="Name" i]', + descriptionTextArea: 'textarea[placeholder="Description" i]', + button: '.mat-dialog-actions button', + validationMessage: '.mat-hint span' + }; + + title: ElementFinder = this.component.element(by.css(CreateOrEditFolderDialog.selectors.title)); + nameInput: ElementFinder = this.component.element(by.css(CreateOrEditFolderDialog.selectors.nameInput)); + descriptionTextArea: ElementFinder = this.component.element(by.css(CreateOrEditFolderDialog.selectors.descriptionTextArea)); + createButton: ElementFinder = this.component.element(by.cssContainingText(CreateOrEditFolderDialog.selectors.button, 'Create')); + cancelButton: ElementFinder = this.component.element(by.cssContainingText(CreateOrEditFolderDialog.selectors.button, 'Cancel')); + updateButton: ElementFinder = this.component.element(by.cssContainingText(CreateOrEditFolderDialog.selectors.button, 'Update')); + validationMessage: ElementFinder = this.component.element(by.css(CreateOrEditFolderDialog.selectors.validationMessage)); + + constructor(ancestor?: ElementFinder) { + super(CreateOrEditFolderDialog.selectors.root, ancestor); + } + + waitForDialogToOpen() { + return browser.wait(EC.presenceOf(this.title), BROWSER_WAIT_TIMEOUT) + .then(() => browser.wait(EC.presenceOf(browser.element(by.css('.cdk-overlay-backdrop'))), BROWSER_WAIT_TIMEOUT)); + + } + + waitForDialogToClose() { + return browser.wait(EC.stalenessOf(this.title), BROWSER_WAIT_TIMEOUT); + } + + getTitle(): promise.Promise { + return this.title.getText(); + } + + isValidationMessageDisplayed(): promise.Promise { + return this.validationMessage.isDisplayed(); + } + + getValidationMessage(): promise.Promise { + return this.isValidationMessageDisplayed() + .then(() => this.validationMessage.getText()); + } + + enterName(name: string) { + return this.nameInput.clear() + // .then(() => this.nameInput.sendKeys(name)); + .then(() => Utils.typeInField(this.nameInput, name)); + } + + enterDescription(description: string) { + return this.descriptionTextArea.clear() + // .then(() => this.descriptionTextArea.sendKeys(description)); + .then(() => Utils.typeInField(this.descriptionTextArea, description)); + } + + deleteNameWithBackspace(): promise.Promise { + return this.nameInput.clear() + .then(() => { + return this.nameInput.sendKeys(' ', protractor.Key.CONTROL, 'a', protractor.Key.NULL, protractor.Key.BACK_SPACE); + }); + } + + clickCreate() { + return this.createButton.click(); + } + + clickCancel() { + return this.cancelButton.click() + .then(() => this.waitForDialogToClose()); + } + + clickUpdate() { + return this.updateButton.click(); + } +} diff --git a/e2e/components/header/header.ts b/e2e/components/header/header.ts new file mode 100755 index 0000000000..ef151d54d9 --- /dev/null +++ b/e2e/components/header/header.ts @@ -0,0 +1,42 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, by } from 'protractor'; +import { Component } from '../component'; +import { UserInfo } from './user-info'; + +export class Header extends Component { + private locators = { + logoLink: by.css('.app-menu__title'), + userInfo: by.css('app-current-user') + }; + + logoLink: ElementFinder = this.component.element(this.locators.logoLink); + userInfo: UserInfo = new UserInfo(this.component); + + constructor(ancestor?: ElementFinder) { + super('app-header', ancestor); + } +} diff --git a/e2e/components/header/user-info.ts b/e2e/components/header/user-info.ts new file mode 100755 index 0000000000..b5e8400801 --- /dev/null +++ b/e2e/components/header/user-info.ts @@ -0,0 +1,64 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, by, promise } from 'protractor'; +import { Menu } from '../menu/menu'; +import { Component } from '../component'; + +export class UserInfo extends Component { + private locators = { + avatar: by.css('.current-user__avatar'), + fullName: by.css('.current-user__full-name'), + menuItems: by.css('[mat-menu-item]') + }; + + fullName: ElementFinder = this.component.element(this.locators.fullName); + avatar: ElementFinder = this.component.element(this.locators.avatar); + + menu: Menu = new Menu(); + + constructor(ancestor?: ElementFinder) { + super('app-current-user', ancestor); + } + + openMenu(): promise.Promise { + const { menu, avatar } = this; + + return avatar.click() + .then(() => menu.wait()) + .then(() => menu); + } + + get name(): promise.Promise { + return this.fullName.getText(); + } + + signOut(): promise.Promise { + return this.openMenu() + .then(menu => { + menu.clickMenuItem('Sign out'); + }); + } +} diff --git a/e2e/components/login/login.ts b/e2e/components/login/login.ts new file mode 100755 index 0000000000..5b6a306a84 --- /dev/null +++ b/e2e/components/login/login.ts @@ -0,0 +1,105 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { by, ElementFinder, promise } from 'protractor'; +import { Component } from '../component'; + +export class LoginComponent extends Component { + static selector = 'adf-login'; + + private locators = { + usernameInput: by.css('input#username'), + passwordInput: by.css('input#password'), + passwordVisibility: by.css('.adf-login-password-icon'), + submitButton: by.css('button#login-button'), + errorMessage: by.css('.login-error-message'), + copyright: by.css('.copyright') + }; + + usernameInput: ElementFinder = this.component.element(this.locators.usernameInput); + passwordInput: ElementFinder = this.component.element(this.locators.passwordInput); + submitButton: ElementFinder = this.component.element(this.locators.submitButton); + errorMessage: ElementFinder = this.component.element(this.locators.errorMessage); + copyright: ElementFinder = this.component.element(this.locators.copyright); + passwordVisibility: ElementFinder = this.component.element(this.locators.passwordVisibility); + + constructor(ancestor?: ElementFinder) { + super(LoginComponent.selector, ancestor); + } + + enterUsername(username: string): LoginComponent { + const { usernameInput } = this; + + usernameInput.clear(); + usernameInput.sendKeys(username); + + return this; + } + + enterPassword(password: string): LoginComponent { + const { passwordInput } = this; + + passwordInput.clear(); + passwordInput.sendKeys(password); + + return this; + } + + enterCredentials(username: string, password: string) { + this.enterUsername(username).enterPassword(password); + + return this; + } + + submit(): promise.Promise { + return this.submitButton.click(); + } + + getPasswordVisibility() { + return this.passwordVisibility.getText() + .then(text => { + if (text.endsWith('visibility_off')) { + return false; + } else { + if (text.endsWith('visibility')) { + return true; + } + } + }); + } + + isPasswordShown() { + return this.passwordInput.getAttribute('type') + .then(type => { + if (type === 'text') { + return true; + } else { + if (type === 'password') { + return false; + } + } + }); + } +} diff --git a/e2e/components/menu/menu.ts b/e2e/components/menu/menu.ts new file mode 100755 index 0000000000..ba6796a8c0 --- /dev/null +++ b/e2e/components/menu/menu.ts @@ -0,0 +1,106 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, ElementArrayFinder, by, browser, ExpectedConditions as EC, promise } from 'protractor'; +import { BROWSER_WAIT_TIMEOUT } from '../../configs'; +import { Component } from '../component'; + +export class Menu extends Component { + private static selectors = { + root: '.mat-menu-panel', + item: '.mat-menu-item', + icon: '.mat-icon', + uploadFiles: 'input[id="upload-multiple-files"]' + }; + + items: ElementArrayFinder = this.component.all(by.css(Menu.selectors.item)); + backdrop: ElementFinder = browser.element(by.css('.cdk-overlay-backdrop')); + uploadFiles: ElementFinder = this.component.element(by.css(Menu.selectors.uploadFiles)); + + constructor(ancestor?: ElementFinder) { + super(Menu.selectors.root, ancestor); + } + + waitForMenuToOpen() { + return browser.wait(EC.presenceOf(browser.element(by.css('.mat-menu-panel'))), BROWSER_WAIT_TIMEOUT) + .then(() => browser.wait(EC.presenceOf(browser.element(by.css('.cdk-overlay-backdrop'))), BROWSER_WAIT_TIMEOUT)) + .then(() => browser.wait(EC.visibilityOf(this.items.get(0)), BROWSER_WAIT_TIMEOUT)); + } + + waitForMenuToClose() { + return browser.wait(EC.not(EC.presenceOf(browser.element(by.css('.mat-menu-panel')))), BROWSER_WAIT_TIMEOUT); + } + + closeMenu() { + if (this.backdrop.isPresent()) { + return this.backdrop.click(); + } else { + return browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform(); + } + } + + getNthItem(nth: number): ElementFinder { + return this.items.get(nth - 1); + } + + getItemByLabel(menuItem: string): ElementFinder { + return this.component.element(by.cssContainingText(Menu.selectors.item, menuItem)); + } + + getItemTooltip(menuItem: string): promise.Promise { + return this.getItemByLabel(menuItem).getAttribute('title'); + } + + getItemIconText(menuItem: string) { + return this.getItemByLabel(menuItem).element(by.css(Menu.selectors.icon)).getText(); + + } + + getItemsCount(): promise.Promise { + return this.items.count(); + } + + clickNthItem(nth: number): promise.Promise { + const elem = this.getNthItem(nth); + return browser.wait(EC.elementToBeClickable(elem), BROWSER_WAIT_TIMEOUT) + .then(() => browser.actions().mouseMove(elem).click().perform()) + .then(() => this.waitForMenuToClose()); + } + + clickMenuItem(menuItem: string): promise.Promise { + const elem = this.getItemByLabel(menuItem); + return browser.wait(EC.elementToBeClickable(elem), BROWSER_WAIT_TIMEOUT) + .then(() => elem.click()) + .then(() => this.waitForMenuToClose()); + } + + isMenuItemPresent(title: string): promise.Promise { + return this.component.element(by.cssContainingText(Menu.selectors.item, title)).isPresent(); + } + + uploadFile() { + return this.uploadFiles; + } +} diff --git a/e2e/components/pagination/pagination.ts b/e2e/components/pagination/pagination.ts new file mode 100755 index 0000000000..47a07dd853 --- /dev/null +++ b/e2e/components/pagination/pagination.ts @@ -0,0 +1,98 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, promise, by } from 'protractor'; +import { Menu } from '../menu/menu'; +import { Component } from '../component'; + +export class Pagination extends Component { + private static selectors = { + root: 'adf-pagination', + range: '.adf-pagination__range', + maxItems: '.adf-pagination__max-items', + currentPage: '.adf-pagination__current-page', + totalPages: '.adf-pagination__total-pages', + + previousButton: '.adf-pagination__previous-button', + nextButton: '.adf-pagination__next-button', + maxItemsButton: '.adf-pagination__max-items + button[mat-icon-button]', + pagesButton: '.adf-pagination__current-page + button[mat-icon-button]' + }; + + range: ElementFinder = this.component.element(by.css(Pagination.selectors.range)); + maxItems: ElementFinder = this.component.element(by.css(Pagination.selectors.maxItems)); + currentPage: ElementFinder = this.component.element(by.css(Pagination.selectors.currentPage)); + totalPages: ElementFinder = this.component.element(by.css(Pagination.selectors.totalPages)); + previousButton: ElementFinder = this.component.element(by.css(Pagination.selectors.previousButton)); + nextButton: ElementFinder = this.component.element(by.css(Pagination.selectors.nextButton)); + maxItemsButton: ElementFinder = this.component.element(by.css(Pagination.selectors.maxItemsButton)); + pagesButton: ElementFinder = this.component.element(by.css(Pagination.selectors.pagesButton)); + + menu: Menu = new Menu(); + + constructor(ancestor?: ElementFinder) { + super(Pagination.selectors.root, ancestor); + } + + openMaxItemsMenu(): promise.Promise { + const { menu, maxItemsButton } = this; + + return maxItemsButton.click() + .then(() => menu.waitForMenuToOpen()) + .then(() => menu); + } + + openCurrentPageMenu(): promise.Promise { + const { menu, pagesButton } = this; + + return pagesButton.click() + .then(() => menu.waitForMenuToOpen()) + .then(() => menu); + } + + getText(elem: ElementFinder) { + return elem.getText(); + } + + resetToDefaultPageSize(): promise.Promise { + return this.openMaxItemsMenu() + .then(menu => menu.clickMenuItem('25')) + .then(() => this.menu.waitForMenuToClose()); + } + + resetToDefaultPageNumber(): promise.Promise { + return this.openCurrentPageMenu() + .then(menu => menu.clickMenuItem('1')) + .then(() => this.menu.waitForMenuToClose()); + } + + clickNext(): promise.Promise { + return this.nextButton.click(); + } + + clickPrevious(): promise.Promise { + return this.previousButton.click(); + } +} diff --git a/e2e/components/sidenav/sidenav.ts b/e2e/components/sidenav/sidenav.ts new file mode 100755 index 0000000000..53d4baf84e --- /dev/null +++ b/e2e/components/sidenav/sidenav.ts @@ -0,0 +1,82 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, ElementArrayFinder, by, promise } from 'protractor'; +import { Menu } from '../menu/menu'; +import { Component } from '../component'; + +export class Sidenav extends Component { + private static selectors = { + root: 'app-sidenav', + link: '.sidenav-menu__item', + label: '.menu__item--label', + activeLink: '.menu__item--active', + newButton: '.sidenav__section--new__button' + }; + + links: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.link)); + activeLink: ElementFinder = this.component.element(by.css(Sidenav.selectors.activeLink)); + newButton: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.newButton)); + + menu: Menu = new Menu(); + + constructor(ancestor?: ElementFinder) { + super(Sidenav.selectors.root, ancestor); + } + + openNewMenu(): promise.Promise { + const { menu, newButton } = this; + + return newButton.click() + .then(() => menu.waitForMenuToOpen()) + .then(() => menu); + } + + openCreateDialog(): any { + return this.openNewMenu() + .then(() => this.menu.clickMenuItem('Create folder')); + } + + isActiveByLabel(label: string): promise.Promise { + return this.getLinkByLabel(label).getAttribute('class') + .then(className => className.includes(Sidenav.selectors.activeLink.replace('.', ''))); + } + + getLink(label: string): ElementFinder { + return this.component.element(by.cssContainingText(Sidenav.selectors.link, label)); + } + + getLinkByLabel(label: string): ElementFinder { + return this.component.element(by.cssContainingText(Sidenav.selectors.label, label)); + } + + getLinkTooltip(label: string): promise.Promise { + return this.getLink(label).getAttribute('title'); + } + + navigateToLinkByLabel(label: string): promise.Promise { + return this.getLinkByLabel(label).click(); + } +} diff --git a/e2e/components/toolbar/toolbar-actions.ts b/e2e/components/toolbar/toolbar-actions.ts new file mode 100755 index 0000000000..6847a306de --- /dev/null +++ b/e2e/components/toolbar/toolbar-actions.ts @@ -0,0 +1,64 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, ElementArrayFinder, by, promise } from 'protractor'; +import { Menu } from '../menu/menu'; +import { Component } from '../component'; + +export class ToolbarActions extends Component { + private static selectors = { + root: 'adf-toolbar', + button: '.mat-icon-button' + }; + + menu: Menu = new Menu(); + buttons: ElementArrayFinder = this.component.all(by.css(ToolbarActions.selectors.button)); + + constructor(ancestor?: ElementFinder) { + super(ToolbarActions.selectors.root, ancestor); + } + + isEmpty(): promise.Promise { + return this.buttons.count().then(count => (count === 0)); + } + + isButtonPresent(title: string): promise.Promise { + return this.component.element(by.css(`${ToolbarActions.selectors.button}[title="${title}"]`)).isPresent(); + } + + getButtonByLabel(label: string): ElementFinder { + return this.component.element(by.cssContainingText(ToolbarActions.selectors.button, label)); + } + + getButtonByTitleAttribute(title: string): ElementFinder { + return this.component.element(by.css(`${ToolbarActions.selectors.button}[title="${title}"]`)); + } + + openMoreMenu() { + return this.getButtonByTitleAttribute('More actions').click() + .then(() => this.menu.waitForMenuToOpen()) + .then(() => this.menu); + } +} diff --git a/e2e/components/toolbar/toolbar-breadcrumb.ts b/e2e/components/toolbar/toolbar-breadcrumb.ts new file mode 100755 index 0000000000..7b939d120a --- /dev/null +++ b/e2e/components/toolbar/toolbar-breadcrumb.ts @@ -0,0 +1,82 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder, ElementArrayFinder, by, promise } from 'protractor'; +import { Component } from '../component'; + +export class ToolbarBreadcrumb extends Component { + private static selectors = { + root: 'adf-breadcrumb', + item: '.adf-breadcrumb-item', + currentItem: '.adf-breadcrumb-item-current' + }; + + items: ElementArrayFinder = this.component.all(by.css(ToolbarBreadcrumb.selectors.item)); + currentItem: ElementFinder = this.component.element(by.css(ToolbarBreadcrumb.selectors.currentItem)); + + constructor(ancestor?: ElementFinder) { + super(ToolbarBreadcrumb.selectors.root, ancestor); + } + + getNthItem(nth: number): ElementFinder { + return this.items.get(nth - 1); + } + + getNthItemName(nth: number) { + return this.getNthItem(nth).getText(); + } + + getItemsCount(): promise.Promise { + return this.items.count(); + } + + getAllItems() { + return this.items.map(elem => elem.getText().then(str => str.split('\nchevron_right')[0])); + } + + getFirstItemName(): promise.Promise { + return this.items.get(0).getText(); + } + + getCurrentItem() { + return this.currentItem; + } + + getCurrentItemName(): promise.Promise { + return this.currentItem.getText(); + } + + clickItem(name: string) { + return this.component.element(by.css(`${ToolbarBreadcrumb.selectors.item}[title=${name}]`)).click(); + } + + clickNthItem(nth: number) { + return this.getNthItem(nth).click(); + } + + getNthItemTooltip(nth: number) { + return this.getNthItem(nth).getAttribute('title'); + } +} diff --git a/e2e/components/toolbar/toolbar.ts b/e2e/components/toolbar/toolbar.ts new file mode 100755 index 0000000000..7bfbcfba05 --- /dev/null +++ b/e2e/components/toolbar/toolbar.ts @@ -0,0 +1,42 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ElementFinder } from 'protractor'; +import { Component } from '../component'; +import { ToolbarActions } from './toolbar-actions'; +import { ToolbarBreadcrumb } from './toolbar-breadcrumb'; + +export class Toolbar extends Component { + private static selectors = { + root: '.inner-layout__header' + }; + + actions: ToolbarActions = new ToolbarActions(this.component); + breadcrumb: ToolbarBreadcrumb = new ToolbarBreadcrumb(this.component); + + constructor(ancestor?: ElementFinder) { + super(Toolbar.selectors.root, ancestor); + } +} diff --git a/e2e/configs.ts b/e2e/configs.ts new file mode 100755 index 0000000000..3ac50a40db --- /dev/null +++ b/e2e/configs.ts @@ -0,0 +1,78 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +export const BROWSER_RESOLUTION_WIDTH = 1200; +export const BROWSER_RESOLUTION_HEIGHT = 800; + +export const BROWSER_WAIT_TIMEOUT = 30000; + +// Application configs +export const APP_HOST = 'http://localhost:3000'; + +// Repository configs +export const REPO_API_HOST = 'http://localhost:8080'; +export const REPO_API_TENANT = '-default-'; + +// Admin details +export const ADMIN_USERNAME = 'admin'; +export const ADMIN_PASSWORD = 'admin'; +export const ADMIN_FULL_NAME = 'Administrator'; + +// Application Routes +export const APP_ROUTES = { + FAVORITES: '/favorites', + FILE_LIBRARIES: '/libraries', + LOGIN: '/login', + LOGOUT: '/logout', + PERSONAL_FILES: '/personal-files', + RECENT_FILES: '/recent-files', + SHARED_FILES: '/shared', + TRASHCAN: '/trashcan' +}; + +// Sidebar labels +export const SIDEBAR_LABELS = { + PERSONAL_FILES: 'Personal Files', + FILE_LIBRARIES: 'File Libraries', + SHARED_FILES: 'Shared', + RECENT_FILES: 'Recent Files', + FAVORITES: 'Favorites', + TRASH: 'Trash' +}; + +// Site visibility +export const SITE_VISIBILITY = { + PUBLIC: 'PUBLIC', + MODERATED: 'MODERATED', + PRIVATE: 'PRIVATE' +}; + +// Site roles +export const SITE_ROLES = { + SITE_CONSUMER: 'SiteConsumer', + SITE_COLLABORATOR: 'SiteCollaborator', + SITE_CONTRIBUTOR: 'SiteContributor', + SITE_MANAGER: 'SiteManager' +}; diff --git a/e2e/pages/browsing-page.ts b/e2e/pages/browsing-page.ts new file mode 100755 index 0000000000..d5eab3de17 --- /dev/null +++ b/e2e/pages/browsing-page.ts @@ -0,0 +1,40 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { promise } from 'protractor'; +import { Header, DataTable, Pagination, Toolbar, Sidenav } from '../components/components'; +import { Page } from './page'; + +export class BrowsingPage extends Page { + header = new Header(this.app); + sidenav = new Sidenav(this.app); + toolbar = new Toolbar(this.app); + dataTable = new DataTable(this.app); + pagination = new Pagination(this.app); + + signOut(): promise.Promise { + return this.header.userInfo.signOut(); + } +} diff --git a/e2e/pages/login-page.ts b/e2e/pages/login-page.ts new file mode 100755 index 0000000000..87fcf6981c --- /dev/null +++ b/e2e/pages/login-page.ts @@ -0,0 +1,75 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +import { browser, ExpectedConditions as EC, promise } from 'protractor'; +import { LoginComponent } from '../components/components'; +import { Page } from './page'; +import { Utils } from '../utilities/utils'; + +import { + ADMIN_USERNAME, + ADMIN_PASSWORD, + BROWSER_WAIT_TIMEOUT, + APP_ROUTES +} from '../configs'; + +export class LoginPage extends Page { + login: LoginComponent = new LoginComponent(this.app); + + /** @override */ + constructor() { + super(APP_ROUTES.LOGIN); + } + + /** @override */ + load(): promise.Promise { + return super.load().then(() => { + const { submitButton } = this.login; + const hasSubmitButton = EC.presenceOf(submitButton); + + return browser.wait(hasSubmitButton, BROWSER_WAIT_TIMEOUT) + .then(() => Utils.clearLocalStorage()) + .then(() => browser.manage().deleteAllCookies()); + }); + } + + loginWith(username: string, password?: string): promise.Promise { + const pass = password || username; + return this.load() + .then(() => this.login.enterCredentials(username, pass).submit()) + .then(() => super.waitForApp()); + } + + loginWithAdmin(): promise.Promise { + return this.load() + .then(() => this.loginWith(ADMIN_USERNAME, ADMIN_PASSWORD)); + } + + tryLoginWith(username: string, password?: string): promise.Promise { + const pass = password || username; + return this.load() + .then(() => this.login.enterCredentials(username, pass).submit()) + .then(() => browser.wait(EC.presenceOf(this.login.errorMessage), BROWSER_WAIT_TIMEOUT)); + } +} diff --git a/e2e/pages/logout-page.ts b/e2e/pages/logout-page.ts new file mode 100755 index 0000000000..b78cb04430 --- /dev/null +++ b/e2e/pages/logout-page.ts @@ -0,0 +1,43 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { promise } from 'protractor'; +import { Page } from './page'; +import { APP_ROUTES } from '../configs'; +import { Utils } from '../utilities/utils'; + +export class LogoutPage extends Page { + /** @override */ + constructor() { + super(APP_ROUTES.LOGIN); + } + + /** @override */ + load(): promise.Promise { + return Utils.clearLocalStorage() + .then(() => Utils.clearSessionStorage()) + .then(() => super.load()); + } +} diff --git a/e2e/pages/page.ts b/e2e/pages/page.ts new file mode 100755 index 0000000000..b2dce1d523 --- /dev/null +++ b/e2e/pages/page.ts @@ -0,0 +1,110 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser, element, by, ElementFinder, promise, ExpectedConditions as EC } from 'protractor'; +import { BROWSER_WAIT_TIMEOUT } from './../configs'; + +export abstract class Page { + private static USE_HASH_STRATEGY = true; + + private locators = { + app: by.css('app-root'), + layout: by.css('app-layout'), + overlay: by.css('.cdk-overlay-container'), + dialogContainer: by.css('.mat-dialog-container'), + snackBarContainer: '.cdk-overlay-pane snack-bar-container.mat-snack-bar-container', + snackBar: 'simple-snack-bar', + snackBarAction: 'button.mat-simple-snackbar-action' + }; + + public app: ElementFinder = element(this.locators.app); + public layout: ElementFinder = element(this.locators.layout); + public overlay: ElementFinder = element(this.locators.overlay); + snackBar: ElementFinder = browser.$(this.locators.snackBar); + dialogContainer: ElementFinder = element(this.locators.dialogContainer); + snackBarContainer: ElementFinder = browser.$(this.locators.snackBarContainer); + snackBarAction: ElementFinder = browser.$(this.locators.snackBarAction); + + constructor(public url: string = '') {} + + get title(): promise.Promise { + return browser.getTitle(); + } + + load(relativeUrl: string = ''): promise.Promise { + const hash = Page.USE_HASH_STRATEGY ? '/#' : ''; + const path = `${hash}${this.url}${relativeUrl}`; + + return browser.get(path); + } + + waitForApp() { + return browser.wait(EC.presenceOf(this.layout), BROWSER_WAIT_TIMEOUT); + } + + waitForSnackBarToAppear() { + return browser.wait(EC.visibilityOf(this.snackBarContainer), BROWSER_WAIT_TIMEOUT); + } + + waitForSnackBarToClose() { + return browser.wait(EC.not(EC.visibilityOf(this.snackBarContainer)), BROWSER_WAIT_TIMEOUT); + } + + waitForDialog() { + return browser.wait(EC.visibilityOf(this.dialogContainer), BROWSER_WAIT_TIMEOUT); + } + + waitForDialogToClose() { + return browser.wait(EC.not(EC.visibilityOf(this.dialogContainer)), BROWSER_WAIT_TIMEOUT); + } + + refresh(): promise.Promise { + return browser.refresh(); + } + + getDialogActionByLabel(label) { + return element(by.cssContainingText('.mat-button-wrapper', label)) + } + + isSnackBarDisplayed(): promise.Promise { + return this.snackBar.isDisplayed(); + } + + getSnackBarMessage(): promise.Promise { + return this.waitForSnackBarToAppear() + .then(() => this.snackBar.getAttribute('innerText')); + } + + getSnackBarAction() { + return this.waitForSnackBarToAppear() + .then(() => this.snackBarAction); + } + + clickSnackBarAction() { + return browser.executeScript(function (elem) { + elem.click(); + }, this.snackBarAction); + } +} diff --git a/e2e/pages/pages.ts b/e2e/pages/pages.ts new file mode 100755 index 0000000000..196228230b --- /dev/null +++ b/e2e/pages/pages.ts @@ -0,0 +1,28 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +export * from './browsing-page'; +export * from './login-page'; +export * from './logout-page'; diff --git a/e2e/suites/actions/create-folder.test.ts b/e2e/suites/actions/create-folder.test.ts new file mode 100755 index 0000000000..d3b4024d84 --- /dev/null +++ b/e2e/suites/actions/create-folder.test.ts @@ -0,0 +1,278 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; + +import { SIDEBAR_LABELS, SITE_VISIBILITY, SITE_ROLES } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-folder-dialog'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Create folder', () => { + const username = `user-${Utils.random()}`; + + const parent = `parent-${Utils.random()}`; + const folderName1 = `folder-${Utils.random()}`; + const folderName2 = `folder-${Utils.random()}`; + const folderDescription = 'description of my folder'; + const duplicateFolderName = `folder-${Utils.random()}`; + const nameWithSpaces = ` folder-${Utils.random()} `; + + const siteName = `site-private-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const personalFilesPage = new BrowsingPage(); + const createDialog = new CreateOrEditFolderDialog(); + const { dataTable } = personalFilesPage; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PRIVATE)) + .then(() => apis.admin.nodes.createFolders([ folderName1 ], `Sites/${siteName}/documentLibrary`)) + .then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER)) + .then(() => apis.user.nodes.createFolders([ duplicateFolderName ], parent)) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); + }); + + afterAll(done => { + Promise + .all([ + apis.admin.sites.deleteSite(siteName), + apis.user.nodes.deleteNodes([ parent ]), + logoutPage.load() + ]) + .then(done); + }); + + it('option is enabled when having enough permissions', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openNewMenu()) + .then(menu => { + const isEnabled = menu.getItemByLabel('Create folder').isEnabled(); + expect(isEnabled).toBe(true, 'Create folder is not enabled'); + }); + }); + + it('creates new folder with name', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => createDialog.enterName(folderName1)) + .then(() => createDialog.clickCreate()) + .then(() => createDialog.waitForDialogToClose()) + .then(() => dataTable.waitForHeader()) + .then(() => { + const isPresent = dataTable.getRowName(folderName1).isPresent(); + expect(isPresent).toBe(true, 'Folder not displayed in list view'); + }); + }); + + it('creates new folder with name and description', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => createDialog.enterName(folderName2)) + .then(() => createDialog.enterDescription(folderDescription)) + .then(() => createDialog.clickCreate()) + .then(() => createDialog.waitForDialogToClose()) + .then(() => dataTable.waitForHeader()) + .then(() => expect(dataTable.getRowName(folderName2).isPresent()).toBe(true, 'Folder not displayed')) + .then(() => apis.user.nodes.getNodeDescription(folderName2, parent)) + .then(desc => expect(desc).toEqual(folderDescription)); + }); + + it('enabled option tooltip', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openNewMenu()) + .then(menu => browser.actions().mouseMove(menu.getItemByLabel('Create folder')).perform() + .then(() => menu)) + .then(menu => { + expect(menu.getItemTooltip('Create folder')).toContain('Create new folder'); + }); + }); + + it('option is disabled when not enough permissions', () => { + const fileLibrariesPage = new BrowsingPage(); + + fileLibrariesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => fileLibrariesPage.dataTable.doubleClickOnItemName(siteName)) + .then(() => fileLibrariesPage.dataTable.doubleClickOnItemName(folderName1)) + .then(() => fileLibrariesPage.sidenav.openNewMenu()) + .then(menu => { + const isEnabled = menu.getItemByLabel('Create folder').isEnabled(); + expect(isEnabled).toBe(false, 'Create folder is not disabled'); + }); + }); + + it('disabled option tooltip', () => { + const fileLibrariesPage = new BrowsingPage(); + + fileLibrariesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => fileLibrariesPage.dataTable.doubleClickOnItemName(siteName)) + .then(() => fileLibrariesPage.dataTable.doubleClickOnItemName(folderName1)) + .then(() => fileLibrariesPage.sidenav.openNewMenu()) + .then(menu => browser.actions().mouseMove(menu.getItemByLabel('Create folder')).perform() + .then(() => menu)) + .then(menu => { + const tooltip = menu.getItemTooltip('Create folder'); + expect(tooltip).toContain(`You can't create a folder here`); + }); + }); + + it('dialog UI elements', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => { + const dialogTitle = createDialog.getTitle(); + const isFolderNameDisplayed = createDialog.nameInput.isDisplayed(); + const isDescriptionDisplayed = createDialog.descriptionTextArea.isDisplayed(); + const isCreateEnabled = createDialog.createButton.isEnabled(); + const isCancelEnabled = createDialog.cancelButton.isEnabled(); + + expect(dialogTitle).toMatch('Create new folder'); + expect(isFolderNameDisplayed).toBe(true, 'Name input is not displayed'); + expect(isDescriptionDisplayed).toBe(true, 'Description field is not displayed'); + expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); + expect(isCancelEnabled).toBe(true, 'Cancel button is not enabled'); + }); + }); + + it('with empty folder name', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => createDialog.deleteNameWithBackspace()) + .then(() => { + const isCreateEnabled = createDialog.createButton.isEnabled(); + const validationMessage = createDialog.getValidationMessage(); + + expect(isCreateEnabled).toBe(false, 'Create button is enabled'); + expect(validationMessage).toMatch('Folder name is required'); + }); + }); + + it('with folder name ending with a dot "."', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => createDialog.enterName('folder-name.')) + .then(() => { + const isCreateEnabled = createDialog.createButton.isEnabled(); + const validationMessage = createDialog.getValidationMessage(); + + expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); + expect(validationMessage).toMatch(`Folder name can't end with a period .`); + }); + }); + + it('with folder name containing special characters', () => { + const namesWithSpecialChars = [ 'a*a', 'a"a', 'aa', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a' ]; + + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => namesWithSpecialChars.forEach(name => { + createDialog.enterName(name); + + const isCreateEnabled = createDialog.createButton.isEnabled(); + const validationMessage = createDialog.getValidationMessage(); + + expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); + expect(validationMessage).toContain(`Folder name can't contain these characters`); + })); + }); + + it('with folder name containing only spaces', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => createDialog.enterName(' ')) + .then(() => { + const isCreateEnabled = createDialog.createButton.isEnabled(); + const validationMessage = createDialog.getValidationMessage(); + + expect(isCreateEnabled).toBe(false, 'Create button is not disabled'); + expect(validationMessage).toMatch(`Folder name can't contain only spaces`); + }); + }); + + it('cancel folder creation', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => createDialog.enterName('test')) + .then(() => createDialog.enterDescription('test description')) + .then(() => createDialog.clickCancel()) + .then(() => { + expect(createDialog.component.isPresent()).not.toBe(true, 'dialog is not closed'); + }); + }); + + it('duplicate folder name', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => createDialog.enterName(duplicateFolderName)) + .then(() => createDialog.clickCreate()) + .then(() => personalFilesPage.getSnackBarMessage()) + .then(message => { + expect(message).toEqual(`There's already a folder with this name. Try a different name.`); + expect(createDialog.component.isPresent()).toBe(true, 'dialog is not present'); + }); + }); + + it('trim ending spaces from folder name', () => { + personalFilesPage.dataTable.doubleClickOnItemName(parent) + .then(() => personalFilesPage.sidenav.openCreateDialog()) + .then(() => createDialog.waitForDialogToOpen()) + .then(() => createDialog.enterName(nameWithSpaces)) + .then(() => createDialog.clickCreate()) + .then(() => createDialog.waitForDialogToClose()) + .then(() => dataTable.waitForHeader()) + .then(() => { + const isPresent = dataTable.getRowName(nameWithSpaces.trim()).isPresent(); + expect(isPresent).toBe(true, 'Folder not displayed in list view'); + }); + }); +}); diff --git a/e2e/suites/actions/delete.test.ts b/e2e/suites/actions/delete.test.ts new file mode 100755 index 0000000000..c401680ae1 --- /dev/null +++ b/e2e/suites/actions/delete.test.ts @@ -0,0 +1,503 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { SIDEBAR_LABELS } from '../../configs'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; + +describe('Delete content', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, toolbar } = page; + + beforeAll(done => { + apis.admin.people.createUser(username).then(done); + }); + + afterAll(done => { + apis.admin.trashcan.emptyTrash().then(done); + }); + + xit(''); + + describe('on Personal Files', () => { + const file1 = `file1-${Utils.random()}.txt`; let file1Id; + const file2 = `file2-${Utils.random()}.txt`; let file2Id; + const file3 = `file3-${Utils.random()}.txt`; + const file4 = `file4-${Utils.random()}.txt`; let file4Id; + const folder1 = `folder1-${Utils.random()}`; let folder1Id; + const folder2 = `folder2-${Utils.random()}`; let folder2Id; + const fileLocked1 = `fileLocked-${Utils.random()}.txt`; let fileLocked1Id; + + beforeAll(done => { + apis.user.nodes.createFile(file1).then(resp => file1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(file2).then(resp => file2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolder(folder2).then(resp => folder2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(file3, folder1Id)) + .then(() => apis.user.nodes.createFile(file4, folder2Id).then(resp => file4Id = resp.data.entry.id)) + .then(() => apis.user.nodes.lockFile(file4Id)) + + .then(() => apis.user.nodes.createFile(fileLocked1).then(resp => fileLocked1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.lockFile(fileLocked1Id)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + page.refresh().then(done); + }); + + afterAll(done => { + Promise.all([ + logoutPage.load(), + apis.user.nodes.unlockFile(file4Id) + .then(() => apis.user.nodes.unlockFile(fileLocked1Id)) + .then(() => apis.user.nodes.deleteNodesById([file1Id, file2Id, folder1Id, folder2Id, fileLocked1Id])) + ]) + .then(done); + }); + + it('delete a file and check notification', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.clickOnItemName(file1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`${file1} deleted`); + expect(dataTable.getRowName(file1).isPresent()).toBe(false, 'Item was not removed from list'); + items--; + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => expect(dataTable.getRowName(file1).isPresent()).toBe(true, 'Item is not in trash')) + + .then(() => apis.user.trashcan.restore(file1Id)); + }); + + it('delete multiple files and check notification', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.selectMultipleItems([file1, file2]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`Deleted 2 items`); + expect(dataTable.getRowName(file1).isPresent()).toBe(false, `${file1} was not removed from list`); + expect(dataTable.getRowName(file2).isPresent()).toBe(false, `${file2} was not removed from list`); + items = items - 2; + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(file1).isPresent()).toBe(true, `${file1} is not in trash`); + expect(dataTable.getRowName(file2).isPresent()).toBe(true, `${file2} is not in trash`); + }) + + .then(() => apis.user.trashcan.restore(file1Id)) + .then(() => apis.user.trashcan.restore(file2Id)); + }); + + it('delete a folder with content', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.clickOnItemName(folder1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => { + expect(dataTable.getRowName(folder1).isPresent()).toBe(false, 'Item was not removed from list'); + items--; + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(folder1).isPresent()).toBe(true, 'Item is not in trash'); + expect(dataTable.getRowName(file3).isPresent()).toBe(false, 'Item is in trash'); + }) + + .then(() => apis.user.trashcan.restore(folder1Id)); + }); + + it('delete a folder containing locked files', () => { + dataTable.clickOnItemName(folder2) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`${folder2} couldn't be deleted`); + expect(dataTable.getRowName(folder2).isPresent()).toBe(true, 'Item was removed from list'); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(folder2).isPresent()).toBe(false, 'Item is in trash'); + expect(dataTable.getRowName(file4).isPresent()).toBe(false, 'Item is in trash'); + }); + }); + + it('notification on multiple items deletion - some items fail to delete', () => { + dataTable.selectMultipleItems([file1, folder2]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => expect(message).toContain(`Deleted 1 item, 1 couldn't be deleted`)) + + .then(() => apis.user.trashcan.restore(file1Id)); + }); + + it('Notification on multiple items deletion - all items fail to delete', () => { + dataTable.selectMultipleItems([fileLocked1, folder2]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => expect(message).toEqual(`2 items couldn't be deleted`)); + }); + }); + + describe('on Shared Files', () => { + const sharedFile1 = `sharedFile1-${Utils.random()}.txt`; let sharedFile1Id; + const sharedFile2 = `sharedFile2-${Utils.random()}.txt`; let sharedFile2Id; + const sharedFile3 = `sharedFile3-${Utils.random()}.txt`; let sharedFile3Id; + + beforeAll(done => { + apis.user.nodes.createFile(sharedFile1).then(resp => sharedFile1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(sharedFile2).then(resp => sharedFile2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(sharedFile3).then(resp => sharedFile3Id = resp.data.entry.id)) + .then(() => apis.user.shared.shareFilesByIds([sharedFile1Id, sharedFile2Id, sharedFile3Id])) + .then(() => apis.user.shared.waitForApi({ expect: 3 })) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + page.refresh().then(done); + }); + + afterAll(done => { + Promise.all([ + logoutPage.load(), + apis.user.nodes.deleteNodesById([sharedFile1Id, sharedFile2Id, sharedFile3Id]) + ]) + .then(done); + }); + + it('delete a file and check notification', () => { + dataTable.clickOnItemName(sharedFile1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`${sharedFile1} deleted`); + expect(dataTable.getRowName(sharedFile1).isPresent()).toBe(false, 'Item was not removed from list'); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => expect(dataTable.getRowName(sharedFile1).isPresent()).toBe(true, 'Item is not in trash')) + + .then(() => apis.user.trashcan.restore(sharedFile1Id)); + }); + + it('delete multiple files and check notification', () => { + dataTable.selectMultipleItems([sharedFile2, sharedFile3]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`Deleted 2 items`); + expect(dataTable.getRowName(sharedFile2).isPresent()).toBe(false, `${sharedFile2} was not removed from list`); + expect(dataTable.getRowName(sharedFile3).isPresent()).toBe(false, `${sharedFile3} was not removed from list`); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(sharedFile2).isPresent()).toBe(true, `${sharedFile2} is not in trash`); + expect(dataTable.getRowName(sharedFile3).isPresent()).toBe(true, `${sharedFile3} is not in trash`); + }) + + .then(() => apis.user.trashcan.restore(sharedFile2Id)) + .then(() => apis.user.trashcan.restore(sharedFile3Id)); + }); + }); + + describe('on Favorites', () => { + const favoriteFile1 = `favFile1-${Utils.random()}.txt`; let favoriteFile1Id; + const favoriteFile2 = `favFile2-${Utils.random()}.txt`; let favoriteFile2Id; + const favoriteFile3 = `favFile3-${Utils.random()}.txt`; + const favoriteFile4 = `favFile4-${Utils.random()}.txt`; let favoriteFile4Id; + const favoriteFolder1 = `favFolder1-${Utils.random()}`; let favoriteFolder1Id; + const favoriteFolder2 = `favFolder2-${Utils.random()}`; let favoriteFolder2Id; + const favoriteFileLocked1 = `favFileLocked-${Utils.random()}.txt`; let favoriteFileLocked1Id; + + beforeAll(done => { + apis.user.nodes.createFile(favoriteFile1).then(resp => favoriteFile1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(favoriteFile2).then(resp => favoriteFile2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolder(favoriteFolder1).then(resp => favoriteFolder1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolder(favoriteFolder2).then(resp => favoriteFolder2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(favoriteFile3, favoriteFolder1Id)) + .then(() => apis.user.nodes.createFile(favoriteFile4, favoriteFolder2Id).then(resp => favoriteFile4Id = resp.data.entry.id)) + .then(() => apis.user.nodes.lockFile(favoriteFile4Id)) + + .then(() => apis.user.nodes.createFile(favoriteFileLocked1).then(resp => favoriteFileLocked1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.lockFile(favoriteFileLocked1Id)) + + .then(() => apis.user.favorites.addFavoritesByIds('file', [favoriteFile1Id, favoriteFile2Id, favoriteFileLocked1Id])) + .then(() => apis.user.favorites.addFavoritesByIds('folder', [favoriteFolder1Id, favoriteFolder2Id])) + .then(() => apis.user.favorites.waitForApi({ expect: 5 })) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + page.refresh().then(done); + }); + + afterAll(done => { + Promise.all([ + logoutPage.load(), + apis.user.nodes.unlockFile(favoriteFile4Id) + .then(() => apis.user.nodes.unlockFile(favoriteFileLocked1Id)) + .then(() => apis.user.nodes.deleteNodesById([ + favoriteFile1Id, favoriteFile2Id, favoriteFolder1Id, favoriteFolder2Id, favoriteFileLocked1Id + ])) + ]) + .then(done); + }); + + it('delete a file and check notification', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.clickOnItemName(favoriteFile1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`${favoriteFile1} deleted`); + expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(false, 'Item was not removed from list'); + items--; + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(true, 'Item is not in trash')) + + .then(() => apis.user.trashcan.restore(favoriteFile1Id)); + }); + + it('delete multiple files and check notification', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.selectMultipleItems([favoriteFile1, favoriteFile2]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`Deleted 2 items`); + expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(false, `${favoriteFile1} was not removed from list`); + expect(dataTable.getRowName(favoriteFile2).isPresent()).toBe(false, `${favoriteFile2} was not removed from list`); + items = items - 2; + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(true, `${favoriteFile1} is not in trash`); + expect(dataTable.getRowName(favoriteFile2).isPresent()).toBe(true, `${favoriteFile2} is not in trash`); + }) + + .then(() => apis.user.trashcan.restore(favoriteFile1Id)) + .then(() => apis.user.trashcan.restore(favoriteFile2Id)); + }); + + it('delete a folder with content', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + dataTable.clickOnItemName(favoriteFolder1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => { + expect(dataTable.getRowName(favoriteFolder1).isPresent()).toBe(false, 'Item was not removed from list'); + items--; + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(favoriteFolder1).isPresent()).toBe(true, 'Item is not in trash'); + expect(dataTable.getRowName(favoriteFile3).isPresent()).toBe(false, 'Item is in trash'); + }) + + .then(() => apis.user.trashcan.restore(favoriteFolder1Id)); + }); + + it('delete a folder containing locked files', () => { + dataTable.clickOnItemName(favoriteFolder2) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`${favoriteFolder2} couldn't be deleted`); + expect(dataTable.getRowName(favoriteFolder2).isPresent()).toBe(true, 'Item was removed from list'); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(favoriteFolder2).isPresent()).toBe(false, 'Item is in trash'); + expect(dataTable.getRowName(favoriteFile4).isPresent()).toBe(false, 'Item is in trash'); + }); + }); + + it('notification on multiple items deletion - some items fail to delete', () => { + dataTable.selectMultipleItems([favoriteFile1, favoriteFolder2]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`Deleted 1 item, 1 couldn't be deleted`); + }) + + .then(() => apis.user.trashcan.restore(favoriteFile1Id)); + }); + + it('Notification on multiple items deletion - all items fail to delete', () => { + dataTable.selectMultipleItems([favoriteFileLocked1, favoriteFolder2]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toEqual(`2 items couldn't be deleted`); + }); + }); + }); + + describe('on Recent Files', () => { + const recentFile1 = `recentFile1-${Utils.random()}.txt`; let recentFile1Id; + const recentFile2 = `recentFile2-${Utils.random()}.txt`; let recentFile2Id; + const recentFile3 = `recentFile3-${Utils.random()}.txt`; let recentFile3Id; + + beforeAll(done => { + apis.user.nodes.createFile(recentFile1).then(resp => recentFile1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(recentFile2).then(resp => recentFile2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(recentFile3).then(resp => recentFile3Id = resp.data.entry.id)) + .then(() => apis.user.search.waitForApi(username, { expect: 3 })) + + .then(() => loginPage.loginWith(username)) + + .then((): any => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.isEmptyList()) + .then(empty => { + if (empty) { + browser.sleep(6000).then(() => page.refresh()); + } + }) + ) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + page.refresh().then(done); + }); + + afterAll(done => { + Promise.all([ + logoutPage.load(), + apis.user.nodes.deleteNodesById([recentFile1Id, recentFile2Id, recentFile3Id]) + ]) + .then(done); + }); + + it('delete a file and check notification', () => { + dataTable.clickOnItemName(recentFile1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`${recentFile1} deleted`); + expect(dataTable.getRowName(recentFile1).isPresent()).toBe(false, 'Item was not removed from list'); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => expect(dataTable.getRowName(recentFile1).isPresent()).toBe(true, 'Item is not in trash')) + + .then(() => apis.user.trashcan.restore(recentFile1Id)); + }); + + it('delete multiple files and check notification', () => { + dataTable.selectMultipleItems([recentFile2, recentFile3]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`Deleted 2 items`); + expect(dataTable.getRowName(recentFile2).isPresent()).toBe(false, `${recentFile2} was not removed from list`); + expect(dataTable.getRowName(recentFile3).isPresent()).toBe(false, `${recentFile3} was not removed from list`); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(recentFile2).isPresent()).toBe(true, `${recentFile2} is not in trash`); + expect(dataTable.getRowName(recentFile3).isPresent()).toBe(true, `${recentFile3} is not in trash`); + }) + + .then(() => apis.user.trashcan.restore(recentFile2Id)) + .then(() => apis.user.trashcan.restore(recentFile3Id)); + }); + }); +}); diff --git a/e2e/suites/actions/edit-folder.test.ts b/e2e/suites/actions/edit-folder.test.ts new file mode 100755 index 0000000000..137dcfe3fa --- /dev/null +++ b/e2e/suites/actions/edit-folder.test.ts @@ -0,0 +1,187 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { protractor, browser } from 'protractor'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { SIDEBAR_LABELS, SITE_VISIBILITY, SITE_ROLES } from '../../configs'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-folder-dialog'; +import { Utils } from '../../utilities/utils'; + +describe('Edit folder', () => { + const username = `user-${Utils.random()}`; + + const parent = `parent-${Utils.random()}`; + const folderName = `folder-${Utils.random()}`; + const folderDescription = 'my folder description'; + + const folderNameToEdit = `folder-${Utils.random()}`; + const duplicateFolderName = `folder-${Utils.random()}`; + + const folderNameEdited = `folder-${Utils.random()}`; + const folderDescriptionEdited = 'description edited'; + + const siteName = `site-private-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const personalFilesPage = new BrowsingPage(); + const editDialog = new CreateOrEditFolderDialog(); + const { dataTable } = personalFilesPage; + const editButton = personalFilesPage.toolbar.actions.getButtonByTitleAttribute('Edit'); + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PRIVATE)) + .then(() => apis.admin.nodes.createFolders([ folderName ], `Sites/${siteName}/documentLibrary`)) + .then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER)) + + .then(() => apis.user.nodes.createFolder( parent )) + .then(resp => apis.user.nodes.createFolder( folderName, resp.data.entry.id, '', folderDescription )) + .then(() => apis.user.nodes.createFolders([ folderNameToEdit, duplicateFolderName ], parent)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.doubleClickOnItemName(parent)) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + browser.actions().sendKeys(protractor.Key.ESCAPE).perform().then(done); + }); + + afterAll(done => { + Promise + .all([ + apis.admin.sites.deleteSite(siteName), + apis.user.nodes.deleteNodes([ parent ]), + logoutPage.load() + ]) + .then(done); + }); + + it('dialog UI defaults', () => { + dataTable.clickOnItemName(folderName) + .then(() => editButton.click()) + .then(() => { + expect(editDialog.getTitle()).toEqual('Edit folder'); + expect(editDialog.nameInput.getAttribute('value')).toBe(folderName); + expect(editDialog.descriptionTextArea.getAttribute('value')).toBe(folderDescription); + expect(editDialog.updateButton.isEnabled()).toBe(true, 'upload button is not enabled'); + expect(editDialog.cancelButton.isEnabled()).toBe(true, 'cancel button is not enabled'); + }); + }); + + it('properties are modified when pressing OK', () => { + dataTable.clickOnItemName(folderNameToEdit) + .then(() => editButton.click()) + .then(() => editDialog.waitForDialogToOpen()) + .then(() => editDialog.enterDescription(folderDescriptionEdited)) + .then(() => editDialog.enterName(folderNameEdited)) + .then(() => editDialog.clickUpdate()) + .then(() => editDialog.waitForDialogToClose()) + .then(() => dataTable.waitForHeader()) + .then(() => expect(dataTable.getRowName(folderNameEdited).isPresent()).toBe(true, 'Folder not displayed')) + .then(() => apis.user.nodes.getNodeDescription(folderNameEdited, parent)) + .then(desc => expect(desc).toEqual(folderDescriptionEdited)); + }); + + it('with empty folder name', () => { + dataTable.clickOnItemName(folderName) + .then(() => editButton.click()) + .then(() => editDialog.deleteNameWithBackspace()) + .then(() => { + expect(editDialog.updateButton.isEnabled()).toBe(false, 'upload button is not enabled'); + expect(editDialog.getValidationMessage()).toMatch('Folder name is required'); + }); + }); + + it('with name with special characters', () => { + const namesWithSpecialChars = [ 'a*a', 'a"a', 'aa', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a' ]; + + dataTable.clickOnItemName(folderName) + .then(() => editButton.click()) + .then(() => namesWithSpecialChars.forEach(name => { + editDialog.enterName(name); + + expect(editDialog.updateButton.isEnabled()).toBe(false, 'upload button is not disabled'); + expect(editDialog.getValidationMessage()).toContain(`Folder name can't contain these characters`); + })); + }); + + it('with name ending with a dot', () => { + dataTable.clickOnItemName(folderName) + .then(() => editButton.click()) + .then(() => editDialog.nameInput.sendKeys('.')) + .then(() => { + expect(editDialog.updateButton.isEnabled()).toBe(false, 'upload button is not enabled'); + expect(editDialog.getValidationMessage()).toMatch(`Folder name can't end with a period .`); + }); + }); + + it('Cancel button', () => { + dataTable.clickOnItemName(folderName) + .then(() => editButton.click()) + .then(() => editDialog.clickCancel()) + .then(() => { + expect(editDialog.component.isPresent()).not.toBe(true, 'dialog is not closed'); + }); + }); + + it('with duplicate folder name', () => { + dataTable.clickOnItemName(folderName) + .then(() => editButton.click()) + .then(() => editDialog.enterName(duplicateFolderName)) + .then(() => editDialog.clickUpdate()) + .then(() => personalFilesPage.getSnackBarMessage()) + .then(message => { + expect(message).toEqual(`There's already a folder with this name. Try a different name.`); + expect(editDialog.component.isPresent()).toBe(true, 'dialog is not present'); + }); + }); + + it('trim ending spaces', () => { + dataTable.clickOnItemName(folderName) + .then(() => editButton.click()) + .then(() => editDialog.nameInput.sendKeys(' ')) + .then(() => editDialog.clickUpdate()) + .then(() => editDialog.waitForDialogToClose()) + .then(() => { + expect(personalFilesPage.snackBar.isPresent()).not.toBe(true, 'notification appears'); + expect(dataTable.getRowName(folderName).isPresent()).toBe(true, 'Folder not displayed in list view'); + }); + }); +}); diff --git a/e2e/suites/actions/mark-favorite.test.ts b/e2e/suites/actions/mark-favorite.test.ts new file mode 100644 index 0000000000..f6f79cf090 --- /dev/null +++ b/e2e/suites/actions/mark-favorite.test.ts @@ -0,0 +1,419 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { SIDEBAR_LABELS } from '../../configs'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; +import { browser } from 'protractor'; + +describe('Mark items as favorites', () => { + const username = `user-${Utils.random()}`; + + const file1NotFav = `file-${Utils.random()}.txt`; + const file2NotFav = `file-${Utils.random()}.txt`; + const file3Fav = `file-${Utils.random()}.txt`; + const file4Fav = `file-${Utils.random()}.txt`; + const folder1 = `folder-${Utils.random()}`; + + let file1Id, file2Id, file3Id, file4Id, folder1Id; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, toolbar } = page; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.user.nodes.createFile( file1NotFav ).then(resp => file1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile( file2NotFav ).then(resp => file2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile( file3Fav ).then(resp => file3Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile( file4Fav ).then(resp => file4Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolder( folder1 ).then(resp => folder1Id = resp.data.entry.id)) + + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)) + .then(() => apis.user.favorites.addFavoriteById('file', file4Id)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.nodes.deleteNodesById([ file1Id, file2Id, file3Id, file4Id, folder1Id ]), + logoutPage.load() + ]) + .then(done); + }); + + xit(''); + + describe('on Personal Files', () => { + beforeAll(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + // browser.actions().sendKeys(protractor.Key.ESCAPE).perform().then(done); + browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); + }); + + it('Favorite action has empty star icon for unfavorited item', () => { + dataTable.clickOnItemName(file1NotFav) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => expect(toolbar.actions.menu.getItemIconText('Favorite')).toEqual('star_border')); + }); + + it('Favorite action has empty star icon for multiple selection of items when some are not favorite', () => { + dataTable.selectMultipleItems([ file1NotFav, file3Fav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => expect(toolbar.actions.menu.getItemIconText('Favorite')).toEqual('star_border')); + }); + + it('Favorite action has full star icon for favorited items', () => { + dataTable.clickOnItemName(file3Fav) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => expect(toolbar.actions.menu.getItemIconText('Favorite')).toEqual('star')); + }); + + it('favorite a file', () => { + dataTable.clickOnItemName(file1NotFav) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 3 })) + .then(() => apis.user.favorites.isFavorite(file1Id)) + .then(isFavorite => expect(isFavorite).toBe(true, `${file1NotFav} not marked as favorite`)) + + .then(() => apis.user.favorites.removeFavoriteById(file1Id)); + }); + + it('favorite a folder', () => { + dataTable.clickOnItemName(folder1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 3 })) + .then(() => apis.user.favorites.isFavorite(folder1Id)) + .then(isFavorite => expect(isFavorite).toBe(true, `${folder1} not marked as favorite`)) + + .then(() => apis.user.favorites.removeFavoriteById(folder1Id)); + }); + + it('unfavorite an item', () => { + dataTable.clickOnItemName(file3Fav) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 1 })) + .then(() => apis.user.favorites.isFavorite(file3Id)) + .then(isFavorite => expect(isFavorite).toBe(false, `${file3Fav} is marked as favorite`)) + + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)); + }); + + it('favorite multiple items - all unfavorite', () => { + dataTable.selectMultipleItems([ file1NotFav, file2NotFav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 4 })) + .then(() => Promise.all([ + apis.user.favorites.isFavorite(file1Id), + apis.user.favorites.isFavorite(file2Id) + ])) + .then(resp => { + expect(resp[0]).toBe(true, 'item not marked as favorite'); + expect(resp[1]).toBe(true, 'item not marked as favorite'); + }) + + .then(() => apis.user.favorites.removeFavoriteById(file1Id)) + .then(() => apis.user.favorites.removeFavoriteById(file2Id)); + }); + + it('favorite multiple items - some favorite and some unfavorite', () => { + dataTable.selectMultipleItems([ file1NotFav, file3Fav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 3 })) + .then(() => Promise.all([ + apis.user.favorites.isFavorite(file1Id), + apis.user.favorites.isFavorite(file3Id) + ])) + .then(resp => { + expect(resp[0]).toBe(true, 'item not marked as favorite'); + expect(resp[1]).toBe(true, 'item not marked as favorite'); + }) + + .then(() => apis.user.favorites.removeFavoriteById(file1Id)); + }); + + it('unfavorite multiple items', () => { + dataTable.selectMultipleItems([ file3Fav, file4Fav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => browser.sleep(2000)) + .then(() => Promise.all([ + apis.user.favorites.isFavorite(file3Id), + apis.user.favorites.isFavorite(file4Id) + ])) + .then(resp => { + expect(resp[0]).toBe(false, 'item marked as favorite'); + expect(resp[1]).toBe(false, 'item marked as favorite'); + }) + + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)) + .then(() => apis.user.favorites.addFavoriteById('file', file4Id)); + }); + }); + + describe('on Recent Files', () => { + beforeAll(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + // browser.actions().sendKeys(protractor.Key.ESCAPE).perform().then(done); + browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); + }); + + it('favorite a file', () => { + dataTable.clickOnItemName(file1NotFav) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 3 })) + .then(() => apis.user.favorites.isFavorite(file1Id)) + .then(isFavorite => expect(isFavorite).toBe(true, `${file1NotFav} not marked as favorite`)) + + .then(() => apis.user.favorites.removeFavoriteById(file1Id)); + }); + + it('unfavorite an item', () => { + dataTable.clickOnItemName(file3Fav) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 1 })) + .then(() => apis.user.favorites.isFavorite(file3Id)) + .then(isFavorite => expect(isFavorite).toBe(false, `${file3Fav} is marked as favorite`)) + + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)); + }); + + it('favorite multiple items - all unfavorite', () => { + dataTable.selectMultipleItems([ file1NotFav, file2NotFav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 4 })) + .then(() => Promise.all([ + apis.user.favorites.isFavorite(file1Id), + apis.user.favorites.isFavorite(file2Id) + ])) + .then(resp => { + expect(resp[0]).toBe(true, 'item not marked as favorite'); + expect(resp[1]).toBe(true, 'item not marked as favorite'); + }) + + .then(() => apis.user.favorites.removeFavoriteById(file1Id)) + .then(() => apis.user.favorites.removeFavoriteById(file2Id)); + }); + + it('favorite multiple items - some favorite and some unfavorite', () => { + dataTable.selectMultipleItems([ file1NotFav, file3Fav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 3 })) + .then(() => Promise.all([ + apis.user.favorites.isFavorite(file1Id), + apis.user.favorites.isFavorite(file3Id) + ])) + .then(resp => { + expect(resp[0]).toBe(true, 'item not marked as favorite'); + expect(resp[1]).toBe(true, 'item not marked as favorite'); + }) + + .then(() => apis.user.favorites.removeFavoriteById(file1Id)); + }); + + it('unfavorite multiple items', () => { + dataTable.selectMultipleItems([ file3Fav, file4Fav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => browser.sleep(2000)) + .then(() => Promise.all([ + apis.user.favorites.isFavorite(file3Id), + apis.user.favorites.isFavorite(file4Id) + ])) + .then(resp => { + expect(resp[0]).toBe(false, 'item marked as favorite'); + expect(resp[1]).toBe(false, 'item marked as favorite'); + }) + + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)) + .then(() => apis.user.favorites.addFavoriteById('file', file4Id)); + }); + }); + + describe('on Shared Files', () => { + beforeAll(done => { + apis.user.shared.shareFilesByIds([ file1Id, file2Id, file3Id, file4Id ]) + .then(() => apis.user.shared.waitForApi({ expect: 4 })) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + // browser.actions().sendKeys(protractor.Key.ESCAPE).perform().then(done); + browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); + }); + + it('favorite a file', () => { + dataTable.clickOnItemName(file1NotFav) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 3 })) + .then(() => apis.user.favorites.isFavorite(file1Id)) + .then(isFavorite => expect(isFavorite).toBe(true, `${file1NotFav} not marked as favorite`)) + + .then(() => apis.user.favorites.removeFavoriteById(file1Id)); + }); + + it('unfavorite an item', () => { + dataTable.clickOnItemName(file3Fav) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 1 })) + .then(() => apis.user.favorites.isFavorite(file3Id)) + .then(isFavorite => expect(isFavorite).toBe(false, `${file3Fav} is marked as favorite`)) + + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)); + }); + + it('favorite multiple items - all unfavorite', () => { + dataTable.selectMultipleItems([ file1NotFav, file2NotFav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 4 })) + .then(() => Promise.all([ + apis.user.favorites.isFavorite(file1Id), + apis.user.favorites.isFavorite(file2Id) + ])) + .then(resp => { + expect(resp[0]).toBe(true, 'item not marked as favorite'); + expect(resp[1]).toBe(true, 'item not marked as favorite'); + }) + + .then(() => apis.user.favorites.removeFavoriteById(file1Id)) + .then(() => apis.user.favorites.removeFavoriteById(file2Id)); + }); + + it('favorite multiple items - some favorite and some unfavorite', () => { + dataTable.selectMultipleItems([ file1NotFav, file3Fav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 3 })) + .then(() => Promise.all([ + apis.user.favorites.isFavorite(file1Id), + apis.user.favorites.isFavorite(file3Id) + ])) + .then(resp => { + expect(resp[0]).toBe(true, 'item not marked as favorite'); + expect(resp[1]).toBe(true, 'item not marked as favorite'); + }) + + .then(() => apis.user.favorites.removeFavoriteById(file1Id)); + }); + + it('unfavorite multiple items', () => { + dataTable.selectMultipleItems([ file3Fav, file4Fav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => browser.sleep(2000)) + .then(() => Promise.all([ + apis.user.favorites.isFavorite(file3Id), + apis.user.favorites.isFavorite(file4Id) + ])) + .then(resp => { + expect(resp[0]).toBe(false, 'item marked as favorite'); + expect(resp[1]).toBe(false, 'item marked as favorite'); + }) + + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)) + .then(() => apis.user.favorites.addFavoriteById('file', file4Id)); + }); + }); + + describe('on Favorites', () => { + beforeAll(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + page.refresh().then(done); + }); + + it('unfavorite an item', () => { + dataTable.clickOnItemName(file3Fav) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => apis.user.favorites.waitForApi({ expect: 1 })) + .then(() => apis.user.favorites.isFavorite(file3Id)) + .then(isFavorite => { + expect(isFavorite).toBe(false, 'item is marked as favorite'); + expect(dataTable.getRowName(file3Fav).isPresent()).toBe(false, 'item still displayed'); + }) + + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)); + }); + + it('unfavorite multiple items', () => { + dataTable.selectMultipleItems([ file3Fav, file4Fav ]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Favorite')) + .then(() => browser.sleep(2000)) + .then(() => apis.user.favorites.isFavorite(file3Id)) + .then(resp => { + expect(resp).toBe(false, 'file3 marked as favorite'); + expect(dataTable.getRowName(file3Fav).isPresent()).toBe(false, 'file3 still displayed'); + }) + .then(() => apis.user.favorites.isFavorite(file4Id)) + .then(resp => { + expect(resp).toBe(false, 'file4 marked as favorite'); + expect(dataTable.getRowName(file4Fav).isPresent()).toBe(false, 'file4 still displayed'); + }) + + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)) + .then(() => apis.user.favorites.addFavoriteById('file', file4Id)); + }); + }); + +}); diff --git a/e2e/suites/actions/permanently-delete.test.ts b/e2e/suites/actions/permanently-delete.test.ts new file mode 100755 index 0000000000..1025feefd5 --- /dev/null +++ b/e2e/suites/actions/permanently-delete.test.ts @@ -0,0 +1,122 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { SIDEBAR_LABELS } from '../../configs'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; + +describe('Permanently delete from Trash', () => { + const username = `user-${Utils.random()}`; + + const file1 = `file-${Utils.random()}.txt`; + const file2 = `file-${Utils.random()}.txt`; + let filesIds; + + const folder1 = `folder-${Utils.random()}`; + const folder2 = `folder-${Utils.random()}`; + let foldersIds; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const trashPage = new BrowsingPage(); + const { dataTable, toolbar } = trashPage; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.user.nodes.createFiles([ file1, file2 ])) + .then(resp => filesIds = resp.data.list.entries.map(entries => entries.entry.id)) + .then(() => apis.user.nodes.createFolders([ folder1, folder2 ])) + .then(resp => foldersIds = resp.data.list.entries.map(entries => entries.entry.id)) + + .then(() => apis.user.nodes.deleteNodesById(filesIds, false)) + .then(() => apis.user.nodes.deleteNodesById(foldersIds, false)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + trashPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.admin.trashcan.emptyTrash(), + logoutPage.load() + ]) + .then(done); + }); + + it('delete file [C217094] [C217091] [C217092]', () => { + dataTable.clickOnItemName(file1) + .then(() => toolbar.actions.getButtonByTitleAttribute('Permanently delete').click()) + .then(() => trashPage.waitForDialog()) + .then(() => trashPage.getDialogActionByLabel('Delete')) + .then((elm) => elm.click()) + .then(() => trashPage.waitForDialogToClose()) + .then(() => trashPage.getSnackBarMessage()) + .then(text => { + expect(text).toEqual(`${file1} deleted`); + expect(dataTable.getRowName(file1).isPresent()).toBe(false, 'Item was not deleted'); + }); + }); + + it('delete folder [C217091] [C217092]', () => { + dataTable.clickOnItemName(folder1) + .then(() => toolbar.actions.getButtonByTitleAttribute('Permanently delete').click()) + .then(() => trashPage.waitForDialog()) + .then(() => trashPage.getDialogActionByLabel('Delete')) + .then((elm) => elm.click()) + .then(() => trashPage.waitForDialogToClose()) + .then(() => trashPage.getSnackBarMessage()) + .then(text => { + expect(text).toEqual(`${folder1} deleted`); + expect(dataTable.getRowName(folder1).isPresent()).toBe(false, 'Item was not deleted'); + }); + }); + + it('delete multiple items [C217093]', () => { + dataTable.selectMultipleItems([ file2, folder2 ]) + .then(() => toolbar.actions.getButtonByTitleAttribute('Permanently delete').click()) + .then(() => trashPage.waitForDialog()) + .then(() => trashPage.getDialogActionByLabel('Delete')) + .then((elm) => elm.click()) + .then(() => trashPage.waitForDialogToClose()) + .then(() => trashPage.getSnackBarMessage()) + .then(text => { + expect(text).toEqual(`2 items deleted`); + expect(dataTable.getRowName(file2).isPresent()).toBe(false, 'Item was not deleted'); + expect(dataTable.getRowName(folder2).isPresent()).toBe(false, 'Item was not deleted'); + }); + }); +}); diff --git a/e2e/suites/actions/restore.test.ts b/e2e/suites/actions/restore.test.ts new file mode 100755 index 0000000000..c6f3794072 --- /dev/null +++ b/e2e/suites/actions/restore.test.ts @@ -0,0 +1,268 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { APP_ROUTES, SIDEBAR_LABELS } from '../../configs'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; + +describe('Restore from Trash', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, toolbar } = page; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.admin.trashcan.emptyTrash(), + logoutPage.load() + ]) + .then(done); + }); + + xit(''); + + describe('successful restore', () => { + const file = `file-${Utils.random()}.txt`; let fileId; + const folder = `folder-${Utils.random()}`; let folderId; + + beforeAll(done => { + apis.user.nodes.createFile(file).then(resp => fileId = resp.data.entry.id) + .then(() => apis.user.nodes.createFolder(folder).then(resp => folderId = resp.data.entry.id)) + .then(() => apis.user.nodes.deleteNodesById([ fileId, folderId ], false)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + apis.user.trashcan.emptyTrash().then(done); + }); + + it('restore file', () => { + dataTable.clickOnItemName(file) + .then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click()) + .then(() => page.getSnackBarMessage()) + .then(text => { + expect(text).toContain(`${file} restored`); + expect(text).toContain(`View`); + expect(dataTable.getRowName(file).isPresent()).toBe(false, 'Item was not removed from list'); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)) + .then(() => page.dataTable.waitForHeader()) + .then(() => { + expect(page.dataTable.getRowName(file).isPresent()).toBe(true, 'Item not displayed in list'); + }) + + .then(() => apis.user.nodes.deleteNodeById(fileId, false)); + }); + + it('restore folder', () => { + dataTable.clickOnItemName(folder) + .then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click()) + .then(() => page.getSnackBarMessage()) + .then(text => { + expect(text).toContain(`${folder} restored`); + expect(text).toContain(`View`); + expect(dataTable.getRowName(folder).isPresent()).toBe(false, 'Item was not removed from list'); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)) + .then(() => page.dataTable.waitForHeader()) + .then(() => { + expect(page.dataTable.getRowName(folder).isPresent()).toBe(true, 'Item not displayed in list'); + }) + + .then(() => apis.user.nodes.deleteNodeById(folderId, false)); + }); + + it('restore multiple items', () => { + dataTable.selectMultipleItems([ file, folder ]) + .then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click()) + .then(() => page.getSnackBarMessage()) + .then(text => { + expect(text).toContain(`Restore successful`); + expect(text).not.toContain(`View`); + expect(dataTable.getRowName(file).isPresent()).toBe(false, 'Item was not removed from list'); + expect(dataTable.getRowName(folder).isPresent()).toBe(false, 'Item was not removed from list'); + }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)) + .then(() => page.dataTable.waitForHeader()) + .then(() => { + expect(page.dataTable.getRowName(file).isPresent()).toBe(true, 'Item not displayed in list'); + expect(page.dataTable.getRowName(folder).isPresent()).toBe(true, 'Item not displayed in list'); + }) + + .then(() => apis.user.nodes.deleteNodesById([ fileId, folderId ], false)); + }); + + it('View from notification', () => { + dataTable.clickOnItemName(file) + .then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click()) + .then(() => page.clickSnackBarAction()) + .then(() => page.dataTable.waitForHeader()) + .then(() => { + expect(page.sidenav.isActiveByLabel('Personal Files')).toBe(true, 'Personal Files sidebar link not active'); + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES); + }) + + .then(() => apis.user.nodes.deleteNodeById(fileId, false)); + }); + }); + + describe('failure to restore', () => { + const file1 = `file-${Utils.random()}.txt`; let file1Id1, file1Id2; + const file2 = `file-${Utils.random()}.txt`; let file2Id; + + const folder1 = `folder-${Utils.random()}`; let folder1Id; + const folder2 = `folder-${Utils.random()}`; let folder2Id; + + beforeAll(done => { + apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(file1, folder1Id).then(resp => file1Id1 = resp.data.entry.id)) + .then(() => apis.user.nodes.deleteNodeById(file1Id1, false)) + .then(() => apis.user.nodes.createFile(file1, folder1Id).then(resp => file1Id2 = resp.data.entry.id)) + + .then(() => apis.user.nodes.createFolder(folder2).then(resp => folder2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(file2, folder2Id).then(resp => file2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.deleteNodeById(file2Id, false)) + .then(() => apis.user.nodes.deleteNodeById(folder2Id, false)) + + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.nodes.deleteNodeById(file1Id2), + apis.user.trashcan.emptyTrash() + ]) + .then(done); + }); + + it('Restore a file when another file with same name exists on the restore location', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.clickOnItemName(file1)) + .then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click()) + .then(() => page.getSnackBarMessage()) + .then(text => expect(text).toEqual(`Can't restore, ${file1} already exists`)); + }); + + it('Restore a file when original location no longer exists', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.clickOnItemName(file2)) + .then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click()) + .then(() => page.getSnackBarMessage()) + .then(text => expect(text).toEqual(`Can't restore ${file2}, the original location no longer exists`)); + }); + + }); + + describe('Notification on partial success', () => { + const folder1 = `folder1-${Utils.random()}.txt`; let folder1Id; + const folder2 = `folder2-${Utils.random()}.txt`; let folder2Id; + const file1 = `file-${Utils.random()}.txt`; let file1Id; + const file2 = `file-${Utils.random()}.txt`; let file2Id; + + const folder3 = `folder3-${Utils.random()}.txt`; let folder3Id; + const folder4 = `folder4-${Utils.random()}.txt`; let folder4Id; + const file3 = `file3-${Utils.random()}.txt`; let file3Id; + const file4 = `file4-${Utils.random()}.txt`; let file4Id; + const file5 = `file5-${Utils.random()}.txt`; let file5Id; + + beforeAll(done => { + apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(file1, folder1Id).then(resp => file1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolder(folder2).then(resp => folder2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(file2, folder2Id).then(resp => file2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.deleteNodeById(file1Id, false)) + .then(() => apis.user.nodes.deleteNodeById(folder1Id, false)) + .then(() => apis.user.nodes.deleteNodeById(file2Id, false)) + + .then(() => apis.user.nodes.createFolder(folder3).then(resp => folder3Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(file3, folder3Id).then(resp => file3Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(file4, folder3Id).then(resp => file4Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolder(folder4).then(resp => folder4Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(file5, folder4Id).then(resp => file5Id = resp.data.entry.id)) + .then(() => apis.user.nodes.deleteNodeById(file3Id, false)) + .then(() => apis.user.nodes.deleteNodeById(file4Id, false)) + .then(() => apis.user.nodes.deleteNodeById(folder3Id, false)) + .then(() => apis.user.nodes.deleteNodeById(file5Id, false)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.trashcan.emptyTrash(), + logoutPage.load() + ]) + .then(done); + }); + + it('one failure', () => { + dataTable.selectMultipleItems([ file1, file2 ]) + .then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click()) + .then(() => page.getSnackBarMessage()) + .then(text => expect(text).toEqual(`Can't restore ${file1}, the original location no longer exists`)); + }); + + it('multiple failures', () => { + dataTable.selectMultipleItems([ file3, file4, file5 ]) + .then(() => toolbar.actions.getButtonByTitleAttribute('Restore').click()) + .then(() => page.getSnackBarMessage()) + .then(text => expect(text).toEqual('2 items not restored because of issues with the restore location')); + }); + }); +}); diff --git a/e2e/suites/actions/toolbar-multiple-selection.test.ts b/e2e/suites/actions/toolbar-multiple-selection.test.ts new file mode 100755 index 0000000000..56c67ac1de --- /dev/null +++ b/e2e/suites/actions/toolbar-multiple-selection.test.ts @@ -0,0 +1,543 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser, protractor } from 'protractor'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; + +describe('Toolbar actions - multiple selection : ', () => { + const user1 = `user-${Utils.random()}`; + const user2 = `user-${Utils.random()}`; + + const file1 = `file-${Utils.random()}.txt`; + let file1Id; + const file2 = `file-${Utils.random()}.txt`; + let file2Id; + + const folder1 = `folder-${Utils.random()}`; + let folder1Id; + const folder2 = `folder-${Utils.random()}`; + let folder2Id; + + const fileForDelete1 = `file-${Utils.random()}.txt`; let fileForDelete1Id; + const fileForDelete2 = `file-${Utils.random()}.txt`; let fileForDelete2Id; + const folderForDelete1 = `folder-${Utils.random()}`; let folderForDelete1Id; + const folderForDelete2 = `folder-${Utils.random()}`; let folderForDelete2Id; + + const siteName = `site-private-${Utils.random()}`; + const file1Admin = `file-${Utils.random()}.txt`; + const file2Admin = `file-${Utils.random()}.txt`; + const folder1Admin = `folder-${Utils.random()}`; + const folder2Admin = `folder-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(user1, user1) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable } = page; + const { toolbar } = page; + + beforeAll(done => { + apis.admin.people.createUser(user1) + .then(() => apis.user.nodes.createFiles([ file1 ]).then(resp => file1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFiles([ file2 ]).then(resp => file2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolders([ folder1 ]).then(resp => folder1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolders([ folder2 ]).then(resp => folder2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFiles([ fileForDelete1 ]).then(resp => fileForDelete1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFiles([ fileForDelete2 ]).then(resp => fileForDelete2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolders([ folderForDelete1 ]).then(resp => folderForDelete1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolders([ folderForDelete2 ]).then(resp => folderForDelete2Id = resp.data.entry.id)) + + .then(() => apis.user.shared.shareFilesByIds([ file1Id, file2Id ])) + + .then(() => apis.user.favorites.addFavoritesByIds('file', [ file1Id, file2Id ])) + .then(() => apis.user.favorites.addFavoritesByIds('folder', [ folder1Id, folder2Id ])) + + .then(() => apis.user.nodes.deleteNodesById([ + fileForDelete1Id, fileForDelete2Id, folderForDelete1Id, folderForDelete2Id + ], false)) + + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.nodes.deleteNodesById([ file1Id, file2Id, folder1Id, folder2Id ]), + apis.user.trashcan.emptyTrash(), + logoutPage.load() + ]) + .then(done); + }); + + xit(''); + + describe('Personal Files', () => { + beforeAll(done => { + loginPage.loginWith(user1).then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('unselect selected items - single click', () => { + dataTable.selectMultipleItems([ file1, file2, folder1, folder2 ]) + .then(() => expect(dataTable.countSelectedRows()).toEqual(4, 'incorrect selected rows number')) + .then(() => dataTable.clickOnItemName(file1)) + .then(() => expect(dataTable.countSelectedRows()).toEqual(1, 'incorrect selected rows number')) + .then(() => dataTable.clearSelection()); + }); + + it('unselect selected items - CMD+click', () => { + dataTable.selectMultipleItems([ file1, file2, folder1, folder2 ]) + .then(() => expect(dataTable.countSelectedRows()).toEqual(4, 'incorrect selected rows number')) + .then(() => browser.actions().sendKeys(protractor.Key.COMMAND).perform()) + .then(() => dataTable.clickOnItemName(file1)) + .then(() => dataTable.clickOnItemName(file2)) + .then(() => browser.actions().sendKeys(protractor.Key.NULL).perform()) + .then(() => expect(dataTable.countSelectedRows()).toEqual(2, 'incorrect selected rows number')) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when multiple files are selected', () => { + dataTable.selectMultipleItems([file1, file2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when multiple folders are selected', () => { + dataTable.selectMultipleItems([folder1, folder2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when both files and folders are selected', () => { + dataTable.selectMultipleItems([file1, file2, folder1, folder2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + }); + + describe('File Libraries', () => { + beforeAll(done => { + apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC) + .then(() => apis.admin.people.createUser(user2)) + .then(() => apis.admin.sites.addSiteMember(siteName, user1, SITE_ROLES.SITE_MANAGER)) + .then(() => apis.admin.sites.addSiteMember(siteName, user2, SITE_ROLES.SITE_CONSUMER)) + .then(() => apis.admin.nodes.createFiles([ file1Admin, file2Admin ], `Sites/${siteName}/documentLibrary`)) + .then(() => apis.admin.nodes.createFolders([ folder1Admin, folder2Admin ], `Sites/${siteName}/documentLibrary`)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.doubleClickOnItemName(siteName)) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + apis.admin.sites.deleteSite(siteName).then(done); + }); + + xit(''); + + describe('user is Manager', () => { + beforeAll(done => { + loginPage.loginWith(user1).then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('correct actions appear when multiple files are selected', () => { + dataTable.selectMultipleItems([file1Admin, file2Admin]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when multiple folders are selected', () => { + dataTable.selectMultipleItems([folder1Admin, folder2Admin]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when both files and folders are selected', () => { + dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + }); + + describe('user is Consumer', () => { + beforeAll(done => { + loginPage.loginWith(user2).then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('correct actions appear when multiple files are selected', () => { + dataTable.selectMultipleItems([file1Admin, file2Admin]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when multiple folders are selected', () => { + dataTable.selectMultipleItems([folder1Admin, folder2Admin]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when both files and folders are selected', () => { + dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + }); + }); + + describe('Shared Files', () => { + beforeAll(done => { + loginPage.loginWith(user1).then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('correct actions appear when multiple files are selected', () => { + dataTable.selectMultipleItems([file1, file2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + }); + + describe('Recent Files', () => { + beforeAll(done => { + loginPage.loginWith(user1).then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('correct actions appear when multiple files are selected', () => { + dataTable.selectMultipleItems([file1, file2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + }); + + describe('Favorites', () => { + beforeAll(done => { + loginPage.loginWith(user1).then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('correct actions appear when multiple files are selected', () => { + dataTable.selectMultipleItems([file1, file2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when multiple folders are selected', () => { + dataTable.selectMultipleItems([folder1, folder2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when both files and folders are selected', () => { + dataTable.selectMultipleItems([file1, file2, folder1, folder2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + // .then(() => browser.$('body').click()) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clearSelection()); + }); + }); + + // [C217090] + describe('Trash', () => { + beforeAll(done => { + loginPage.loginWith(user1).then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('correct actions appear when multiple files are selected', () => { + dataTable.selectMultipleItems([fileForDelete1, fileForDelete2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('Permanently delete')) + .toBe(true, 'Permanently delete is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, 'Restore is not displayed for selected files'); + }) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when multiple folders are selected', () => { + dataTable.selectMultipleItems([folderForDelete1, folderForDelete2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('Permanently delete')) + .toBe(true, 'Permanently delete is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, 'Restore is not displayed for selected files'); + }) + .then(() => dataTable.clearSelection()); + }); + + it('correct actions appear when both files and folders are selected', () => { + dataTable.selectMultipleItems([fileForDelete1, fileForDelete2, folderForDelete1, folderForDelete2]) + .then(() => { + expect(toolbar.actions.isButtonPresent('Permanently delete')) + .toBe(true, 'Permanently delete is displayed for selected files'); + expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, 'Restore is not displayed for selected files'); + }) + .then(() => dataTable.clearSelection()); + }); + }); +}); diff --git a/e2e/suites/actions/toolbar-single-selection.test.ts b/e2e/suites/actions/toolbar-single-selection.test.ts new file mode 100755 index 0000000000..61e20a22c4 --- /dev/null +++ b/e2e/suites/actions/toolbar-single-selection.test.ts @@ -0,0 +1,752 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; + +describe('Toolbar actions - single selection : ', () => { + const username = `user-${Utils.random()}`; + const username2 = `user-${Utils.random()}`; + + const fileUser = `file-${Utils.random()}.txt`; let fileUserId; + + const folderUser = `folder-${Utils.random()}`; let folderUserId; + + const fileForDelete = `file-${Utils.random()}.txt`; let fileForDeleteId; + + const folderForDelete = `folder-${Utils.random()}`; let folderForDeleteId; + + const siteName = `site-private-${Utils.random()}`; + const fileAdmin = `file-${Utils.random()}.txt`; + const folderAdmin = `folder-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, toolbar } = page; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.user.nodes.createFiles([ fileUser ])) + .then(resp => fileUserId = resp.data.entry.id) + .then(() => apis.user.nodes.createFiles([ fileForDelete ])) + .then(resp => fileForDeleteId = resp.data.entry.id) + .then(() => apis.user.nodes.createFolders([ folderForDelete ])) + .then(resp => folderForDeleteId = resp.data.entry.id) + .then(() => apis.user.nodes.createFolders([ folderUser ])) + .then(resp => folderUserId = resp.data.entry.id) + .then(() => apis.user.shared.shareFileById(fileUserId)) + .then(() => apis.user.favorites.addFavoriteById('file', fileUserId)) + .then(() => apis.user.favorites.addFavoriteById('folder', folderUserId)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.nodes.deleteNodeById(fileUserId), + apis.user.nodes.deleteNodeById(folderUserId), + logoutPage.load() + ]) + .then(done); + }); + + xit(''); + + describe('General tests', () => { + const userSite = `site-${Utils.random()}`; + + beforeAll(done => { + apis.user.sites.createSite(userSite, SITE_VISIBILITY.PUBLIC) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.sites.deleteSite(userSite), + logoutPage.load() + ]) + .then(done); + }); + + it('actions not displayed for top level of File Libraries', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.clickOnItemName(userSite)) + .then(() => expect(toolbar.actions.isEmpty()).toBe(true, 'toolbar not empty')); + }); + + it('selected row is marked with a check circle icon', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.clickOnItemName(fileUser)) + .then(() => expect(dataTable.hasCheckMarkIcon(fileUser)).toBe(true, 'check mark missing')); + }); + + describe('granular permissions', () => { + const site = `site-${Utils.random()}`; + const file1 = `file-${Utils.random()}`; let file1Id; + const file2 = `file-${Utils.random()}`; let file2Id; + + beforeAll(done => { + apis.admin.sites.createSite(site, SITE_VISIBILITY.PRIVATE) + .then(() => apis.admin.nodes.createFiles([ file1 ], `Sites/${site}/documentLibrary`) + .then(resp => file1Id = resp.data.entry.id)) + .then(() => apis.admin.nodes.createFiles([ file2 ], `Sites/${site}/documentLibrary`) + .then(resp => file2Id = resp.data.entry.id)) + .then(() => apis.admin.sites.addSiteMember(site, username, SITE_ROLES.SITE_CONSUMER)) + .then(() => apis.admin.nodes.setGranularPermission(file1Id, false, username, SITE_ROLES.SITE_CONSUMER)) + .then(() => apis.admin.nodes.setGranularPermission(file2Id, false, username, SITE_ROLES.SITE_MANAGER)) + + .then(() => apis.user.shared.shareFileById(file1Id)) + .then(() => apis.admin.shared.shareFileById(file2Id)) + + .then(() => apis.user.favorites.addFavoritesByIds('file', [file1Id, file2Id])) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.admin.sites.deleteSite(site), + logoutPage.load() + ]) + .then(done); + }); + + describe('actions update accordingly for files with different granular permissions', () => { + it('on File Libraries', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.doubleClickOnItemName(site)) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.clickOnItemName(file1)) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file1}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file1}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file1}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file1}`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${file1}`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${file1}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file1}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clickOnItemName(file2)) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file2}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file2}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file2}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file2}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${file2}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${file2}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file2}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + + it('on Shared Files', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.clickOnItemName(file1)) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file1}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file1}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file1}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file1}`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${file1}`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${file1}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file1}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clickOnItemName(file2)) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file2}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file2}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file2}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file2}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${file2}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${file2}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file2}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + + // disabled until ACA-1184 is done + xit('on Favorites', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.clickOnItemName(file1)) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file1}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file1}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file1}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file1}`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${file1}`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${file1}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file1}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()) + .then(() => dataTable.clickOnItemName(file2)) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${file2}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${file2}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${file2}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${file2}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${file2}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${file2}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${file2}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + }); + + describe('correct actions are displayed when selecting multiple files with different granular permissions', () => { + it('on File Libraries', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.doubleClickOnItemName(site)) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.selectMultipleItems([ file1, file2 ])) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for selected files`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for selected files`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for selected files`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + + it('on Shared Files', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.selectMultipleItems([ file1, file2 ])) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for selected files`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for selected files`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for selected files`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + + // disabled until ACA-1184 is done + xit('on Favorites', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.selectMultipleItems([ file1, file2 ])) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for selected files`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for selected files`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for selected files`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + }); + + xit(''); + }); + }); + + describe('Personal Files', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('actions are not displayed when no item is selected', () => { + expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`); + }); + + it('actions are displayed when a file is selected', () => { + dataTable.clickOnItemName(fileUser) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileUser}`); + }); + }); + + it('actions are displayed when a folder is selected', () => { + dataTable.clickOnItemName(folderUser) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderUser}`); + }); + }); + + it('correct actions appear when a file is selected', () => { + dataTable.clickOnItemName(fileUser) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileUser}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileUser}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileUser}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileUser}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + + it('correct actions appear when a folder is selected', () => { + dataTable.clickOnItemName(folderUser) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for ${folderUser}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not enabled for ${folderUser}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, `Edit is not displayed for ${folderUser}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${folderUser}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${folderUser}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${folderUser}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${folderUser}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + }); + + describe('File Libraries', () => { + beforeAll(done => { + apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC) + .then(() => apis.admin.people.createUser(username2)) + .then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_MANAGER)) + .then(() => apis.admin.sites.addSiteMember(siteName, username2, SITE_ROLES.SITE_CONSUMER)) + .then(() => apis.admin.nodes.createFiles([ fileAdmin ], `Sites/${siteName}/documentLibrary`)) + .then(() => apis.admin.nodes.createFolders([ folderAdmin ], `Sites/${siteName}/documentLibrary`)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.doubleClickOnItemName(siteName)) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + apis.admin.sites.deleteSite(siteName).then(done); + }); + + xit(''); + + describe('user is Manager', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('actions are not displayed when no item is selected', () => { + expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`); + }); + + it('actions are displayed when a file is selected', () => { + dataTable.clickOnItemName(fileAdmin) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileAdmin}`); + }); + }); + + it('actions are displayed when a folder is selected', () => { + dataTable.clickOnItemName(folderAdmin) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderAdmin}`); + }); + }); + + it('correct actions appear when a file is selected', () => { + dataTable.clickOnItemName(fileAdmin) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileAdmin}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileAdmin}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileAdmin}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileAdmin}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileAdmin}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileAdmin}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileAdmin}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + + it('correct actions appear when a folder is selected', () => { + dataTable.clickOnItemName(folderAdmin) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for ${folderAdmin}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not enabled for ${folderAdmin}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, `Edit is not displayed for ${folderAdmin}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${folderAdmin}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${folderAdmin}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${folderAdmin}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${folderAdmin}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + }); + + describe('user is Consumer', () => { + beforeAll(done => { + loginPage.loginWith(username2).then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('actions are not displayed when no item is selected', () => { + expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`); + }); + + it('actions are displayed when a file is selected', () => { + dataTable.clickOnItemName(fileAdmin) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileAdmin}`); + }); + }); + + it('actions are displayed when a folder is selected', () => { + dataTable.clickOnItemName(folderAdmin) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderAdmin}`); + }); + }); + + it('correct actions appear when a file is selected', () => { + dataTable.clickOnItemName(fileAdmin) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileAdmin}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileAdmin}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileAdmin}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileAdmin}`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${fileAdmin}`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${fileAdmin}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileAdmin}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + + it('correct actions appear when a folder is selected', () => { + dataTable.clickOnItemName(folderAdmin) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for ${folderAdmin}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not enabled for ${folderAdmin}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${folderAdmin}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${folderAdmin}`); + expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for ${folderAdmin}`); + expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for ${folderAdmin}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${folderAdmin}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + }); + }); + + describe('Shared Files', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('actions are not displayed when no item is selected', () => { + expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`); + }); + + it('actions are displayed when a file is selected', () => { + dataTable.clickOnItemName(fileUser) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileUser}`); + }); + }); + + it('correct actions appear when a file is selected', () => { + dataTable.clickOnItemName(fileUser) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileUser}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileUser}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileUser}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileUser}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + }); + + describe('Recent Files', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('actions are not displayed when no item is selected', () => { + expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`); + }); + + it('actions are displayed when a file is selected', () => { + dataTable.clickOnItemName(fileUser) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileUser}`); + }); + }); + + it('correct actions appear when a file is selected', () => { + dataTable.clickOnItemName(fileUser) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileUser}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileUser}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileUser}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileUser}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + }); + + describe('Favorites', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('actions are not displayed when no item is selected', () => { + expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`); + }); + + it('actions are displayed when a file is selected', () => { + dataTable.clickOnItemName(fileUser) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileUser}`); + }); + }); + + it('actions are displayed when a folder is selected', () => { + dataTable.clickOnItemName(folderUser) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderUser}`); + }); + }); + + it('correct actions appear when a file is selected', () => { + dataTable.clickOnItemName(fileUser) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for ${fileUser}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for ${fileUser}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for ${fileUser}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${fileUser}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${fileUser}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + + it('correct actions appear when a folder is selected', () => { + dataTable.clickOnItemName(folderUser) + .then(() => { + expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for ${folderUser}`); + expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not enabled for ${folderUser}`); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, `Edit is not displayed for ${folderUser}`); + }) + .then(() => toolbar.actions.openMoreMenu()) + .then(menu => { + expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for ${folderUser}`); + expect(menu.isMenuItemPresent('Delete')).toBe(true, `Delete is not displayed for ${folderUser}`); + expect(menu.isMenuItemPresent('Move')).toBe(true, `Move is not displayed for ${folderUser}`); + expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for ${folderUser}`); + }) + .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); + }); + }); + + // [C217090] + describe('Trash', () => { + beforeAll(done => { + apis.user.nodes.deleteNodeById(fileForDeleteId, false) + .then(() => apis.user.nodes.deleteNodeById(folderForDeleteId, false)) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.trashcan.permanentlyDelete(fileForDeleteId), + apis.user.trashcan.permanentlyDelete(folderForDeleteId), + logoutPage.load() + ]) + .then(done); + }); + + it('actions are not displayed when no item is selected', () => { + expect(toolbar.actions.isEmpty()).toBe(true, `actions displayed though nothing selected`); + }); + + it('actions are displayed when a file is selected', () => { + dataTable.clickOnItemName(fileForDelete) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${fileForDelete}`); + }); + }); + + it('actions are displayed when a folder is selected', () => { + dataTable.clickOnItemName(folderForDelete) + .then(() => { + expect(toolbar.actions.isEmpty()).toBe(false, `actions not displayed for ${folderForDelete}`); + }); + }); + + it('correct actions appear when a file is selected', () => { + dataTable.clickOnItemName(fileForDelete) + .then(() => { + expect(toolbar.actions.isButtonPresent('Permanently delete')) + .toBe(true, `Permanently delete is not displayed for ${fileForDelete}`); + expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, `Restore is not displayed for ${fileForDelete}`); + }); + }); + + it('correct actions appear when a folder is selected', () => { + dataTable.clickOnItemName(folderForDelete) + .then(() => { + expect(toolbar.actions.isButtonPresent('Permanently delete')) + .toBe(true, `Permanently delete is displayed for ${folderForDelete}`); + expect(toolbar.actions.isButtonPresent('Restore')).toBe(true, `Restore is not enabled for ${folderForDelete}`); + }); + }); + }); +}); diff --git a/e2e/suites/actions/undo-delete.test.ts b/e2e/suites/actions/undo-delete.test.ts new file mode 100755 index 0000000000..2409444d4a --- /dev/null +++ b/e2e/suites/actions/undo-delete.test.ts @@ -0,0 +1,423 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { SIDEBAR_LABELS } from '../../configs'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; + +describe('Undo delete content', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, toolbar } = page; + + beforeAll(done => { + apis.admin.people.createUser(username).then(done); + }); + + afterAll(done => { + apis.admin.trashcan.emptyTrash().then(done); + }); + + xit(''); + + describe('on Personal Files', () => { + const file1 = `file1-${Utils.random()}.txt`; let file1Id; + const file2 = `file2-${Utils.random()}.txt`; let file2Id; + const file3 = `file3-${Utils.random()}.txt`; let file3Id; + const file4 = `file4-${Utils.random()}.txt`; + const folder1 = `folder1-${Utils.random()}`; let folder1Id; + const folder2 = `folder2-${Utils.random()}`; let folder2Id; + const fileLocked2 = `fileLocked2-${Utils.random()}.txt`; let fileLocked2Id; + + beforeAll(done => { + apis.user.nodes.createFile(file1).then(resp => file1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(file2).then(resp => file2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(file3).then(resp => file3Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(file4, folder1Id)) + .then(() => apis.user.nodes.createFolder(folder2).then(resp => folder2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(fileLocked2, folder2Id).then(resp => fileLocked2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.lockFile(fileLocked2Id)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + page.refresh().then(done); + }); + + afterAll(done => { + Promise.all([ + logoutPage.load(), + apis.user.nodes.unlockFile(fileLocked2Id) + .then(() => apis.user.nodes.deleteNodesById([file1Id, file2Id, file3Id, folder1Id, folder2Id])) + ]) + .then(done); + }); + + it('Successful delete notification shows Undo action', () => { + dataTable.clickOnItemName(file1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).toContain(`Undo`); + }) + + .then(() => apis.user.trashcan.restore(file1Id)); + }); + + it('Unsuccessful delete notification does not show Undo action', () => { + dataTable.clickOnItemName(folder2) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => { + expect(message).not.toContain(`Undo`); + }); + }); + + it('Undo delete of file', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.clickOnItemName(file1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => { + expect(dataTable.getRowName(file1).isPresent()).toBe(true, 'Item was not restored'); + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }); + }); + + it('Undo delete of folder with content', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.clickOnItemName(folder1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => { + expect(dataTable.getRowName(folder1).isPresent()).toBe(true, 'Item was not restored'); + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }) + .then(() => dataTable.doubleClickOnItemName(folder1)) + .then(() => { + expect(dataTable.getRowName(file4).isPresent()).toBe(true, 'file from folder not restored'); + }); + }); + + it('undo delete of multiple files', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.selectMultipleItems([file2, file3]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => { + expect(dataTable.getRowName(file2).isPresent()).toBe(true, `${file2} was not removed from list`); + expect(dataTable.getRowName(file3).isPresent()).toBe(true, `${file3} was not removed from list`); + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }); + }); + }); + + describe('on Shared Files', () => { + const sharedFile1 = `sharedFile1-${Utils.random()}`; let sharedFile1Id; + const sharedFile2 = `sharedFile2-${Utils.random()}`; let sharedFile2Id; + const sharedFile3 = `sharedFile3-${Utils.random()}`; let sharedFile3Id; + const sharedFile4 = `sharedFile4-${Utils.random()}`; let sharedFile4Id; + + beforeAll(done => { + apis.user.nodes.createFile(sharedFile1).then(resp => sharedFile1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(sharedFile2).then(resp => sharedFile2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(sharedFile3).then(resp => sharedFile3Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(sharedFile4).then(resp => sharedFile4Id = resp.data.entry.id)) + .then(() => apis.user.shared.shareFilesByIds([sharedFile1Id, sharedFile2Id, sharedFile3Id, sharedFile4Id])) + .then(() => apis.user.shared.waitForApi({ expect: 4 })) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + page.refresh().then(done); + }); + + afterAll(done => { + Promise.all([ + logoutPage.load(), + apis.user.nodes.deleteNodesById([sharedFile2Id, sharedFile3Id, sharedFile4Id]) + ]) + .then(done); + }); + + it('Successful delete notification shows Undo action', () => { + dataTable.clickOnItemName(sharedFile1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => expect(message).toContain(`Undo`)); + }); + + it('Undo delete of file', () => { + dataTable.clickOnItemName(sharedFile2) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => expect(dataTable.getRowName(sharedFile2).isPresent()).toBe(false, 'Item was not restored')); + }); + + it('undo delete of multiple files', () => { + dataTable.selectMultipleItems([sharedFile3, sharedFile4]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(sharedFile3).isPresent()).toBe(false, `${sharedFile3} was not restored`); + expect(dataTable.getRowName(sharedFile4).isPresent()).toBe(false, `${sharedFile4} was not restored`); + }); + }); + }); + + describe('on Favorites', () => { + const favoriteFile1 = `favFile1-${Utils.random()}.txt`; let favoriteFile1Id; + const favoriteFile2 = `favFile2-${Utils.random()}.txt`; let favoriteFile2Id; + const favoriteFile4 = `favFile4-${Utils.random()}.txt`; + const favoriteFileLocked2 = `favFileLocked2-${Utils.random()}.txt`; let favoriteFileLocked2Id; + const favoriteFolder1 = `favFolder1-${Utils.random()}`; let favoriteFolder1Id; + const favoriteFolder2 = `favFolder2-${Utils.random()}`; let favoriteFolder2Id; + + beforeAll(done => { + apis.user.nodes.createFile(favoriteFile1).then(resp => favoriteFile1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(favoriteFile2).then(resp => favoriteFile2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolder(favoriteFolder1).then(resp => favoriteFolder1Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(favoriteFile4, favoriteFolder1Id)) + .then(() => apis.user.nodes.createFolder(favoriteFolder2).then(resp => favoriteFolder2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(favoriteFileLocked2, favoriteFolder2Id) + .then(resp => favoriteFileLocked2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.lockFile(favoriteFileLocked2Id)) + + .then(() => apis.user.favorites.addFavoritesByIds('file', [favoriteFile1Id, favoriteFile2Id])) + .then(() => apis.user.favorites.addFavoritesByIds('folder', [favoriteFolder1Id, favoriteFolder2Id])) + .then(() => apis.user.favorites.waitForApi({ expect: 4 })) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + page.refresh().then(done); + }); + + afterAll(done => { + Promise.all([ + logoutPage.load(), + apis.user.nodes.unlockFile(favoriteFileLocked2Id) + .then(() => apis.user.nodes.deleteNodesById([favoriteFile1Id, favoriteFile2Id, favoriteFolder1Id, favoriteFolder2Id])) + ]) + .then(done); + }); + + it('Successful delete notification shows Undo action', () => { + dataTable.clickOnItemName(favoriteFile1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => expect(message).toContain(`Undo`)) + + .then(() => apis.user.trashcan.restore(favoriteFile1Id)); + }); + + it('Unsuccessful delete notification does not show Undo action', () => { + dataTable.clickOnItemName(favoriteFolder2) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => expect(message).not.toContain(`Undo`)); + }); + + it('Undo delete of file', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.clickOnItemName(favoriteFile1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => { + expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(true, 'Item was not restored'); + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }); + }); + + it('Undo delete of folder with content', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.clickOnItemName(favoriteFolder1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => { + expect(dataTable.getRowName(favoriteFolder1).isPresent()).toBe(true, 'Item was not restored'); + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }) + .then(() => dataTable.doubleClickOnItemName(favoriteFolder1)) + .then(() => expect(dataTable.getRowName(favoriteFile4).isPresent()).toBe(true, 'file from folder not restored')); + }); + + it('undo delete of multiple files', () => { + let items: number; + page.dataTable.countRows().then(number => { items = number; }); + + dataTable.selectMultipleItems([favoriteFile1, favoriteFile2]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => { + expect(dataTable.getRowName(favoriteFile1).isPresent()).toBe(true, `${favoriteFile1} was not removed from list`); + expect(dataTable.getRowName(favoriteFile2).isPresent()).toBe(true, `${favoriteFile2} was not removed from list`); + expect(page.pagination.range.getText()).toContain(`1-${items} of ${items}`); + }); + }); + }); + + describe('on Recent Files', () => { + const recentFile1 = `recentFile1-${Utils.random()}.txt`; let recentFile1Id; + const recentFile2 = `recentFile2-${Utils.random()}.txt`; let recentFile2Id; + const recentFile3 = `recentFile3-${Utils.random()}.txt`; let recentFile3Id; + const recentFile4 = `recentFile4-${Utils.random()}.txt`; let recentFile4Id; + + beforeAll(done => { + apis.user.nodes.createFile(recentFile1).then(resp => recentFile1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(recentFile2).then(resp => recentFile2Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(recentFile3).then(resp => recentFile3Id = resp.data.entry.id)) + .then(() => apis.user.nodes.createFile(recentFile4).then(resp => recentFile4Id = resp.data.entry.id)) + .then(() => apis.user.search.waitForApi(username, { expect: 4 })) + + .then(() => loginPage.loginWith(username)) + + .then((): any => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.isEmptyList()) + .then(empty => { + if (empty) { + browser.sleep(6000).then(() => page.refresh()); + } + }) + ) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + page.refresh().then(done); + }); + + afterAll(done => { + Promise.all([ + logoutPage.load(), + apis.user.nodes.deleteNodesById([recentFile2Id, recentFile3Id, recentFile4Id]) + ]) + .then(done); + }); + + it('Successful delete notification shows Undo action', () => { + dataTable.clickOnItemName(recentFile1) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.getSnackBarMessage()) + .then(message => expect(message).toContain(`Undo`)); + }); + + // due to the fact that the search api is slow to update, + // we cannot test that the restored file is displayed in the Recent Files list + // without adding a very big browser.sleep followed by a page.refresh + // so for the moment we're testing that the restored file is not displayed in the Trash + it('Undo delete of file', () => { + dataTable.clickOnItemName(recentFile2) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => expect(dataTable.getRowName(recentFile2).isPresent()).toBe(false, 'Item is in Trash')); + }); + + // due to the fact that the search api is slow to update, + // we cannot test that the restored file is displayed in the Recent Files list + // without adding a very big browser.sleep followed by a page.refresh + // so for the moment we're testing that the restored file is not displayed in the Trash + it('undo delete of multiple files', () => { + dataTable.selectMultipleItems([recentFile3, recentFile4]) + .then(() => toolbar.actions.openMoreMenu()) + .then(() => toolbar.actions.menu.clickMenuItem('Delete')) + .then(() => page.clickSnackBarAction()) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => { + expect(dataTable.getRowName(recentFile3).isPresent()).toBe(false, `${recentFile3} is in Trash`); + expect(dataTable.getRowName(recentFile4).isPresent()).toBe(false, `${recentFile4} is in Trash`); + }); + }); + }); +}); diff --git a/e2e/suites/actions/upload-file.test.ts b/e2e/suites/actions/upload-file.test.ts new file mode 100755 index 0000000000..7789d43662 --- /dev/null +++ b/e2e/suites/actions/upload-file.test.ts @@ -0,0 +1,74 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +// import { browser, protractor, promise } from 'protractor'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { SIDEBAR_LABELS } from '../../configs'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { Utils } from '../../utilities/utils'; + +describe('Upload files', () => { + const username = `user-${Utils.random()}`; + + const folder1 = `folder1-${Utils.random()}`; let folder1Id; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable } = page; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.user.nodes.createFolder(folder1).then(resp => folder1Id = resp.data.entry.id)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + Promise.all([ + // apis.user.nodes.deleteNodeById(folder1Id), + logoutPage.load() + ]) + .then(done); + }); + + it('Upload a file', () => { + dataTable.doubleClickOnItemName(folder1) + .then(() => page.sidenav.openNewMenu()) + .then(() => page.sidenav.menu.uploadFile().sendKeys(`${__dirname}/create-folder.test.ts`)); + }); +}); diff --git a/e2e/suites/application/page-titles.test.ts b/e2e/suites/application/page-titles.test.ts new file mode 100755 index 0000000000..07197ca50a --- /dev/null +++ b/e2e/suites/application/page-titles.test.ts @@ -0,0 +1,128 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; + +import { SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; + +describe('Page titles', () => { + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + + xit(''); + + describe('on Login / Logout pages', () => { + it('on Login page', () => { + loginPage.load() + .then(() => { + expect(browser.getTitle()).toContain('Sign in'); + }); + }); + + it('after logout', () => { + loginPage.loginWithAdmin() + .then(() => page.signOut()) + .then(() => { + expect(browser.getTitle()).toContain('Sign in'); + }); + }); + + it('when pressing Back after Logout', () => { + loginPage.loginWithAdmin() + .then(() => page.signOut()) + .then(() => browser.navigate().back()) + .then(() => { + expect(browser.getTitle()).toContain('Sign in'); + }); + }); + }); + + describe('on list views', () => { + beforeAll(done => { + loginPage.loginWithAdmin().then(done); + }); + + afterAll(done => { + logoutPage.load() + .then(done); + }); + + it('Personal Files page', () => { + const label = SIDEBAR_LABELS.PERSONAL_FILES; + + page.sidenav.navigateToLinkByLabel(label) + .then(() => { + expect(browser.getTitle()).toContain(label); + }); + }); + + it('File Libraries page', () => { + const label = SIDEBAR_LABELS.FILE_LIBRARIES; + + page.sidenav.navigateToLinkByLabel(label) + .then(() => { + expect(browser.getTitle()).toContain(label); + }); + }); + + it('Shared Files page', () => { + const label = SIDEBAR_LABELS.SHARED_FILES; + + page.sidenav.navigateToLinkByLabel(label) + .then(() => { + expect(browser.getTitle()).toContain(label); + }); + }); + + it('Recent Files page', () => { + const label = SIDEBAR_LABELS.RECENT_FILES; + + page.sidenav.navigateToLinkByLabel(label) + .then(() => { + expect(browser.getTitle()).toContain(label); + }); + }); + + it('Favorites page', () => { + const label = SIDEBAR_LABELS.FAVORITES; + + page.sidenav.navigateToLinkByLabel(label) + .then(() => { + expect(browser.getTitle()).toContain(label); + }); + }); + + it('Trash page', () => { + const label = SIDEBAR_LABELS.TRASH; + + page.sidenav.navigateToLinkByLabel(label) + .then(() => { + expect(browser.getTitle()).toContain(label); + }); + }); + }); +}); diff --git a/e2e/suites/authentication/login.test.ts b/e2e/suites/authentication/login.test.ts new file mode 100755 index 0000000000..3ab8cdfab6 --- /dev/null +++ b/e2e/suites/authentication/login.test.ts @@ -0,0 +1,237 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; + +import { APP_ROUTES } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Login', () => { + const peopleApi = new RepoClient().people; + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + + const testUser = `user-${Utils.random()}@alfness`; + + const russianUser = { + username: `пользвате${Utils.random()}`, + password: '密碼中國' + }; + + const johnDoe = { + username: `user-${Utils.random()}`, + get password() { return this.username; }, + firstName: 'John', + lastName: 'Doe' + }; + + const disabledUser = `user-${Utils.random()}`; + const testUser2 = { + username: `user-${Utils.random()}`, + password: 'user2 password' + }; + const newPassword = 'new password'; + + beforeAll(done => { + Promise + .all([ + peopleApi.createUser(testUser), + peopleApi.createUser(russianUser.username, russianUser.password), + peopleApi.createUser(johnDoe.username, johnDoe.password, { + firstName: johnDoe.firstName, + lastName: johnDoe.lastName + }), + peopleApi.createUser(disabledUser).then(() => peopleApi.disableUser(disabledUser)), + peopleApi.createUser(testUser2.username, testUser2.password) + ]) + .then(done); + }); + + afterEach(done => { + logoutPage.load() + .then(() => Utils.clearLocalStorage()) + .then(done); + }); + + xit(''); + + describe('general tests', () => { + beforeEach(done => { + loginPage.load().then(done); + }); + + it('login page default values', () => { + expect(loginPage.login.usernameInput.isEnabled()).toBe(true, 'username input is not enabled'); + expect(loginPage.login.passwordInput.isEnabled()).toBe(true, 'password input is not enabled'); + expect(loginPage.login.submitButton.isEnabled()).toBe(false, 'SIGN IN button is enabled'); + expect(loginPage.login.getPasswordVisibility()).toBe(false, 'Password is not hidden by default'); + }); + + it('change password visibility', () => { + loginPage.login.enterPassword('some password'); + expect(loginPage.login.isPasswordShown()).toBe(false, 'password is visible'); + loginPage.login.passwordVisibility.click() + .then(() => { + expect(loginPage.login.getPasswordVisibility()).toBe(true, 'Password visibility not changed'); + expect(loginPage.login.isPasswordShown()).toBe(true, 'password is not visible'); + }); + }); + }); + + describe('with valid credentials', () => { + it('navigate to "Personal Files"', () => { + const { username } = johnDoe; + + loginPage.loginWith(username) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES); + }); + }); + + it(`displays user's name in header`, () => { + const { userInfo } = new BrowsingPage(APP_ROUTES.PERSONAL_FILES).header; + const { username, firstName, lastName } = johnDoe; + + loginPage.loginWith(username) + .then(() => { + expect(userInfo.name).toEqual(`${firstName} ${lastName}`); + }); + }); + + it(`logs in with user having username containing "@"`, () => { + loginPage + .loginWith(testUser) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES); + }); + }); + + it('logs in with user with non-latin characters', () => { + const { username, password } = russianUser; + + loginPage + .loginWith(username, password) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES); + }); + }); + + it('redirects to Home Page when navigating to the Login page while already logged in', () => { + const { username } = johnDoe; + + loginPage + .loginWith(username) + .then(() => browser.get(APP_ROUTES.LOGIN) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES); + }) + ); + }); + + it('redirects to Personal Files when pressing browser Back while already logged in ', () => { + const { username } = johnDoe; + + loginPage + .loginWith(username) + .then(() => browser.navigate().back()) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES); + }); + }); + + it('user is able to login after changing his password', () => { + loginPage.loginWith(testUser2.username, testUser2.password) + .then(() => logoutPage.load()) + .then(() => peopleApi.changePassword(testUser2.username, newPassword)) + .then(() => loginPage.loginWith(testUser2.username, newPassword)) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES); + }); + }); + }); + + describe('with invalid credentials', () => { + const { login: loginComponent } = loginPage; + const { submitButton, errorMessage } = loginComponent; + + beforeEach(done => { + loginPage.load().then(done); + }); + + it('disabled submit button when no credentials are entered', () => { + expect(submitButton.isEnabled()).toBe(false); + }); + + it('disabled submit button when password is empty', () => { + loginComponent.enterUsername('any-username'); + expect(submitButton.isEnabled()).toBe(false); + }); + + it('disabled submit button when username is empty', () => { + loginPage.login.enterPassword('any-password'); + expect(submitButton.isEnabled()).toBe(false); + }); + + it('shows error when entering nonexistent user', () => { + loginPage + .tryLoginWith('nonexistent-user', 'any-password') + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN); + expect(errorMessage.isDisplayed()).toBe(true); + expect(errorMessage.getText()).toBe(`You've entered an unknown username or password`); + }); + }); + + it('shows error when entering invalid password', () => { + const { username } = johnDoe; + + loginPage + .tryLoginWith(username, 'incorrect-password') + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN); + expect(errorMessage.isDisplayed()).toBe(true); + expect(errorMessage.getText()).toBe(`You've entered an unknown username or password`); + }); + }); + + it('unauthenticated user is redirected to Login page', () => { + browser.get(APP_ROUTES.PERSONAL_FILES) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN); + }); + }); + + it('disabled user is not logged in', () => { + loginPage.tryLoginWith(disabledUser) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN); + expect(errorMessage.isDisplayed()).toBe(true); + expect(errorMessage.getText()).toBe(`You've entered an unknown username or password`); + }); + }); + }); +}); diff --git a/e2e/suites/authentication/logout.test.ts b/e2e/suites/authentication/logout.test.ts new file mode 100755 index 0000000000..dfb79669a3 --- /dev/null +++ b/e2e/suites/authentication/logout.test.ts @@ -0,0 +1,82 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; +import { APP_ROUTES } from '../../configs'; + +describe('Logout', () => { + const page = new BrowsingPage(); + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + + const peopleApi = new RepoClient().people; + + const johnDoe = `user-${Utils.random()}`; + + beforeAll((done) => { + peopleApi + .createUser(johnDoe) + .then(done); + }); + + beforeEach((done) => { + loginPage.loginWith(johnDoe).then(done); + }); + + afterEach((done) => { + logoutPage.load().then(done); + }); + + it('Sign out option is available [C213143]', () => { + page.header.userInfo.openMenu() + .then(() => expect(page.header.userInfo.menu.isMenuItemPresent('Sign out')).toBe(true, 'Sign out option not displayed')); + }); + + it('redirects to Login page on sign out [C213144]', () => { + page.signOut() + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN); + }); + }); + + it('redirects to Login page when pressing browser Back after logout [C213145]', () => { + page.signOut() + .then(() => browser.navigate().back()) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN); + }); + }); + + it('redirects to Login page when trying to access a part of the app after logout [C213146]', () => { + page.signOut() + .then(() => page.load('/favorites')) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.LOGIN); + }); + }); +}); diff --git a/e2e/suites/list-views/empty-list.test.ts b/e2e/suites/list-views/empty-list.test.ts new file mode 100755 index 0000000000..dd9ea40cd5 --- /dev/null +++ b/e2e/suites/list-views/empty-list.test.ts @@ -0,0 +1,108 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Empty list views', () => { + const username = `user-${Utils.random()}`; + const password = username; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, password) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable } = page; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('empty Personal Files', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => { + expect(dataTable.isEmptyList()).toBe(true, 'list is not empty'); + expect(dataTable.getEmptyDragAndDropText()).toContain('Drag and drop'); + }); + }); + + it('empty File Libraries [C217099]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => { + expect(dataTable.isEmptyList()).toBe(true, 'list is not empty'); + expect(dataTable.getEmptyStateTitle()).toContain(`You aren't a member of any File Libraries yet`); + expect(dataTable.getEmptyStateSubtitle()).toContain('Join sites to upload, view, and share files.'); + }); + }); + + it('empty Shared Files', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => { + expect(dataTable.isEmptyList()).toBe(true, 'list is not empty'); + expect(dataTable.getEmptyStateTitle()).toContain('No shared files or folders'); + expect(dataTable.getEmptyStateSubtitle()).toContain('Items you share using the Share option are shown here.'); + }); + }); + + it('empty Recent Files [C213169]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => { + expect(dataTable.isEmptyList()).toBe(true, 'list is not empty'); + expect(dataTable.getEmptyStateTitle()).toContain('No recent files'); + expect(dataTable.getEmptyStateSubtitle()).toContain('Items you upload or edit in the last 30 days are shown here.'); + }); + }); + + it('empty Favorites', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => { + expect(dataTable.isEmptyList()).toBe(true, 'list is not empty'); + expect(dataTable.getEmptyStateTitle()).toContain('No favorite files or folders'); + expect(dataTable.getEmptyStateSubtitle()).toContain('Favorite items that you want to easily find later.'); + }); + }); + + it('empty Trash', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => { + expect(dataTable.isEmptyList()).toBe(true, 'list is not empty'); + expect(dataTable.getEmptyStateTitle()).toContain('Trash is empty'); + expect(dataTable.getEmptyStateText()).toContain('Items you delete are moved to the Trash.'); + expect(dataTable.getEmptyStateText()).toContain('Empty Trash to permanently delete items.'); + }); + }); +}); diff --git a/e2e/suites/list-views/favorites.test.ts b/e2e/suites/list-views/favorites.test.ts new file mode 100755 index 0000000000..3cd8ae546e --- /dev/null +++ b/e2e/suites/list-views/favorites.test.ts @@ -0,0 +1,156 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Favorites', () => { + const username = `user-${Utils.random()}`; + const password = username; + + const siteName = `site-${Utils.random()}`; + const folderName = `folder-${Utils.random()}`; + const fileName1 = `file1-${Utils.random()}.txt`; + const fileName2 = `file2-${Utils.random()}.txt`; + const fileName3 = `file3-${Utils.random()}.txt`; let file3Id; + const fileName4 = `file4-${Utils.random()}.txt`; let file4Id; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, password) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const favoritesPage = new BrowsingPage(); + const { dataTable } = favoritesPage; + const { breadcrumb } = favoritesPage.toolbar; + + beforeAll(done => { + apis.admin.people.createUser(username) + + .then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC)) + .then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_MANAGER)) + .then(() => apis.admin.nodes.createFiles([ fileName1 ], `Sites/${siteName}/documentLibrary`) + .then(resp => apis.user.favorites.addFavoriteById('file', resp.data.entry.id))) + .then(() => apis.user.nodes.createFolders([ folderName ]) + .then(resp => apis.user.favorites.addFavoriteById('folder', resp.data.entry.id))) + .then(() => apis.user.nodes.createFiles([ fileName2 ], folderName) + .then(resp => apis.user.favorites.addFavoriteById('file', resp.data.entry.id))) + .then(() => apis.user.nodes.createFiles([ fileName3 ], folderName) + .then(resp => file3Id = resp.data.entry.id) + .then(() => apis.user.favorites.addFavoriteById('file', file3Id)) + .then(() => apis.user.nodes.deleteNodeById(file3Id, false))) + .then(() => apis.user.nodes.createFiles([ fileName4 ], folderName) + .then(resp => file4Id = resp.data.entry.id) + .then(() => apis.user.favorites.addFavoriteById('file', file4Id)) + .then(() => apis.user.nodes.deleteNodeById(file4Id, false)) + .then(() => apis.user.trashcan.restore(file4Id))) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + favoritesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.admin.sites.deleteSite(siteName), + apis.user.nodes.deleteNodes([ folderName ]), + apis.admin.trashcan.emptyTrash(), + logoutPage.load() + ]) + .then(done); + }); + + it('has the correct columns', () => { + const labels = [ 'Name', 'Location', 'Size', 'Modified', 'Modified by' ]; + const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label)); + + expect(dataTable.getColumnHeaders().count()).toBe(5 + 1, 'Incorrect number of columns'); + + elements.forEach((element, index) => { + expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`); + }); + }); + + it('displays the favorite files and folders [C213226]', () => { + expect(dataTable.countRows()).toEqual(4, 'Incorrect number of items displayed'); + expect(dataTable.getRowName(fileName1).isPresent()).toBe(true, `${fileName1} not displayed`); + expect(dataTable.getRowName(fileName2).isPresent()).toBe(true, `${fileName2} not displayed`); + expect(dataTable.getRowName(folderName).isPresent()).toBe(true, `${folderName} not displayed`); + }); + + it(`file not displayed if it's in the Trashcan [C213228]`, () => { + expect(dataTable.getRowName(fileName3).isPresent()).not.toBe(true, `${fileName3} is displayed`); + }); + + it(`file is displayed after it is restored from Trashcan [C213229]`, () => { + expect(dataTable.getRowName(fileName4).isPresent()).toBe(true, `${fileName4} not displayed`); + }); + + it('Location column displays the parent folder of the files [C213231]', () => { + expect(dataTable.getItemLocation(fileName1).getText()).toEqual(siteName); + expect(dataTable.getItemLocation(fileName2).getText()).toEqual(folderName); + expect(dataTable.getItemLocation(folderName).getText()).toEqual('Personal Files'); + }); + + it('Location column displays a tooltip with the entire path of the file [C213671]', () => { + expect(dataTable.getItemLocationTooltip(fileName1)).toEqual(`File Libraries/${siteName}`); + expect(dataTable.getItemLocationTooltip(fileName2)).toEqual(`Personal Files/${folderName}`); + expect(dataTable.getItemLocationTooltip(folderName)).toEqual('Personal Files'); + }); + + it('Location column redirect - item in user Home [C213650] [C260968]', () => { + dataTable.clickItemLocation(folderName) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files' ])); + }); + + it('Location column redirect - file in folder [C213650] [C260968]', () => { + dataTable.clickItemLocation(fileName2) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', folderName ])); + }); + + it('Location column redirect - file in site [C213650] [C260969]', () => { + dataTable.clickItemLocation(fileName1) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'File Libraries', siteName ])); + }); + + it('Navigate into folder from Favorites [C213230]', () => { + dataTable.doubleClickOnItemName(folderName) + .then(() => dataTable.waitForHeader()) + .then(() => breadcrumb.getCurrentItemName()) + .then(name => { + expect(name).toBe(folderName); + }); + }); + +}); diff --git a/e2e/suites/list-views/file-libraries.test.ts b/e2e/suites/list-views/file-libraries.test.ts new file mode 100755 index 0000000000..3f6567dddb --- /dev/null +++ b/e2e/suites/list-views/file-libraries.test.ts @@ -0,0 +1,161 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { by } from 'protractor'; + +import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('File Libraries', () => { + const username = `user-${Utils.random()}`; + const password = username; + + const sitePrivate = `private-${Utils.random()}`; + const siteModerated = `moderated-${Utils.random()}`; + const sitePublic = `public-${Utils.random()}`; + const siteName = `siteName-${Utils.random()}`; + const siteId1 = Utils.random(); + const siteId2 = Utils.random(); + const adminSite = `admin-${Utils.random()}`; + + const siteDescription = 'my site description'; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, password) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const fileLibrariesPage = new BrowsingPage(); + const { dataTable } = fileLibrariesPage; + + beforeAll(done => { + Promise + .all([ + apis.admin.people.createUser(username), + apis.admin.sites.createSite(sitePublic, SITE_VISIBILITY.PUBLIC), + apis.admin.sites.createSite(siteModerated, SITE_VISIBILITY.MODERATED, { description: siteDescription }), + apis.admin.sites.createSite(sitePrivate, SITE_VISIBILITY.PRIVATE, { description: '' }), + apis.admin.sites.createSite(adminSite, SITE_VISIBILITY.PUBLIC), + apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC, { id: siteId1 }), + apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC, { id: siteId2 }) + ]) + .then(() => apis.admin.sites.addSiteMember(sitePublic, username, SITE_ROLES.SITE_CONSUMER)) + .then(() => apis.admin.sites.addSiteMember(siteModerated, username, SITE_ROLES.SITE_MANAGER)) + .then(() => apis.admin.sites.addSiteMember(sitePrivate, username, SITE_ROLES.SITE_CONTRIBUTOR)) + .then(() => apis.admin.sites.addSiteMember(siteId1, username, SITE_ROLES.SITE_CONTRIBUTOR)) + .then(() => apis.admin.sites.addSiteMember(siteId2, username, SITE_ROLES.SITE_CONTRIBUTOR)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + fileLibrariesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.admin.sites.deleteSites([ + sitePublic, + siteModerated, + sitePrivate, + adminSite, + siteId1, + siteId2 + ]), + logoutPage.load() + ]) + .then(done); + }); + + it('has the correct columns', () => { + const labels = [ 'Title', 'Status' ]; + const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label)); + + expect(dataTable.getColumnHeaders().count()).toBe(2 + 1, 'Incorrect number of columns'); + + elements.forEach((element, index) => { + expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`); + }); + }); + + it('User can see only the sites he is a member of [C217095]', () => { + const sitesCount = dataTable.countRows(); + + const expectedSites = { + [sitePrivate]: SITE_VISIBILITY.PRIVATE, + [siteModerated]: SITE_VISIBILITY.MODERATED, + [sitePublic]: SITE_VISIBILITY.PUBLIC + }; + + expect(sitesCount).toEqual(5, 'Incorrect number of sites displayed'); + expect(dataTable.getRowName(adminSite).isPresent()).toBe(false, 'Incorrect site appears in list'); + + dataTable.getRows() + .map((row) => { + return row.all(dataTable.cell).map(cell => cell.getText()); + }) + .then((rowCells) => { + return rowCells.reduce((acc, cell) => { + acc[cell[1]] = cell[2].toUpperCase(); + return acc; + }, {}); + }) + .then((sitesList) => { + Object.keys(expectedSites).forEach((site) => { + expect(sitesList[site]).toEqual(expectedSites[site]); + }); + }); + }); + + it('Site ID is displayed when two sites have the same name [C217098]', () => { + const expectedSites = [ + `${siteName} (${siteId1})`, + `${siteName} (${siteId2})` + ]; + dataTable.getCellsContainingName(siteName) + .then(resp => { + const expectedJSON = JSON.stringify(expectedSites.sort()); + const actualJSON = JSON.stringify(resp.sort()); + expect(actualJSON).toEqual(expectedJSON); + }); + }); + + it('Tooltip for sites without description [C217096]', () => { + const tooltip = dataTable.getItemNameTooltip(sitePrivate); + expect(tooltip).toBe(`${sitePrivate}`); + }); + + it('Tooltip for sites with description [C217097]', () => { + const tooltip = dataTable.getItemNameTooltip(siteModerated); + expect(tooltip).toBe(`${siteDescription}`); + }); +}); diff --git a/e2e/suites/list-views/permissions.test.ts b/e2e/suites/list-views/permissions.test.ts new file mode 100755 index 0000000000..9b637babb8 --- /dev/null +++ b/e2e/suites/list-views/permissions.test.ts @@ -0,0 +1,181 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Special permissions', () => { + const username = `user-${Utils.random()}`; + const password = username; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, password) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const recentFilesPage = new BrowsingPage(); + const favoritesPage = new BrowsingPage(); + const sharedPage = new BrowsingPage(); + const { dataTable } = recentFilesPage; + + xit(''); + + beforeAll(done => { + apis.admin.people.createUser(username).then(done); + }); + + describe('file not displayed if user no longer has permissions on it', () => { + const sitePrivate = `private-${Utils.random()}`; + const fileName = `file-${Utils.random()}.txt`; + let fileId; + + beforeAll(done => { + apis.admin.sites.createSite(sitePrivate, SITE_VISIBILITY.PRIVATE) + .then(() => apis.admin.sites.addSiteMember(sitePrivate, username, SITE_ROLES.SITE_COLLABORATOR)) + .then(() => apis.admin.nodes.createFiles([ fileName ], `Sites/${sitePrivate}/documentLibrary`) + .then(resp => fileId = resp.data.entry.id)) + .then(() => apis.user.favorites.addFavoriteById('file', fileId)) + .then(() => apis.admin.shared.shareFileById(fileId)) + .then(() => apis.user.nodes.editNodeContent(fileId, 'edited by user')) + + .then(() => apis.user.search.waitForApi(username, { expect: 1 })) + .then(() => apis.user.shared.waitForApi({ expect: 1 })) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterEach(done => { + apis.admin.sites.addSiteMember(sitePrivate, username, SITE_ROLES.SITE_COLLABORATOR).then(done); + }); + + afterAll(done => { + Promise.all([ + apis.admin.sites.deleteSite(sitePrivate), + logoutPage.load() + ]) + .then(done); + }); + + it('on Recent Files [C213173]', () => { + recentFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items'); + }) + .then(() => apis.admin.sites.deleteSiteMember(sitePrivate, username)) + .then(() => recentFilesPage.refresh()) + .then(() => { + expect(dataTable.countRows()).toBe(0, 'Incorrect number of items'); + }); + }); + + it('on Favorites [C213227]', () => { + favoritesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items'); + }) + .then(() => apis.admin.sites.deleteSiteMember(sitePrivate, username)) + .then(() => favoritesPage.refresh()) + .then(() => { + expect(dataTable.countRows()).toBe(0, 'Incorrect number of items'); + }); + }); + + it('on Shared Files [C213116]', () => { + sharedPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items'); + }) + .then(() => apis.admin.sites.deleteSiteMember(sitePrivate, username)) + .then(() => sharedPage.refresh()) + .then(() => { + expect(dataTable.countRows()).toBe(0, 'Incorrect number of items'); + }); + }); + }); + + describe(`Location column is empty if user doesn't have permissions on the file's parent folder`, () => { + const sitePrivate = `private-${Utils.random()}`; + const fileName = `file-${Utils.random()}.txt`; + let fileId; + + beforeAll(done => { + apis.admin.sites.createSite(sitePrivate, SITE_VISIBILITY.PRIVATE) + .then(() => apis.admin.sites.addSiteMember(sitePrivate, username, SITE_ROLES.SITE_COLLABORATOR)) + .then(() => apis.admin.sites.getDocLibId(sitePrivate)) + .then(resp => apis.user.nodes.createFile(fileName, resp)) + .then(resp => fileId = resp.data.entry.id) + .then(() => apis.user.favorites.addFavoriteById('file', fileId)) + .then(() => apis.user.shared.shareFileById(fileId)) + .then(() => apis.user.shared.waitForApi({ expect: 1 })) + .then(() => apis.user.search.waitForApi(username, { expect: 1 })) + .then(() => apis.admin.sites.deleteSiteMember(sitePrivate, username)) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.admin.sites.deleteSite(sitePrivate), + logoutPage.load() + ]) + .then(done); + }); + + it(`on Recent Files [C213178]`, () => { + recentFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items'); + expect(dataTable.getItemLocation(fileName).getText()).toEqual(''); + }); + }); + + it(`on Favorites [C213672]`, () => { + favoritesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items'); + expect(dataTable.getItemLocation(fileName).getText()).toEqual(''); + }); + }); + + it(`on Shared Files [C213668]`, () => { + sharedPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items'); + expect(dataTable.getItemLocation(fileName).getText()).toEqual(''); + }); + }); + }); +}); diff --git a/e2e/suites/list-views/personal-files.test.ts b/e2e/suites/list-views/personal-files.test.ts new file mode 100755 index 0000000000..88bdd95dee --- /dev/null +++ b/e2e/suites/list-views/personal-files.test.ts @@ -0,0 +1,176 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; + +import { SIDEBAR_LABELS, APP_ROUTES } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Personal Files', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const personalFilesPage = new BrowsingPage(); + const { dataTable } = personalFilesPage; + + const adminFolder = `admin-folder-${Utils.random()}`; + + const userFolder = `user-folder-${Utils.random()}`; + const userFile = `file-${Utils.random()}.txt`; + + beforeAll(done => { + Promise + .all([ + apis.admin.people.createUser(username), + apis.admin.nodes.createFolders([ adminFolder ]) + ]) + .then(() => apis.user.nodes.createFolders([ userFolder ])) + .then(() => apis.user.nodes.createFiles([ userFile ], userFolder)) + .then(done); + }); + + afterAll(done => { + Promise + .all([ + apis.admin.nodes.deleteNodes([ adminFolder ]), + apis.user.nodes.deleteNodes([ userFolder ]) + ]) + .then(done); + }); + + xit(''); + + describe(`Admin user's personal files`, () => { + beforeAll(done => { + loginPage.loginWithAdmin().then(done); + }); + + beforeEach(done => { + personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('has "Data Dictionary" folder [C213241]', () => { + expect(dataTable.getRowName('Data Dictionary').isPresent()).toBe(true); + }); + + it('has created content', () => { + expect(dataTable.getRowName(adminFolder).isPresent()).toBe(true); + }); + }); + + describe(`Regular user's personal files`, () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + beforeEach(done => { + personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('has the correct columns [C217142]', () => { + const labels = [ 'Name', 'Size', 'Modified', 'Modified by' ]; + const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label)); + + expect(dataTable.getColumnHeaders().count()).toBe(4 + 1, 'Incorrect number of columns'); + + elements.forEach((element, index) => { + expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`); + }); + }); + + it('has default sorted column [C217143]', () => { + expect(dataTable.getSortedColumnHeader().getText()).toBe('Modified'); + }); + + it('has user created content [C213242]', () => { + expect(dataTable.getRowName(userFolder).isPresent()) + .toBe(true); + }); + + it('navigates to folder [C213244]', () => { + const getNodeIdPromise = apis.user.nodes + .getNodeByPath(`/${userFolder}`) + .then(response => response.data.entry.id); + + const navigatePromise = dataTable + .doubleClickOnItemName(userFolder) + .then(() => dataTable.waitForHeader()); + + Promise + .all([ + getNodeIdPromise, + navigatePromise + ]) + .then(([ nodeId ]) => { + expect(browser.getCurrentUrl()) + .toContain(nodeId, 'Node ID is not in the URL'); + + expect(dataTable.getRowName(userFile).isPresent()) + .toBe(true, 'user file is missing'); + }); + }); + + it('redirects to Personal Files on clicking the link from sidebar [C213245]', () => { + personalFilesPage.dataTable.doubleClickOnItemName(userFolder) + .then(() => personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES)) + .then(() => browser.getCurrentUrl()) + .then(url => expect(url.endsWith(APP_ROUTES.PERSONAL_FILES)).toBe(true, 'incorrect url')); + }); + + it('page loads correctly after browser refresh [C213246]', () => { + personalFilesPage.refresh() + .then(() => expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES)); + }); + + it('page load by URL [C213247]', () => { + let url; + browser.getCurrentUrl() + .then(resp => url = resp) + .then(() => personalFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => browser.get(url)) + .then(() => expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES)); + }); + }); +}); diff --git a/e2e/suites/list-views/recent-files.test.ts b/e2e/suites/list-views/recent-files.test.ts new file mode 100755 index 0000000000..0902c7c70f --- /dev/null +++ b/e2e/suites/list-views/recent-files.test.ts @@ -0,0 +1,141 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { SITE_VISIBILITY, SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Recent Files', () => { + const username = `user-${Utils.random()}`; + + const folderName = `folder-${Utils.random()}`; let folderId; + const fileName1 = `file-${Utils.random()}.txt`; + const fileName2 = `file-${Utils.random()}.txt`; let file2Id; + const fileName3 = `file-${Utils.random()}.txt`; + + const siteName = `site-${Utils.random()}`; + const folderSite = `folder2-${Utils.random()}`; let folderSiteId; + const fileSite = `file-${Utils.random()}.txt`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const recentFilesPage = new BrowsingPage(); + const { dataTable } = recentFilesPage; + const { breadcrumb } = recentFilesPage.toolbar; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.user.nodes.createFolders([ folderName ])).then(resp => folderId = resp.data.entry.id) + .then(() => apis.user.nodes.createFiles([ fileName1 ], folderName)) + .then(() => apis.user.nodes.createFiles([ fileName2 ])).then(resp => file2Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFiles([ fileName3 ]).then(resp => apis.user.nodes.deleteNodeById(resp.data.entry.id, false))) + + .then(() => apis.user.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC)) + .then(() => apis.user.sites.getDocLibId(siteName)) + .then(resp => apis.user.nodes.createFolder(folderSite, resp)).then(resp => folderSiteId = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(fileSite, folderSiteId)) + + .then(() => apis.user.search.waitForApi(username, { expect: 3 })) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + recentFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.nodes.deleteNodesById([ folderId, file2Id ]), + apis.user.sites.deleteSite(siteName), + apis.admin.trashcan.emptyTrash(), + logoutPage.load() + ]) + .then(done); + }); + + it('has the correct columns [C213168]', () => { + const labels = [ 'Name', 'Location', 'Size', 'Modified' ]; + const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label)); + + expect(dataTable.getColumnHeaders().count()).toBe(4 + 1, 'Incorrect number of columns'); + + elements.forEach((element, index) => { + expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`); + }); + }); + + it('default sorting column [C213171]', () => { + expect(dataTable.getSortedColumnHeader().getText()).toBe('Modified'); + expect(dataTable.getSortingOrder()).toBe('desc'); + }); + + it('displays the files added by the current user in the last 30 days [C213170]', () => { + expect(dataTable.countRows()).toEqual(3, 'Incorrect number of files displayed'); + expect(dataTable.getRowName(fileName1).isPresent()).toBe(true, `${fileName1} not displayed`); + expect(dataTable.getRowName(fileName2).isPresent()).toBe(true, `${fileName2} not displayed`); + expect(dataTable.getRowName(fileSite).isPresent()).toBe(true, `${fileSite} not displayed`); + }); + + it(`file not displayed if it's in the Trashcan [C213174]`, () => { + expect(dataTable.getRowName(fileName3).isPresent()).not.toBe(true, `${fileName3} is displayed`); + }); + + it('Location column displays the parent folder of the file [C213175]', () => { + expect(dataTable.getItemLocation(fileName1).getText()).toEqual(folderName); + expect(dataTable.getItemLocation(fileName2).getText()).toEqual('Personal Files'); + expect(dataTable.getItemLocation(fileSite).getText()).toEqual(folderSite); + }); + + it('Location column displays a tooltip with the entire path of the file [C213177]', () => { + expect(dataTable.getItemLocationTooltip(fileName1)).toEqual(`Personal Files/${folderName}`); + expect(dataTable.getItemLocationTooltip(fileName2)).toEqual('Personal Files'); + expect(dataTable.getItemLocationTooltip(fileSite)).toEqual(`File Libraries/${siteName}/${folderSite}`); + }); + + it('Location column redirect - file in user Home [C213176] [C260968]', () => { + dataTable.clickItemLocation(fileName2) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files' ])); + }); + + it('Location column redirect - file in folder [C213176] [C260968]', () => { + dataTable.clickItemLocation(fileName1) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', folderName ])); + }); + + it('Location column redirect - file in site [C213176] [C260969]', () => { + dataTable.clickItemLocation(fileSite) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'File Libraries', siteName, folderSite ])); + }); +}); diff --git a/e2e/suites/list-views/shared-files.test.ts b/e2e/suites/list-views/shared-files.test.ts new file mode 100755 index 0000000000..b8168d3c07 --- /dev/null +++ b/e2e/suites/list-views/shared-files.test.ts @@ -0,0 +1,142 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Shared Files', () => { + const username = `user-${Utils.random()}`; + const password = username; + + const siteName = `site-${Utils.random()}`; + const fileAdmin = `file-${Utils.random()}.txt`; + + const folderUser = `folder-${Utils.random()}`; + const file1User = `file1-${Utils.random()}.txt`; let file1Id; + const file2User = `file2-${Utils.random()}.txt`; let file2Id; + const file3User = `file3-${Utils.random()}.txt`; let file3Id; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, password) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const sharedFilesPage = new BrowsingPage(); + const { dataTable } = sharedFilesPage; + const { breadcrumb } = sharedFilesPage.toolbar; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC)) + .then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER)) + .then(() => apis.admin.nodes.createFiles([ fileAdmin ], `Sites/${siteName}/documentLibrary`)) + .then(resp => apis.admin.shared.shareFileById(resp.data.entry.id)) + + .then(() => apis.user.nodes.createFolders([ folderUser ])) + .then(() => apis.user.nodes.createFiles([ file1User ], folderUser)).then(resp => file1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(file2User)).then(resp => file2Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(file3User)).then(resp => file3Id = resp.data.entry.id) + .then(() => apis.user.shared.shareFilesByIds([file1Id, file2Id, file3Id])) + + .then(() => apis.user.shared.waitForApi({ expect: 4 })) + .then(() => apis.user.nodes.deleteNodeById(file2Id)) + .then(() => apis.user.shared.unshareFile(file3User)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + sharedFilesPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + sharedFilesPage.refresh().then(done); + }); + + afterAll(done => { + Promise.all([ + apis.admin.sites.deleteSite(siteName), + apis.user.nodes.deleteNodes([ folderUser ]), + logoutPage.load() + ]) + .then(done); + }); + + it('has the correct columns [C213113]', () => { + const labels = [ 'Name', 'Location', 'Size', 'Modified', 'Modified by', 'Shared by' ]; + const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label)); + + expect(dataTable.getColumnHeaders().count()).toBe(6 + 1, 'Incorrect number of columns'); + + elements.forEach((element, index) => { + expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`); + }); + }); + + it('default sorting column [C213115]', () => { + expect(dataTable.getSortedColumnHeader().getText()).toBe('Modified'); + expect(dataTable.getSortingOrder()).toBe('desc'); + }); + + it('displays the files shared by everyone [C213114]', () => { + expect(dataTable.getRowName(fileAdmin).isPresent()).toBe(true, `${fileAdmin} not displayed`); + expect(dataTable.getRowName(file1User).isPresent()).toBe(true, `${file1User} not displayed`); + }); + + it(`file not displayed if it's in the Trashcan [C213117]`, () => { + expect(dataTable.getRowName(file2User).isPresent()).toBe(false, `${file2User} is displayed`); + }); + + it('unshared file is not displayed [C213118]', () => { + expect(dataTable.getRowName(file3User).isPresent()).toBe(false, `${file3User} is displayed`); + }); + + it('Location column displays the parent folder of the file [C213665]', () => { + expect(dataTable.getItemLocation(fileAdmin).getText()).toEqual(siteName); + expect(dataTable.getItemLocation(file1User).getText()).toEqual(folderUser); + }); + + it('Location column redirect - file in user Home [C213666] [C260968]', () => { + dataTable.clickItemLocation(file1User) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', folderUser ])); + }); + + it('Location column redirect - file in site [C213666] [C260969]', () => { + dataTable.clickItemLocation(fileAdmin) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'File Libraries', siteName ])); + }); + + it('Location column displays a tooltip with the entire path of the file [C213667]', () => { + expect(dataTable.getItemLocationTooltip(fileAdmin)).toEqual(`File Libraries/${siteName}`); + expect(dataTable.getItemLocationTooltip(file1User)).toEqual(`Personal Files/${folderUser}`); + }); +}); diff --git a/e2e/suites/list-views/tooltips.test.ts b/e2e/suites/list-views/tooltips.test.ts new file mode 100755 index 0000000000..43e12985b2 --- /dev/null +++ b/e2e/suites/list-views/tooltips.test.ts @@ -0,0 +1,330 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('File / folder tooltips', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const parent = `parent-${Utils.random()}`; + + const file = `file1-${Utils.random()}`; + const fileWithDesc = `file2-${Utils.random()}`; + const fileWithTitle = `file3-${Utils.random()}`; + const fileWithTitleAndDesc = `file4-${Utils.random()}`; + const fileNameEqTitleEqDesc = `file5-${Utils.random()}`; + const fileNameEqTitleDiffDesc = `file6-${Utils.random()}`; + const fileNameEqDescDiffTitle = `file7-${Utils.random()}`; + const fileTitleEqDesc = `file8-${Utils.random()}`; + let parentId, file1Id, file2Id, file3Id, file4Id, file5Id, file6Id, file7Id, file8Id; + + const fileTitle = 'file title'; + const fileDescription = 'file description'; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable } = page; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.user.nodes.createFolder( parent )) + .then(resp => parentId = resp.data.entry.id) + + .then(() => Promise.all([ + apis.user.nodes.createFile(file, parentId).then(resp => file1Id = resp.data.entry.id), + apis.user.nodes.createFile(fileWithDesc, parentId, '', fileDescription).then(resp => file2Id = resp.data.entry.id), + apis.user.nodes.createFile(fileWithTitle, parentId, fileTitle).then(resp => file3Id = resp.data.entry.id), + apis.user.nodes.createFile(fileWithTitleAndDesc, parentId, fileTitle, fileDescription) + .then(resp => file4Id = resp.data.entry.id), + apis.user.nodes.createFile(fileNameEqTitleEqDesc, parentId, fileNameEqTitleEqDesc, fileNameEqTitleEqDesc) + .then(resp => file5Id = resp.data.entry.id), + apis.user.nodes.createFile(fileNameEqTitleDiffDesc, parentId, fileNameEqTitleDiffDesc, fileDescription) + .then(resp => file6Id = resp.data.entry.id), + apis.user.nodes.createFile(fileNameEqDescDiffTitle, parentId, fileTitle, fileNameEqDescDiffTitle) + .then(resp => file7Id = resp.data.entry.id), + apis.user.nodes.createFile(fileTitleEqDesc, parentId, fileTitle, fileTitle).then(resp => file8Id = resp.data.entry.id) + ])) + + .then(() => apis.user.shared.shareFilesByIds([ file1Id, file2Id, file3Id, file4Id, file5Id, file6Id, file7Id, file8Id ])) + + .then(() => apis.user.favorites.addFavoritesByIds('file', [ + file1Id, file2Id, file3Id, file4Id, file5Id, file6Id, file7Id, file8Id + ])) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.nodes.deleteNodes([ parent ]), + apis.admin.trashcan.emptyTrash(), + logoutPage.load() + ]) + .then(done); + }); + + xit(''); + + describe('on Personal Files', () => { + beforeAll(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.doubleClickOnItemName(parent)) + .then(done); + }); + + it('File with name, no title, no description', () => { + expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`); + }); + + it('File with name and description, no title', () => { + expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`); + }); + + it('File with name and title, no description', () => { + expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`); + }); + + it('File with name and title and description, all different', () => { + expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`); + }); + + it('File with name and title and description, all equal', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`); + }); + + it('File with name = title, different description', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`); + }); + + it('File with name = description, different title', () => { + expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`); + }); + + it('File with title = description, different name', () => { + expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`); + }); + }); + + describe('on Recent Files', () => { + beforeAll(done => { + apis.user.search.waitForApi(username, { expect: 8 }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES)) + .then(done); + }); + + it('File with name, no title, no description', () => { + expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`); + }); + + it('File with name and description, no title', () => { + expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`); + }); + + it('File with name and title, no description', () => { + expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`); + }); + + it('File with name and title and description, all different', () => { + expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`); + }); + + it('File with name and title and description, all equal', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`); + }); + + it('File with name = title, different description', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`); + }); + + it('File with name = description, different title', () => { + expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`); + }); + + it('File with title = description, different name', () => { + expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`); + }); + }); + + // disabled until ACA-518 is done + xdescribe('on Shared Files', () => { + beforeAll(done => { + apis.user.shared.waitForApi({ expect: 8 }) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES)) + .then(done); + }); + + it('File with name, no title, no description', () => { + expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`); + }); + + it('File with name and description, no title', () => { + expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`); + }); + + it('File with name and title, no description', () => { + expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`); + }); + + it('File with name and title and description, all different', () => { + expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`); + }); + + it('File with name and title and description, all equal', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`); + }); + + it('File with name = title, different description', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`); + }); + + it('File with name = description, different title', () => { + expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`); + }); + + it('File with title = description, different name', () => { + expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`); + }); + }); + + describe('on Favorites', () => { + beforeAll(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES).then(done); + }); + + it('File with name, no title, no description', () => { + expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`); + }); + + it('File with name and description, no title', () => { + expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`); + }); + + it('File with name and title, no description', () => { + expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`); + }); + + it('File with name and title and description, all different', () => { + expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`); + }); + + it('File with name and title and description, all equal', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`); + }); + + it('File with name = title, different description', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`); + }); + + it('File with name = description, different title', () => { + expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`); + }); + + it('File with title = description, different name', () => { + expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`); + }); + }); + + describe('on Trash', () => { + const parentForTrash = `parent-${Utils.random()}`; + let parentForTrashId, file1TrashId, file2TrashId, file3TrashId, file4TrashId; + let file5TrashId, file6TrashId, file7TrashId, file8TrashId; + + beforeAll(done => { + apis.user.nodes.createFolder( parentForTrash ) + .then(resp => parentForTrashId = resp.data.entry.id) + .then(() => Promise.all([ + apis.user.nodes.createFile(file, parentForTrashId) + .then(resp => file1TrashId = resp.data.entry.id), + apis.user.nodes.createFile(fileWithDesc, parentForTrashId, '', fileDescription) + .then(resp => file2TrashId = resp.data.entry.id), + apis.user.nodes.createFile(fileWithTitle, parentForTrashId, fileTitle) + .then(resp => file3TrashId = resp.data.entry.id), + apis.user.nodes.createFile(fileWithTitleAndDesc, parentForTrashId, fileTitle, fileDescription) + .then(resp => file4TrashId = resp.data.entry.id), + apis.user.nodes.createFile(fileNameEqTitleEqDesc, parentForTrashId, fileNameEqTitleEqDesc, fileNameEqTitleEqDesc) + .then(resp => file5TrashId = resp.data.entry.id), + apis.user.nodes.createFile(fileNameEqTitleDiffDesc, parentForTrashId, fileNameEqTitleDiffDesc, fileDescription) + .then(resp => file6TrashId = resp.data.entry.id), + apis.user.nodes.createFile(fileNameEqDescDiffTitle, parentForTrashId, fileTitle, fileNameEqDescDiffTitle) + .then(resp => file7TrashId = resp.data.entry.id), + apis.user.nodes.createFile(fileTitleEqDesc, parentForTrashId, fileTitle, fileTitle) + .then(resp => file8TrashId = resp.data.entry.id) + ])) + + .then(() => apis.user.nodes.deleteNodesById([ + file1TrashId, file2TrashId, file3TrashId, file4TrashId, file5TrashId, file6TrashId, file7TrashId, file8TrashId + ], false)) + + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(done); + }); + + afterAll(done => { + apis.user.nodes.deleteNodes([ parentForTrash ]).then(done); + }); + + it('File with name, no title, no description', () => { + expect(dataTable.getItemNameTooltip(file)).toEqual(`${file}`); + }); + + it('File with name and description, no title', () => { + expect(dataTable.getItemNameTooltip(fileWithDesc)).toEqual(`${fileWithDesc}\n${fileDescription}`); + }); + + it('File with name and title, no description', () => { + expect(dataTable.getItemNameTooltip(fileWithTitle)).toEqual(`${fileWithTitle}\n${fileTitle}`); + }); + + it('File with name and title and description, all different', () => { + expect(dataTable.getItemNameTooltip(fileWithTitleAndDesc)).toEqual(`${fileTitle}\n${fileDescription}`); + }); + + it('File with name and title and description, all equal', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleEqDesc)).toEqual(`${fileNameEqTitleEqDesc}`); + }); + + it('File with name = title, different description', () => { + expect(dataTable.getItemNameTooltip(fileNameEqTitleDiffDesc)).toEqual(`${fileNameEqTitleDiffDesc}\n${fileDescription}`); + }); + + it('File with name = description, different title', () => { + expect(dataTable.getItemNameTooltip(fileNameEqDescDiffTitle)).toEqual(`${fileTitle}\n${fileNameEqDescDiffTitle}`); + }); + + it('File with title = description, different name', () => { + expect(dataTable.getItemNameTooltip(fileTitleEqDesc)).toEqual(`${fileTitle}`); + }); + }); +}); diff --git a/e2e/suites/list-views/trash.test.ts b/e2e/suites/list-views/trash.test.ts new file mode 100755 index 0000000000..8af8827bf0 --- /dev/null +++ b/e2e/suites/list-views/trash.test.ts @@ -0,0 +1,169 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + + +import { SITE_VISIBILITY, SITE_ROLES, SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Trash', () => { + const username = `user-${Utils.random()}`; + + const siteName = `site-${Utils.random()}`; + const fileSite = `file-${Utils.random()}.txt`; let fileSiteId; + + const folderAdmin = `folder-${Utils.random()}`; let folderAdminId; + const fileAdmin = `file-${Utils.random()}.txt`; let fileAdminId; + + const folderUser = `folder-${Utils.random()}`; let folderUserId; + const fileUser = `file-${Utils.random()}.txt`; let fileUserId; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const trashPage = new BrowsingPage(); + const { dataTable } = trashPage; + const { breadcrumb } = trashPage.toolbar; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.admin.nodes.createFiles([ fileAdmin ]).then(resp => fileAdminId = resp.data.entry.id)) + .then(() => apis.admin.nodes.createFolders([ folderAdmin ]).then(resp => folderAdminId = resp.data.entry.id)) + .then(() => apis.admin.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC)) + .then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_MANAGER)) + .then(() => apis.admin.nodes.createFiles([ fileSite ], `Sites/${siteName}/documentLibrary`) + .then(resp => fileSiteId = resp.data.entry.id)) + .then(() => apis.user.nodes.createFiles([ fileUser ]).then(resp => fileUserId = resp.data.entry.id)) + .then(() => apis.user.nodes.createFolders([ folderUser ]).then(resp => folderUserId = resp.data.entry.id)) + + .then(() => apis.admin.nodes.deleteNodesById([ fileAdminId, folderAdminId ], false)) + .then(() => apis.user.nodes.deleteNodesById([ fileSiteId, fileUserId, folderUserId ], false)) + + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.admin.sites.deleteSite(siteName), + apis.admin.trashcan.emptyTrash() + ]) + .then(done); + }); + + xit(''); + + describe('as admin', () => { + beforeAll(done => { + loginPage.loginWithAdmin().then(done); + }); + + beforeEach(done => { + trashPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('has the correct columns', () => { + const labels = [ 'Name', 'Location', 'Size', 'Deleted', 'Deleted by' ]; + const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label)); + + expect(dataTable.getColumnHeaders().count()).toBe(5 + 1, 'Incorrect number of columns'); + + elements.forEach((element, index) => { + expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`); + }); + }); + + it('displays the files and folders deleted by everyone [C213217]', () => { + expect(dataTable.countRows()).toEqual(5, 'Incorrect number of deleted items displayed'); + + expect(dataTable.getRowName(fileAdmin).isPresent()).toBe(true, `${fileAdmin} not displayed`); + expect(dataTable.getRowName(folderAdmin).isPresent()).toBe(true, `${folderAdmin} not displayed`); + expect(dataTable.getRowName(fileUser).isPresent()).toBe(true, `${fileUser} not displayed`); + expect(dataTable.getRowName(folderUser).isPresent()).toBe(true, `${folderUser} not displayed`); + expect(dataTable.getRowName(fileSite).isPresent()).toBe(true, `${fileSite} not displayed`); + }); + }); + + describe('as user', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + beforeEach(done => { + trashPage.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('has the correct columns', () => { + const labels = [ 'Name', 'Location', 'Size', 'Deleted', 'Deleted by' ]; + const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label)); + + expect(dataTable.getColumnHeaders().count()).toBe(5 + 1, 'Incorrect number of columns'); + + elements.forEach((element, index) => { + expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`); + }); + }); + + it('displays the files and folders deleted by the user [C213218]', () => { + expect(dataTable.countRows()).toEqual(3, 'Incorrect number of deleted items displayed'); + + expect(dataTable.getRowName(fileSite).isPresent()).toBe(true, `${fileSite} not displayed`); + expect(dataTable.getRowName(fileUser).isPresent()).toBe(true, `${fileUser} not displayed`); + expect(dataTable.getRowName(folderUser).isPresent()).toBe(true, `${folderUser} not displayed`); + expect(dataTable.getRowName(fileAdmin).isPresent()).toBe(false, `${fileAdmin} is displayed`); + }); + + it('default sorting column [C213219]', () => { + expect(dataTable.getSortedColumnHeader().getText()).toBe('Deleted'); + expect(dataTable.getSortingOrder()).toBe('desc'); + }); + + it('Location column redirect - file in user Home [C217144] [C260968]', () => { + dataTable.clickItemLocation(fileUser) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files' ])); + }); + + it('Location column redirect - file in site [C217144] [C260969]', () => { + dataTable.clickItemLocation(fileSite) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'File Libraries', siteName ])); + }); + }); +}); diff --git a/e2e/suites/navigation/breadcrumb.test.ts b/e2e/suites/navigation/breadcrumb.test.ts new file mode 100755 index 0000000000..419950ed38 --- /dev/null +++ b/e2e/suites/navigation/breadcrumb.test.ts @@ -0,0 +1,244 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; + +import { SIDEBAR_LABELS, SITE_VISIBILITY } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Breadcrumb', () => { + const username = `user-${Utils.random()}`; + + const parent = `parent-${Utils.random()}`; let parentId; + const subfolder1 = `subfolder1-${Utils.random()}`; let subfolder1Id; + const subfolder2 = `subfolder2-${Utils.random()}`; let subfolder2Id; + const fileName1 = `file1-${Utils.random()}.txt`; + + const siteName = `site-${Utils.random()}`; + + const parent2 = `parent2-${Utils.random()}`; let parent2Id; + const folder1 = `folder1-${Utils.random()}`; let folder1Id; + const folder1Renamed = `renamed-${Utils.random()}`; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { breadcrumb } = page.toolbar; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + + beforeAll(done => { + apis.admin.people.createUser(username) + .then(() => apis.user.nodes.createFolder(parent)).then(resp => parentId = resp.data.entry.id) + .then(() => apis.user.nodes.createFolder(subfolder1, parentId)).then(resp => subfolder1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFolder(subfolder2, subfolder1Id)).then(resp => subfolder2Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(fileName1, subfolder2Id)) + + .then(() => apis.user.nodes.createFolder(parent2)).then(resp => parent2Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFolder(folder1, parent2Id)).then(resp => folder1Id = resp.data.entry.id) + + .then(() => apis.user.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC)) + .then(() => apis.user.sites.getDocLibId(siteName)) + .then(resp => apis.user.nodes.createFolder(parent, resp)).then(resp => parentId = resp.data.entry.id) + .then(() => apis.user.nodes.createFolder(subfolder1, parentId)).then(resp => subfolder1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFolder(subfolder2, subfolder1Id)).then(resp => subfolder2Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(fileName1, subfolder2Id)) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + apis.user.nodes.deleteNodeById(parentId), + apis.user.nodes.deleteNodeById(parent2Id), + apis.user.sites.deleteSite(siteName), + logoutPage.load() + ]) + .then(done); + }); + + it('Personal Files breadcrumb main node [C260964]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => { + expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items'); + expect(breadcrumb.getCurrentItemName()).toBe('Personal Files'); + }); + }); + + it('File Libraries breadcrumb main node [C260966]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => { + expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items'); + expect(breadcrumb.getCurrentItemName()).toBe('File Libraries'); + }); + }); + + it('Recent Files breadcrumb main node [C260971]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => { + expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items'); + expect(breadcrumb.getCurrentItemName()).toBe('Recent Files'); + }); + }); + + it('Shared Files breadcrumb main node [C260972]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => { + expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items'); + expect(breadcrumb.getCurrentItemName()).toBe('Shared Files'); + }); + }); + + it('Favorites breadcrumb main node [C260973]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => { + expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items'); + expect(breadcrumb.getCurrentItemName()).toBe('Favorites'); + }); + }); + + it('Trash breadcrumb main node [C260974]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => { + expect(breadcrumb.getItemsCount()).toEqual(1, 'Breadcrumb has incorrect number of items'); + expect(breadcrumb.getCurrentItemName()).toBe('Trash'); + }); + }); + + it('Personal Files breadcrumb for a folder hierarchy [C260965]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => page.dataTable.waitForHeader()) + .then(() => page.dataTable.doubleClickOnItemName(parent)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) + .then(() => { + const expectedBreadcrumb = [ 'Personal Files', parent, subfolder1, subfolder2 ]; + expect(breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); + }); + }); + + it('File Libraries breadcrumb for a folder hierarchy [C260967]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => page.dataTable.waitForHeader()) + .then(() => page.dataTable.doubleClickOnItemName(siteName)) + .then(() => page.dataTable.doubleClickOnItemName(parent)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) + .then(() => { + const expectedItems = [ 'File Libraries', siteName, parent, subfolder1, subfolder2 ]; + expect(breadcrumb.getAllItems()).toEqual(expectedItems); + }); + }); + + it('User can navigate to any location by clicking on a step from the breadcrumb [C213235]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => page.dataTable.waitForHeader()) + .then(() => page.dataTable.doubleClickOnItemName(parent)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) + .then(() => breadcrumb.clickItem(subfolder1)) + .then(() => { + const expectedBreadcrumb = [ 'Personal Files', parent, subfolder1 ]; + expect(breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); + }); + }); + + it('Tooltip appears on hover on a step in breadcrumb [C213237]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => page.dataTable.waitForHeader()) + .then(() => page.dataTable.doubleClickOnItemName(parent)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) + .then(() => { + expect(breadcrumb.getNthItemTooltip(3)).toEqual(subfolder1); + }); + }); + + it('Breadcrumb updates correctly when folder is renamed [C213238]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => page.dataTable.waitForHeader()) + .then(() => page.dataTable.doubleClickOnItemName(parent2)) + .then(() => page.dataTable.doubleClickOnItemName(folder1)) + .then(() => page.dataTable.wait()) + .then(() => apis.user.nodes.renameNode(folder1Id, folder1Renamed).then(done => done)) + .then(() => page.refresh()) + .then(() => page.dataTable.wait()) + .then(() => { + expect(breadcrumb.getCurrentItemName()).toEqual(folder1Renamed); + }); + }); + + it('Browser back navigates to previous location regardless of breadcrumb steps [C213240]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => page.dataTable.waitForHeader()) + .then(() => page.dataTable.doubleClickOnItemName(parent)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) + .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) + .then(() => page.dataTable.waitForEmptyState()) + .then(() => browser.navigate().back()) + .then(() => { + const expectedBreadcrumb = [ 'Personal Files', parent, subfolder1, subfolder2 ]; + expect(breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); + }); + }); + + // disabled cause of ACA-1039 + xdescribe('as admin', () => { + const user2 = 'a_user'; + const userFolder = `userFolder-${Utils.random()}`; let userFolderId; + const user2Api = new RepoClient(user2, user2); + + beforeAll(done => { + logoutPage.load() + .then(() => apis.admin.people.createUser(user2)) + .then(() => user2Api.nodes.createFolder(userFolder).then(resp => userFolderId = resp.data.entry.id)) + .then(() => loginPage.loginWithAdmin()) + .then(done); + }); + + afterAll(done => { + Promise.all([ + user2Api.nodes.deleteNodeById(userFolderId), + logoutPage.load() + ]) + .then(done); + }); + + it(`Breadcrumb on navigation to a user's home [C260970]`, () => { + page.dataTable.doubleClickOnItemName('User Homes') + .then(() => page.dataTable.doubleClickOnItemName(user2)) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', 'User Homes', user2 ])) + .then(() => page.dataTable.doubleClickOnItemName(userFolder)) + .then(() => expect(breadcrumb.getAllItems()).toEqual([ 'Personal Files', 'User Homes', user2, userFolder ])); + }); + }); +}); diff --git a/e2e/suites/navigation/sidebar.test.ts b/e2e/suites/navigation/sidebar.test.ts new file mode 100755 index 0000000000..531fc36d23 --- /dev/null +++ b/e2e/suites/navigation/sidebar.test.ts @@ -0,0 +1,139 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; + +import { APP_ROUTES, SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; + +describe('Sidebar', () => { + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { sidenav } = page; + + beforeAll(done => { + loginPage.loginWithAdmin().then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('has "Personal Files" as default', () => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES); + expect(sidenav.isActiveByLabel('Personal Files')).toBe(true, 'Active link'); + }); + + it('navigates to "File Libraries"', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.FILE_LIBRARIES); + expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.FILE_LIBRARIES)).toBe(true); + }); + }); + + it('navigates to "Personal Files"', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.PERSONAL_FILES); + expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.PERSONAL_FILES)).toBe(true); + }); + }); + + it('navigates to "Shared Files"', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.SHARED_FILES); + expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.SHARED_FILES)).toBe(true); + }); + }); + + it('navigates to "Recent Files"', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.RECENT_FILES); + expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.RECENT_FILES)).toBe(true); + }); + }); + + it('navigates to "Favorites"', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.FAVORITES); + expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.FAVORITES)).toBe(true); + }); + }); + + it('navigates to "Trash"', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => { + expect(browser.getCurrentUrl()).toContain(APP_ROUTES.TRASHCAN); + expect(sidenav.isActiveByLabel(SIDEBAR_LABELS.TRASH)).toBe(true); + }); + }); + + it('Personal Files tooltip', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => { + expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.PERSONAL_FILES)).toContain('View your Personal Files'); + }); + }); + + it('File Libraries tooltip', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) + .then(() => { + expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.FILE_LIBRARIES)).toContain('Access File Libraries'); + }); + }); + + it('Shared Files tooltip', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => { + expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.SHARED_FILES)).toContain('View files that have been shared'); + }); + }); + + it('Recent Files tooltip', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => { + expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.RECENT_FILES)).toContain('View files you recently edited'); + }); + }); + + it('Favorites tooltip', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => { + expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.FAVORITES)).toContain('View your favorite files and folders'); + }); + }); + + it('Trash tooltip', () => { + sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => { + expect(sidenav.getLinkTooltip(SIDEBAR_LABELS.TRASH)).toContain('View deleted files in the trash'); + }); + }); +}); diff --git a/e2e/suites/pagination/pag-favorites.test.ts b/e2e/suites/pagination/pag-favorites.test.ts new file mode 100755 index 0000000000..2244be6e85 --- /dev/null +++ b/e2e/suites/pagination/pag-favorites.test.ts @@ -0,0 +1,228 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Pagination on Favorites', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + const { nodes: nodesApi, favorites: favoritesApi } = apis.user; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, pagination } = page; + + const parent = `parent-${Utils.random()}`; + const files = Array(101) + .fill('file') + .map((name, index): string => `${name}-${index + 1}.txt`); + let filesIds; + + const file = `file-${Utils.random()}.txt`; let fileId; + + beforeAll(done => { + apis.admin.people.createUser(username).then(done); + }); + + xit(''); + + describe('on empty page', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('pagination controls not displayed [C213164]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => { + expect(pagination.range.isPresent()).toBe(false); + expect(pagination.maxItems.isPresent()).toBe(false); + expect(pagination.currentPage.isPresent()).toBe(false); + expect(pagination.totalPages.isPresent()).toBe(false); + expect(pagination.previousButton.isPresent()).toBe(false); + expect(pagination.nextButton.isPresent()).toBe(false); + }); + }); + }); + + describe('on single page', () => { + beforeAll(done => { + nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id) + .then(() => favoritesApi.addFavoriteById('file', fileId)) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + nodesApi.deleteNodeById(fileId), + logoutPage.load() + ]) + .then(done); + }); + + it('page selector not displayed when having a single page [C213165]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed')); + }); + }); + + describe('on multiple pages', () => { + beforeAll(done => { + nodesApi.createFiles(files, parent) + .then(resp => filesIds = resp.data.list.entries.map(entries => entries.entry.id)) + .then(() => favoritesApi.addFavoritesByIds('file', filesIds)) + .then(() => favoritesApi.waitForApi({ expect: 101 })) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FAVORITES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); + }); + + afterAll(done => { + Promise.all([ + nodesApi.deleteNodes([ parent ]), + logoutPage.load() + ]) + .then(done); + }); + + it('default values [C213157]', () => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(pagination.maxItems.getText()).toContain('25'); + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.totalPages.getText()).toContain('of 5'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + }); + + it('page sizes [C213157]', () => { + pagination.openMaxItemsMenu() + .then(() => { + const [ first, second, third ] = [1, 2, 3] + .map(nth => pagination.menu.getNthItem(nth).getText()); + expect(first).toBe('25'); + expect(second).toBe('50'); + expect(third).toBe('100'); + }) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the page size [C213158]', () => { + pagination.openMaxItemsMenu() + .then(() => pagination.menu.clickMenuItem('50')) + .then(() => { + expect(pagination.getText(pagination.maxItems)).toContain('50'); + expect(pagination.getText(pagination.totalPages)).toContain('of 3'); + }) + .then(() => pagination.openMaxItemsMenu()) + .then(() => pagination.menu.clickMenuItem('100')) + .then(() => { + expect(pagination.getText(pagination.maxItems)).toContain('100'); + expect(pagination.getText(pagination.totalPages)).toContain('of 2'); + }) + .then(() => pagination.resetToDefaultPageSize()); + }); + + it('current page menu items', () => { + pagination.openCurrentPageMenu() + .then(() => expect(pagination.menu.getItemsCount()).toBe(5)) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the current page from menu [C260518]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(3)) + .then(() => { + expect(pagination.getText(pagination.range)).toContain('51-75 of 101'); + expect(pagination.getText(pagination.currentPage)).toContain('Page 3'); + expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + expect(dataTable.getRowName('file-40.txt').isPresent()).toBe(true, 'File not found on page'); + }) + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to next page [C213160]', () => { + pagination.nextButton.click() + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('26-50 of 101'); + expect(dataTable.getRowName('file-70.txt').isPresent()).toBe(true, 'File not found on page'); + }) + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to previous page [C213160]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(2)) + .then(() => dataTable.waitForHeader()) + .then(() => pagination.previousButton.click()) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(dataTable.getRowName('file-88.txt').isPresent()) + .toBe(true, 'File not found on page'); + }) + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('Previous button is disabled on first page [C260519]', () => { + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page'); + }); + + it('Next button is disabled on last page [C260519]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(5)) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page'); + expect(pagination.currentPage.getText()).toContain('Page 5'); + expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page'); + }); + }); + }); +}); diff --git a/e2e/suites/pagination/pag-personal-files.test.ts b/e2e/suites/pagination/pag-personal-files.test.ts new file mode 100755 index 0000000000..beb5806384 --- /dev/null +++ b/e2e/suites/pagination/pag-personal-files.test.ts @@ -0,0 +1,228 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Pagination on Personal Files', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + const { nodes: nodesApi } = apis.user; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, pagination } = page; + + const parent = `parent-${Utils.random()}`; + const files = Array(101) + .fill('file') + .map((name, index): string => `${name}-${index + 1}.txt`); + + const file = `file-${Utils.random()}.txt`; let fileId; + + beforeAll(done => { + apis.admin.people.createUser(username).then(done); + }); + + xit(''); + + describe('on empty page', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('pagination controls not displayed [C213164]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => { + expect(pagination.range.isPresent()).toBe(false); + expect(pagination.maxItems.isPresent()).toBe(false); + expect(pagination.currentPage.isPresent()).toBe(false); + expect(pagination.totalPages.isPresent()).toBe(false); + expect(pagination.previousButton.isPresent()).toBe(false); + expect(pagination.nextButton.isPresent()).toBe(false); + }); + }); + }); + + describe('on single page', () => { + beforeAll(done => { + nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + nodesApi.deleteNodeById(fileId), + logoutPage.load() + ]) + .then(done); + }); + + it('page selector not displayed when having a single page [C213165]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed')); + }); + }); + + describe('on multiple pages', () => { + beforeAll(done => { + nodesApi.createFiles(files, parent) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => dataTable.doubleClickOnItemName(parent)) + .then(done); + }); + + afterEach(done => { + browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); + }); + + afterAll(done => { + Promise.all([ + nodesApi.deleteNodes([ parent ]), + logoutPage.load() + ]) + .then(done); + }); + + it('default values [C213157]', () => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(pagination.maxItems.getText()).toContain('25'); + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.totalPages.getText()).toContain('of 5'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + }); + + it('page sizes [C213157]', () => { + pagination.openMaxItemsMenu() + .then(() => { + const [ first, second, third ] = [1, 2, 3] + .map(nth => pagination.menu.getNthItem(nth).getText()); + expect(first).toBe('25'); + expect(second).toBe('50'); + expect(third).toBe('100'); + }) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the page size [C213158]', () => { + pagination.openMaxItemsMenu() + .then(() => pagination.menu.clickMenuItem('50')) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.maxItems.getText()).toContain('50'); + expect(pagination.totalPages.getText()).toContain('of 3'); + }) + .then(() => pagination.openMaxItemsMenu()) + .then(() => pagination.menu.clickMenuItem('100')) + .then(() => { + expect(pagination.getText(pagination.maxItems)).toContain('100'); + expect(pagination.getText(pagination.totalPages)).toContain('of 2'); + }) + .then(() => pagination.resetToDefaultPageSize()); + }); + + it('current page menu items', () => { + pagination.openCurrentPageMenu() + .then(() => expect(pagination.menu.getItemsCount()).toBe(5)) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the current page from menu [C260518]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(3)) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('51-75 of 101'); + expect(pagination.currentPage.getText()).toContain('Page 3'); + expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + expect(dataTable.getRowName('file-60.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to next page [C213160]', () => { + pagination.clickNext() + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('26-50 of 101'); + expect(dataTable.getRowName('file-30.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to previous page [C213160]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(2)) + .then(() => dataTable.waitForHeader()) + .then(() => pagination.clickPrevious()) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(dataTable.getRowName('file-12.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('Previous button is disabled on first page [C260519]', () => { + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page'); + }); + + it('Next button is disabled on last page [C260519]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(5)) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page'); + expect(pagination.currentPage.getText()).toContain('Page 5'); + expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page'); + }); + }); + }); +}); diff --git a/e2e/suites/pagination/pag-recent-files.test.ts b/e2e/suites/pagination/pag-recent-files.test.ts new file mode 100755 index 0000000000..bf3baa066c --- /dev/null +++ b/e2e/suites/pagination/pag-recent-files.test.ts @@ -0,0 +1,230 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Pagination on Recent Files', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + const { nodes: nodesApi, search: searchApi } = apis.user; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, pagination } = page; + + const parent = `parent-${Utils.random()}`; + const files = Array(101) + .fill('file') + .map((name, index): string => `${name}-${index + 1}.txt`); + + const file = `file-${Utils.random()}.txt`; let fileId; + + beforeAll(done => { + apis.admin.people.createUser(username).then(done); + }); + + xit(''); + + describe('on empty page', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('pagination controls not displayed [C213164]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => { + expect(pagination.range.isPresent()).toBe(false); + expect(pagination.maxItems.isPresent()).toBe(false); + expect(pagination.currentPage.isPresent()).toBe(false); + expect(pagination.totalPages.isPresent()).toBe(false); + expect(pagination.previousButton.isPresent()).toBe(false); + expect(pagination.nextButton.isPresent()).toBe(false); + }); + }); + }); + + describe('on single page', () => { + beforeAll(done => { + nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id) + .then(() => searchApi.waitForApi(username, { expect: 1 })) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + nodesApi.deleteNodeById(fileId), + logoutPage.load() + ]) + .then(done); + }); + + it('page selector not displayed when having a single page [C213165]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed')); + }); + }); + + describe('on multiple pages', () => { + beforeAll(done => { + nodesApi.createFiles(files, parent) + .then(() => searchApi.waitForApi(username, { expect: 101 })) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.RECENT_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); + }); + + afterAll(done => { + Promise.all([ + nodesApi.deleteNodes([ parent ]), + logoutPage.load() + ]) + .then(done); + }); + + it('default values [C213157]', () => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(pagination.maxItems.getText()).toContain('25'); + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.totalPages.getText()).toContain('of 5'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + }); + + it('page sizes [C213157]', () => { + pagination.openMaxItemsMenu() + .then(() => { + const [ first, second, third ] = [1, 2, 3] + .map(nth => pagination.menu.getNthItem(nth).getText()); + expect(first).toBe('25'); + expect(second).toBe('50'); + expect(third).toBe('100'); + }) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the page size [C213158]', () => { + pagination.openMaxItemsMenu() + .then(() => pagination.menu.clickMenuItem('50')) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.maxItems.getText()).toContain('50'); + expect(pagination.totalPages.getText()).toContain('of 3'); + }) + .then(() => pagination.openMaxItemsMenu()) + .then(() => pagination.menu.clickMenuItem('100')) + .then(() => { + expect(pagination.getText(pagination.maxItems)).toContain('100'); + expect(pagination.getText(pagination.totalPages)).toContain('of 2'); + }) + .then(() => pagination.resetToDefaultPageSize()); + }); + + it('current page menu items', () => { + pagination.openCurrentPageMenu() + .then(() => expect(pagination.menu.getItemsCount()).toBe(5)) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the current page from menu [C260518]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(3)) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('51-75 of 101'); + expect(pagination.currentPage.getText()).toContain('Page 3'); + expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + expect(dataTable.getRowName('file-40.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to next page [C213160]', () => { + pagination.nextButton.click() + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('26-50 of 101'); + expect(dataTable.getRowName('file-70.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to previous page [C213160]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(2)) + .then(() => dataTable.waitForHeader()) + .then(() => pagination.previousButton.click()) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(dataTable.getRowName('file-88.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('Previous button is disabled on first page [C260519]', () => { + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page'); + }); + + it('Next button is disabled on last page [C260519]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(5)) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page'); + expect(pagination.currentPage.getText()).toContain('Page 5'); + expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page'); + }); + }); + }); +}); diff --git a/e2e/suites/pagination/pag-shared-files.test.ts b/e2e/suites/pagination/pag-shared-files.test.ts new file mode 100755 index 0000000000..ae0b47511d --- /dev/null +++ b/e2e/suites/pagination/pag-shared-files.test.ts @@ -0,0 +1,236 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Pagination on Shared Files', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + const { nodes: nodesApi, shared: sharedApi } = apis.user; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, pagination } = page; + + const parent = `parent-${Utils.random()}`; + const files = Array(101) + .fill('file') + .map((name, index): string => `${name}-${index + 1}.txt`); + let filesIds; + + const file = `file-${Utils.random()}.txt`; let fileId; + + beforeAll(done => { + apis.admin.people.createUser(username).then(done); + }); + + xit(''); + + describe('on empty page', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('pagination controls not displayed [C213164]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => { + expect(pagination.range.isPresent()).toBe(false); + expect(pagination.maxItems.isPresent()).toBe(false); + expect(pagination.currentPage.isPresent()).toBe(false); + expect(pagination.totalPages.isPresent()).toBe(false); + expect(pagination.previousButton.isPresent()).toBe(false); + expect(pagination.nextButton.isPresent()).toBe(false); + }); + }); + }); + + describe('on single page', () => { + beforeAll(done => { + nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id) + .then(() => sharedApi.shareFileById(fileId)) + .then(() => sharedApi.waitForApi({ expect: 1 })) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + nodesApi.deleteNodeById(fileId), + logoutPage.load() + ]) + .then(done); + }); + + it('page selector not displayed when having a single page [C213165]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed')); + }); + }); + + describe('on multiple pages', () => { + beforeAll(done => { + nodesApi.createFiles(files, parent) + .then(resp => filesIds = resp.data.list.entries.map(entries => entries.entry.id)) + + .then(() => sharedApi.shareFilesByIds(filesIds)) + .then(() => sharedApi.waitForApi({ expect: 101 })) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); + }); + + afterAll(done => { + Promise.all([ + nodesApi.deleteNodes([ parent ]), + logoutPage.load() + ]) + .then(done); + }); + + it('default values [C213157]', () => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(pagination.maxItems.getText()).toContain('25'); + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.totalPages.getText()).toContain('of 5'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + }); + + it('page sizes [C213157]', () => { + pagination.openMaxItemsMenu() + .then(() => { + const [ first, second, third ] = [1, 2, 3] + .map(nth => pagination.menu.getNthItem(nth).getText()); + expect(first).toBe('25'); + expect(second).toBe('50'); + expect(third).toBe('100'); + }) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the page size [C213158]', () => { + pagination.openMaxItemsMenu() + .then(() => pagination.menu.clickMenuItem('50')) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.maxItems.getText()).toContain('50'); + expect(pagination.totalPages.getText()).toContain('of 3'); + }) + .then(() => pagination.openMaxItemsMenu()) + .then(() => pagination.menu.clickMenuItem('100')) + .then(() => { + expect(pagination.getText(pagination.maxItems)).toContain('100'); + expect(pagination.getText(pagination.totalPages)).toContain('of 2'); + }) + .then(() => pagination.resetToDefaultPageSize()); + }); + + it('current page menu items', () => { + pagination.openCurrentPageMenu() + .then(() => expect(pagination.menu.getItemsCount()).toBe(5)) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the current page from menu [C260518]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(3)) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('51-75 of 101'); + expect(pagination.currentPage.getText()).toContain('Page 3'); + expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + expect(dataTable.getRowName('file-40.txt').isPresent()) + .toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to next page [C213160]', () => { + pagination.nextButton.click() + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('26-50 of 101'); + expect(dataTable.getRowName('file-70.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to previous page [C213160]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(2)) + .then(() => dataTable.waitForHeader()) + .then(() => pagination.previousButton.click()) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(dataTable.getRowName('file-88.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('Previous button is disabled on first page [C260519]', () => { + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page'); + }); + + it('Next button is disabled on last page [C260519]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(5)) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page'); + expect(pagination.currentPage.getText()).toContain('Page 5'); + expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page'); + }); + }); + }); +}); diff --git a/e2e/suites/pagination/pag-trash.test.ts b/e2e/suites/pagination/pag-trash.test.ts new file mode 100755 index 0000000000..35452d2c35 --- /dev/null +++ b/e2e/suites/pagination/pag-trash.test.ts @@ -0,0 +1,233 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser } from 'protractor'; +import { SIDEBAR_LABELS } from '../../configs'; +import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages'; +import { Utils } from '../../utilities/utils'; +import { RepoClient } from '../../utilities/repo-client/repo-client'; + +describe('Pagination on Trash', () => { + const username = `user-${Utils.random()}`; + + const apis = { + admin: new RepoClient(), + user: new RepoClient(username, username) + }; + const { nodes: nodesApi, trashcan: trashApi } = apis.user; + + const loginPage = new LoginPage(); + const logoutPage = new LogoutPage(); + const page = new BrowsingPage(); + const { dataTable, pagination } = page; + + const filesForDelete = Array(101) + .fill('file') + .map((name, index): string => `${name}-${index + 1}.txt`); + let filesDeletedIds; + + const file = `file-${Utils.random()}.txt`; let fileId; + + beforeAll(done => { + apis.admin.people.createUser(username).then(done); + }); + + xit(''); + + describe('on empty page', () => { + beforeAll(done => { + loginPage.loginWith(username).then(done); + }); + + afterAll(done => { + logoutPage.load().then(done); + }); + + it('pagination controls not displayed [C213164]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => { + expect(pagination.range.isPresent()).toBe(false); + expect(pagination.maxItems.isPresent()).toBe(false); + expect(pagination.currentPage.isPresent()).toBe(false); + expect(pagination.totalPages.isPresent()).toBe(false); + expect(pagination.previousButton.isPresent()).toBe(false); + expect(pagination.nextButton.isPresent()).toBe(false); + }); + }); + }); + + describe('on single page', () => { + beforeAll(done => { + nodesApi.createFile(file).then(resp => fileId = resp.data.entry.id) + .then(() => nodesApi.deleteNodeById(fileId, false)) + .then(() => trashApi.waitForApi({ expect: 1 })) + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + afterAll(done => { + Promise.all([ + trashApi.emptyTrash(), + logoutPage.load() + ]) + .then(done); + }); + + it('page selector not displayed when having a single page [C213165]', () => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(() => expect(pagination.pagesButton.isPresent()).toBe(false, 'page selector displayed')); + }); + }); + + describe('on multiple pages', () => { + beforeAll(done => { + nodesApi.createFiles(filesForDelete) + .then(resp => filesDeletedIds = resp.data.list.entries.map(entries => entries.entry.id)) + .then(() => nodesApi.deleteNodesById(filesDeletedIds, false)) + .then(() => trashApi.waitForApi({expect: 101})) + + .then(() => loginPage.loginWith(username)) + .then(done); + }); + + beforeEach(done => { + page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH) + .then(() => dataTable.waitForHeader()) + .then(done); + }); + + afterEach(done => { + browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); + }); + + afterAll(done => { + Promise.all([ + trashApi.emptyTrash(), + logoutPage.load() + ]) + .then(done); + }); + + it('default values [C213157]', () => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(pagination.maxItems.getText()).toContain('25'); + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.totalPages.getText()).toContain('of 5'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + }); + + it('page sizes [C213157]', () => { + pagination.openMaxItemsMenu() + .then(() => { + const [ first, second, third ] = [1, 2, 3] + .map(nth => pagination.menu.getNthItem(nth).getText()); + expect(first).toBe('25'); + expect(second).toBe('50'); + expect(third).toBe('100'); + }) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the page size [C213158]', () => { + pagination.openMaxItemsMenu() + .then(() => pagination.menu.clickMenuItem('50')) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.maxItems.getText()).toContain('50'); + expect(pagination.totalPages.getText()).toContain('of 3'); + }) + .then(() => pagination.openMaxItemsMenu()) + .then(() => pagination.menu.clickMenuItem('100')) + .then(() => { + expect(pagination.getText(pagination.maxItems)).toContain('100'); + expect(pagination.getText(pagination.totalPages)).toContain('of 2'); + }) + .then(() => pagination.resetToDefaultPageSize()); + }); + + it('current page menu items', () => { + pagination.openCurrentPageMenu() + .then(() => expect(pagination.menu.getItemsCount()).toBe(5)) + .then(() => pagination.menu.closeMenu()); + }); + + it('change the current page from menu [C260518]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(3)) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('51-75 of 101'); + expect(pagination.currentPage.getText()).toContain('Page 3'); + expect(pagination.previousButton.isEnabled()).toBe(true, 'Previous button is not enabled'); + expect(pagination.nextButton.isEnabled()).toBe(true, 'Next button is not enabled'); + expect(dataTable.getRowName('file-40.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to next page [C213160]', () => { + pagination.nextButton.click() + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('26-50 of 101'); + expect(dataTable.getRowName('file-70.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('navigate to previous page [C213160]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(2)) + .then(() => dataTable.waitForHeader()) + .then(() => pagination.previousButton.click()) + .then(() => dataTable.waitForHeader()) + .then(() => { + expect(pagination.range.getText()).toContain('1-25 of 101'); + expect(dataTable.getRowName('file-88.txt').isPresent()).toBe(true, 'File not found on page'); + }) + + .then(() => pagination.resetToDefaultPageNumber()); + }); + + it('Previous button is disabled on first page [C260519]', () => { + expect(pagination.currentPage.getText()).toContain('Page 1'); + expect(pagination.previousButton.isEnabled()).toBe(false, 'Previous button is enabled on first page'); + }); + + it('Next button is disabled on last page [C260519]', () => { + pagination.openCurrentPageMenu() + .then(() => pagination.menu.clickNthItem(5)) + .then(() => { + expect(dataTable.countRows()).toBe(1, 'Incorrect number of items on the last page'); + expect(pagination.currentPage.getText()).toContain('Page 5'); + expect(pagination.nextButton.isEnabled()).toBe(false, 'Next button is enabled on last page'); + }); + }); + }); +}); diff --git a/e2e/tsconfig.e2e.json b/e2e/tsconfig.e2e.json old mode 100644 new mode 100755 diff --git a/e2e/utilities/repo-client/apis/favorites/favorites-api.ts b/e2e/utilities/repo-client/apis/favorites/favorites-api.ts new file mode 100755 index 0000000000..3e92d78387 --- /dev/null +++ b/e2e/utilities/repo-client/apis/favorites/favorites-api.ts @@ -0,0 +1,118 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { promise } from 'protractor'; +import { RepoApi } from '../repo-api'; +import { NodesApi } from '../nodes/nodes-api'; +import { RepoClient } from './../../repo-client'; +import { Utils } from '../../../../utilities/utils'; + +export class FavoritesApi extends RepoApi { + + addFavorite(api: RepoClient, nodeType: string, name: string): Promise { + return api.nodes.getNodeByPath(name) + .then((response) => { + const { id } = response.data.entry; + return ([{ + target: { + [nodeType]: { + guid: id + } + } + }]); + }) + .then((data) => { + return this.post(`/people/-me-/favorites`, { data }); + }) + .catch(this.handleError); + } + + addFavoriteById(nodeType: 'file' | 'folder', id: string): Promise { + const data = [{ + target: { + [nodeType]: { + guid: id + } + } + }]; + return this + .post(`/people/-me-/favorites`, { data }) + .catch(this.handleError); + } + + addFavoritesByIds(nodeType: 'file' | 'folder', ids: string[]): Promise { + return ids.reduce((previous, current) => ( + previous.then(() => this.addFavoriteById(nodeType, current)) + ), Promise.resolve()); + } + + getFavorites(): Promise { + return this + .get('/people/-me-/favorites') + .catch(this.handleError); + } + + getFavoriteById(nodeId: string): Promise { + return this + .get(`/people/-me-/favorites/${nodeId}`) + .catch(this.handleError); + } + + isFavorite(nodeId: string) { + return this.getFavorites() + .then(resp => JSON.stringify(resp.data.list.entries).includes(nodeId)) + } + + removeFavorite(api: RepoClient, nodeType: string, name: string): Promise { + return api.nodes.getNodeByPath(name) + .then((response) => { + const { id } = response.data.entry; + return this.delete(`/people/-me-/favorites/${id}`); + }) + .catch(this.handleError); + } + + removeFavoriteById(nodeId: string) { + return this + .delete(`/people/-me-/favorites/${nodeId}`) + .catch(this.handleError); + } + + waitForApi(data) { + const favoriteFiles = () => { + return this.getFavorites() + .then(response => response.data.list.pagination.totalItems) + .then(totalItems => { + if ( totalItems < data.expect) { + return Promise.reject(totalItems); + } else { + return Promise.resolve(totalItems); + } + }); + }; + + return Utils.retryCall(favoriteFiles); + } +} diff --git a/e2e/utilities/repo-client/apis/nodes/node-body-create.ts b/e2e/utilities/repo-client/apis/nodes/node-body-create.ts new file mode 100755 index 0000000000..d82201ab2c --- /dev/null +++ b/e2e/utilities/repo-client/apis/nodes/node-body-create.ts @@ -0,0 +1,38 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +export const NODE_TYPE_FILE = 'cm:content'; +export const NODE_TYPE_FOLDER = 'cm:folder'; +export const NODE_TITLE = 'cm:title'; +export const NODE_DESCRIPTION = 'cm:description'; + +export class NodeBodyCreate { + constructor( + public name: string, + public nodeType: string, + public relativePath: string = '/', + public properties?: any[] + ) {} +} diff --git a/e2e/utilities/repo-client/apis/nodes/node-content-tree.ts b/e2e/utilities/repo-client/apis/nodes/node-content-tree.ts new file mode 100755 index 0000000000..65915d4800 --- /dev/null +++ b/e2e/utilities/repo-client/apis/nodes/node-content-tree.ts @@ -0,0 +1,85 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { NodeBodyCreate, NODE_TYPE_FILE, NODE_TYPE_FOLDER, NODE_TITLE, NODE_DESCRIPTION } from './node-body-create'; + +export interface NodeContentTree { + name?: string; + files?: string[]; + folders?: (string|NodeContentTree)[]; + title?: string; + description?: string; +} + +export function flattenNodeContentTree(content: NodeContentTree, relativePath: string = '/'): NodeBodyCreate[] { + const { name, files, folders, title, description } = content; + let data: NodeBodyCreate[] = []; + let properties: any; + + properties = { + [NODE_TITLE]: title, + [NODE_DESCRIPTION]: description + }; + + if (name) { + data = data.concat([{ + nodeType: NODE_TYPE_FOLDER, + name, + relativePath, + properties + }]); + + relativePath = (relativePath === '/') + ? `/${name}` + : `${relativePath}/${name}`; + } + + if (folders) { + const foldersData: NodeBodyCreate[] = folders + .map((folder: (string|NodeContentTree)): NodeBodyCreate[] => { + const folderData: NodeContentTree = (typeof folder === 'string') + ? { name: folder } + : folder; + + return flattenNodeContentTree(folderData, relativePath); + }) + .reduce((nodesData: NodeBodyCreate[], folderData: NodeBodyCreate[]) => nodesData.concat(folderData), []); + + data = data.concat(foldersData); + } + + if (files) { + const filesData: NodeBodyCreate[] = files + .map((filename: string): NodeBodyCreate => ({ + nodeType: NODE_TYPE_FILE, + name: filename, + relativePath + })); + + data = data.concat(filesData); + } + + return data; +} diff --git a/e2e/utilities/repo-client/apis/nodes/nodes-api.ts b/e2e/utilities/repo-client/apis/nodes/nodes-api.ts new file mode 100755 index 0000000000..bde0a2a110 --- /dev/null +++ b/e2e/utilities/repo-client/apis/nodes/nodes-api.ts @@ -0,0 +1,182 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { RepoApi } from '../repo-api'; +import { NodeBodyCreate, NODE_TYPE_FILE, NODE_TYPE_FOLDER } from './node-body-create'; +import { NodeContentTree, flattenNodeContentTree } from './node-content-tree'; + +export class NodesApi extends RepoApi { + // nodes + getNodeByPath(relativePath: string = '/'): Promise { + return this + .get(`/nodes/-my-`, { parameters: { relativePath } }) + .catch(this.handleError); + } + + getNodeById(id: string): Promise { + return this + .get(`/nodes/${id}`) + .catch(this.handleError); + } + + getNodeDescription(name: string, relativePath: string = '/') { + relativePath = (relativePath === '/') + ? `${name}` + : `${relativePath}/${name}`; + + return this.getNodeByPath(`${relativePath}`) + .then(response => response.data.entry.properties['cm:description']); + } + + deleteNodeById(id: string, permanent: boolean = true): Promise { + return this + .delete(`/nodes/${id}?permanent=${permanent}`) + .catch(this.handleError); + } + + deleteNodeByPath(path: string, permanent: boolean = true): Promise { + return this + .getNodeByPath(path) + .then((response: any): string => response.data.entry.id) + .then((id: string): any => this.deleteNodeById(id, permanent)) + .catch(this.handleError); + } + + deleteNodes(names: string[], relativePath: string = '', permanent: boolean = true): Promise { + return names.reduce((previous, current) => ( + previous.then(() => this.deleteNodeByPath(`${relativePath}/${current}`, permanent)) + ), Promise.resolve()); + } + + deleteNodesById(ids: string[], permanent: boolean = true): Promise { + return ids.reduce((previous, current) => ( + previous.then(() => this.deleteNodeById(current, permanent)) + ), Promise.resolve()); + } + + // children + getNodeChildren(nodeId: string): Promise { + return this + .get(`/nodes/${nodeId}/children`) + .catch(this.handleError); + } + + createNode(nodeType: string, name: string, parentId: string = '-my-', title: string = '', description: string = ''): Promise { + const data = { + name: name, + nodeType: nodeType, + properties: { + 'cm:title': title, 'cm:description': description + } + }; + + return this + .post(`/nodes/${parentId}/children`, { data }) + .catch(this.handleError); + } + + createFile(name: string, parentId: string = '-my-', title: string = '', description: string = ''): Promise { + return this.createNode('cm:content', name, parentId, title, description); + } + + createFolder(name: string, parentId: string = '-my-', title: string = '', description: string = ''): Promise { + return this.createNode('cm:folder', name, parentId, title, description); + } + + createChildren(data: NodeBodyCreate[]): Promise { + return this + .post(`/nodes/-my-/children`, { data }) + .catch(this.handleError); + } + + createContent(content: NodeContentTree, relativePath: string = '/'): Promise { + return this.createChildren(flattenNodeContentTree(content, relativePath)); + } + + createFolders(names: string[], relativePath: string = '/'): Promise { + return this.createContent({ folders: names }, relativePath); + } + + createFiles(names: string[], relativePath: string = '/'): Promise { + return this.createContent({ files: names }, relativePath); + } + + // node content + getNodeContent(nodeId: string): Promise { + return this + .get(`/nodes/${nodeId}/content`) + .catch(this.handleError); + } + + editNodeContent(nodeId: string, content: string): Promise { + return this + .put(`/nodes/${nodeId}/content`, { data: content }) + .catch(this.handleError); + } + + renameNode(nodeId: string, newName: string): Promise { + return this + .put(`/nodes/${nodeId}`, { data: { name: newName } }) + .catch(this.handleError); + } + + // node permissions + setGranularPermission(nodeId: string, inheritPermissions: boolean = false, username: string, role: string): Promise { + const data = { + permissions: { + isInheritanceEnabled: inheritPermissions, + locallySet: [ + { + authorityId: username, + name: role + } + ] + } + }; + + return this + .put(`/nodes/${nodeId}`, { data }) + .catch(this.handleError); + } + + getNodePermissions(nodeId: string): Promise { + return this + .get(`/nodes/${nodeId}?include=permissions`) + .catch(this.handleError); + } + + // lock node + lockFile(nodeId: string, lockType: string = 'FULL') { + return this + .post(`/nodes/${nodeId}/lock?include=isLocked`, { data: { 'type': lockType } }) + .catch(this.handleError); + } + + unlockFile(nodeId: string) { + return this + .post(`/nodes/${nodeId}/unlock`) + .catch(this.handleError); + } +} diff --git a/e2e/utilities/repo-client/apis/people/people-api-models.ts b/e2e/utilities/repo-client/apis/people/people-api-models.ts new file mode 100755 index 0000000000..93be7980c6 --- /dev/null +++ b/e2e/utilities/repo-client/apis/people/people-api-models.ts @@ -0,0 +1,43 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +export class Person { + id?: string; + password?: string; + firstName?: string; + lastName?: string; + email?: string; + properties?: any; + + constructor(username: string, password: string, details: Person) { + this.id = username; + this.password = password || username; + this.firstName = username; + this.lastName = username; + this.email = `${username}@alfresco.com`; + + Object.assign(this, details); + } +} diff --git a/e2e/utilities/repo-client/apis/people/people-api.ts b/e2e/utilities/repo-client/apis/people/people-api.ts new file mode 100755 index 0000000000..2ede559824 --- /dev/null +++ b/e2e/utilities/repo-client/apis/people/people-api.ts @@ -0,0 +1,70 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { RepoApi } from '../repo-api'; +import { Person } from './people-api-models'; + +export class PeopleApi extends RepoApi { + getUser(username: string) { + return this + .get(`/people/${username}`) + .catch(this.handleError); + } + + updateUser(username: string, details?: Person): Promise { + if (details.id) { + delete details.id; + } + + return this + .put(`/people/${username}`, { data: details }) + .catch(this.handleError); + } + + createUser(username: string, password?: string, details?: Person): Promise { + const person: Person = new Person(username, password, details); + const onSuccess = (response) => response; + const onError = (response) => { + return (response.statusCode === 409) + ? Promise.resolve(this.updateUser(username, person)) + : Promise.reject(response); + }; + + return this + .post(`/people`, { data: person }) + .then(onSuccess, onError) + .catch(this.handleError); + } + + disableUser(username: string): Promise { + return this.put(`/people/${username}`, { data: { enabled: false } }) + .catch(this.handleError); + } + + changePassword(username: string, newPassword: string) { + return this.put(`/people/${username}`, { data: { password: newPassword } }) + .catch(this.handleError); + } +} diff --git a/e2e/utilities/repo-client/apis/repo-api.ts b/e2e/utilities/repo-client/apis/repo-api.ts new file mode 100755 index 0000000000..ee61ce6dfe --- /dev/null +++ b/e2e/utilities/repo-client/apis/repo-api.ts @@ -0,0 +1,71 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { RestClient, RestClientArgs, RestClientResponse } from '../../rest-client/rest-client'; +import { RepoClientAuth, RepoClientConfig } from '../repo-client-models'; + +export abstract class RepoApi { + private client: RestClient; + private defaults: RepoClientConfig = new RepoClientConfig(); + + constructor( + auth: RepoClientAuth = new RepoClientAuth(), + private config?: RepoClientConfig + ) { + const { username, password } = auth; + + this.client = new RestClient(username, password); + } + + private createEndpointUri(endpoint: string, apiDefinition: string = 'alfresco'): string { + const { defaults, config } = this; + const { host, tenant } = Object.assign(defaults, config); + + return `${host}/alfresco/api/${tenant}/public/${apiDefinition}/versions/1${endpoint}`; + } + + protected handleError(response: RestClientResponse) { + const { request: { method, path, data }, data: error } = response; + + console.log(`ERROR on ${method}\n${path}\n${data}`); + console.log(error); + } + + protected get(endpoint: string, args: RestClientArgs = {}, apiDefinition: string = 'alfresco') { + return this.client.get(this.createEndpointUri(endpoint, apiDefinition), args); + } + + protected post(endpoint: string, args: RestClientArgs = {}, apiDefinition: string = 'alfresco') { + return this.client.post(this.createEndpointUri(endpoint, apiDefinition), args); + } + + protected put(endpoint: string, args: RestClientArgs = {}, apiDefinition: string = 'alfresco') { + return this.client.put(this.createEndpointUri(endpoint, apiDefinition), args); + } + + protected delete(endpoint: string, args: RestClientArgs = {}, apiDefinition: string = 'alfresco') { + return this.client.delete(this.createEndpointUri(endpoint, apiDefinition), args); + } +} diff --git a/e2e/utilities/repo-client/apis/search/search-api.ts b/e2e/utilities/repo-client/apis/search/search-api.ts new file mode 100755 index 0000000000..bb09fabd49 --- /dev/null +++ b/e2e/utilities/repo-client/apis/search/search-api.ts @@ -0,0 +1,71 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { RepoApi } from '../repo-api'; +import { Utils } from '../../../../utilities/utils'; + +export class SearchApi extends RepoApi { + apiDefinition = 'search'; + + search(data: any[]): Promise { + return this + .post(`/search`, { data }, this.apiDefinition) + .catch(this.handleError); + } + + queryRecentFiles(username: string): Promise { + const data = { + query: { + query: '*', + language: 'afts' + }, + filterQueries: [ + { query: `cm:modified:[NOW/DAY-30DAYS TO NOW/DAY+1DAY]` }, + { query: `cm:modifier:${username} OR cm:creator:${username}` }, + { query: `TYPE:"content" AND -TYPE:"app:filelink" AND -TYPE:"fm:post"` } + ] + }; + + return this + .post(`/search`, { data }, this.apiDefinition) + .catch(this.handleError); + } + + waitForApi(username, data) { + const recentFiles = () => { + return this.queryRecentFiles(username) + .then(response => response.data.list.pagination.totalItems) + .then(totalItems => { + if ( totalItems < data.expect) { + return Promise.reject(totalItems); + } else { + return Promise.resolve(totalItems); + } + }); + }; + + return Utils.retryCall(recentFiles); + } +} diff --git a/e2e/utilities/repo-client/apis/shared-links/shared-links-api.ts b/e2e/utilities/repo-client/apis/shared-links/shared-links-api.ts new file mode 100755 index 0000000000..6140dcd74f --- /dev/null +++ b/e2e/utilities/repo-client/apis/shared-links/shared-links-api.ts @@ -0,0 +1,79 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { RepoApi } from '../repo-api'; +import { NodesApi } from '../nodes/nodes-api'; +import { RepoClient } from './../../repo-client'; +import { Utils } from '../../../../utilities/utils'; + +export class SharedLinksApi extends RepoApi { + + shareFileById(id: string): Promise { + const data = [{ nodeId: id }]; + + return this.post(`/shared-links`, { data }) + .catch(this.handleError); + } + + shareFilesByIds(ids: string[]): Promise { + return ids.reduce((previous, current) => ( + previous.then(() => this.shareFileById(current)) + ), Promise.resolve()); + } + + getSharedIdOfNode(name: string) { + return this.getSharedLinks() + .then(resp => resp.data.list.entries.find(entries => entries.entry.name === name)) + .then(resp => resp.entry.id) + .catch(this.handleError); + } + + unshareFile(name: string) { + return this.getSharedIdOfNode(name) + .then(id => this.delete(`/shared-links/${id}`)) + .catch(this.handleError); + } + + getSharedLinks(): Promise { + return this.get(`/shared-links`) + .catch(this.handleError); + } + + waitForApi(data) { + const sharedFiles = () => { + return this.getSharedLinks() + .then(response => response.data.list.pagination.totalItems) + .then(totalItems => { + if ( totalItems < data.expect) { + return Promise.reject(totalItems); + } else { + return Promise.resolve(totalItems); + } + }); + }; + + return Utils.retryCall(sharedFiles); + } +} diff --git a/e2e/utilities/repo-client/apis/sites/sites-api-models.ts b/e2e/utilities/repo-client/apis/sites/sites-api-models.ts new file mode 100755 index 0000000000..598aad9003 --- /dev/null +++ b/e2e/utilities/repo-client/apis/sites/sites-api-models.ts @@ -0,0 +1,42 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { SITE_VISIBILITY } from '../../../../configs'; + +export class Site { + title?: string; + visibility?: string = SITE_VISIBILITY.PUBLIC; + id?: string; + description?: string; + + constructor(title: string, visibility: string, details: Site) { + this.title = title; + this.visibility = visibility; + this.id = title; + this.description = `${title} description`; + + Object.assign(this, details); + } +} diff --git a/e2e/utilities/repo-client/apis/sites/sites-api.ts b/e2e/utilities/repo-client/apis/sites/sites-api.ts new file mode 100755 index 0000000000..a824893ba0 --- /dev/null +++ b/e2e/utilities/repo-client/apis/sites/sites-api.ts @@ -0,0 +1,124 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { RepoApi } from '../repo-api'; +import { Site } from './sites-api-models'; + +export class SitesApi extends RepoApi { + getSite(id: string): Promise { + return this + .get(`/sites/${id}`) + .catch(this.handleError); + } + + getSiteContainers(siteId: string): Promise { + return this + .get(`/sites/${siteId}/containers`) + .then(resp => resp.data.list.entries) + .catch(this.handleError); + } + + getDocLibId(siteId: string) { + return this.getSiteContainers(siteId) + .then(resp => resp[0].entry.id) + .catch(this.handleError); + } + + updateSite(id: string, details?: Site): Promise { + if (details.id) { + delete details.id; + } + + return this + .put(`/sites/${id}`, { data: details }) + .catch(this.handleError); + } + + createOrUpdateSite(title: string, visibility: string, details?: Site): Promise { + const site: Site = new Site(title, visibility, details); + const onSuccess = (response) => response; + const onError = (response) => { + return (response.statusCode === 409) + ? Promise.resolve(this.updateSite(site.id, site)) + : Promise.reject(response); + }; + + return this + .post(`/sites`, { data: site }) + .then(onSuccess, onError) + .catch(this.handleError); + } + + createSite(title: string, visibility: string, details?: Site): Promise { + const site: Site = new Site(title, visibility, details); + return this + .post(`/sites`, { data: site }) + .catch(this.handleError); + } + + createSites(titles: string[], visibility: string): Promise { + return titles.reduce((previous, current) => ( + previous.then(() => this.createSite(current, visibility)) + ), Promise.resolve()); + } + + deleteSite(id: string, permanent: boolean = true): Promise { + return this + .delete(`/sites/${id}?permanent=${permanent}`) + .catch(this.handleError); + } + + deleteSites(ids: string[], permanent: boolean = true): Promise { + return ids.reduce((previous, current) => ( + previous.then(() => this.deleteSite(current)) + ), Promise.resolve()); + } + + updateSiteMember(siteId: string, userId: string, role: string): Promise { + return this + .put(`/sites/${siteId}/members/${userId}`, { data: { role } }) + .catch(this.handleError); + } + + addSiteMember(siteId: string, userId: string, role: string): Promise { + const onSuccess = (response) => response; + const onError = (response) => { + return (response.statusCode === 409) + ? Promise.resolve(this.updateSiteMember(siteId, userId, role)) + : Promise.reject(response); + }; + + return this + .post(`/sites/${siteId}/members`, { data: { role, id: userId } }) + .then(onSuccess, onError) + .catch(this.handleError); + } + + deleteSiteMember(siteId: string, userId: string): Promise { + return this + .delete(`/sites/${siteId}/members/${userId}`) + .catch(this.handleError); + } +} diff --git a/e2e/utilities/repo-client/apis/trashcan/trashcan-api.ts b/e2e/utilities/repo-client/apis/trashcan/trashcan-api.ts new file mode 100755 index 0000000000..0f94d5ee6a --- /dev/null +++ b/e2e/utilities/repo-client/apis/trashcan/trashcan-api.ts @@ -0,0 +1,76 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { RepoApi } from '../repo-api'; +import { Utils } from '../../../../utilities/utils'; + +export class TrashcanApi extends RepoApi { + permanentlyDelete(id: string): Promise { + return this + .delete(`/deleted-nodes/${id}`) + .catch(this.handleError); + } + + restore(id: string) { + return this + .post(`/deleted-nodes/${id}/restore`) + .catch(this.handleError); + } + + getDeletedNodes(): Promise { + return this + .get(`/deleted-nodes?maxItems=1000`) + .catch(this.handleError); + } + + emptyTrash(): Promise { + return this.getDeletedNodes() + .then(resp => { + return resp.data.list.entries.map(entries => entries.entry.id); + }) + .then(ids => { + return ids.reduce((previous, current) => ( + previous.then(() => this.permanentlyDelete(current)) + ), Promise.resolve()); + }) + .catch(this.handleError); + } + + waitForApi(data) { + const deletedFiles = () => { + return this.getDeletedNodes() + .then(response => response.data.list.pagination.totalItems) + .then(totalItems => { + if ( totalItems < data.expect) { + return Promise.reject(totalItems); + } else { + return Promise.resolve(totalItems); + } + }); + }; + + return Utils.retryCall(deletedFiles); + } +} diff --git a/e2e/utilities/repo-client/repo-client-models.ts b/e2e/utilities/repo-client/repo-client-models.ts new file mode 100755 index 0000000000..a352eb8824 --- /dev/null +++ b/e2e/utilities/repo-client/repo-client-models.ts @@ -0,0 +1,46 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { + ADMIN_USERNAME, + ADMIN_PASSWORD, + REPO_API_HOST, + REPO_API_TENANT +} from '../../configs'; + +export class RepoClientAuth { + static DEFAULT_USERNAME: string = ADMIN_USERNAME; + static DEFAULT_PASSWORD: string = ADMIN_PASSWORD; + + constructor( + public username: string = RepoClientAuth.DEFAULT_USERNAME, + public password: string = RepoClientAuth.DEFAULT_PASSWORD + ) {} +} + +export class RepoClientConfig { + host?: string = REPO_API_HOST; + tenant?: string = REPO_API_TENANT; +} diff --git a/e2e/utilities/repo-client/repo-client.ts b/e2e/utilities/repo-client/repo-client.ts new file mode 100755 index 0000000000..e3ffc0107d --- /dev/null +++ b/e2e/utilities/repo-client/repo-client.ts @@ -0,0 +1,59 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { RepoClientAuth, RepoClientConfig } from './repo-client-models'; + +import { PeopleApi } from './apis/people/people-api'; +import { NodesApi } from './apis/nodes/nodes-api'; +import { SitesApi } from './apis/sites/sites-api'; +import { FavoritesApi } from './apis/favorites/favorites-api'; +import { SharedLinksApi } from './apis/shared-links/shared-links-api'; +import { TrashcanApi } from './apis/trashcan/trashcan-api'; +import { SearchApi } from './apis/search/search-api'; + +export class RepoClient { + public people: PeopleApi = new PeopleApi(this.auth, this.config); + public nodes: NodesApi = new NodesApi(this.auth, this.config); + public sites: SitesApi = new SitesApi(this.auth, this.config); + public favorites: FavoritesApi = new FavoritesApi(this.auth, this.config); + public shared: SharedLinksApi = new SharedLinksApi(this.auth, this.config); + public trashcan: TrashcanApi = new TrashcanApi(this.auth, this.config); + public search: SearchApi = new SearchApi(this.auth, this.config); + + constructor( + private username: string = RepoClientAuth.DEFAULT_USERNAME, + private password: string = RepoClientAuth.DEFAULT_PASSWORD, + private config?: RepoClientConfig + ) {} + + private get auth(): RepoClientAuth { + const { username, password } = this; + return { username, password }; + } +} + +export * from './apis/nodes/node-body-create'; +export * from './apis/nodes/node-content-tree'; +export * from './apis/nodes/nodes-api'; diff --git a/e2e/utilities/reporters/console/console-logger.ts b/e2e/utilities/reporters/console/console-logger.ts new file mode 100755 index 0000000000..756bfb4a86 --- /dev/null +++ b/e2e/utilities/reporters/console/console-logger.ts @@ -0,0 +1,79 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +/* tslint:disable */ +const chalk = require('chalk'); +/* tslint:enable */ + +export const log = { + i: 0, + + get indentation(): string { + return new Array(this.i).fill(' ').join(''); + }, + + indent() { + this.i++; + return this; + }, + + dedent() { + this.i--; + return this; + }, + + log(message: string = '', options: any = { ignoreIndentation: false }) { + const indentation = (!options.ignoreIndentation) + ? this.indentation + : ''; + + console.log(`${indentation}${message}`); + + return this; + }, + + blank() { + return this.log(); + }, + + info(message: string = '', options: any = { bold: false, title: false }) { + const { bold } = options; + const style = (bold ? chalk.bold : chalk).gray; + + return this.log(style(message), options); + }, + + success(message: string = '', options: any = { bold: false }) { + const style = options.bold ? chalk.bold.green : chalk.green; + + return this.log(style(message), options); + }, + + error(message: string = '', options: any = { bold: false }) { + const style = options.bold ? chalk.bold.red : chalk.red; + + return this.log(style(message), options); + } +}; diff --git a/e2e/utilities/reporters/console/console.ts b/e2e/utilities/reporters/console/console.ts new file mode 100755 index 0000000000..2f92e394ab --- /dev/null +++ b/e2e/utilities/reporters/console/console.ts @@ -0,0 +1,90 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { log } from './console-logger'; + +const errors = []; + +export const consoleReporter = { + jasmineStarted(suiteInfo) { + log.blank().info( + `Running ${suiteInfo.totalSpecsDefined} tests`, + { bold: true, title: true } + ).blank(); + }, + + suiteStarted(suite) { + log.info(suite.description).indent(); + }, + + specDone: (spec) => { + const { + status, + description, + failedExpectations + } = spec; + + if (status === 'passed') { + log.success(`∙ ${description}`); + } + + if (status === 'failed') { + log.error(`✕ ${description}`, { bold: true }); + + errors.push(spec); + + failedExpectations.forEach((failed) => { + log.error(` ${failed.message}`); + }); + } + }, + + suiteDone: (result) => { + log.dedent(); + }, + + jasmineDone: (result) => { + if (!!errors.length) { + log .blank() + .blank() + .info(`${errors.length} failing tests`, { bold: true, title: true }); + + errors.forEach(error => { + log .blank() + .error(`✕ ${error.fullName}`, { bold: true }); + + error.failedExpectations.forEach(failed => { + log .info(`${failed.message}`) + .blank() + .error(`${failed.stack}`); + }); + }); + } else { + log.success(`All tests passed!`, { bold: true }); + } + + log.blank().blank(); + } +}; diff --git a/e2e/utilities/rest-client/rest-client-models.ts b/e2e/utilities/rest-client/rest-client-models.ts new file mode 100755 index 0000000000..6b5098d402 --- /dev/null +++ b/e2e/utilities/rest-client/rest-client-models.ts @@ -0,0 +1,63 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +interface RequestConfig { + timeout?: number; + noDelay?: boolean; + keepAlive?: boolean; + keepAliveDelay?: number; +} + +interface ResponseConfig { + timeout?: number; +} + +interface ResponseRequest { + method: string; + path: string; + data: string; +} + +export interface NodeRestClient { + get(uri: string, callback: Function): Function; + post(uri: string, callback: Function): Function; + put(uri: string, callback: Function): Function; + delete(uri: string, callback: Function): Function; +} + +export interface RestClientArgs { + data?: any; + parameters?: any; + headers?: any; + requestConfig?: RequestConfig; + responseConfig?: ResponseConfig; +} + +export interface RestClientResponse { + request: ResponseRequest; + data: any; + statusMessage: string; + statusCode: number; +} diff --git a/e2e/utilities/rest-client/rest-client.ts b/e2e/utilities/rest-client/rest-client.ts new file mode 100755 index 0000000000..49b724a9b4 --- /dev/null +++ b/e2e/utilities/rest-client/rest-client.ts @@ -0,0 +1,89 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Client } from 'node-rest-client'; +import { NodeRestClient, RestClientArgs, RestClientResponse } from './rest-client-models'; + +export * from './rest-client-models'; + +export class RestClient { + private static DEFAULT_HEADERS = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }; + + private client: NodeRestClient; + + constructor(user: string, password: string) { + this.client = (new Client({ user, password })); + } + + get(uri: string, args: RestClientArgs = {}): Promise { + return this.promisify('get', uri, args); + } + + post(uri: string, args: RestClientArgs = {}): Promise { + return this.promisify('post', uri, args); + } + + put(uri: string, args: RestClientArgs = {}): Promise { + return this.promisify('put', uri, args); + } + + delete(uri: string, args: RestClientArgs = {}): Promise { + return this.promisify('delete', uri, args); + } + + private createArgs(args: RestClientArgs = {}): RestClientArgs { + const data = JSON.stringify(args.data); + + return Object.assign({}, RestClient.DEFAULT_HEADERS, args, { data }); + } + + private promisify(fnName: string, uri: string, args: RestClientArgs): Promise { + const fn: Function = this.client[fnName]; + const fnArgs = [ encodeURI(uri), this.createArgs(args) ]; + + return new Promise((resolve, reject) => { + const fnCallback = (data, rawResponse) => { + const { + statusCode, statusMessage, + req: { method, path } + } = rawResponse; + + const response: RestClientResponse = { + data, statusCode, statusMessage, + request: { method, path, data: args.data } + }; + + (response.statusCode >= 400) + ? reject(response) + : resolve(response); + }; + + fn(...fnArgs, fnCallback); + }); + } +} diff --git a/e2e/utilities/utils.ts b/e2e/utilities/utils.ts new file mode 100755 index 0000000000..901d8f5a4a --- /dev/null +++ b/e2e/utilities/utils.ts @@ -0,0 +1,73 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { browser, promise, ElementFinder, ExpectedConditions as EC } from 'protractor'; +import { BROWSER_WAIT_TIMEOUT } from '../configs'; + +export class Utils { + // generate a random value + static random(): string { + return Math.random().toString(36).substring(3, 10).toLowerCase(); + } + + // local storage + static clearLocalStorage(): promise.Promise { + return browser.executeScript('window.localStorage.clear();'); + } + + // session storage + static clearSessionStorage(): promise.Promise { + return browser.executeScript('window.sessionStorage.clear();'); + } + + static retryCall(fn: () => Promise , retry: number = 30, delay: number = 1000): Promise { + const rerun = (retries, fn) => { + fn().catch(err => retries > 1 + ? rerun(retries - 1, fn) + : Promise.reject(err)); + }; + + const pause = (duration) => new Promise(res => setTimeout(res, duration)); + + const run = (retries, fn, delay = 1000) => + fn().catch(err => retries > 1 + ? pause(delay).then(() => run(retries - 1, fn, delay)) + : Promise.reject(err)); + + return run(retry, fn); + } + + static waitUntilElementClickable(element: ElementFinder) { + return browser.wait(EC.elementToBeClickable(element), BROWSER_WAIT_TIMEOUT); + } + + static typeInField(elem: ElementFinder, value: string) { + for ( let i = 0; i < value.length; i++ ) { + const c = value.charAt(i); + elem.sendKeys(c); + browser.sleep(100); + } + } +} diff --git a/package-lock.json b/package-lock.json index f998d1faef..3696d78d4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,15 +40,6 @@ "zone.js": "0.8.14" }, "dependencies": { - "alfresco-js-api": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.3.0.tgz", - "integrity": "sha512-IhsSNoPl8cbw/V24kw420sGoVp6rBakC2kN4gKe3bPdERvSWRehw5bojMQhnSPDmS2PqC5C23HaVV+whOwkpDg==", - "requires": { - "event-emitter": "0.3.4", - "superagent": "3.8.2" - } - }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -90,18 +81,38 @@ "@ngx-translate/core": "9.1.1", "alfresco-js-api": "2.3.0", "chart.js": "2.5.0", - "core-js": "2.5.3", + "core-js": "2.4.1", "hammerjs": "2.0.8", "minimatch": "3.0.4", "moment": "2.20.1", "ng2-charts": "1.6.0", - "pdfjs-dist": "2.0.303", + "pdfjs-dist": "1.5.404", "raphael": "2.2.7", "reflect-metadata": "0.1.10", "rxjs": "5.5.2", "systemjs": "0.19.27", "tslib": "1.9.0", - "zone.js": "0.8.20" + "zone.js": "0.8.14" + }, + "dependencies": { + "core-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", + "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=" + }, + "pdfjs-dist": { + "version": "1.5.404", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz", + "integrity": "sha1-hYXGUWquIU1ZCXXo+ys8PzrxTO8=", + "requires": { + "node-ensure": "0.0.0" + } + }, + "zone.js": { + "version": "0.8.14", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.14.tgz", + "integrity": "sha1-DE2ySxeCMidMy0P3jJnbfzZCts8=" + } } }, "@angular-devkit/build-optimizer": { @@ -132,7 +143,7 @@ "requires": { "ajv": "5.5.2", "chokidar": "1.7.0", - "rxjs": "5.5.9", + "rxjs": "5.5.10", "source-map": "0.5.7" }, "dependencies": { @@ -149,9 +160,9 @@ } }, "rxjs": { - "version": "5.5.9", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.9.tgz", - "integrity": "sha512-DHG9AHmCmgaFWgjBcXp6NxFDmh3MvIA62GqTWmLnTzr/3oZ6h5hLD8NA+9j+GF0jEwklNIpI4KuuyLG8UWMEvQ==", + "version": "5.5.10", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz", + "integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==", "dev": true, "requires": { "symbol-observable": "1.0.1" @@ -172,13 +183,13 @@ "dev": true, "requires": { "@ngtools/json-schema": "1.2.0", - "rxjs": "5.5.9" + "rxjs": "5.5.10" }, "dependencies": { "rxjs": { - "version": "5.5.9", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.9.tgz", - "integrity": "sha512-DHG9AHmCmgaFWgjBcXp6NxFDmh3MvIA62GqTWmLnTzr/3oZ6h5hLD8NA+9j+GF0jEwklNIpI4KuuyLG8UWMEvQ==", + "version": "5.5.10", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz", + "integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==", "dev": true, "requires": { "symbol-observable": "1.0.1" @@ -253,11 +264,11 @@ "portfinder": "1.0.13", "postcss": "6.0.21", "postcss-import": "11.1.0", - "postcss-loader": "2.1.3", + "postcss-loader": "2.1.4", "postcss-url": "7.3.2", "raw-loader": "0.5.1", "resolve": "1.7.1", - "rxjs": "5.5.9", + "rxjs": "5.5.10", "sass-loader": "6.0.7", "semver": "5.5.0", "silent-error": "1.1.0", @@ -265,7 +276,7 @@ "style-loader": "0.19.1", "stylus": "0.54.5", "stylus-loader": "3.0.2", - "uglifyjs-webpack-plugin": "1.2.4", + "uglifyjs-webpack-plugin": "1.2.5", "url-loader": "0.6.2", "webpack": "3.11.0", "webpack-dev-middleware": "1.12.2", @@ -276,9 +287,9 @@ }, "dependencies": { "rxjs": { - "version": "5.5.9", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.9.tgz", - "integrity": "sha512-DHG9AHmCmgaFWgjBcXp6NxFDmh3MvIA62GqTWmLnTzr/3oZ6h5hLD8NA+9j+GF0jEwklNIpI4KuuyLG8UWMEvQ==", + "version": "5.5.10", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz", + "integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==", "dev": true, "requires": { "symbol-observable": "1.0.1" @@ -466,15 +477,15 @@ "integrity": "sha512-7aVP4994Hu8vRdTTohXkfGWEwLhrdNP3EZnWyBootm5zshWqlQojUGweZe5zwewsKcixeVOiy2YtW+aI4aGSLA==", "dev": true, "requires": { - "rxjs": "5.5.9", + "rxjs": "5.5.10", "semver": "5.5.0", "semver-intersect": "1.3.1" }, "dependencies": { "rxjs": { - "version": "5.5.9", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.9.tgz", - "integrity": "sha512-DHG9AHmCmgaFWgjBcXp6NxFDmh3MvIA62GqTWmLnTzr/3oZ6h5hLD8NA+9j+GF0jEwklNIpI4KuuyLG8UWMEvQ==", + "version": "5.5.10", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz", + "integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==", "dev": true, "requires": { "symbol-observable": "1.0.1" @@ -516,9 +527,9 @@ "dev": true }, "@types/selenium-webdriver": { - "version": "2.53.43", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz", - "integrity": "sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.8.tgz", + "integrity": "sha512-yrqQvb1EZhH+ONMzUmsEnBjzitortVv0lynRe5US2+FofdoMWUE4wf7v4peCd62fqXq8COCVTbpS1/jIg5EbuQ==", "dev": true }, "@types/strip-bom": { @@ -600,9 +611,9 @@ "optional": true }, "adm-zip": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", - "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", + "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", "dev": true }, "after": { @@ -1011,7 +1022,7 @@ "dev": true, "requires": { "browserslist": "2.11.3", - "caniuse-lite": "1.0.30000828", + "caniuse-lite": "1.0.30000830", "normalize-range": "0.1.2", "num2fraction": "1.2.2", "postcss": "6.0.21", @@ -1257,9 +1268,9 @@ "dev": true }, "base64-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz", - "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", "dev": true }, "base64id": { @@ -1372,9 +1383,9 @@ } }, "blocking-proxy": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-0.0.5.tgz", - "integrity": "sha1-RikF4Nz76pcPQao3Ij3anAexkSs=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", "dev": true, "requires": { "minimist": "1.2.0" @@ -1576,7 +1587,7 @@ "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==", "dev": true, "requires": { - "base64-js": "1.2.3", + "base64-js": "1.3.0", "ieee754": "1.1.11" } }, @@ -1727,7 +1738,7 @@ "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000828", + "caniuse-lite": "1.0.30000830", "electron-to-chromium": "1.3.42" } }, @@ -1737,7 +1748,7 @@ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { - "base64-js": "1.2.3", + "base64-js": "1.3.0", "ieee754": "1.1.11", "isarray": "1.0.0" } @@ -1906,9 +1917,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000828", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000828.tgz", - "integrity": "sha512-v+ySC6Ih8N8CyGZYd4svPipuFIqskKsTOi18chFM0qtu1G8mGuSYajb+h49XDWgmzX8MRDOp1Agw6KQaPUdIhg==", + "version": "1.0.30000830", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000830.tgz", + "integrity": "sha512-yMqGkujkoOIZfvOYiWdqPALgY/PVGiqCHUJb6yNq7xhI/pR+gQO0U2K6lRDqAiJv4+CIU3CtTLblNGw0QGnr6g==", "dev": true }, "caseless": { @@ -2578,7 +2589,7 @@ "loader-utils": "1.1.0", "minimatch": "3.0.4", "p-limit": "1.2.0", - "serialize-javascript": "1.4.0" + "serialize-javascript": "1.5.0" }, "dependencies": { "is-extglob": { @@ -2659,7 +2670,7 @@ "cipher-base": "1.0.4", "inherits": "2.0.3", "md5.js": "1.3.4", - "ripemd160": "2.0.1", + "ripemd160": "2.0.2", "sha.js": "2.4.11" } }, @@ -2672,7 +2683,7 @@ "cipher-base": "1.0.4", "create-hash": "1.2.0", "inherits": "2.0.3", - "ripemd160": "2.0.1", + "ripemd160": "2.0.2", "safe-buffer": "5.1.1", "sha.js": "2.4.11" } @@ -3263,9 +3274,9 @@ "dev": true }, "ejs": { - "version": "2.5.8", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.8.tgz", - "integrity": "sha512-QIDZL54fyV8MDcAsO91BMH1ft2qGGaHIJsJIA/+t+7uvXol1dm413fPcUgUb4k8F/9457rx4/KFE4XfDifrQxQ==", + "version": "2.5.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.9.tgz", + "integrity": "sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ==", "dev": true }, "electron-to-chromium": { @@ -3493,6 +3504,12 @@ } } }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "dev": true + }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -5673,9 +5690,9 @@ "dev": true }, "html-minifier": { - "version": "3.5.14", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.14.tgz", - "integrity": "sha512-sZjw6zhQgyUnIlIPU+W80XpRjWjdxHtNcxjfyOskOsCTDKytcfLY04wsQY/83Yqb4ndoiD2FtauiL7Yg6uUQFQ==", + "version": "3.5.15", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.15.tgz", + "integrity": "sha512-OZa4rfb6tZOZ3Z8Xf0jKxXkiDcFWldQePGYFDcgKqES2sXeWaEv9y6QQvWUtX3ySI3feApQi5uCsHLINQ6NoAw==", "dev": true, "requires": { "camel-case": "3.0.0", @@ -5694,7 +5711,7 @@ "dev": true, "requires": { "bluebird": "3.5.1", - "html-minifier": "3.5.14", + "html-minifier": "3.5.15", "loader-utils": "0.2.17", "lodash": "4.17.5", "pretty-error": "2.1.1", @@ -5939,6 +5956,12 @@ "dev": true, "optional": true }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, "import-local": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", @@ -6541,23 +6564,21 @@ "handlebars": "4.0.11" } }, + "items": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/items/-/items-2.1.1.tgz", + "integrity": "sha1-i9FtnIOxlSneWuoyGsqtp4NkoZg=", + "dev": true + }, "jasmine": { - "version": "2.99.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.99.0.tgz", - "integrity": "sha1-jKctEC5jm4Z8ZImFbg4YqceqQrc=", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", "dev": true, "requires": { "exit": "0.1.2", "glob": "7.1.2", - "jasmine-core": "2.99.1" - }, - "dependencies": { - "jasmine-core": { - "version": "2.99.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", - "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=", - "dev": true - } + "jasmine-core": "2.8.0" } }, "jasmine-core": { @@ -6772,6 +6793,53 @@ } } }, + "jszip": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz", + "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==", + "dev": true, + "requires": { + "core-js": "2.3.0", + "es6-promise": "3.0.2", + "lie": "3.1.1", + "pako": "1.0.6", + "readable-stream": "2.0.6" + }, + "dependencies": { + "core-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", + "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, "karma": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.0.tgz", @@ -7017,7 +7085,16 @@ "integrity": "sha512-NqAFodJdpBUuf1iD+Ij8hQvF0rCFKlO2KaieoQzAPhFgzLCtJnC7Z7x5gQbGNjoe++wOKAtAmwVEIBLqq2Yp1A==", "dev": true, "requires": { - "ejs": "2.5.8" + "ejs": "2.5.9" + } + }, + "lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "dev": true, + "requires": { + "immediate": "3.0.6" } }, "load-json-file": { @@ -7932,7 +8009,7 @@ "stream-browserify": "2.0.1", "stream-http": "2.8.1", "string_decoder": "1.1.1", - "timers-browserify": "2.0.6", + "timers-browserify": "2.0.10", "tty-browserify": "0.0.0", "url": "0.11.0", "util": "0.10.3", @@ -7953,6 +8030,60 @@ "integrity": "sha1-QAlrCM560OoUaAhjr0ScfHWl0cg=", "dev": true }, + "node-rest-client": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/node-rest-client/-/node-rest-client-3.1.0.tgz", + "integrity": "sha1-4L623aeyDMC2enhHzxLF/EGcN8M=", + "dev": true, + "requires": { + "debug": "2.2.0", + "follow-redirects": "1.4.1", + "xml2js": "0.4.19" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "follow-redirects": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", + "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", + "dev": true, + "requires": { + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, "node-sass": { "version": "4.8.3", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.8.3.tgz", @@ -8771,7 +8902,7 @@ "requires": { "create-hash": "1.2.0", "create-hmac": "1.1.7", - "ripemd160": "2.0.1", + "ripemd160": "2.0.2", "safe-buffer": "5.1.1", "sha.js": "2.4.11" } @@ -8861,20 +8992,20 @@ "integrity": "sha512-y/bKfbQz2Nn/QBC08bwvYUxEFOVGfPIUOTsJ2CK5inzlXW9SdYR1x4pEsG9blRAF/PX+wRNdOah+gx/hv4q7dw==", "dev": true, "requires": { - "chalk": "2.3.2", + "chalk": "2.4.0", "source-map": "0.6.1", - "supports-color": "5.3.0" + "supports-color": "5.4.0" }, "dependencies": { "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz", + "integrity": "sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw==", "dev": true, "requires": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", - "supports-color": "5.3.0" + "supports-color": "5.4.0" } }, "has-flag": { @@ -8890,9 +9021,9 @@ "dev": true }, "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { "has-flag": "3.0.0" @@ -8945,9 +9076,9 @@ } }, "postcss-loader": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.3.tgz", - "integrity": "sha512-RuBcNE8rjCkIB0IsbmkGFRmQJTeQJfCI88E0VTarPNTvaNSv9OFv1DvTwgtAN/qlzyiELsmmmtX/tEzKp/cdug==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.4.tgz", + "integrity": "sha512-L2p654oK945B/gDFUGgOhh7uzj19RWoY1SVMeJVoKno1H2MdbQ0RppR/28JGju4pMb22iRC7BJ9aDzbxXSLf4A==", "dev": true, "requires": { "loader-utils": "1.1.0", @@ -9025,32 +9156,44 @@ "dev": true }, "protractor": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.1.2.tgz", - "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.3.1.tgz", + "integrity": "sha512-AW9qJ0prx2QEMy1gnhJ1Sl1WBQL2R3fx/VnG09FEmWprPIQPK14t0B83OB/pAGddpxiDCAAV0KiNNLf2c2Y/lQ==", "dev": true, "requires": { - "@types/node": "6.0.105", + "@types/node": "6.0.106", "@types/q": "0.0.32", "@types/selenium-webdriver": "2.53.43", - "blocking-proxy": "0.0.5", + "blocking-proxy": "1.0.1", "chalk": "1.1.3", "glob": "7.1.2", - "jasmine": "2.99.0", + "jasmine": "2.8.0", "jasminewd2": "2.2.0", "optimist": "0.6.1", "q": "1.4.1", "saucelabs": "1.3.0", - "selenium-webdriver": "3.0.1", + "selenium-webdriver": "3.6.0", "source-map-support": "0.4.18", "webdriver-js-extender": "1.0.0", "webdriver-manager": "12.0.6" }, "dependencies": { "@types/node": { - "version": "6.0.105", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.105.tgz", - "integrity": "sha512-fMIbw7iw91TSInS3b2DtDse5VaQEZqs0oTjvRNIFHnoHbnji+dLwpzL1L6dYGL39RzDNPHM/Off+VNcMk4ahwQ==", + "version": "6.0.106", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.106.tgz", + "integrity": "sha512-U4Zv5fx7letrisRv6HgSSPSY00FZM4NMIkilt+IAExvQLuNa6jYVwCKcnSs2NqTN4+KDl9PskvcCiMce9iePCA==", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "2.53.43", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz", + "integrity": "sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==", + "dev": true + }, + "adm-zip": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", + "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", "dev": true }, "ansi-styles": { @@ -9119,12 +9262,33 @@ "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", "dev": true }, + "selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "requires": { + "jszip": "3.1.5", + "rimraf": "2.6.2", + "tmp": "0.0.30", + "xml2js": "0.4.19" + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, "webdriver-manager": { "version": "12.0.6", "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.0.6.tgz", @@ -9831,24 +9995,13 @@ } }, "ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { - "hash-base": "2.0.2", + "hash-base": "3.0.4", "inherits": "2.0.3" - }, - "dependencies": { - "hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", - "dev": true, - "requires": { - "inherits": "2.0.3" - } - } } }, "run-queue": { @@ -9860,6 +10013,12 @@ "aproba": "1.2.0" } }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", + "dev": true + }, "rxjs": { "version": "5.5.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.2.tgz", @@ -9962,12 +10121,12 @@ "dev": true }, "selenium-webdriver": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz", - "integrity": "sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c=", + "version": "4.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.1.tgz", + "integrity": "sha512-z88rdjHAv3jmTZ7KSGUkTvo4rGzcDGMq0oXWHNIDK96Gs31JKVdu9+FMtT4KBrVoibg8dUicJDok6GnqqttO5Q==", "dev": true, "requires": { - "adm-zip": "0.4.7", + "jszip": "3.1.5", "rimraf": "2.6.2", "tmp": "0.0.30", "xml2js": "0.4.19" @@ -10056,9 +10215,9 @@ } }, "serialize-javascript": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.4.0.tgz", - "integrity": "sha1-fJWFFNtqwkQ6irwGLcn3iGp/YAU=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", + "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==", "dev": true }, "serve-index": { @@ -11113,9 +11272,9 @@ "dev": true }, "timers-browserify": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.6.tgz", - "integrity": "sha512-HQ3nbYRAowdVd0ckGFvmJPPCOH/CHleFN/Y0YQCX1DVaB7t+KFvisuyN09fuP8Jtp1CpfSh8O8bMkHbdbPe6Pw==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", "dev": true, "requires": { "setimmediate": "1.0.5" @@ -11288,7 +11447,7 @@ "dev": true, "requires": { "arrify": "1.0.1", - "chalk": "2.3.2", + "chalk": "2.4.0", "diff": "3.5.0", "make-error": "1.3.4", "minimist": "1.2.0", @@ -11300,14 +11459,14 @@ }, "dependencies": { "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz", + "integrity": "sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw==", "dev": true, "requires": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", - "supports-color": "5.3.0" + "supports-color": "5.4.0" } }, "has-flag": { @@ -11338,9 +11497,9 @@ } }, "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { "has-flag": "3.0.0" @@ -11401,7 +11560,7 @@ "requires": { "babel-code-frame": "6.26.0", "builtin-modules": "1.1.1", - "chalk": "2.3.2", + "chalk": "2.4.0", "commander": "2.15.1", "diff": "3.5.0", "glob": "7.1.2", @@ -11414,14 +11573,14 @@ }, "dependencies": { "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz", + "integrity": "sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw==", "dev": true, "requires": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", - "supports-color": "5.3.0" + "supports-color": "5.4.0" } }, "has-flag": { @@ -11431,9 +11590,9 @@ "dev": true }, "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { "has-flag": "3.0.0" @@ -11505,9 +11664,9 @@ "dev": true }, "typescript": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", - "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz", + "integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==", "dev": true }, "uglify-js": { @@ -11536,15 +11695,15 @@ "optional": true }, "uglifyjs-webpack-plugin": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.4.tgz", - "integrity": "sha512-z0IbjpW8b3O/OVn+TTZN4pI29RN1zktFBXLIzzfZ+++cUtZ1ERSlLWgpE/5OERuEUs1ijVQnpYAkSlpoVmQmSQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz", + "integrity": "sha512-hIQJ1yxAPhEA2yW/i7Fr+SXZVMp+VEI3d42RTHBgQd2yhp/1UdBcR3QEWPV5ahBxlqQDMEMTuTEvDHSFINfwSw==", "dev": true, "requires": { "cacache": "10.0.4", "find-cache-dir": "1.0.0", "schema-utils": "0.4.5", - "serialize-javascript": "1.4.0", + "serialize-javascript": "1.5.0", "source-map": "0.6.1", "uglify-es": "3.3.9", "webpack-sources": "1.1.0", @@ -11939,6 +12098,52 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, + "wait-on": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-2.1.0.tgz", + "integrity": "sha512-hDwJ674+7dfiiK/cxtYCwPxlnjXDjto/pCz1PF02sXUhqCqCWsgvxZln0699PReWqXXgkxqkF6DDo5Rj9sjNvw==", + "dev": true, + "requires": { + "core-js": "2.5.3", + "joi": "9.2.0", + "minimist": "1.2.0", + "request": "2.81.0", + "rx": "4.1.0" + }, + "dependencies": { + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "isemail": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-2.2.1.tgz", + "integrity": "sha1-A1PT2aYpUQgMJiwqoKQrjqjp4qY=", + "dev": true + }, + "joi": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-9.2.0.tgz", + "integrity": "sha1-M4WseQGSEwy+Iw6ALsAskhW7/to=", + "dev": true, + "requires": { + "hoek": "4.2.1", + "isemail": "2.2.1", + "items": "2.1.1", + "moment": "2.20.1", + "topo": "2.0.2" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "watchpack": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.5.0.tgz", @@ -12325,10 +12530,10 @@ "selenium-webdriver": "2.53.3" }, "dependencies": { - "adm-zip": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", - "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", + "@types/selenium-webdriver": { + "version": "2.53.43", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz", + "integrity": "sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==", "dev": true }, "sax": { @@ -12719,7 +12924,7 @@ "sockjs-client": "1.1.4", "spdy": "3.4.7", "strip-ansi": "3.0.1", - "supports-color": "5.3.0", + "supports-color": "5.4.0", "webpack-dev-middleware": "1.12.2", "yargs": "6.6.0" }, @@ -13086,9 +13291,9 @@ } }, "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { "has-flag": "3.0.0" diff --git a/package.json b/package.json index 331c14da86..770480b5eb 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,6 @@ "ng": "ng", "start": "npm run server-versions && ng serve --open", "start:prod": "npm run server-versions && ng serve --prod --open", - "start:docker": "docker-compose up --build", "build": "npm run server-versions && ng build --prod", "build:prod": "npm run server-versions && ng build --prod", "build:dev": "npm run server-versions && ng build", @@ -14,8 +13,13 @@ "test": "ng test --code-coverage", "test:ci": "ng test --code-coverage --single-run --no-progress && cat ./coverage/lcov.info | ./node_modules/.bin/codacy-coverage && rm -rf ./coverage", "lint": "ng lint", - "e2e": "ng e2e", - "server-versions": "rimraf ./src/versions.json && npm list --depth=0 --json=true --prod=true > ./src/versions.json || exit 0" + "server-versions": "rimraf ./src/versions.json && npm list --depth=0 --json=true --prod=true > ./src/versions.json || exit 0", + "_e2e": "ng e2e", + "wd:update": "webdriver-manager update --gecko=false", + "e2e": "npm run wd:update && protractor protractor.conf.js", + "start:docker": "docker-compose up -d --build && wait-on http://localhost:8080 && wait-on http://localhost:3000", + "stop:docker": "docker-compose stop", + "e2e:docker": "npm run start:docker && npm run e2e && npm run stop:docker" }, "private": true, "dependencies": { @@ -53,22 +57,27 @@ "@types/jasmine": "^2.5.53", "@types/jasminewd2": "^2.0.2", "@types/node": "9.3.0", + "@types/selenium-webdriver": "^3.0.8", "codacy-coverage": "^2.0.3", "codelyzer": "^4.0.1", "jasmine-core": "~2.8.0", "jasmine-reporters": "^2.2.1", "jasmine-spec-reporter": "~4.2.1", "jasmine2-protractor-utils": "^1.3.0", + "jasminewd2": "^2.2.0", "karma": "~2.0.0", "karma-chrome-launcher": "~2.2.0", "karma-cli": "~1.0.1", "karma-coverage-istanbul-reporter": "^1.2.1", "karma-jasmine": "~1.1.0", "karma-jasmine-html-reporter": "^0.2.2", - "protractor": "~5.1.2", + "node-rest-client": "^3.1.0", + "protractor": "5.3.1", "rimraf": "2.6.2", + "selenium-webdriver": "4.0.0-alpha.1", "ts-node": "~4.1.0", "tslint": "~5.9.1", - "typescript": "~2.5.3" + "typescript": "~2.7.2", + "wait-on": "2.1.0" } } diff --git a/protractor.conf.js b/protractor.conf.js old mode 100644 new mode 100755 index 9a1a1b39c8..3971e2d2cd --- a/protractor.conf.js +++ b/protractor.conf.js @@ -11,9 +11,15 @@ const width = 1366; const height = 768; exports.config = { - allScriptsTimeout: 30000, + allScriptsTimeout: 60000, specs: [ + './e2e/suites/authentication/*.test.ts', + './e2e/suites/list-views/*.test.ts', + './e2e/suites/application/page-titles.test.ts', + './e2e/suites/navigation/*.test.ts', + './e2e/suites/pagination/*.test.ts', + './e2e/suites/actions/*.test.ts' ], capabilities: { @@ -28,12 +34,12 @@ exports.config = { directConnect: true, - baseUrl: 'http://localhost:4200', + baseUrl: 'http://localhost:3000', framework: 'jasmine2', jasmineNodeOpts: { showColors: true, - defaultTimeoutInterval: 50000, + defaultTimeoutInterval: 90000, print: function() {} }, From 6615fda7b3af4c819666cec8464ca13217bdf66c Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 25 Apr 2018 12:07:37 +0100 Subject: [PATCH 002/179] upgrade package lock after release --- package-lock.json | 1433 ++++++++------------------------------------- 1 file changed, 260 insertions(+), 1173 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3696d78d4e..c804b491a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "alfresco-content-app", - "version": "1.1.0", + "version": "1.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -254,7 +254,7 @@ "less-loader": "4.1.0", "license-webpack-plugin": "1.3.1", "loader-utils": "1.1.0", - "lodash": "4.17.5", + "lodash": "4.17.10", "memory-fs": "0.4.1", "minimatch": "3.0.4", "node-modules-path": "1.0.1", @@ -544,16 +544,6 @@ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, - "JSONStream": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", - "integrity": "sha1-wQI3G27Dp887hHygDCC7D85Mbeo=", - "dev": true, - "requires": { - "jsonparse": "1.3.1", - "through": "2.3.8" - } - }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -593,16 +583,6 @@ } } }, - "acorn-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.3.0.tgz", - "integrity": "sha512-efP54n3d1aLfjL2UMdaXa6DsswwzJeI5rqhbFvXMrKiJ6eJFpf+7R0zN7t8IC+XKn2YOAFAv6xbBNgHUkoHWLw==", - "dev": true, - "requires": { - "acorn": "5.5.3", - "xtend": "4.0.1" - } - }, "addressparser": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz", @@ -828,12 +808,6 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", - "dev": true - }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -856,18 +830,6 @@ "es-abstract": "1.11.0" } }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", - "dev": true - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", - "dev": true - }, "array-slice": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", @@ -959,30 +921,13 @@ "dev": true, "optional": true }, - "astw": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", - "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=", - "dev": true, - "requires": { - "acorn": "4.0.13" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", - "dev": true - } - } - }, "async": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", "dev": true, "requires": { - "lodash": "4.17.5" + "lodash": "4.17.10" } }, "async-each": { @@ -1049,6 +994,28 @@ "optional": true, "requires": { "follow-redirects": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", + "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.9" + } + } } }, "babel-code-frame": { @@ -1100,7 +1067,7 @@ "babel-types": "6.26.0", "detect-indent": "4.0.0", "jsesc": "1.3.0", - "lodash": "4.17.5", + "lodash": "4.17.10", "source-map": "0.5.7", "trim-right": "1.0.1" } @@ -1134,7 +1101,7 @@ "babel-traverse": "6.26.0", "babel-types": "6.26.0", "babylon": "6.18.0", - "lodash": "4.17.5" + "lodash": "4.17.10" } }, "babel-traverse": { @@ -1151,7 +1118,7 @@ "debug": "2.6.9", "globals": "9.18.0", "invariant": "2.2.4", - "lodash": "4.17.5" + "lodash": "4.17.10" }, "dependencies": { "debug": { @@ -1173,7 +1140,7 @@ "requires": { "babel-runtime": "6.26.0", "esutils": "2.0.2", - "lodash": "4.17.5", + "lodash": "4.17.10", "to-fast-properties": "1.0.3" } }, @@ -1495,173 +1462,6 @@ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, - "browser-pack": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", - "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "combine-source-map": "0.8.0", - "defined": "1.0.0", - "safe-buffer": "5.1.1", - "through2": "2.0.3", - "umd": "3.0.3" - } - }, - "browser-resolve": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", - "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "browserify": { - "version": "14.5.0", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-14.5.0.tgz", - "integrity": "sha512-gKfOsNQv/toWz+60nSPfYzuwSEdzvV2WdxrVPUbPD/qui44rAkB3t3muNtmmGYHqrG56FGwX9SUEQmzNLAeS7g==", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "assert": "1.4.1", - "browser-pack": "6.1.0", - "browser-resolve": "1.11.2", - "browserify-zlib": "0.2.0", - "buffer": "5.1.0", - "cached-path-relative": "1.0.1", - "concat-stream": "1.5.2", - "console-browserify": "1.1.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.12.0", - "defined": "1.0.0", - "deps-sort": "2.0.0", - "domain-browser": "1.1.7", - "duplexer2": "0.1.4", - "events": "1.1.1", - "glob": "7.1.2", - "has": "1.0.1", - "htmlescape": "1.1.1", - "https-browserify": "1.0.0", - "inherits": "2.0.3", - "insert-module-globals": "7.0.6", - "labeled-stream-splicer": "2.0.1", - "module-deps": "4.1.1", - "os-browserify": "0.3.0", - "parents": "1.0.1", - "path-browserify": "0.0.0", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "read-only-stream": "2.0.0", - "readable-stream": "2.3.6", - "resolve": "1.7.1", - "shasum": "1.0.2", - "shell-quote": "1.6.1", - "stream-browserify": "2.0.1", - "stream-http": "2.8.1", - "string_decoder": "1.0.3", - "subarg": "1.0.0", - "syntax-error": "1.4.0", - "through2": "2.0.3", - "timers-browserify": "1.4.2", - "tty-browserify": "0.0.0", - "url": "0.11.0", - "util": "0.10.3", - "vm-browserify": "0.0.4", - "xtend": "4.0.1" - }, - "dependencies": { - "buffer": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz", - "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==", - "dev": true, - "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.11" - } - }, - "concat-stream": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", - "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.0.6", - "typedarray": "0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "domain-browser": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", - "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", - "dev": true, - "requires": { - "process": "0.11.10" - } - } - } - }, "browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", @@ -1878,12 +1678,6 @@ "schema-utils": "0.4.5" } }, - "cached-path-relative": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", - "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=", - "dev": true - }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", @@ -1983,7 +1777,7 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.1.3", + "fsevents": "1.2.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -2120,7 +1914,7 @@ "commander": "2.15.1", "joi": "12.0.0", "lcov-parse": "1.0.0", - "lodash": "4.17.5", + "lodash": "4.17.10", "log-driver": "1.2.7", "request": "2.85.0", "request-promise": "4.2.2" @@ -2278,9 +2072,9 @@ "dev": true }, "codelyzer": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.2.1.tgz", - "integrity": "sha512-CKwfgpfkqi9dyzy4s6ELaxJ54QgJ6A8iTSsM4bzHbLuTpbKncvNc3DUlCvpnkHBhK47gEf4qFsWoYqLrJPhy6g==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.3.0.tgz", + "integrity": "sha512-RLMrtLwrBS0dfo2/KTP+2NHofCpzcuh0bEp/A/naqvQonbUL4AW/qWQdbpn8dMNudtpmzEx9eS8KEpGdVPg1BA==", "dev": true, "requires": { "app-root-path": "2.0.1", @@ -2323,27 +2117,7 @@ "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", "dev": true, "requires": { - "lodash": "4.17.5" - } - }, - "combine-source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", - "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", - "dev": true, - "requires": { - "convert-source-map": "1.1.3", - "inline-source-map": "0.6.2", - "lodash.memoize": "3.0.4", - "source-map": "0.5.7" - }, - "dependencies": { - "convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", - "dev": true - } + "lodash": "4.17.10" } }, "combined-stream": { @@ -2721,7 +2495,7 @@ "create-hmac": "1.1.7", "diffie-hellman": "5.0.3", "inherits": "2.0.3", - "pbkdf2": "3.0.14", + "pbkdf2": "3.0.16", "public-encrypt": "4.0.2", "randombytes": "2.0.6", "randomfill": "1.0.4" @@ -2953,12 +2727,6 @@ } } }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, "degenerator": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", @@ -3040,18 +2808,6 @@ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "dev": true }, - "deps-sort": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", - "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "shasum": "1.0.2", - "subarg": "1.0.0", - "through2": "2.0.3" - } - }, "des.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", @@ -3083,16 +2839,6 @@ "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=", "dev": true }, - "detective": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", - "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", - "dev": true, - "requires": { - "acorn": "5.5.3", - "defined": "1.0.0" - } - }, "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", @@ -3236,15 +2982,6 @@ "dev": true, "optional": true }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "2.3.6" - } - }, "duplexify": { "version": "3.5.4", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.4.tgz", @@ -3688,9 +3425,9 @@ } }, "eventemitter3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", - "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.0.1.tgz", + "integrity": "sha512-QOCPu979MMWX9XNlfRZoin+Wm+bK1SP7vv3NGUniYwuSJK/+cPA10blMaeRgzg31RvoSFk6FsCDVa4vNryBTGA==", "dev": true }, "events": { @@ -4080,25 +3817,12 @@ } }, "follow-redirects": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", - "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", + "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", "dev": true, - "optional": true, "requires": { - "debug": "2.6.9" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - } + "debug": "3.1.0" } }, "for-in": { @@ -4213,39 +3937,29 @@ "dev": true }, "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.2.tgz", + "integrity": "sha512-iownA+hC4uHFp+7gwP/y5SzaiUo7m2vpa0dhpzw8YuKtiZsz7cIXsFbXpLEeBM6WuCQyw1MH4RRe6XI8GFUctQ==", "dev": true, "optional": true, "requires": { "nan": "2.10.0", - "node-pre-gyp": "0.6.39" + "node-pre-gyp": "0.9.1" }, "dependencies": { "abbrev": { - "version": "1.1.0", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, "ansi-regex": { "version": "2.1.1", "bundled": true, "dev": true }, "aproba": { - "version": "1.1.1", + "version": "1.2.0", "bundled": true, "dev": true, "optional": true @@ -4257,243 +3971,91 @@ "optional": true, "requires": { "delegates": "1.0.0", - "readable-stream": "2.2.9" + "readable-stream": "2.3.6" } }, - "asn1": { - "version": "0.2.3", + "balanced-match": { + "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, - "assert-plus": { - "version": "0.2.0", + "brace-expansion": { + "version": "1.1.11", "bundled": true, "dev": true, - "optional": true + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } }, - "asynckit": { - "version": "0.4.0", + "chownr": { + "version": "1.0.1", "bundled": true, "dev": true, "optional": true }, - "aws-sign2": { - "version": "0.6.0", + "code-point-at": { + "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, - "aws4": { - "version": "1.6.0", + "concat-map": { + "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, - "balanced-match": { - "version": "0.4.2", + "console-control-strings": { + "version": "1.1.0", "bundled": true, "dev": true }, - "bcrypt-pbkdf": { - "version": "1.0.1", + "core-util-is": { + "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } + "optional": true }, - "block-stream": { - "version": "0.0.9", + "debug": { + "version": "2.6.9", "bundled": true, "dev": true, + "optional": true, "requires": { - "inherits": "2.0.3" + "ms": "2.0.0" } }, - "boom": { - "version": "2.10.1", + "deep-extend": { + "version": "0.4.2", "bundled": true, "dev": true, - "requires": { - "hoek": "2.16.3" - } + "optional": true }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", + "delegates": { + "version": "1.0.0", "bundled": true, "dev": true, "optional": true }, "detect-libc": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", + "version": "1.0.3", "bundled": true, "dev": true, "optional": true }, - "form-data": { - "version": "2.1.4", + "fs-minipass": { + "version": "1.2.5", "bundled": true, "dev": true, "optional": true, "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" + "minipass": "2.2.4" } }, "fs.realpath": { "version": "1.0.0", "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } + "optional": true }, "gauge": { "version": "2.7.4", @@ -4501,7 +4063,7 @@ "dev": true, "optional": true, "requires": { - "aproba": "1.1.1", + "aproba": "1.2.0", "console-control-strings": "1.1.0", "has-unicode": "2.0.1", "object-assign": "4.1.1", @@ -4511,27 +4073,11 @@ "wide-align": "1.1.2" } }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, "glob": { "version": "7.1.2", "bundled": true, "dev": true, + "optional": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -4541,64 +4087,35 @@ "path-is-absolute": "1.0.1" } }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, "has-unicode": { "version": "2.0.1", "bundled": true, "dev": true, "optional": true }, - "hawk": { - "version": "3.1.3", + "iconv-lite": { + "version": "0.4.21", "bundled": true, "dev": true, + "optional": true, "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" + "safer-buffer": "2.1.2" } }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", + "ignore-walk": { + "version": "3.0.1", "bundled": true, "dev": true, "optional": true, "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" + "minimatch": "3.0.4" } }, "inflight": { "version": "1.0.6", "bundled": true, "dev": true, + "optional": true, "requires": { "once": "1.4.0", "wrappy": "1.0.2" @@ -4610,7 +4127,7 @@ "dev": true }, "ini": { - "version": "1.3.4", + "version": "1.3.5", "bundled": true, "dev": true, "optional": true @@ -4623,111 +4140,43 @@ "number-is-nan": "1.0.1" } }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, "isarray": { "version": "1.0.0", "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, "dev": true, "optional": true }, - "json-stable-stringify": { - "version": "1.0.1", + "minimatch": { + "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { - "jsonify": "0.0.0" + "brace-expansion": "1.1.11" } }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", + "minimist": { + "version": "0.0.8", "bundled": true, "dev": true }, - "mime-types": { - "version": "2.1.15", + "minipass": { + "version": "2.2.4", "bundled": true, "dev": true, "requires": { - "mime-db": "1.27.0" + "safe-buffer": "5.1.1", + "yallist": "3.0.2" } }, - "minimatch": { - "version": "3.0.4", + "minizlib": { + "version": "1.1.0", "bundled": true, "dev": true, + "optional": true, "requires": { - "brace-expansion": "1.1.7" + "minipass": "2.2.4" } }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, "mkdirp": { "version": "0.5.1", "bundled": true, @@ -4742,23 +4191,33 @@ "dev": true, "optional": true }, + "needle": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.9", + "iconv-lite": "0.4.21", + "sax": "1.2.4" + } + }, "node-pre-gyp": { - "version": "0.6.39", + "version": "0.9.1", "bundled": true, "dev": true, "optional": true, "requires": { - "detect-libc": "1.0.2", - "hawk": "3.1.3", + "detect-libc": "1.0.3", "mkdirp": "0.5.1", + "needle": "2.2.0", "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" + "npm-packlist": "1.1.10", + "npmlog": "4.1.2", + "rc": "1.2.6", + "rimraf": "2.6.2", + "semver": "5.5.0", + "tar": "4.4.1" } }, "nopt": { @@ -4767,12 +4226,28 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" + "abbrev": "1.1.1", + "osenv": "0.1.5" + } + }, + "npm-bundled": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.1.10", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "3.0.1", + "npm-bundled": "1.0.3" } }, "npmlog": { - "version": "4.1.0", + "version": "4.1.2", "bundled": true, "dev": true, "optional": true, @@ -4788,12 +4263,6 @@ "bundled": true, "dev": true }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, "object-assign": { "version": "4.1.1", "bundled": true, @@ -4821,7 +4290,7 @@ "optional": true }, "osenv": { - "version": "0.1.4", + "version": "0.1.5", "bundled": true, "dev": true, "optional": true, @@ -4833,39 +4302,23 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, "dev": true, "optional": true }, "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", + "version": "2.0.0", "bundled": true, "dev": true, "optional": true }, "rc": { - "version": "1.2.1", + "version": "1.2.6", "bundled": true, "dev": true, "optional": true, "requires": { "deep-extend": "0.4.2", - "ini": "1.3.4", + "ini": "1.3.5", "minimist": "1.2.0", "strip-json-comments": "2.0.1" }, @@ -4879,64 +4332,48 @@ } }, "readable-stream": { - "version": "2.2.9", + "version": "2.3.6", "bundled": true, "dev": true, + "optional": true, "requires": { - "buffer-shims": "1.0.0", "core-util-is": "1.0.2", "inherits": "2.0.3", "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", "util-deprecate": "1.0.2" } }, - "request": { - "version": "2.81.0", + "rimraf": { + "version": "2.6.2", "bundled": true, "dev": true, "optional": true, "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" + "glob": "7.1.2" } }, - "rimraf": { - "version": "2.6.1", + "safe-buffer": { + "version": "5.1.1", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", "bundled": true, "dev": true, - "requires": { - "glob": "7.1.2" - } + "optional": true }, - "safe-buffer": { - "version": "5.0.1", + "sax": { + "version": "1.2.4", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "semver": { - "version": "5.3.0", + "version": "5.5.0", "bundled": true, "dev": true, "optional": true @@ -4953,39 +4390,6 @@ "dev": true, "optional": true }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, "string-width": { "version": "1.0.2", "bundled": true, @@ -4997,19 +4401,14 @@ } }, "string_decoder": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, + "optional": true, "requires": { - "safe-buffer": "5.0.1" + "safe-buffer": "5.1.1" } }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, "strip-ansi": { "version": "3.0.1", "bundled": true, @@ -5025,81 +4424,26 @@ "optional": true }, "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", + "version": "4.4.1", "bundled": true, "dev": true, "optional": true, "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" + "chownr": "1.0.1", + "fs-minipass": "1.2.5", + "minipass": "2.2.4", + "minizlib": "1.1.0", + "mkdirp": "0.5.1", + "safe-buffer": "5.1.1", + "yallist": "3.0.2" } }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, "util-deprecate": { "version": "1.0.2", "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, "dev": true, "optional": true }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, "wide-align": { "version": "1.1.2", "bundled": true, @@ -5113,6 +4457,11 @@ "version": "1.0.2", "bundled": true, "dev": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true, + "dev": true } } }, @@ -5346,7 +4695,7 @@ "optional": true, "requires": { "glob": "7.1.2", - "lodash": "4.17.5", + "lodash": "4.17.10", "minimatch": "3.0.4" } }, @@ -5635,7 +4984,7 @@ "dev": true, "optional": true, "requires": { - "lodash": "4.17.5", + "lodash": "4.17.10", "request": "2.81.0" } }, @@ -5701,7 +5050,7 @@ "he": "1.1.1", "param-case": "2.1.1", "relateurl": "0.2.7", - "uglify-js": "3.3.21" + "uglify-js": "3.3.22" } }, "html-webpack-plugin": { @@ -5713,7 +5062,7 @@ "bluebird": "3.5.1", "html-minifier": "3.5.15", "loader-utils": "0.2.17", - "lodash": "4.17.5", + "lodash": "4.17.10", "pretty-error": "2.1.1", "toposort": "1.0.6" }, @@ -5732,12 +5081,6 @@ } } }, - "htmlescape": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", - "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", - "dev": true - }, "htmlparser2": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", @@ -5804,18 +5147,19 @@ } }, "http-parser-js": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.11.tgz", - "integrity": "sha512-QCR5O2AjjMW8Mo4HyI1ctFcv+O99j/0g367V3YoVnrNw5hkDvAWZD0lWGcc+F4yN3V55USPCVix4efb75HxFfA==", + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.12.tgz", + "integrity": "sha1-uc+/Sizybw/DSxDKFImid3HjR08=", "dev": true }, "http-proxy": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", - "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "dev": true, "requires": { - "eventemitter3": "1.2.0", + "eventemitter3": "3.0.1", + "follow-redirects": "1.4.1", "requires-port": "1.0.0" } }, @@ -5847,9 +5191,9 @@ "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", "dev": true, "requires": { - "http-proxy": "1.16.2", + "http-proxy": "1.17.0", "is-glob": "3.1.0", - "lodash": "4.17.5", + "lodash": "4.17.10", "micromatch": "2.3.11" }, "dependencies": { @@ -6028,32 +5372,6 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, - "inline-source-map": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", - "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - }, - "insert-module-globals": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.6.tgz", - "integrity": "sha512-R3sidKJr3SsggqQQ5cEwQb3pWG8RNx0UnpyeiOSR6jorRIeAOzH2gkTWnNdMnyRiVbjrG047K7UCtlMkQ1Mo9w==", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "combine-source-map": "0.8.0", - "concat-stream": "1.6.2", - "is-buffer": "1.1.6", - "lexical-scope": "1.2.0", - "path-is-absolute": "1.0.1", - "process": "0.11.10", - "through2": "2.0.3", - "xtend": "4.0.1" - } - }, "internal-ip": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", @@ -6588,9 +5906,9 @@ "dev": true }, "jasmine-reporters": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/jasmine-reporters/-/jasmine-reporters-2.3.0.tgz", - "integrity": "sha1-64y3NZZYVyqH7vSqCIo2MDbzeSo=", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/jasmine-reporters/-/jasmine-reporters-2.3.1.tgz", + "integrity": "sha1-9C1XjplmlhY0MdkRwxZ5cZ+0Ozs=", "dev": true, "requires": { "mkdirp": "0.5.1", @@ -6760,12 +6078,6 @@ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "dev": true }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, "jsonpointer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", @@ -6841,14 +6153,13 @@ } }, "karma": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.0.tgz", - "integrity": "sha512-K9Kjp8CldLyL9ANSUctDyxC7zH3hpqXj/K09qVf06K3T/kXaHtFZ5tQciK7OzQu68FLvI89Na510kqQ2LCbpIw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.2.tgz", + "integrity": "sha1-TS25QChQpmVR+nhLAWT7CCTtjEs=", "dev": true, "requires": { "bluebird": "3.5.1", "body-parser": "1.18.2", - "browserify": "14.5.0", "chokidar": "1.7.0", "colors": "1.1.2", "combine-lists": "1.0.1", @@ -6859,9 +6170,9 @@ "expand-braces": "0.1.2", "glob": "7.1.2", "graceful-fs": "4.1.11", - "http-proxy": "1.16.2", + "http-proxy": "1.17.0", "isbinaryfile": "3.0.2", - "lodash": "4.17.5", + "lodash": "4.17.10", "log4js": "2.5.3", "mime": "1.6.0", "minimatch": "3.0.4", @@ -6873,7 +6184,7 @@ "socket.io": "2.0.4", "source-map": "0.6.1", "tmp": "0.0.33", - "useragent": "2.3.0" + "useragent": "2.2.1" }, "dependencies": { "source-map": { @@ -6961,25 +6272,6 @@ "graceful-fs": "4.1.11" } }, - "labeled-stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz", - "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", - "dev": true, - "requires": { - "inherits": "2.0.3", - "isarray": "2.0.4", - "stream-splicer": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", - "dev": true - } - } - }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", @@ -7039,15 +6331,6 @@ "type-check": "0.3.2" } }, - "lexical-scope": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", - "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=", - "dev": true, - "requires": { - "astw": "2.2.0" - } - }, "libbase64": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", @@ -7145,9 +6428,9 @@ } }, "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", "dev": true }, "lodash.assign": { @@ -7163,12 +6446,6 @@ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, - "lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", - "dev": true - }, "lodash.mergewith": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", @@ -7426,7 +6703,7 @@ "dev": true, "optional": true, "requires": { - "lodash": "4.17.5" + "lodash": "4.17.10" } }, "debug": { @@ -7722,70 +6999,6 @@ "minimist": "0.0.8" } }, - "module-deps": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz", - "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "browser-resolve": "1.11.2", - "cached-path-relative": "1.0.1", - "concat-stream": "1.5.2", - "defined": "1.0.0", - "detective": "4.7.1", - "duplexer2": "0.1.4", - "inherits": "2.0.3", - "parents": "1.0.1", - "readable-stream": "2.3.6", - "resolve": "1.7.1", - "stream-combiner2": "1.1.1", - "subarg": "1.0.0", - "through2": "2.0.3", - "xtend": "4.0.1" - }, - "dependencies": { - "concat-stream": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", - "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.0.6", - "typedarray": "0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - } - } - } - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, "moment": { "version": "2.20.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz", @@ -8050,32 +7263,6 @@ "ms": "0.7.1" } }, - "follow-redirects": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", - "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", - "dev": true, - "requires": { - "debug": "3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, "ms": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", @@ -8733,15 +7920,6 @@ "no-case": "2.3.2" } }, - "parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", - "dev": true, - "requires": { - "path-platform": "0.11.15" - } - }, "parse-asn1": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", @@ -8752,7 +7930,7 @@ "browserify-aes": "1.2.0", "create-hash": "1.2.0", "evp_bytestokey": "1.0.3", - "pbkdf2": "3.0.14" + "pbkdf2": "3.0.16" } }, "parse-glob": { @@ -8854,12 +8032,6 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, - "path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", - "dev": true - }, "path-proxy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz", @@ -8895,9 +8067,9 @@ } }, "pbkdf2": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", - "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", + "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", "dev": true, "requires": { "create-hash": "1.2.0", @@ -9191,9 +8363,9 @@ "dev": true }, "adm-zip": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", - "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.9.tgz", + "integrity": "sha512-eknaJ3Io/JasGGinVeqY5TsPlQgHbiNlHnK5zdFPRNs9XRggDykKz8zPesneOMEZJxWji7G3CfsUW0Ds9Dw0Bw==", "dev": true }, "ansi-styles": { @@ -9295,7 +8467,7 @@ "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=", "dev": true, "requires": { - "adm-zip": "0.4.7", + "adm-zip": "0.4.9", "chalk": "1.1.3", "del": "2.2.2", "glob": "7.1.2", @@ -9577,15 +8749,6 @@ } } }, - "read-only-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", - "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", - "dev": true, - "requires": { - "readable-stream": "2.3.6" - } - }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -9900,7 +9063,7 @@ "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", "dev": true, "requires": { - "lodash": "4.17.5" + "lodash": "4.17.10" } }, "requestretry": { @@ -9911,7 +9074,7 @@ "optional": true, "requires": { "extend": "3.0.1", - "lodash": "4.17.5", + "lodash": "4.17.10", "request": "2.81.0", "when": "3.7.8" } @@ -10049,7 +9212,7 @@ "optional": true, "requires": { "glob": "7.1.2", - "lodash": "4.17.5", + "lodash": "4.17.10", "scss-tokenizer": "0.2.3", "yargs": "7.1.0" } @@ -10334,27 +9497,6 @@ } } }, - "shasum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", - "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", - "dev": true, - "requires": { - "json-stable-stringify": "0.0.1", - "sha.js": "2.4.11" - }, - "dependencies": { - "json-stable-stringify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", - "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", - "dev": true, - "requires": { - "jsonify": "0.0.0" - } - } - } - }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -10370,18 +9512,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dev": true, - "requires": { - "array-filter": "0.0.1", - "array-map": "0.0.0", - "array-reduce": "0.0.0", - "jsonify": "0.0.0" - } - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -10669,7 +9799,7 @@ "faye-websocket": "0.11.1", "inherits": "2.0.3", "json3": "3.3.2", - "url-parse": "1.3.0" + "url-parse": "1.4.0" }, "dependencies": { "debug": { @@ -10937,16 +10067,6 @@ "readable-stream": "2.3.6" } }, - "stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "dev": true, - "requires": { - "duplexer2": "0.1.4", - "readable-stream": "2.3.6" - } - }, "stream-each": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", @@ -10976,16 +10096,6 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", "dev": true }, - "stream-splicer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", - "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", - "dev": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" - } - }, "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", @@ -11153,23 +10263,6 @@ } } }, - "subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", - "dev": true, - "requires": { - "minimist": "1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, "superagent": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.2.tgz", @@ -11201,15 +10294,6 @@ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, - "syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "dev": true, - "requires": { - "acorn-node": "1.3.0" - } - }, "systemjs": { "version": "0.19.27", "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-0.19.27.tgz", @@ -11452,7 +10536,7 @@ "make-error": "1.3.4", "minimist": "1.2.0", "mkdirp": "0.5.1", - "source-map-support": "0.5.4", + "source-map-support": "0.5.5", "tsconfig": "7.0.0", "v8flags": "3.0.2", "yn": "2.0.0" @@ -11488,11 +10572,12 @@ "dev": true }, "source-map-support": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.4.tgz", - "integrity": "sha512-PETSPG6BjY1AHs2t64vS2aqAgu6dMIMXJULWFBGbh2Gr8nVLbCFDo6i/RMMvviIQ2h1Z8+5gQhVKSn2je9nmdg==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.5.tgz", + "integrity": "sha512-mR7/Nd5l1z6g99010shcXJiNEaf3fEtmLhRB/sBcQVJGodcHCULPp2y4Sfa43Kv2zq7T+Izmfp/WHCR6dYkQCA==", "dev": true, "requires": { + "buffer-from": "1.0.0", "source-map": "0.6.1" } }, @@ -11670,9 +10755,9 @@ "dev": true }, "uglify-js": { - "version": "3.3.21", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.21.tgz", - "integrity": "sha512-uy82472lH8tshK3jS3c5IFb5MmNKd/5qyBd0ih8sM42L3jWvxnE339U9gZU1zufnLVs98Stib9twq8dLm2XYCA==", + "version": "3.3.22", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.22.tgz", + "integrity": "sha512-tqw96rL6/BG+7LM5VItdhDjTQmL5zG/I0b2RqWytlgeHe2eydZHuBHdA9vuGpCDhH/ZskNGcqDhivoR2xt8RIw==", "dev": true, "requires": { "commander": "2.15.1", @@ -11740,12 +10825,6 @@ "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", "dev": true }, - "umd": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", - "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", - "dev": true - }, "underscore": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", @@ -11942,19 +11021,19 @@ } }, "url-parse": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.3.0.tgz", - "integrity": "sha512-zPvPA3T7P6M+0iNsgX+iAcAz4GshKrowtQBHHc/28tVsBc8jK7VRCNX+2GEcoE6zDB6XqXhcyiUWPVZY6C70Cg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.0.tgz", + "integrity": "sha512-ERuGxDiQ6Xw/agN4tuoCRbmwRuZP0cJ1lJxJubXr5Q/5cDa78+Dc4wfvtxzhzhkm5VvmW6Mf8EVj9SPGN4l8Lg==", "dev": true, "requires": { - "querystringify": "1.0.0", + "querystringify": "2.0.0", "requires-port": "1.0.0" }, "dependencies": { "querystringify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz", - "integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz", + "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==", "dev": true } } @@ -11977,13 +11056,21 @@ } }, "useragent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", - "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz", + "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", "dev": true, "requires": { - "lru-cache": "4.1.2", + "lru-cache": "2.2.4", "tmp": "0.0.33" + }, + "dependencies": { + "lru-cache": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", + "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", + "dev": true + } } }, "util": { @@ -12215,7 +11302,7 @@ "anymatch": "2.0.0", "async-each": "1.0.1", "braces": "2.3.2", - "fsevents": "1.1.3", + "fsevents": "1.2.2", "glob-parent": "3.1.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -12995,7 +12082,7 @@ "anymatch": "2.0.0", "async-each": "1.0.1", "braces": "2.3.2", - "fsevents": "1.1.3", + "fsevents": "1.2.2", "glob-parent": "3.1.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -13343,7 +12430,7 @@ "integrity": "sha512-/0QYwW/H1N/CdXYA2PNPVbsxO3u2Fpz34vs72xm03SRfg6bMNGfMJIQEpQjKRvkG2JvT6oRJFpDtSrwbX8Jzvw==", "dev": true, "requires": { - "lodash": "4.17.5" + "lodash": "4.17.10" } }, "webpack-sources": { @@ -13379,7 +12466,7 @@ "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", "dev": true, "requires": { - "http-parser-js": "0.4.11", + "http-parser-js": "0.4.12", "websocket-extensions": "0.1.3" } }, From 1ce890e1783346f09b78bc3a45a7317d7a72b260 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 25 Apr 2018 13:30:15 +0100 Subject: [PATCH 003/179] upgrade to ADF 2.4.x alpha (#331) --- package-lock.json | 42 ++++++++++++++++++++++++++++++------------ package.json | 6 +++--- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index c804b491a4..ec86141a3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.3.0.tgz", - "integrity": "sha512-nLGjVv9xT1masbyxLg4ZY77qKFgs3kaMpm4zblpSNxN8gQnY1uG/rB5l+bevmlKosXqQgezjwgvEpvjU7Nb2oQ==", + "version": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-3bc419e12852527bf82047010d4bf7280712140c.tgz", + "integrity": "sha512-HoHYXtLiWLcSsdSR09FzE0bE6Mx5u9IMPu3foUt6MYR5h0pHk/+DpCx/ODi8ABny9d3saxDk91cpmOI1/4jBgw==", "requires": { - "@alfresco/adf-core": "2.3.0", + "@alfresco/adf-core": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.3.0", + "alfresco-js-api": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -40,6 +40,15 @@ "zone.js": "0.8.14" }, "dependencies": { + "alfresco-js-api": { + "version": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19.tgz", + "integrity": "sha512-BSysLJxGEIcdAOMd/F1kk92KXuDnFwIM10g26EfykhTa0s+PVy0xxEkgQJ3QWeGt4OgNet/ViRkTnj6BkyRFAg==", + "requires": { + "event-emitter": "0.3.4", + "superagent": "3.8.2" + } + }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -61,9 +70,9 @@ } }, "@alfresco/adf-core": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.3.0.tgz", - "integrity": "sha512-Gl8L2EKuCydUaNn7u6grT7yjxg4k04cvtT+i9fz+rloBp3YTF/a2XoqGhcHgQfi0hO6Cc8O+oVmDfDjGkW9QoQ==", + "version": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-3bc419e12852527bf82047010d4bf7280712140c.tgz", + "integrity": "sha512-EGPtv7KlTAsXkHIxRzm0qT+RgUosYoEDLxzimgw1Nj9bdBPh9hDmoUG8iKg9k8hC7uugTvsgdKUgU+eLQN43pQ==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -79,7 +88,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.3.0", + "alfresco-js-api": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -95,6 +104,15 @@ "zone.js": "0.8.14" }, "dependencies": { + "alfresco-js-api": { + "version": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19.tgz", + "integrity": "sha512-BSysLJxGEIcdAOMd/F1kk92KXuDnFwIM10g26EfykhTa0s+PVy0xxEkgQJ3QWeGt4OgNet/ViRkTnj6BkyRFAg==", + "requires": { + "event-emitter": "0.3.4", + "superagent": "3.8.2" + } + }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -637,9 +655,9 @@ "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=" }, "alfresco-js-api": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.3.0.tgz", - "integrity": "sha512-IhsSNoPl8cbw/V24kw420sGoVp6rBakC2kN4gKe3bPdERvSWRehw5bojMQhnSPDmS2PqC5C23HaVV+whOwkpDg==", + "version": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19.tgz", + "integrity": "sha512-BSysLJxGEIcdAOMd/F1kk92KXuDnFwIM10g26EfykhTa0s+PVy0xxEkgQJ3QWeGt4OgNet/ViRkTnj6BkyRFAg==", "requires": { "event-emitter": "0.3.4", "superagent": "3.8.2" diff --git a/package.json b/package.json index 770480b5eb..f42ee6cc82 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.3.0", - "@alfresco/adf-core": "2.3.0", + "@alfresco/adf-content-services": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", + "@alfresco/adf-core": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -41,7 +41,7 @@ "@mat-datetimepicker/core": "1.0.1", "@mat-datetimepicker/moment": "1.0.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.3.0", + "alfresco-js-api": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", "core-js": "2.5.3", "hammerjs": "2.0.8", "moment-es6": "1.0.0", From ba07880fbd7dd010c1a843e69a3ce4b3914aabde Mon Sep 17 00:00:00 2001 From: Bogdan Cilibiu Date: Thu, 26 Apr 2018 09:47:33 +0300 Subject: [PATCH 004/179] fix tooltip --- src/app/components/sidenav/sidenav.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index e5c288acad..7fb3f30b57 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -24,7 +24,7 @@ [disabled]="!permission.check(node, ['create'])" (error)="openSnackMessage($event)" [adf-create-folder]="node?.id" - [title]=" + [attr.title]=" ( permission.check(node, ['create']) ? 'APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER' : 'APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER_NOT_ALLOWED' From 633611ec2eb3f1cc4f34614310b684fa96166eeb Mon Sep 17 00:00:00 2001 From: Bogdan Cilibiu Date: Thu, 26 Apr 2018 10:16:12 +0300 Subject: [PATCH 005/179] tooltip --- src/app/components/favorites/favorites.component.html | 2 +- src/app/components/files/files.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 8b54addb12..19c57a87a6 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -27,7 +27,7 @@ mat-icon-button color="primary" *ngIf="showEditOption(documentList.selection)" - title="{{ 'APP.ACTIONS.EDIT' | translate }}" + [attr.title]="'APP.ACTIONS.EDIT' | translate" (error)="openSnackMessage($event)" [adf-edit-folder]="documentList.selection[0]?.entry"> create diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index 27c2380e74..0fd10629e9 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -29,7 +29,7 @@ color="primary" mat-icon-button *ngIf="canEditFolder(documentList.selection)" - title="{{ 'APP.ACTIONS.EDIT' | translate }}" + [attr.title]="'APP.ACTIONS.EDIT' | translate" (error)="openSnackMessage($event)" [adf-edit-folder]="documentList.selection[0]?.entry"> create From f0789c90f4adb4c27cd581e6082a3c143d188db9 Mon Sep 17 00:00:00 2001 From: Bogdan Cilibiu Date: Thu, 26 Apr 2018 11:44:11 +0300 Subject: [PATCH 006/179] UX text --- src/assets/i18n/en.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index d3f9b478ed..8d0e088ed6 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -222,5 +222,13 @@ "EMPTY": "Please choose a document to see the versions of it.", "NO_PERMISSION": "You don't have permission to manage the versions of this content." } + }, + "CORE": { + "METADATA": { + "ACTIONS": { + "SAVE": "Save changes", + "CANCEL": "Discard changes" + } + } } } From 40b1c368d98ce2b27218ab61fe3b8a680246c35a Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 27 Apr 2018 11:32:55 +0100 Subject: [PATCH 007/179] update search filter configuration --- src/app.config.json | 128 ++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 65 deletions(-) diff --git a/src/app.config.json b/src/app.config.json index 6db201ac8d..111986f786 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -8,19 +8,10 @@ "languagePicker": false, "pagination": { "size": 25, - "supportedPageSizes": [ - 25, - 50, - 100 - ] + "supportedPageSizes": [25, 50, 100] }, "files": { - "excluded": [ - ".DS_Store", - "desktop.ini", - "thumbs.db", - ".git" - ] + "excluded": [".DS_Store", "desktop.ini", "thumbs.db", ".git"] }, "adf-version-manager": { "allowComments": true, @@ -162,10 +153,8 @@ } }, "search": { - "limits": { - "permissionEvaluationTime": null, - "permissionEvaluationCount": null - }, + "include": ["path", "allowableOperations"], + "fields": [], "filterQueries": [ { "query": "TYPE:'cm:folder' OR TYPE:'cm:content'" }, { "query": "NOT cm:creator:System" } @@ -176,39 +165,45 @@ { "field": "content.size", "mincount": 1, "label": "Size" }, { "field": "creator", "mincount": 1, "label": "Creator" }, { "field": "modifier", "mincount": 1, "label": "Modifier" } - ] + ] }, "facetQueries": [ { "query": "created:2018", "label": "Created This Year" }, { "query": "content.mimetype", "label": "Type" }, - { "query": "content.size:[0 TO 10240]", "label": "Size: xtra small"}, - { "query": "content.size:[10240 TO 102400]", "label": "Size: small"}, - { "query": "content.size:[102400 TO 1048576]", "label": "Size: medium" }, - { "query": "content.size:[1048576 TO 16777216]", "label": "Size: large" }, - { "query": "content.size:[16777216 TO 134217728]", "label": "Size: xtra large" }, - { "query": "content.size:[134217728 TO MAX]", "label": "Size: XX large" } + { + "query": "content.size:[0 TO 10240]", + "label": "Size: xtra small" + }, + { + "query": "content.size:[10240 TO 102400]", + "label": "Size: small" + }, + { + "query": "content.size:[102400 TO 1048576]", + "label": "Size: medium" + }, + { + "query": "content.size:[1048576 TO 16777216]", + "label": "Size: large" + }, + { + "query": "content.size:[16777216 TO 134217728]", + "label": "Size: xtra large" + }, + { + "query": "content.size:[134217728 TO MAX]", + "label": "Size: XX large" + } ], "query": { "categories": [ - { - "id": "broken", - "name": "Broken Facet", - "enabled": false, - "expanded": false, - "component": { - "selector": "adf-search-text", - "settings": { - "field": "fieldname" - } - } - }, { "id": "queryName", "name": "Name", "enabled": true, "expanded": true, "component": { - "selector": "adf-search-text", + "selector": "text", "settings": { "pattern": "cm:name:'(.*?)'", "field": "cm:name", @@ -217,55 +212,58 @@ } }, { - "id": "queryFields", - "name": "Fields", + "id": "contentSize", + "name": "Content Size", "enabled": true, - "expanded": false, "component": { - "selector": "adf-search-fields", + "selector": "slider", "settings": { - "field": null, - "options": [ - { "name": "Name", "value": "name", "fields": ["name"], "default": true }, - { "name": "File Size", "value": "content.sizeInBytes", "fields": ["content"], "default": true }, - { "name": "Modified On", "value": "modifiedAt", "fields": ["modifiedAt"], "default": true }, - { "name": "Modified By", "value": "modifiedByUser.displayName", "fields": ["modifiedByUser"], "default": true } - ] + "field": "cm:content.size", + "min": 0, + "max": 18, + "step": 1, + "thumbLabel": true } } }, { - "id": "queryType", - "name": "Type", + "id": "contentSizeRange", + "name": "Content Size (range)", "enabled": true, - "expanded": false, "component": { - "selector": "adf-search-radio", + "selector": "number-range", "settings": { - "field": null, - "options": [ - { "name": "None", "value": "", "default": true }, - { "name": "All", "value": "TYPE:'cm:folder' OR TYPE:'cm:content'" }, - { "name": "Folder", "value": "TYPE:'cm:folder'" }, - { "name": "Document", "value": "TYPE:'cm:content'" } - ] + "field": "cm:content.size" } } }, { - "id": "queryLocations", - "name": "Locations", + "id": "queryType", + "name": "Type", "enabled": true, - "expanded": false, "component": { - "selector": "adf-search-scope-locations", + "selector": "radio", "settings": { "field": null, "options": [ - { "name": "Default", "value": "nodes", "default": true }, - { "name": "Nodes", "value": "nodes" }, - { "name": "Deleted Nodes", "value": "deleted-nodes" }, - { "name": "Versions", "value": "versions" } + { + "name": "None", + "value": "", + "default": true + }, + { + "name": "All", + "value": + "TYPE:'cm:folder' OR TYPE:'cm:content'" + }, + { + "name": "Folder", + "value": "TYPE:'cm:folder'" + }, + { + "name": "Document", + "value": "TYPE:'cm:content'" + } ] } } From bd19889e647a524f9d95a7dfced1c36b0403ed6a Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 27 Apr 2018 11:49:23 +0100 Subject: [PATCH 008/179] update to latest ADF alpha --- package-lock.json | 36 ++++++++++++++++++------------------ package.json | 6 +++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec86141a3f..b5c4353bba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-3bc419e12852527bf82047010d4bf7280712140c.tgz", - "integrity": "sha512-HoHYXtLiWLcSsdSR09FzE0bE6Mx5u9IMPu3foUt6MYR5h0pHk/+DpCx/ODi8ABny9d3saxDk91cpmOI1/4jBgw==", + "version": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d.tgz", + "integrity": "sha512-EHYvODiv3w12jbPCZacFSQ2fhwx5FVdmidsU+3ngWWXELjXuWIFhUWv02nEw3BBDO0xA/UkC2D4ASN0GVNNlyA==", "requires": { - "@alfresco/adf-core": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", + "@alfresco/adf-core": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", + "alfresco-js-api": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -41,9 +41,9 @@ }, "dependencies": { "alfresco-js-api": { - "version": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19.tgz", - "integrity": "sha512-BSysLJxGEIcdAOMd/F1kk92KXuDnFwIM10g26EfykhTa0s+PVy0xxEkgQJ3QWeGt4OgNet/ViRkTnj6BkyRFAg==", + "version": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de.tgz", + "integrity": "sha512-8d9H4fY7rxPoSpDa42EqI9D0lg1AOQOnkP+0Qz1jkS7w/otsOcCT29jlo5Y1avwscS+QNrwo+RMTaVdGnxwqAA==", "requires": { "event-emitter": "0.3.4", "superagent": "3.8.2" @@ -70,9 +70,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-3bc419e12852527bf82047010d4bf7280712140c.tgz", - "integrity": "sha512-EGPtv7KlTAsXkHIxRzm0qT+RgUosYoEDLxzimgw1Nj9bdBPh9hDmoUG8iKg9k8hC7uugTvsgdKUgU+eLQN43pQ==", + "version": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d.tgz", + "integrity": "sha512-cvu/PPHcXW0v9dPJ3EMGmEqIJLH+RkwkkvVWpz3v0Zck0y9KRuXkqxOIOoUJwm1AAwPdbyKxDcKFNxpXZ+EdoQ==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -88,7 +88,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", + "alfresco-js-api": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -105,9 +105,9 @@ }, "dependencies": { "alfresco-js-api": { - "version": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19.tgz", - "integrity": "sha512-BSysLJxGEIcdAOMd/F1kk92KXuDnFwIM10g26EfykhTa0s+PVy0xxEkgQJ3QWeGt4OgNet/ViRkTnj6BkyRFAg==", + "version": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de.tgz", + "integrity": "sha512-8d9H4fY7rxPoSpDa42EqI9D0lg1AOQOnkP+0Qz1jkS7w/otsOcCT29jlo5Y1avwscS+QNrwo+RMTaVdGnxwqAA==", "requires": { "event-emitter": "0.3.4", "superagent": "3.8.2" @@ -655,9 +655,9 @@ "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=" }, "alfresco-js-api": { - "version": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19.tgz", - "integrity": "sha512-BSysLJxGEIcdAOMd/F1kk92KXuDnFwIM10g26EfykhTa0s+PVy0xxEkgQJ3QWeGt4OgNet/ViRkTnj6BkyRFAg==", + "version": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de.tgz", + "integrity": "sha512-8d9H4fY7rxPoSpDa42EqI9D0lg1AOQOnkP+0Qz1jkS7w/otsOcCT29jlo5Y1avwscS+QNrwo+RMTaVdGnxwqAA==", "requires": { "event-emitter": "0.3.4", "superagent": "3.8.2" diff --git a/package.json b/package.json index f42ee6cc82..5b57b0b4a8 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", - "@alfresco/adf-core": "2.4.0-3bc419e12852527bf82047010d4bf7280712140c", + "@alfresco/adf-content-services": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", + "@alfresco/adf-core": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -41,7 +41,7 @@ "@mat-datetimepicker/core": "1.0.1", "@mat-datetimepicker/moment": "1.0.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.3.0-20521af7bbf48e0259bc810f01cdb5b085bc8f19", + "alfresco-js-api": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", "core-js": "2.5.3", "hammerjs": "2.0.8", "moment-es6": "1.0.0", From bf4536fec5868d5091f16327114772c7772d2c34 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 27 Apr 2018 21:46:01 +0300 Subject: [PATCH 009/179] reset selection after each test (#335) --- e2e/suites/actions/toolbar-single-selection.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/e2e/suites/actions/toolbar-single-selection.test.ts b/e2e/suites/actions/toolbar-single-selection.test.ts index 61e20a22c4..0cea2b68b5 100755 --- a/e2e/suites/actions/toolbar-single-selection.test.ts +++ b/e2e/suites/actions/toolbar-single-selection.test.ts @@ -544,6 +544,10 @@ describe('Toolbar actions - single selection : ', () => { .then(done); }); + afterEach(() => { + dataTable.clearSelection(); + }); + afterAll(done => { logoutPage.load().then(done); }); @@ -588,6 +592,10 @@ describe('Toolbar actions - single selection : ', () => { .then(done); }); + afterEach(() => { + dataTable.clearSelection(); + }); + afterAll(done => { logoutPage.load().then(done); }); From 212bd384881eebb2ee8fc59cc7b9d6373d3ba796 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sat, 28 Apr 2018 04:01:03 +0100 Subject: [PATCH 010/179] update to acs 6.0.5-ea (#337) --- .env | 6 +++--- docker-compose/.env | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env b/.env index c0235eaaba..48d0b390fa 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ -ALFRESCO_TAG=6.0.4-ea +ALFRESCO_TAG=6.0.5-ea SHARE_TAG=6.0.a -SOLR6_TAG=1.1.0 +SOLR6_TAG=1.1.1 POSTGRES_TAG=10.1 -ACA_TAG=development +ACA_TAG=latest diff --git a/docker-compose/.env b/docker-compose/.env index c0235eaaba..8d75501a29 100644 --- a/docker-compose/.env +++ b/docker-compose/.env @@ -1,5 +1,5 @@ -ALFRESCO_TAG=6.0.4-ea +ALFRESCO_TAG=6.0.5-ea SHARE_TAG=6.0.a -SOLR6_TAG=1.1.0 +SOLR6_TAG=1.1.1 POSTGRES_TAG=10.1 -ACA_TAG=development +ACA_TAG=master From 46a53392147c42426f49e07751eef08e7494d223 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Sun, 29 Apr 2018 13:15:26 +0300 Subject: [PATCH 011/179] [ACA] E2E - Toolbar - wait for shared api --- e2e/suites/actions/toolbar-single-selection.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/e2e/suites/actions/toolbar-single-selection.test.ts b/e2e/suites/actions/toolbar-single-selection.test.ts index 0cea2b68b5..0ae7ad4f78 100755 --- a/e2e/suites/actions/toolbar-single-selection.test.ts +++ b/e2e/suites/actions/toolbar-single-selection.test.ts @@ -131,6 +131,9 @@ describe('Toolbar actions - single selection : ', () => { .then(() => apis.user.shared.shareFileById(file1Id)) .then(() => apis.admin.shared.shareFileById(file2Id)) + .then(() => apis.user.shared.waitForApi({ expect: 1 })) + .then(() => apis.admin.shared.waitForApi({ expect: 1 })) + .then(() => apis.user.favorites.addFavoritesByIds('file', [file1Id, file2Id])) .then(() => loginPage.loginWith(username)) From 25c5738160b1de94c3a8d8b15fec5d44dd8cc493 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 30 Apr 2018 11:51:27 +0100 Subject: [PATCH 012/179] [ACA-1347] Setup code linting and production builds with CI (#339) --- .angular-cli.json | 2 +- .circleci/config.yml | 47 +++++++++++++++++- docker-compose.yml | 8 +-- docker-compose/proxy/Dockerfile | 4 ++ docker-compose/proxy/nginx.conf | 49 +++++++++++++++++++ e2e/pages/page.ts | 2 +- e2e/suites/actions/delete.test.ts | 4 +- e2e/suites/actions/undo-delete.test.ts | 6 +-- e2e/suites/list-views/shared-files.test.ts | 2 +- .../apis/favorites/favorites-api.ts | 2 +- e2e/utilities/utils.ts | 12 ++--- .../directives/node-copy.directive.spec.ts | 2 +- .../common/directives/node-copy.directive.ts | 5 +- .../directives/node-delete.directive.spec.ts | 2 +- .../directives/node-delete.directive.ts | 9 ++-- .../directives/node-download.directive.ts | 4 +- .../directives/node-info.directive.spec.ts | 2 +- .../common/directives/node-info.directive.ts | 5 +- .../directives/node-move.directive.spec.ts | 2 +- .../common/directives/node-move.directive.ts | 7 +-- .../node-permanent-delete.directive.spec.ts | 2 +- .../directives/node-restore.directive.spec.ts | 2 +- .../directives/node-restore.directive.ts | 5 +- .../directives/node-unshare.directive.ts | 4 +- .../directives/node-versions.directive.ts | 5 +- .../favorites/favorites.component.html | 10 ++-- src/app/components/files/files.component.html | 10 ++-- .../components/preview/preview.component.html | 6 +-- .../recent-files/recent-files.component.html | 10 ++-- .../shared-files/shared-files.component.html | 14 +++--- .../shared-files.component.spec.ts | 2 +- .../trashcan/trashcan.component.html | 2 +- tslint.json | 6 +-- 33 files changed, 176 insertions(+), 78 deletions(-) create mode 100644 docker-compose/proxy/Dockerfile create mode 100644 docker-compose/proxy/nginx.conf diff --git a/.angular-cli.json b/.angular-cli.json index 0e3fb2b064..144b4545c2 100644 --- a/.angular-cli.json +++ b/.angular-cli.json @@ -37,7 +37,7 @@ "test": "test.ts", "tsconfig": "tsconfig.app.json", "testTsconfig": "tsconfig.spec.json", - "prefix": "app", + "prefix": "aca", "styles": [ "./assets/fonts/material-icons/material-icons.css", "./assets/fonts/muli/muli.css", diff --git a/.circleci/config.yml b/.circleci/config.yml index bef30d0312..077b30a374 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,7 @@ version: 2 + jobs: - build: + install: working_directory: ~/alfresco-content-app docker: - image: circleci/node:8-browsers @@ -13,4 +14,48 @@ jobs: key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }} paths: - "node_modules" + lint: + working_directory: ~/alfresco-content-app + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }} + - run: npm install + - run: npm run lint + test: + working_directory: ~/alfresco-content-app + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }} + - run: npm install - run: xvfb-run -a npm run test:ci + build: + working_directory: ~/alfresco-content-app + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }} + - run: npm install + - run: npm run build + +workflows: + version: 2 + build_and_test: + jobs: + - install + - lint: + requires: + - install + - test: + requires: + - install + - build: + requires: + - install diff --git a/docker-compose.yml b/docker-compose.yml index 0129115965..40bf2a1311 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -81,11 +81,13 @@ services: # - ./nginx.conf:/etc/nginx/conf.d/default.conf proxy: - image: nginx + #image: nginx + image: alfresco/alfresco-content-app-proxy + build: ./docker-compose/proxy depends_on: - content-app - volumes: - - ./docker-compose/nginx.conf:/etc/nginx/conf.d/default.conf + # volumes: + # - ./docker-compose/nginx.conf:/etc/nginx/conf.d/default.conf networks: - internal ports: diff --git a/docker-compose/proxy/Dockerfile b/docker-compose/proxy/Dockerfile new file mode 100644 index 0000000000..e9319ec4ab --- /dev/null +++ b/docker-compose/proxy/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:alpine +LABEL version="1.2" +LABEL maintainer="Denys Vuika " +COPY nginx.conf /etc/nginx/nginx.conf diff --git a/docker-compose/proxy/nginx.conf b/docker-compose/proxy/nginx.conf new file mode 100644 index 0000000000..3a53f3e3f2 --- /dev/null +++ b/docker-compose/proxy/nginx.conf @@ -0,0 +1,49 @@ +events { + worker_connections 1024; +} + +http { + server { + listen *:80; + + set $allowOriginSite *; + proxy_pass_request_headers on; + proxy_pass_header Set-Cookie; + + location / { + proxy_pass http://content-app; + + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass_header Set-Cookie; + } + + location /alfresco/ { + proxy_pass http://alfresco:8080; + + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass_header Set-Cookie; + } + + location /share/ { + proxy_pass http://share:8080; + + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass_header Set-Cookie; + } + } +} diff --git a/e2e/pages/page.ts b/e2e/pages/page.ts index b2dce1d523..570b40c007 100755 --- a/e2e/pages/page.ts +++ b/e2e/pages/page.ts @@ -85,7 +85,7 @@ export abstract class Page { } getDialogActionByLabel(label) { - return element(by.cssContainingText('.mat-button-wrapper', label)) + return element(by.cssContainingText('.mat-button-wrapper', label)); } isSnackBarDisplayed(): promise.Promise { diff --git a/e2e/suites/actions/delete.test.ts b/e2e/suites/actions/delete.test.ts index c401680ae1..bb0bf1564f 100755 --- a/e2e/suites/actions/delete.test.ts +++ b/e2e/suites/actions/delete.test.ts @@ -465,7 +465,7 @@ describe('Delete content', () => { .then(done); }); - it('delete a file and check notification', () => { + xit('delete a file and check notification', () => { dataTable.clickOnItemName(recentFile1) .then(() => toolbar.actions.openMoreMenu()) .then(() => toolbar.actions.menu.clickMenuItem('Delete')) @@ -480,7 +480,7 @@ describe('Delete content', () => { .then(() => apis.user.trashcan.restore(recentFile1Id)); }); - it('delete multiple files and check notification', () => { + xit('delete multiple files and check notification', () => { dataTable.selectMultipleItems([recentFile2, recentFile3]) .then(() => toolbar.actions.openMoreMenu()) .then(() => toolbar.actions.menu.clickMenuItem('Delete')) diff --git a/e2e/suites/actions/undo-delete.test.ts b/e2e/suites/actions/undo-delete.test.ts index 2409444d4a..a780644bce 100755 --- a/e2e/suites/actions/undo-delete.test.ts +++ b/e2e/suites/actions/undo-delete.test.ts @@ -383,7 +383,7 @@ describe('Undo delete content', () => { .then(done); }); - it('Successful delete notification shows Undo action', () => { + xit('Successful delete notification shows Undo action', () => { dataTable.clickOnItemName(recentFile1) .then(() => toolbar.actions.openMoreMenu()) .then(() => toolbar.actions.menu.clickMenuItem('Delete')) @@ -395,7 +395,7 @@ describe('Undo delete content', () => { // we cannot test that the restored file is displayed in the Recent Files list // without adding a very big browser.sleep followed by a page.refresh // so for the moment we're testing that the restored file is not displayed in the Trash - it('Undo delete of file', () => { + xit('Undo delete of file', () => { dataTable.clickOnItemName(recentFile2) .then(() => toolbar.actions.openMoreMenu()) .then(() => toolbar.actions.menu.clickMenuItem('Delete')) @@ -408,7 +408,7 @@ describe('Undo delete content', () => { // we cannot test that the restored file is displayed in the Recent Files list // without adding a very big browser.sleep followed by a page.refresh // so for the moment we're testing that the restored file is not displayed in the Trash - it('undo delete of multiple files', () => { + xit('undo delete of multiple files', () => { dataTable.selectMultipleItems([recentFile3, recentFile4]) .then(() => toolbar.actions.openMoreMenu()) .then(() => toolbar.actions.menu.clickMenuItem('Delete')) diff --git a/e2e/suites/list-views/shared-files.test.ts b/e2e/suites/list-views/shared-files.test.ts index b8168d3c07..b81fc56a99 100755 --- a/e2e/suites/list-views/shared-files.test.ts +++ b/e2e/suites/list-views/shared-files.test.ts @@ -116,7 +116,7 @@ describe('Shared Files', () => { expect(dataTable.getRowName(file2User).isPresent()).toBe(false, `${file2User} is displayed`); }); - it('unshared file is not displayed [C213118]', () => { + xit('unshared file is not displayed [C213118]', () => { expect(dataTable.getRowName(file3User).isPresent()).toBe(false, `${file3User} is displayed`); }); diff --git a/e2e/utilities/repo-client/apis/favorites/favorites-api.ts b/e2e/utilities/repo-client/apis/favorites/favorites-api.ts index 3e92d78387..e2de4f8c4d 100755 --- a/e2e/utilities/repo-client/apis/favorites/favorites-api.ts +++ b/e2e/utilities/repo-client/apis/favorites/favorites-api.ts @@ -82,7 +82,7 @@ export class FavoritesApi extends RepoApi { isFavorite(nodeId: string) { return this.getFavorites() - .then(resp => JSON.stringify(resp.data.list.entries).includes(nodeId)) + .then(resp => JSON.stringify(resp.data.list.entries).includes(nodeId)); } removeFavorite(api: RepoClient, nodeType: string, name: string): Promise { diff --git a/e2e/utilities/utils.ts b/e2e/utilities/utils.ts index 901d8f5a4a..92da973bff 100755 --- a/e2e/utilities/utils.ts +++ b/e2e/utilities/utils.ts @@ -43,20 +43,14 @@ export class Utils { } static retryCall(fn: () => Promise , retry: number = 30, delay: number = 1000): Promise { - const rerun = (retries, fn) => { - fn().catch(err => retries > 1 - ? rerun(retries - 1, fn) - : Promise.reject(err)); - }; - const pause = (duration) => new Promise(res => setTimeout(res, duration)); - const run = (retries, fn, delay = 1000) => + const run = (retries) => fn().catch(err => retries > 1 - ? pause(delay).then(() => run(retries - 1, fn, delay)) + ? pause(delay).then(() => run(retries - 1)) : Promise.reject(err)); - return run(retry, fn); + return run(retry); } static waitUntilElementClickable(element: ElementFinder) { diff --git a/src/app/common/directives/node-copy.directive.spec.ts b/src/app/common/directives/node-copy.directive.spec.ts index e32cd3c9a6..0d26ead0c1 100644 --- a/src/app/common/directives/node-copy.directive.spec.ts +++ b/src/app/common/directives/node-copy.directive.spec.ts @@ -45,7 +45,7 @@ import { DocumentListService } from '@alfresco/adf-content-services'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @Component({ - template: '
' + template: '
' }) class TestComponent { selection; diff --git a/src/app/common/directives/node-copy.directive.ts b/src/app/common/directives/node-copy.directive.ts index 91c61268e5..4256ebc5fb 100644 --- a/src/app/common/directives/node-copy.directive.ts +++ b/src/app/common/directives/node-copy.directive.ts @@ -32,11 +32,12 @@ import { NodeActionsService } from '../services/node-actions.service'; import { ContentManagementService } from '../services/content-management.service'; @Directive({ - selector: '[app-copy-node]' + selector: '[acaCopyNode]' }) export class NodeCopyDirective { - @Input('app-copy-node') + // tslint:disable-next-line:no-input-rename + @Input('acaCopyNode') selection: MinimalNodeEntity[]; @HostListener('click') diff --git a/src/app/common/directives/node-delete.directive.spec.ts b/src/app/common/directives/node-delete.directive.spec.ts index 05cce99df6..16ad941af3 100644 --- a/src/app/common/directives/node-delete.directive.spec.ts +++ b/src/app/common/directives/node-delete.directive.spec.ts @@ -36,7 +36,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @Component({ - template: '
' + template: '
' }) class TestComponent { selection; diff --git a/src/app/common/directives/node-delete.directive.ts b/src/app/common/directives/node-delete.directive.ts index dc76f3ab89..758eb24e9a 100644 --- a/src/app/common/directives/node-delete.directive.ts +++ b/src/app/common/directives/node-delete.directive.ts @@ -32,13 +32,14 @@ import { Observable } from 'rxjs/Rx'; import { ContentManagementService } from '../services/content-management.service'; @Directive({ - selector: '[app-delete-node]' + selector: '[acaDeleteNode]' }) export class NodeDeleteDirective { - static RESTORE_MESSAGE_DURATION: number = 3000; - static DELETE_MESSAGE_DURATION: number = 10000; + static RESTORE_MESSAGE_DURATION = 3000; + static DELETE_MESSAGE_DURATION = 10000; - @Input('app-delete-node') + // tslint:disable-next-line:no-input-rename + @Input('acaDeleteNode') selection: MinimalNodeEntity[]; @HostListener('click') diff --git a/src/app/common/directives/node-download.directive.ts b/src/app/common/directives/node-download.directive.ts index d2a6f4275c..b905e6675f 100644 --- a/src/app/common/directives/node-download.directive.ts +++ b/src/app/common/directives/node-download.directive.ts @@ -23,13 +23,13 @@ import { DownloadZipDialogComponent } from '@alfresco/adf-content-services'; /** @deprecated workaround for the ADF 2.3.0 regression. */ @Directive({ - selector: '[appNodeDownload]' + selector: '[acaNodeDownload]' }) export class NodeDownloadDirective { /** Nodes to download. */ // tslint:disable-next-line:no-input-rename - @Input('appNodeDownload') + @Input('acaNodeDownload') nodes: MinimalNodeEntity[]; @HostListener('click') diff --git a/src/app/common/directives/node-info.directive.spec.ts b/src/app/common/directives/node-info.directive.spec.ts index c063e2e809..5b9784615b 100644 --- a/src/app/common/directives/node-info.directive.spec.ts +++ b/src/app/common/directives/node-info.directive.spec.ts @@ -29,7 +29,7 @@ import { AlfrescoApiService, CoreModule } from '@alfresco/adf-core'; import { NodeInfoDirective } from './node-info.directive'; @Component({ - template: '
' + template: '
' }) class TestComponent { selection; diff --git a/src/app/common/directives/node-info.directive.ts b/src/app/common/directives/node-info.directive.ts index 754b1a7df6..0ecd2ea1e0 100644 --- a/src/app/common/directives/node-info.directive.ts +++ b/src/app/common/directives/node-info.directive.ts @@ -28,12 +28,13 @@ import { AlfrescoApiService } from '@alfresco/adf-core'; import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; @Directive({ - selector: '[app-node-info]', + selector: '[acaNodeInfo]', exportAs: 'nodeInfo' }) export class NodeInfoDirective implements OnInit { - @Input('app-node-info') selection: MinimalNodeEntity[]; + // tslint:disable-next-line:no-input-rename + @Input('acaNodeInfo') selection: MinimalNodeEntity[]; @Output() changed: EventEmitter = new EventEmitter(); @Output() error: EventEmitter = new EventEmitter(); diff --git a/src/app/common/directives/node-move.directive.spec.ts b/src/app/common/directives/node-move.directive.spec.ts index e696998493..cb2ac5b159 100644 --- a/src/app/common/directives/node-move.directive.spec.ts +++ b/src/app/common/directives/node-move.directive.spec.ts @@ -36,7 +36,7 @@ import { NodeMoveDirective } from './node-move.directive'; import { ContentManagementService } from '../services/content-management.service'; @Component({ - template: '
' + template: '
' }) class TestComponent { selection; diff --git a/src/app/common/directives/node-move.directive.ts b/src/app/common/directives/node-move.directive.ts index 812e687ec9..d3fab7451e 100644 --- a/src/app/common/directives/node-move.directive.ts +++ b/src/app/common/directives/node-move.directive.ts @@ -33,11 +33,12 @@ import { NodeActionsService } from '../services/node-actions.service'; import { Observable } from 'rxjs/Rx'; @Directive({ - selector: '[app-move-node]' + selector: '[acaMoveNode]' }) export class NodeMoveDirective { - @Input('app-move-node') + // tslint:disable-next-line:no-input-rename + @Input('acaMoveNode') selection: MinimalNodeEntity[]; @HostListener('click') @@ -86,7 +87,7 @@ export class NodeMoveDirective { // in case of success if (info.toLowerCase().indexOf('succes') !== -1) { - let i18nMessageString = 'APP.MESSAGES.INFO.NODE_MOVE.'; + const i18nMessageString = 'APP.MESSAGES.INFO.NODE_MOVE.'; let i18MessageSuffix = ''; if (succeeded) { diff --git a/src/app/common/directives/node-permanent-delete.directive.spec.ts b/src/app/common/directives/node-permanent-delete.directive.spec.ts index f08ffd5d82..e5246daaa6 100644 --- a/src/app/common/directives/node-permanent-delete.directive.spec.ts +++ b/src/app/common/directives/node-permanent-delete.directive.spec.ts @@ -83,7 +83,7 @@ describe('NodePermanentDeleteDirective', () => { spyOn(dialog, 'open').and.returnValue({ afterClosed() { - return Observable.of(true) + return Observable.of(true); } }); }); diff --git a/src/app/common/directives/node-restore.directive.spec.ts b/src/app/common/directives/node-restore.directive.spec.ts index 68b6cab5f1..8a3958b7a0 100644 --- a/src/app/common/directives/node-restore.directive.spec.ts +++ b/src/app/common/directives/node-restore.directive.spec.ts @@ -36,7 +36,7 @@ import { NodeRestoreDirective } from './node-restore.directive'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @Component({ - template: `
` + template: `
` }) class TestComponent { selection = []; diff --git a/src/app/common/directives/node-restore.directive.ts b/src/app/common/directives/node-restore.directive.ts index 8d16d8a675..2b83ad19c0 100644 --- a/src/app/common/directives/node-restore.directive.ts +++ b/src/app/common/directives/node-restore.directive.ts @@ -31,12 +31,13 @@ import { TranslationService, AlfrescoApiService, NotificationService } from '@al import { MinimalNodeEntity, PathInfoEntity, DeletedNodesPaging } from 'alfresco-js-api'; @Directive({ - selector: '[app-restore-node]' + selector: '[acaRestoreNode]' }) export class NodeRestoreDirective { private restoreProcessStatus; - @Input('app-restore-node') + // tslint:disable-next-line:no-input-rename + @Input('acaRestoreNode') selection: MinimalNodeEntity[]; @HostListener('click') diff --git a/src/app/common/directives/node-unshare.directive.ts b/src/app/common/directives/node-unshare.directive.ts index abd6f2b71c..75f4af345d 100644 --- a/src/app/common/directives/node-unshare.directive.ts +++ b/src/app/common/directives/node-unshare.directive.ts @@ -28,12 +28,12 @@ import { AlfrescoApiService } from '@alfresco/adf-core'; import { MinimalNodeEntity } from 'alfresco-js-api'; @Directive({ - selector: '[appUnshareNode]' + selector: '[acaUnshareNode]' }) export class NodeUnshareDirective { // tslint:disable-next-line:no-input-rename - @Input('appUnshareNode') + @Input('acaUnshareNode') selection: MinimalNodeEntity[]; constructor( diff --git a/src/app/common/directives/node-versions.directive.ts b/src/app/common/directives/node-versions.directive.ts index f822e1b828..169e114c17 100644 --- a/src/app/common/directives/node-versions.directive.ts +++ b/src/app/common/directives/node-versions.directive.ts @@ -32,11 +32,12 @@ import { VersionManagerDialogAdapterComponent } from '../../components/versions- import { MatDialog } from '@angular/material'; @Directive({ - selector: '[app-node-versions]' + selector: '[acaNodeVersions]' }) export class NodeVersionsDirective { - @Input('app-node-versions') + // tslint:disable-next-line:no-input-rename + @Input('acaNodeVersions') selection: MinimalNodeEntity[]; @Output() diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 19c57a87a6..8bce8ff2d4 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -68,21 +68,21 @@ @@ -90,7 +90,7 @@ @@ -180,7 +180,7 @@
diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index 0fd10629e9..54dca3a633 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -70,7 +70,7 @@ @@ -78,7 +78,7 @@ @@ -86,7 +86,7 @@ @@ -94,7 +94,7 @@ @@ -183,7 +183,7 @@
diff --git a/src/app/components/preview/preview.component.html b/src/app/components/preview/preview.component.html index 585cec05b8..236345b5ff 100644 --- a/src/app/components/preview/preview.component.html +++ b/src/app/components/preview/preview.component.html @@ -48,7 +48,7 @@ @@ -56,7 +56,7 @@ @@ -72,7 +72,7 @@ diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 18aa9a7dba..77255f50af 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -58,7 +58,7 @@ @@ -66,7 +66,7 @@ @@ -74,7 +74,7 @@ @@ -82,7 +82,7 @@ @@ -168,7 +168,7 @@
diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index a6705935f5..87bcbd565e 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -18,7 +18,7 @@ mat-icon-button *ngIf="hasSelection(documentList.selection)" title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}" - [appNodeDownload]="documentList.selection"> + [acaNodeDownload]="documentList.selection"> get_app @@ -57,7 +57,7 @@ @@ -65,7 +65,7 @@ @@ -73,7 +73,7 @@ @@ -90,7 +90,7 @@ @@ -185,7 +185,7 @@
diff --git a/src/app/components/shared-files/shared-files.component.spec.ts b/src/app/components/shared-files/shared-files.component.spec.ts index 8c4371f8ff..6a1030df89 100644 --- a/src/app/components/shared-files/shared-files.component.spec.ts +++ b/src/app/components/shared-files/shared-files.component.spec.ts @@ -33,7 +33,7 @@ import { NodesApiService, AlfrescoApiService, ContentService, UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, AuthenticationService, - TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective,DataTableComponent + TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent } from '@alfresco/adf-core'; import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; import { TranslateModule } from '@ngx-translate/core'; diff --git a/src/app/components/trashcan/trashcan.component.html b/src/app/components/trashcan/trashcan.component.html index 109c57a0fa..2e32e80c0a 100644 --- a/src/app/components/trashcan/trashcan.component.html +++ b/src/app/components/trashcan/trashcan.component.html @@ -18,7 +18,7 @@ color="primary" mat-icon-button (selection-node-restored)="refresh()" - [app-restore-node]="documentList.selection" + [acaRestoreNode]="documentList.selection" *ngIf="documentList.selection.length" title="{{ 'APP.ACTIONS.RESTORE' | translate }}"> restore diff --git a/tslint.json b/tslint.json index b6e591b2b7..34eed5a450 100644 --- a/tslint.json +++ b/tslint.json @@ -103,7 +103,6 @@ "variable-declaration": "nospace" } ], - "typeof-compare": true, "unified-signatures": true, "variable-name": false, "whitespace": [ @@ -117,7 +116,7 @@ "directive-selector": [ true, "attribute", - "app", + "aca", "camelCase" ], "component-selector": [ @@ -134,7 +133,6 @@ "use-life-cycle-interface": true, "use-pipe-transform-interface": true, "component-class-suffix": true, - "directive-class-suffix": true, - "invoke-injectable": true + "directive-class-suffix": true } } From e40b7f748902e5cfc427f0d2eae80643b7208e17 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 30 Apr 2018 12:42:51 +0100 Subject: [PATCH 013/179] fix PR template --- .github/PULL_REQUEST_TEMPLATE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7f29dd9c02..5ccd541087 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,10 +1,11 @@ ## PR Checklist Please check if your PR fulfills the following requirements: +``` - [ ] The commit message follows our guidelines: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md#commit - [ ] Tests for the changes have been added (for bug fixes / features) - [ ] Docs have been added / updated (for bug fixes / features) - +``` ## PR Type What kind of change does this PR introduce? From 549abeb5575ef75c53de09d4571076d2601e4cf3 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 30 Apr 2018 17:14:52 +0300 Subject: [PATCH 014/179] [ACA-1328] Use ADF Pagination in Personal Files and Libraries (#340) --- .../favorites/favorites.component.html | 14 +- src/app/components/files/files.component.html | 18 +- .../components/files/files.component.spec.ts | 168 ++++++------------ src/app/components/files/files.component.ts | 56 ++---- .../libraries/libraries.component.html | 14 +- src/app/components/page.component.spec.ts | 54 ------ src/app/components/page.component.ts | 25 +-- .../recent-files/recent-files.component.html | 14 +- .../shared-files/shared-files.component.html | 14 +- .../trashcan/trashcan.component.html | 14 +- .../ui/overrides/_alfresco-document-list.scss | 16 +- 11 files changed, 112 insertions(+), 295 deletions(-) diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 8bce8ff2d4..3378d3ed67 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -98,7 +98,7 @@
-
+
- - - - + +
-
+
- - - - + +
diff --git a/src/app/components/files/files.component.spec.ts b/src/app/components/files/files.component.spec.ts index 04c960c0bd..edefece616 100644 --- a/src/app/components/files/files.component.spec.ts +++ b/src/app/components/files/files.component.spec.ts @@ -24,7 +24,7 @@ */ import { Observable } from 'rxjs/Rx'; -import { TestBed, async } from '@angular/core/testing'; +import { TestBed, async, fakeAsync, tick } from '@angular/core/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; @@ -138,55 +138,62 @@ describe('FilesComponent', () => { pagination: {} } }; + + spyOn(component.documentList, 'loadFolder').and.callFake(() => {}); }); - describe('OnInit', () => { - it('set current node', () => { + describe('Current page is valid', () => { + it('should be a valid current page', fakeAsync(() => { spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); - spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); + spyOn(component, 'fetchNodes').and.returnValue(Observable.throw(null)); + component.ngOnInit(); fixture.detectChanges(); + tick(); - expect(component.node).toBe(node); - }); + expect(component.isValidPath).toBe(false); + })); - it('get current node children', () => { + it('should set current page as invalid path', fakeAsync(() => { spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); + component.ngOnInit(); + tick(); fixture.detectChanges(); - expect(component.paging).toBe(page); - }); + expect(component.isValidPath).toBe(true); + })); + }); - it('emits onChangeParent event', () => { + describe('OnInit', () => { + it('should set current node', () => { spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); - spyOn(browsingFilesService.onChangeParent, 'next').and.callFake((val) => val); fixture.detectChanges(); - expect(browsingFilesService.onChangeParent.next) - .toHaveBeenCalledWith(node); + expect(component.node).toBe(node); }); - it('raise error when fetchNode() fails', () => { - spyOn(component, 'fetchNode').and.returnValue(Observable.throw(null)); - spyOn(component, 'onFetchError'); + it('should get current node children', () => { + spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); fixture.detectChanges(); - expect(component.onFetchError).toHaveBeenCalled(); + expect(component.fetchNodes).toHaveBeenCalled(); }); - it('raise error when fetchNodes() fails', () => { + it('emits onChangeParent event', () => { spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); - spyOn(component, 'fetchNodes').and.returnValue(Observable.throw(null)); - spyOn(component, 'onFetchError'); + spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); + spyOn(browsingFilesService.onChangeParent, 'next').and.callFake((val) => val); fixture.detectChanges(); - expect(component.onFetchError).toHaveBeenCalled(); + expect(browsingFilesService.onChangeParent.next) + .toHaveBeenCalledWith(node); }); it('if should navigate to parent if node is not a folder', () => { @@ -205,12 +212,12 @@ describe('FilesComponent', () => { beforeEach(() => { spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); - spyOn(component, 'load'); + spyOn(component.documentList, 'reload'); fixture.detectChanges(); }); - it('calls refresh onContentCopied event if parent is the same', () => { + it('should call refresh onContentCopied event if parent is the same', () => { const nodes = [ { entry: { parentId: '1' } }, { entry: { parentId: '2' } } @@ -220,10 +227,10 @@ describe('FilesComponent', () => { nodeActionsService.contentCopied.next(nodes); - expect(component.load).toHaveBeenCalled(); + expect(component.documentList.reload).toHaveBeenCalled(); }); - it('does not call refresh onContentCopied event when parent mismatch', () => { + it('should not call refresh onContentCopied event when parent mismatch', () => { const nodes = [ { entry: { parentId: '1' } }, { entry: { parentId: '2' } } @@ -233,73 +240,73 @@ describe('FilesComponent', () => { nodeActionsService.contentCopied.next(nodes); - expect(component.load).not.toHaveBeenCalled(); + expect(component.documentList.reload).not.toHaveBeenCalled(); }); - it('calls refresh onCreateFolder event', () => { + it('should call refresh onCreateFolder event', () => { alfrescoContentService.folderCreate.next(); - expect(component.load).toHaveBeenCalled(); + expect(component.documentList.reload).toHaveBeenCalled(); }); - it('calls refresh editFolder event', () => { + it('should call refresh editFolder event', () => { alfrescoContentService.folderEdit.next(); - expect(component.load).toHaveBeenCalled(); + expect(component.documentList.reload).toHaveBeenCalled(); }); - it('calls refresh deleteNode event', () => { + it('should call refresh deleteNode event', () => { contentManagementService.nodeDeleted.next(); - expect(component.load).toHaveBeenCalled(); + expect(component.documentList.reload).toHaveBeenCalled(); }); - it('calls refresh moveNode event', () => { + it('should call refresh moveNode event', () => { contentManagementService.nodeMoved.next(); - expect(component.load).toHaveBeenCalled(); + expect(component.documentList.reload).toHaveBeenCalled(); }); - it('calls refresh restoreNode event', () => { + it('should call refresh restoreNode event', () => { contentManagementService.nodeRestored.next(); - expect(component.load).toHaveBeenCalled(); + expect(component.documentList.reload).toHaveBeenCalled(); }); - it('calls refresh on fileUploadComplete event if parent node match', () => { + it('should call refresh on fileUploadComplete event if parent node match', () => { const file = { file: { options: { parentId: 'parentId' } } }; component.node = { id: 'parentId' }; uploadService.fileUploadComplete.next(file); - expect(component.load).toHaveBeenCalled(); + expect(component.documentList.reload).toHaveBeenCalled(); }); - it('does not call refresh on fileUploadComplete event if parent mismatch', () => { + it('should not call refresh on fileUploadComplete event if parent mismatch', () => { const file = { file: { options: { parentId: 'otherId' } } }; component.node = { id: 'parentId' }; uploadService.fileUploadComplete.next(file); - expect(component.load).not.toHaveBeenCalled(); + expect(component.documentList.reload).not.toHaveBeenCalled(); }); - it('calls refresh on fileUploadDeleted event if parent node match', () => { + it('should call refresh on fileUploadDeleted event if parent node match', () => { const file = { file: { options: { parentId: 'parentId' } } }; component.node = { id: 'parentId' }; uploadService.fileUploadDeleted.next(file); - expect(component.load).toHaveBeenCalled(); + expect(component.documentList.reload).toHaveBeenCalled(); }); - it('does not call refresh on fileUploadDeleted event if parent mismatch', () => { + it('should not call refresh on fileUploadDeleted event if parent mismatch', () => { const file = { file: { options: { parentId: 'otherId' } } }; component.node = { id: 'parentId' }; uploadService.fileUploadDeleted.next(file); - expect(component.load).not.toHaveBeenCalled(); + expect(component.documentList.reload).not.toHaveBeenCalled(); }); }); @@ -311,7 +318,7 @@ describe('FilesComponent', () => { fixture.detectChanges(); }); - it('calls getNode api with node id', () => { + it('should call getNode api with node id', () => { component.fetchNode('nodeId'); expect(nodesApi.getNode).toHaveBeenCalledWith('nodeId'); @@ -326,7 +333,7 @@ describe('FilesComponent', () => { fixture.detectChanges(); }); - it('calls getNode api with node id', () => { + it('should call getNode api with node id', () => { component.fetchNodes('nodeId'); expect(nodesApi.getNodeChildren).toHaveBeenCalledWith('nodeId', jasmine.any(Object)); @@ -341,7 +348,7 @@ describe('FilesComponent', () => { fixture.detectChanges(); }); - it('opens preview if node is file', () => { + it('should open preview if node is file', () => { spyOn(router, 'navigate').and.stub(); node.isFile = true; node.isFolder = false; @@ -358,7 +365,7 @@ describe('FilesComponent', () => { expect(router.navigate['calls'].argsFor(0)[0]).toEqual(['./preview', node.id]); }); - it('navigate if node is folder', () => { + it('should navigate if node is folder', () => { spyOn(component, 'navigate').and.stub(); node.isFolder = true; @@ -376,63 +383,6 @@ describe('FilesComponent', () => { }); }); - describe('load()', () => { - let fetchNodesSpy; - - beforeEach(() => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); - fetchNodesSpy = spyOn(component, 'fetchNodes'); - - fetchNodesSpy.and.returnValue(Observable.of(page)); - - fixture.detectChanges(); - }); - - afterEach(() => { - fetchNodesSpy.calls.reset(); - }); - - it('shows load indicator', () => { - spyOn(component, 'onPageLoaded'); - component.node = { id: 'currentNode' }; - - expect(component.isLoading).toBe(false); - - component.load(true); - - expect(component.isLoading).toBe(true); - }); - - it('does not show load indicator', () => { - spyOn(component, 'onPageLoaded'); - component.node = { id: 'currentNode' }; - - expect(component.isLoading).toBe(false); - - component.load(); - - expect(component.isLoading).toBe(false); - }); - - it('sets data on success', () => { - component.node = { id: 'currentNode' }; - - component.load(); - - expect(component.paging).toBe(page); - expect(component.pagination).toEqual(page.list.pagination); - }); - - it('raise error on fail', () => { - fetchNodesSpy.and.returnValue(Observable.throw(null)); - spyOn(component, 'onFetchError'); - - component.load(); - - expect(component.onFetchError).toHaveBeenCalled(); - }); - }); - describe('onBreadcrumbNavigate()', () => { beforeEach(() => { spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); @@ -441,7 +391,7 @@ describe('FilesComponent', () => { fixture.detectChanges(); }); - it('navigates to node id', () => { + it('should navigates to node id', () => { const routeData = { id: 'some-where-over-the-rainbow' }; spyOn(component, 'navigate'); @@ -460,19 +410,19 @@ describe('FilesComponent', () => { fixture.detectChanges(); }); - it('navigates to node when id provided', () => { + it('should navigates to node when id provided', () => { component.navigate(node.id); expect(router.navigate).toHaveBeenCalledWith(['./', node.id], jasmine.any(Object)); }); - it('navigates to home when id not provided', () => { + it('should navigates to home when id not provided', () => { component.navigate(); expect(router.navigate).toHaveBeenCalledWith(['./'], jasmine.any(Object)); }); - it('it navigate home if node is root', () => { + it('should navigate home if node is root', () => { (component).node = { path: { elements: [ {id: 'node-id'} ] diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index 8eab1d700c..86018017b6 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -24,7 +24,7 @@ */ import { Observable, Subscription } from 'rxjs/Rx'; -import { Component, OnInit, OnDestroy, NgZone } from '@angular/core'; +import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { MinimalNodeEntity, MinimalNodeEntryEntity, PathElementEntity, NodePaging, PathElement } from 'alfresco-js-api'; import { @@ -32,6 +32,8 @@ import { ContentService, AlfrescoApiService, UserPreferencesService, NotificationService } from '@alfresco/adf-core'; +import { DocumentListComponent } from '@alfresco/adf-content-services'; + import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodeActionsService } from '../../common/services/node-actions.service'; @@ -43,6 +45,7 @@ import { PageComponent } from '../page.component'; templateUrl: './files.component.html' }) export class FilesComponent extends PageComponent implements OnInit, OnDestroy { + @ViewChild(DocumentListComponent) documentList: DocumentListComponent; isValidPath = true; @@ -52,7 +55,6 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { sorting = [ 'modifiedAt', 'desc' ]; constructor(private router: Router, - private zone: NgZone, private route: ActivatedRoute, private nodesApi: NodesApiService, private nodeActionsService: NodeActionsService, @@ -80,7 +82,6 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { route.params.subscribe(({ folderId }: Params) => { const nodeId = folderId || data.defaultNodeId; - this.isLoading = true; this.fetchNode(nodeId) .do((node) => { @@ -95,22 +96,20 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { .subscribe( (page) => { this.isValidPath = true; - this.onPageLoaded(page); }, error => { this.isValidPath = false; - this.onFetchError(error); } ); }); this.subscriptions = this.subscriptions.concat([ nodeActionsService.contentCopied.subscribe((nodes) => this.onContentCopied(nodes)), - contentService.folderCreate.subscribe(() => this.load(false, this.pagination)), - contentService.folderEdit.subscribe(() => this.load(false, this.pagination)), - contentManagementService.nodeDeleted.subscribe(() => this.load(false, this.pagination)), - contentManagementService.nodeMoved.subscribe(() => this.load(false, this.pagination)), - contentManagementService.nodeRestored.subscribe(() => this.load(false, this.pagination)), + contentService.folderCreate.subscribe(() => this.documentList.reload()), + contentService.folderEdit.subscribe(() => this.documentList.reload()), + contentManagementService.nodeDeleted.subscribe(() => this.documentList.reload()), + contentManagementService.nodeMoved.subscribe(() => this.documentList.reload()), + contentManagementService.nodeRestored.subscribe(() => this.documentList.reload()), uploadService.fileUploadComplete.subscribe(file => this.onFileUploadedEvent(file)), uploadService.fileUploadDeleted.subscribe((file) => this.onFileUploadedEvent(file)) ]); @@ -189,7 +188,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { onFileUploadedEvent(event: FileUploadEvent) { if (event && event.file.options.parentId === this.getParentNodeId()) { - this.load(false, this.pagination); + this.documentList.reload(); } } @@ -199,43 +198,10 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { return node && node.entry && node.entry.parentId === this.getParentNodeId(); }); if (newNode) { - this.load(false, this.pagination); + this.documentList.reload(); } } - load(showIndicator: boolean = false, options: { maxItems?: number, skipCount?: number } = {}) { - this.isLoading = showIndicator; - - this.fetchNodes(this.getParentNodeId(), options) - .flatMap((page) => { - if (this.isCurrentPageEmpty(page) && this.isNotFirstPage(page)) { - const newSkipCount = options.skipCount - options.maxItems; - - return this.fetchNodes(this.getParentNodeId(), { - skipCount: newSkipCount, maxItems: options.maxItems - }); - } - - return Observable.of(page); - }) - .subscribe( - (page) => this.zone.run(() => this.onPageLoaded(page)), - error => this.onFetchError(error) - ); - } - - isCurrentPageEmpty(page): boolean { - return !this.hasPageEntries(page); - } - - hasPageEntries(page): boolean { - return page && page.list && page.list.entries && page.list.entries.length > 0; - } - - isNotFirstPage(page): boolean { - return (page.list.pagination.skipCount >= page.list.pagination.maxItems); - } - // todo: review this approach once 5.2.3 is out private async updateCurrentNode(node: MinimalNodeEntryEntity) { this.nodePath = null; diff --git a/src/app/components/libraries/libraries.component.html b/src/app/components/libraries/libraries.component.html index aed07e6e6a..60c2798281 100644 --- a/src/app/components/libraries/libraries.component.html +++ b/src/app/components/libraries/libraries.component.html @@ -7,7 +7,7 @@
-
+
- - - - + +
diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index 0b1f78e95c..7b1539f02c 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -58,60 +58,6 @@ describe('PageComponent', () => { }); }); - describe('onFetchError()', () => { - it('sets isLoading state to false', () => { - component.isLoading = true; - - component.onFetchError(); - - expect(component.isLoading).toBe(false); - }); - }); - - describe('onPaginationChange()', () => { - it('fetch children nodes for current node id', () => { - component.node = { id: 'node-id' }; - spyOn(component, 'fetchNodes').and.stub(); - - component.onPaginationChange({pagination: 'pagination-data'}); - - expect(component.fetchNodes).toHaveBeenCalledWith('node-id', { pagination: 'pagination-data' }); - }); - }); - - describe('onPageLoaded()', () => { - let page; - - beforeEach(() => { - page = { - list: { - entries: ['a', 'b', 'c'], - pagination: {} - } - }; - - component.isLoading = true; - component.isEmpty = true; - component.onPageLoaded(page); - }); - - it('sets isLoading state to false', () => { - expect(component.isLoading).toBe(false); - }); - - it('sets component paging data', () => { - expect(component.paging).toBe(page); - }); - - it('sets component pagination data', () => { - expect(component.pagination).toEqual(page.list.pagination); - }); - - it('sets component isEmpty state', () => { - expect(component.isEmpty).toBe(false); - }); - }); - describe('hasSelection()', () => { it('returns true when it has nodes selected', () => { const hasSelection = component.hasSelection([ {}, {} ]); diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 2c66c376bd..2cc52f67ec 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -23,21 +23,13 @@ * along with Alfresco. If not, see . */ -import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api'; +import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco-js-api'; import { UserPreferencesService } from '@alfresco/adf-core'; import { ShareDataRow } from '@alfresco/adf-content-services'; export abstract class PageComponent { - title = 'Page'; - - isLoading = false; - isEmpty = true; infoDrawerOpened = false; - - paging: NodePaging; - pagination: Pagination; - node: MinimalNodeEntryEntity; static isLockedNode(node) { @@ -49,25 +41,10 @@ export abstract class PageComponent { constructor(protected preferences: UserPreferencesService) { } - onFetchError(error: any) { - this.isLoading = false; - } - getParentNodeId(): string { return this.node ? this.node.id : null; } - onPaginationChange(pagination: any) { - this.fetchNodes(this.getParentNodeId(), pagination); - } - - onPageLoaded(page: NodePaging) { - this.isLoading = false; - this.paging = page; - this.pagination = { ...page.list.pagination }; - this.isEmpty = !(page.list.entries && page.list.entries.length > 0); - } - hasSelection(selection: Array): boolean { return selection && selection.length > 0; } diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 77255f50af..1d993701ba 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -91,7 +91,7 @@
-
+
- - - - + +
-
+
- - - - + +
-
+
- - - - + +
diff --git a/src/app/ui/overrides/_alfresco-document-list.scss b/src/app/ui/overrides/_alfresco-document-list.scss index 43846d3a4a..94f837fa8a 100644 --- a/src/app/ui/overrides/_alfresco-document-list.scss +++ b/src/app/ui/overrides/_alfresco-document-list.scss @@ -6,18 +6,6 @@ adf-document-list { background-color: white; // TODO: remove when ADF 2.4.0 is out. } -.adf-document-list--loading { - .adf-data-table { - @include flex-column; - justify-content: center; - align-items: center; - } - - .adf-datatable-table-cell { - border: none !important; - } -} - adf-datatable { @include flex-column; overflow-y: scroll; @@ -99,3 +87,7 @@ adf-datatable { cursor: default; } } + +.adf-pagination__empty { + display: none; +} From 9984fa2bd1068c8ff237229768535e987c93b2c1 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 2 May 2018 09:44:32 +0100 Subject: [PATCH 015/179] upgrade to latest ADF alpha (#341) * upgrade to latest ADF alpha * upgrade to newer alpha * fix search pagination * disable slow test --- .../actions/toolbar-single-selection.test.ts | 2 +- package-lock.json | 32 +--- package.json | 4 +- src/app.config.json | 169 ++++++++++-------- .../components/search/search.component.html | 10 +- src/app/components/search/search.component.ts | 2 +- 6 files changed, 104 insertions(+), 115 deletions(-) diff --git a/e2e/suites/actions/toolbar-single-selection.test.ts b/e2e/suites/actions/toolbar-single-selection.test.ts index 0ae7ad4f78..5c9dc25aee 100755 --- a/e2e/suites/actions/toolbar-single-selection.test.ts +++ b/e2e/suites/actions/toolbar-single-selection.test.ts @@ -184,7 +184,7 @@ describe('Toolbar actions - single selection : ', () => { .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); }); - it('on Shared Files', () => { + xit('on Shared Files', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) .then(() => dataTable.waitForHeader()) .then(() => dataTable.clickOnItemName(file1)) diff --git a/package-lock.json b/package-lock.json index b5c4353bba..951991325f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d.tgz", - "integrity": "sha512-EHYvODiv3w12jbPCZacFSQ2fhwx5FVdmidsU+3ngWWXELjXuWIFhUWv02nEw3BBDO0xA/UkC2D4ASN0GVNNlyA==", + "version": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46.tgz", + "integrity": "sha512-ge3RMlfrt+U1GEt5sksxKP3RLdZ1JjMguE8HsQk8l0Nq/DXRRkpLMJd0g2+AOZ0BpmtlCmZYHlmVJ9u39cLfBw==", "requires": { - "@alfresco/adf-core": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", + "@alfresco/adf-core": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -40,15 +40,6 @@ "zone.js": "0.8.14" }, "dependencies": { - "alfresco-js-api": { - "version": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de.tgz", - "integrity": "sha512-8d9H4fY7rxPoSpDa42EqI9D0lg1AOQOnkP+0Qz1jkS7w/otsOcCT29jlo5Y1avwscS+QNrwo+RMTaVdGnxwqAA==", - "requires": { - "event-emitter": "0.3.4", - "superagent": "3.8.2" - } - }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -70,9 +61,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d.tgz", - "integrity": "sha512-cvu/PPHcXW0v9dPJ3EMGmEqIJLH+RkwkkvVWpz3v0Zck0y9KRuXkqxOIOoUJwm1AAwPdbyKxDcKFNxpXZ+EdoQ==", + "version": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46.tgz", + "integrity": "sha512-iNUd6jvRJssQzYXmB2y+sKaXTDk6miu3u6IZYOgLoZxqbsn91msyMLHDMmVEN0EEnHAVREBspAxvi2wEvZ4Lvw==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -104,15 +95,6 @@ "zone.js": "0.8.14" }, "dependencies": { - "alfresco-js-api": { - "version": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de.tgz", - "integrity": "sha512-8d9H4fY7rxPoSpDa42EqI9D0lg1AOQOnkP+0Qz1jkS7w/otsOcCT29jlo5Y1avwscS+QNrwo+RMTaVdGnxwqAA==", - "requires": { - "event-emitter": "0.3.4", - "superagent": "3.8.2" - } - }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", diff --git a/package.json b/package.json index 5b57b0b4a8..337b83f09f 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", - "@alfresco/adf-core": "2.4.0-b18b041ade818cb8afe681649c1ac1293f6e860d", + "@alfresco/adf-content-services": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", + "@alfresco/adf-core": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", diff --git a/src/app.config.json b/src/app.config.json index 111986f786..0378eb0816 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -154,19 +154,17 @@ }, "search": { "include": ["path", "allowableOperations"], - "fields": [], "filterQueries": [ { "query": "TYPE:'cm:folder' OR TYPE:'cm:content'" }, { "query": "NOT cm:creator:System" } ], - "facetFields": { - "facets": [ - { "field": "content.mimetype", "mincount": 1, "label": "Type" }, - { "field": "content.size", "mincount": 1, "label": "Size" }, - { "field": "creator", "mincount": 1, "label": "Creator" }, - { "field": "modifier", "mincount": 1, "label": "Modifier" } - ] - }, + "facetFields": [ + { "field": "content.mimetype", "mincount": 1, "label": "Type" }, + { "field": "content.size", "mincount": 1, "label": "Size" }, + { "field": "creator", "mincount": 1, "label": "Creator" }, + { "field": "modifier", "mincount": 1, "label": "Modifier" }, + { "field": "created", "mincount": 1, "label": "Created" } + ], "facetQueries": [ { "query": "created:2018", "label": "Created This Year" }, { "query": "content.mimetype", "label": "Type" }, @@ -195,80 +193,93 @@ "label": "Size: XX large" } ], - "query": { - "categories": [ - { - "id": "queryName", - "name": "Name", - "enabled": true, - "expanded": true, - "component": { - "selector": "text", - "settings": { - "pattern": "cm:name:'(.*?)'", - "field": "cm:name", - "placeholder": "Enter the name" - } + "categories": [ + { + "id": "queryName", + "name": "Name", + "enabled": true, + "expanded": true, + "component": { + "selector": "text", + "settings": { + "pattern": "cm:name:'(.*?)'", + "field": "cm:name", + "placeholder": "Enter the name" } - }, - { - "id": "contentSize", - "name": "Content Size", - "enabled": true, - "component": { - "selector": "slider", - "settings": { - "field": "cm:content.size", - "min": 0, - "max": 18, - "step": 1, - "thumbLabel": true - } + } + }, + { + "id": "checkList", + "name": "Check List", + "enabled": true, + "component": { + "selector": "check-list", + "settings": { + "operator": "OR", + "options": [ + { "name": "Folder", "value": "TYPE:'cm:folder'" }, + { "name": "Document", "value": "TYPE:'cm:content'" } + ] } - }, - { - "id": "contentSizeRange", - "name": "Content Size (range)", - "enabled": true, - "component": { - "selector": "number-range", - "settings": { - "field": "cm:content.size" - } + } + }, + { + "id": "contentSize", + "name": "Content Size", + "enabled": true, + "component": { + "selector": "slider", + "settings": { + "field": "cm:content.size", + "min": 0, + "max": 18, + "step": 1, + "thumbLabel": true } - }, - { - "id": "queryType", - "name": "Type", - "enabled": true, - "component": { - "selector": "radio", - "settings": { - "field": null, - "options": [ - { - "name": "None", - "value": "", - "default": true - }, - { - "name": "All", - "value": - "TYPE:'cm:folder' OR TYPE:'cm:content'" - }, - { - "name": "Folder", - "value": "TYPE:'cm:folder'" - }, - { - "name": "Document", - "value": "TYPE:'cm:content'" - } - ] - } + } + }, + { + "id": "contentSizeRange", + "name": "Content Size (range)", + "enabled": true, + "component": { + "selector": "number-range", + "settings": { + "field": "cm:content.size" } } - ] - } + }, + { + "id": "createdDateRange", + "name": "Created Date (range)", + "enabled": true, + "component": { + "selector": "date-range", + "settings": { + "field": "cm:created" + } + } + }, + { + "id": "queryType", + "name": "Type", + "enabled": true, + "component": { + "selector": "radio", + "settings": { + "field": null, + "options": [ + { "name": "None", "value": "", "default": true }, + { + "name": "All", + "value": "TYPE:'cm:folder' OR TYPE:'cm:content'" + }, + { "name": "Folder", "value": "TYPE:'cm:folder'" }, + { "name": "Document", "value": "TYPE:'cm:content'" } + ] + } + } + } + ] } } diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 18aa4ac044..a132eba678 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -7,15 +7,11 @@
- - +
- - +
+ (change)="onPaginationChanged($event)">
diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index 645668776a..87ce6f8980 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -68,7 +68,7 @@ export class SearchComponent implements OnInit { this.data = nodePaging; } - onRefreshPagination(pagination: Pagination) { + onPaginationChanged(pagination: Pagination) { this.maxItems = pagination.maxItems; this.skipCount = pagination.skipCount; From 753f0bfb46509da9c42240c9913ae56b3312a526 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 3 May 2018 09:22:51 +0100 Subject: [PATCH 016/179] remove "download node" workaround for shared links (#342) --- src/app/app.module.ts | 5 +- .../directives/node-download.directive.ts | 126 ------------------ .../shared-files/shared-files.component.html | 2 +- 3 files changed, 2 insertions(+), 131 deletions(-) delete mode 100644 src/app/common/directives/node-download.directive.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 8c17e443a7..f286904467 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -67,7 +67,6 @@ import { NodeActionsService } from './common/services/node-actions.service'; import { NodePermissionService } from './common/services/node-permission.service'; import { MatMenuModule, MatIconModule, MatButtonModule, MatDialogModule, MatInputModule } from '@angular/material'; import { SearchComponent } from './components/search/search.component'; -import { NodeDownloadDirective } from './common/directives/node-download.directive'; @NgModule({ imports: [ @@ -116,9 +115,7 @@ import { NodeDownloadDirective } from './common/directives/node-download.directi NodeVersionsDirective, AppConfigPipe, VersionManagerDialogAdapterComponent, - SearchComponent, - // Workarounds for ADF 2.3.0 - NodeDownloadDirective + SearchComponent ], providers: [ { diff --git a/src/app/common/directives/node-download.directive.ts b/src/app/common/directives/node-download.directive.ts deleted file mode 100644 index b905e6675f..0000000000 --- a/src/app/common/directives/node-download.directive.ts +++ /dev/null @@ -1,126 +0,0 @@ -/*! - * @license - * Copyright 2016 Alfresco Software, Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Directive, Input, HostListener } from '@angular/core'; -import { MatDialog } from '@angular/material'; -import { MinimalNodeEntity } from 'alfresco-js-api'; -import { AlfrescoApiService } from '@alfresco/adf-core'; -import { DownloadZipDialogComponent } from '@alfresco/adf-content-services'; - -/** @deprecated workaround for the ADF 2.3.0 regression. */ -@Directive({ - selector: '[acaNodeDownload]' -}) -export class NodeDownloadDirective { - - /** Nodes to download. */ - // tslint:disable-next-line:no-input-rename - @Input('acaNodeDownload') - nodes: MinimalNodeEntity[]; - - @HostListener('click') - onClick() { - this.downloadNodes(this.nodes); - } - - constructor( - private apiService: AlfrescoApiService, - private dialog: MatDialog) { - } - - /** - * Downloads multiple selected nodes. - * Packs result into a .ZIP archive if there is more than one node selected. - * @param selection Multiple selected nodes to download - */ - downloadNodes(selection: Array) { - if (!selection || selection.length === 0) { - return; - } - - if (selection.length === 1) { - this.downloadNode(selection[0]); - } else { - this.downloadZip(selection); - } - } - - /** - * Downloads a single node. - * Packs result into a .ZIP archive is the node is a Folder. - * @param node Node to download - */ - downloadNode(node: MinimalNodeEntity) { - if (node && node.entry) { - const entry = node.entry; - - if (entry.isFile) { - this.downloadFile(node); - } - - if (entry.isFolder) { - this.downloadZip([node]); - } - - // Check if there's nodeId for Shared Files - if (!entry.isFile && !entry.isFolder && ( entry).nodeId) { - this.downloadFile(node); - } - } - } - - private downloadFile(node: MinimalNodeEntity) { - if (node && node.entry) { - const contentApi = this.apiService.getInstance().content; - const id = ( node.entry).nodeId || node.entry.id; - - const url = contentApi.getContentUrl(id, true); - const fileName = node.entry.name; - - this.download(url, fileName); - } - } - - private downloadZip(selection: Array) { - if (selection && selection.length > 0) { - // nodeId for Shared node - const nodeIds = selection.map((node: any) => (node.entry.nodeId || node.entry.id)); - - this.dialog.open(DownloadZipDialogComponent, { - width: '600px', - disableClose: true, - data: { - nodeIds - } - }); - } - } - - private download(url: string, fileName: string) { - if (url && fileName) { - const link = document.createElement('a'); - - link.style.display = 'none'; - link.download = fileName; - link.href = url; - - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - } - } -} diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index f36f78535e..7e85ca8045 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -18,7 +18,7 @@ mat-icon-button *ngIf="hasSelection(documentList.selection)" title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}" - [acaNodeDownload]="documentList.selection"> + [adfNodeDownload]="documentList.selection"> get_app From fa14bffc1ceeb6fb26ec756b2f246f6eabc6d596 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 3 May 2018 12:11:32 +0100 Subject: [PATCH 017/179] login enhancements (#343) --- src/app.config.json | 3 +- src/app/components/login/login.component.html | 6 +-- .../components/login/login.component.spec.ts | 37 +++++-------------- src/app/components/login/login.component.ts | 13 +------ 4 files changed, 15 insertions(+), 44 deletions(-) diff --git a/src/app.config.json b/src/app.config.json index 0378eb0816..26f08d7ae1 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -2,7 +2,8 @@ "ecmHost": "http://{hostname}{:port}", "application": { "name": "Alfresco Example Content Application", - "logo": "assets/images/alfresco-logo-white.svg" + "logo": "assets/images/alfresco-logo-white.svg", + "copyright": "© 2017 - 2018 Alfresco Software, Inc. All rights reserved." }, "headerColor": "#2196F3", "languagePicker": false, diff --git a/src/app/components/login/login.component.html b/src/app/components/login/login.component.html index b23521bf6c..d6aa3fc8c0 100644 --- a/src/app/components/login/login.component.html +++ b/src/app/components/login/login.component.html @@ -1,7 +1,7 @@ + [showLoginActions]="false"> diff --git a/src/app/components/login/login.component.spec.ts b/src/app/components/login/login.component.spec.ts index 18f006a8a4..fe4f9a2dfb 100644 --- a/src/app/components/login/login.component.spec.ts +++ b/src/app/components/login/login.component.spec.ts @@ -29,7 +29,7 @@ import { Router } from '@angular/router'; import { HttpClientModule } from '@angular/common/http'; import { TranslateModule } from '@ngx-translate/core'; import { Location } from '@angular/common'; -import { TestBed, async } from '@angular/core/testing'; +import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { AuthenticationService, UserPreferencesService, TranslationService, TranslationMock, AppConfigService, StorageService, AlfrescoApiService, @@ -37,14 +37,14 @@ import { } from '@alfresco/adf-core'; import { LoginComponent } from './login.component'; +import { AppConfigPipe } from '../../common/pipes/app-config.pipe'; describe('LoginComponent', () => { - let component; - let fixture; - let router; - let userPreference; - let auth; - let location; + let fixture: ComponentFixture; + let router: Router; + let userPreference: UserPreferencesService; + let auth: AuthenticationService; + let location: Location; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -54,7 +54,8 @@ describe('LoginComponent', () => { RouterTestingModule ], declarations: [ - LoginComponent + LoginComponent, + AppConfigPipe ], providers: [ { provide: TranslationService, useClass: TranslationMock }, @@ -71,7 +72,6 @@ describe('LoginComponent', () => { }); fixture = TestBed.createComponent(LoginComponent); - component = fixture.componentInstance; router = TestBed.get(Router); location = TestBed.get(Location); @@ -101,23 +101,4 @@ describe('LoginComponent', () => { expect(location.forward).toHaveBeenCalled(); }); }); - - describe('onLoginSuccess()', () => { - beforeEach(() => { - spyOn(auth, 'isEcmLoggedIn').and.returnValue(false); - fixture.detectChanges(); - }); - - it('should redirect on success', () => { - component.onLoginSuccess(); - - expect(router.navigateByUrl).toHaveBeenCalledWith('/personal-files'); - }); - - it('should set user preference store prefix', () => { - component.onLoginSuccess({ username: 'bogus' }); - - expect(userPreference.setStoragePrefix).toHaveBeenCalledWith('bogus'); - }); - }); }); diff --git a/src/app/components/login/login.component.ts b/src/app/components/login/login.component.ts index c0e24091e9..76aa0f7229 100644 --- a/src/app/components/login/login.component.ts +++ b/src/app/components/login/login.component.ts @@ -25,18 +25,15 @@ import { Component, OnInit } from '@angular/core'; import { Location } from '@angular/common'; -import { Router } from '@angular/router'; -import { AuthenticationService, UserPreferencesService } from '@alfresco/adf-core'; +import { AuthenticationService } from '@alfresco/adf-core'; @Component({ templateUrl: './login.component.html' }) export class LoginComponent implements OnInit { constructor( - private router: Router, private location: Location, private auth: AuthenticationService, - private userPreferences: UserPreferencesService ) {} ngOnInit() { @@ -44,12 +41,4 @@ export class LoginComponent implements OnInit { this.location.forward(); } } - - onLoginSuccess(data) { - if (data && data.username) { - this.userPreferences.setStoragePrefix(data.username); - } - - this.router.navigateByUrl('/personal-files'); - } } From 7b740fd2e413ca3f04d01015fc99391fb121e717 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 4 May 2018 06:49:08 +0100 Subject: [PATCH 018/179] upgrade to latest ADF (alpha) (#344) * update to latest ADF (alpha) * upgrade code after upgrade * remove styles that are already in ADF * fixes from ADF or AoT * update to latest libs * update libs * upgrade libs --- package-lock.json | 270 ++++++++++++++------------ package.json | 6 +- src/app.config.json | 59 +++--- src/app/ui/application.scss | 2 - src/app/ui/overrides/_adf-viewer.scss | 6 - src/app/ui/overrides/_breadcrumb.scss | 10 - 6 files changed, 175 insertions(+), 178 deletions(-) delete mode 100644 src/app/ui/overrides/_adf-viewer.scss delete mode 100644 src/app/ui/overrides/_breadcrumb.scss diff --git a/package-lock.json b/package-lock.json index 951991325f..5f3b0873b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46.tgz", - "integrity": "sha512-ge3RMlfrt+U1GEt5sksxKP3RLdZ1JjMguE8HsQk8l0Nq/DXRRkpLMJd0g2+AOZ0BpmtlCmZYHlmVJ9u39cLfBw==", + "version": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1.tgz", + "integrity": "sha512-CdlWq86julMSMo0BX0rZ0FKYVa261ZtQb6T1f+XkqwnQtv6QSPv4dEQcvF0f3IWXOpc3LcxOBcVhWq4DBNQsOQ==", "requires": { - "@alfresco/adf-core": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", + "@alfresco/adf-core": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", + "alfresco-js-api": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -61,9 +61,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46.tgz", - "integrity": "sha512-iNUd6jvRJssQzYXmB2y+sKaXTDk6miu3u6IZYOgLoZxqbsn91msyMLHDMmVEN0EEnHAVREBspAxvi2wEvZ4Lvw==", + "version": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1.tgz", + "integrity": "sha512-nsM0k0WCq5s/awvj2o5BxCXTv1RmOLKwcBiW/kw/daCWMrLSESt1Et3YEKm/A1axKPB0aT3xkdTqIkuADjcWKA==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -79,7 +79,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", + "alfresco-js-api": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -258,11 +258,11 @@ "memory-fs": "0.4.1", "minimatch": "3.0.4", "node-modules-path": "1.0.1", - "node-sass": "4.8.3", + "node-sass": "4.9.0", "nopt": "4.0.1", "opn": "5.1.0", "portfinder": "1.0.13", - "postcss": "6.0.21", + "postcss": "6.0.22", "postcss-import": "11.1.0", "postcss-loader": "2.1.4", "postcss-url": "7.3.2", @@ -500,9 +500,9 @@ } }, "@types/jasmine": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.6.tgz", - "integrity": "sha512-clg9raJTY0EOo5pVZKX3ZlMjlYzVU73L71q5OV1jhE2Uezb7oF94jh4CvwrW6wInquQAdhOxJz5VDF2TLUGmmA==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.7.tgz", + "integrity": "sha512-RdbrPcW1aD78UmdLiDa9ZCKrbR5Go8PXh6GCpb4oIOkWVEusubSJJDrP4c5RYOu8m/CBz+ygZpicj6Pgms5a4Q==", "dev": true }, "@types/jasminewd2": { @@ -511,7 +511,7 @@ "integrity": "sha512-hYDVmQZT5VA2kigd4H4bv7vl/OhlympwREUemqBdOqtrYTo5Ytm12a5W5/nGgGYdanGVxj0x/VhZ7J3hOg/YKg==", "dev": true, "requires": { - "@types/jasmine": "2.8.6" + "@types/jasmine": "2.8.7" } }, "@types/node": { @@ -632,14 +632,14 @@ } }, "ajv-keywords": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz", - "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "alfresco-js-api": { - "version": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de.tgz", - "integrity": "sha512-8d9H4fY7rxPoSpDa42EqI9D0lg1AOQOnkP+0Qz1jkS7w/otsOcCT29jlo5Y1avwscS+QNrwo+RMTaVdGnxwqAA==", + "version": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18.tgz", + "integrity": "sha512-Ty3QQdvP+6/Fqe4CUuV6fYqkYG9xYvshnrHEzsFju36FSgNkWxZcOmwAAGVIWeNnCA7DuQqE7D+Vp7pgnPNTxQ==", "requires": { "event-emitter": "0.3.4", "superagent": "3.8.2" @@ -673,7 +673,7 @@ "bluebird": "3.5.1", "buffer-more-ints": "0.0.2", "readable-stream": "1.1.14", - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" }, "dependencies": { "isarray": { @@ -955,9 +955,9 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.0.tgz", - "integrity": "sha512-SuiKH8vbsOyCALjA/+EINmt/Kdl+TQPrtFgW7XZZcwtryFu9e5kQoX3bjCW6mIvGH1fbeAZZuvwGR5IlBRznGw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", + "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", "dev": true }, "autoprefixer": { @@ -967,10 +967,10 @@ "dev": true, "requires": { "browserslist": "2.11.3", - "caniuse-lite": "1.0.30000830", + "caniuse-lite": "1.0.30000833", "normalize-range": "0.1.2", "num2fraction": "1.2.2", - "postcss": "6.0.21", + "postcss": "6.0.22", "postcss-value-parser": "3.3.0" } }, @@ -1473,7 +1473,7 @@ "create-hash": "1.2.0", "evp_bytestokey": "1.0.3", "inherits": "2.0.3", - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "browserify-cipher": { @@ -1538,8 +1538,8 @@ "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000830", - "electron-to-chromium": "1.3.42" + "caniuse-lite": "1.0.30000833", + "electron-to-chromium": "1.3.45" } }, "buffer": { @@ -1711,9 +1711,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000830", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000830.tgz", - "integrity": "sha512-yMqGkujkoOIZfvOYiWdqPALgY/PVGiqCHUJb6yNq7xhI/pR+gQO0U2K6lRDqAiJv4+CIU3CtTLblNGw0QGnr6g==", + "version": "1.0.30000833", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000833.tgz", + "integrity": "sha512-tKNuKu4WLImh4NxoTgntxFpDrRiA0Q6Q1NycNhuMST0Kx+Pt8YnRDW6V8xsyH6AtO2CpAoibatEk5eaEhP3O1g==", "dev": true }, "caseless": { @@ -1777,7 +1777,7 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.2.2", + "fsevents": "1.2.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -1799,7 +1799,7 @@ "dev": true, "requires": { "inherits": "2.0.3", - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "circular-dependency-plugin": { @@ -1864,9 +1864,9 @@ } }, "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", "dev": true }, "clone-deep": { @@ -2047,7 +2047,7 @@ "oauth-sign": "0.8.2", "performance-now": "2.1.0", "qs": "6.5.1", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "stringstream": "0.0.5", "tough-cookie": "2.3.4", "tunnel-agent": "0.6.0", @@ -2204,6 +2204,12 @@ "requires": { "ms": "2.0.0" } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true } } }, @@ -2458,7 +2464,7 @@ "create-hash": "1.2.0", "inherits": "2.0.3", "ripemd160": "2.0.2", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "sha.js": "2.4.11" } }, @@ -2885,7 +2891,7 @@ "dev": true, "requires": { "ip": "1.1.5", - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "dns-txt": { @@ -3017,9 +3023,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.42", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.42.tgz", - "integrity": "sha1-lcM78B0MxAVVauyJn+Yf1NduoPk=", + "version": "1.3.45", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.45.tgz", + "integrity": "sha1-RYrBscXHYM6IEaFtK/vZfsMLr7g=", "dev": true }, "elliptic": { @@ -3425,9 +3431,9 @@ } }, "eventemitter3": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.0.1.tgz", - "integrity": "sha512-QOCPu979MMWX9XNlfRZoin+Wm+bK1SP7vv3NGUniYwuSJK/+cPA10blMaeRgzg31RvoSFk6FsCDVa4vNryBTGA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", "dev": true }, "events": { @@ -3452,7 +3458,7 @@ "dev": true, "requires": { "md5.js": "1.3.4", - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "execa": { @@ -3603,6 +3609,12 @@ "requires": { "ms": "2.0.0" } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true } } }, @@ -3937,9 +3949,9 @@ "dev": true }, "fsevents": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.2.tgz", - "integrity": "sha512-iownA+hC4uHFp+7gwP/y5SzaiUo7m2vpa0dhpzw8YuKtiZsz7cIXsFbXpLEeBM6WuCQyw1MH4RRe6XI8GFUctQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.3.tgz", + "integrity": "sha512-X+57O5YkDTiEQGiw8i7wYc2nQgweIekqkepI8Q3y4wVlurgBt2SuwxTeYUYMZIGpLZH3r/TsMjczCMXE5ZOt7Q==", "dev": true, "optional": true, "requires": { @@ -4682,7 +4694,7 @@ "array-union": "1.0.2", "dir-glob": "2.0.0", "glob": "7.1.2", - "ignore": "3.3.7", + "ignore": "3.3.8", "pify": "3.0.0", "slash": "1.0.0" } @@ -4946,7 +4958,7 @@ "dev": true, "requires": { "inherits": "2.0.3", - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "hash.js": { @@ -5050,7 +5062,7 @@ "he": "1.1.1", "param-case": "2.1.1", "relateurl": "0.2.7", - "uglify-js": "3.3.22" + "uglify-js": "3.3.23" } }, "html-webpack-plugin": { @@ -5064,7 +5076,7 @@ "loader-utils": "0.2.17", "lodash": "4.17.10", "pretty-error": "2.1.1", - "toposort": "1.0.6" + "toposort": "1.0.7" }, "dependencies": { "loader-utils": { @@ -5158,7 +5170,7 @@ "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "dev": true, "requires": { - "eventemitter3": "3.0.1", + "eventemitter3": "3.1.0", "follow-redirects": "1.4.1", "requires-port": "1.0.0" } @@ -5288,9 +5300,9 @@ "dev": true }, "ignore": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", - "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.8.tgz", + "integrity": "sha512-pUh+xUQQhQzevjRHHFqqcTy0/dP/kS9I8HSrUydhihjuD09W6ldVWFtIrwhXdUJHis3i2rZNqEHpZH/cbinFbg==", "dev": true }, "image-size": { @@ -6180,7 +6192,7 @@ "qjobs": "1.2.0", "range-parser": "1.2.0", "rimraf": "2.6.2", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "socket.io": "2.0.4", "source-map": "0.6.1", "tmp": "0.0.33", @@ -6225,9 +6237,9 @@ } }, "karma-jasmine": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.1.tgz", - "integrity": "sha1-b+hA51oRYAydkehLM8RY4cRqNSk=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.2.tgz", + "integrity": "sha1-OU8rJf+0pkS5rabyLUQ+L9CIhsM=", "dev": true }, "karma-jasmine-html-reporter": { @@ -6236,7 +6248,7 @@ "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=", "dev": true, "requires": { - "karma-jasmine": "1.1.1" + "karma-jasmine": "1.1.2" } }, "karma-source-map-support": { @@ -6315,7 +6327,7 @@ "integrity": "sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg==", "dev": true, "requires": { - "clone": "2.1.2", + "clone": "2.1.1", "loader-utils": "1.1.0", "pify": "3.0.0" } @@ -7272,9 +7284,9 @@ } }, "node-sass": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.8.3.tgz", - "integrity": "sha512-tfFWhUsCk/Y19zarDcPo5xpj+IW3qCfOjVdHtYeG6S1CKbQOh1zqylnQK6cV3z9k80yxAnFX9Y+a9+XysDhhfg==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", + "integrity": "sha512-QFHfrZl6lqRU3csypwviz2XLgGNOoWQbo2GOvtsfQqOfL4cy1BtWnhx/XUeAO9LT3ahBzSRXcEO6DdvAH9DzSg==", "dev": true, "optional": true, "requires": { @@ -8075,7 +8087,7 @@ "create-hash": "1.2.0", "create-hmac": "1.1.7", "ripemd160": "2.0.2", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "sha.js": "2.4.11" } }, @@ -8159,20 +8171,20 @@ "dev": true }, "postcss": { - "version": "6.0.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.21.tgz", - "integrity": "sha512-y/bKfbQz2Nn/QBC08bwvYUxEFOVGfPIUOTsJ2CK5inzlXW9SdYR1x4pEsG9blRAF/PX+wRNdOah+gx/hv4q7dw==", + "version": "6.0.22", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.22.tgz", + "integrity": "sha512-Toc9lLoUASwGqxBSJGTVcOQiDqjK+Z2XlWBg+IgYwQMY9vA2f7iMpXVc1GpPcfTSyM5lkxNo0oDwDRO+wm7XHA==", "dev": true, "requires": { - "chalk": "2.4.0", + "chalk": "2.4.1", "source-map": "0.6.1", "supports-color": "5.4.0" }, "dependencies": { "chalk": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz", - "integrity": "sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { "ansi-styles": "3.2.1", @@ -8209,7 +8221,7 @@ "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", "dev": true, "requires": { - "postcss": "6.0.21", + "postcss": "6.0.22", "postcss-value-parser": "3.3.0", "read-cache": "1.0.0", "resolve": "1.7.1" @@ -8254,7 +8266,7 @@ "dev": true, "requires": { "loader-utils": "1.1.0", - "postcss": "6.0.21", + "postcss": "6.0.22", "postcss-load-config": "1.2.0", "schema-utils": "0.4.5" } @@ -8268,7 +8280,7 @@ "mime": "1.6.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", - "postcss": "6.0.21", + "postcss": "6.0.22", "xxhashjs": "0.2.2" } }, @@ -8333,7 +8345,7 @@ "integrity": "sha512-AW9qJ0prx2QEMy1gnhJ1Sl1WBQL2R3fx/VnG09FEmWprPIQPK14t0B83OB/pAGddpxiDCAAV0KiNNLf2c2Y/lQ==", "dev": true, "requires": { - "@types/node": "6.0.106", + "@types/node": "6.0.107", "@types/q": "0.0.32", "@types/selenium-webdriver": "2.53.43", "blocking-proxy": "1.0.1", @@ -8351,9 +8363,9 @@ }, "dependencies": { "@types/node": { - "version": "6.0.106", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.106.tgz", - "integrity": "sha512-U4Zv5fx7letrisRv6HgSSPSY00FZM4NMIkilt+IAExvQLuNa6jYVwCKcnSs2NqTN4+KDl9PskvcCiMce9iePCA==", + "version": "6.0.107", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.107.tgz", + "integrity": "sha512-iuJWRFHqU0tFLCYH6cfBZzMxThAAsNK31FZxoq+fKIDOSZk1p+3IhNWfEdvPJfsQXcTq8z+57s8xjQlrDAB0Gw==", "dev": true }, "@types/selenium-webdriver": { @@ -8661,7 +8673,7 @@ "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "randomfill": { @@ -8671,7 +8683,7 @@ "dev": true, "requires": { "randombytes": "2.0.6", - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "range-parser": { @@ -8819,7 +8831,7 @@ "inherits": "2.0.3", "isarray": "1.0.0", "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "string_decoder": "1.1.1", "util-deprecate": "1.0.2" } @@ -9019,7 +9031,7 @@ "oauth-sign": "0.8.2", "performance-now": "0.2.0", "qs": "6.4.0", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "stringstream": "0.0.5", "tough-cookie": "2.3.4", "tunnel-agent": "0.6.0", @@ -9191,9 +9203,9 @@ } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -9251,7 +9263,7 @@ "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", "requires": { "ajv": "6.4.0", - "ajv-keywords": "3.1.0" + "ajv-keywords": "3.2.0" } }, "scss-tokenizer": { @@ -9475,7 +9487,7 @@ "dev": true, "requires": { "inherits": "2.0.3", - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "shallow-clone": { @@ -9861,7 +9873,7 @@ "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", "dev": true, "requires": { - "atob": "2.1.0", + "atob": "2.1.1", "decode-uri-component": "0.2.0", "resolve-url": "0.2.1", "source-map-url": "0.4.0", @@ -9924,7 +9936,7 @@ "debug": "2.6.9", "handle-thing": "1.2.5", "http-deceiver": "1.2.7", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "select-hose": "2.0.0", "spdy-transport": "2.1.0" }, @@ -9951,7 +9963,7 @@ "hpack.js": "2.1.6", "obuf": "1.1.2", "readable-stream": "2.3.6", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "wbuf": "1.7.3" }, "dependencies": { @@ -10011,7 +10023,7 @@ "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "static-extend": { @@ -10124,7 +10136,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "stringstream": { @@ -10458,9 +10470,9 @@ } }, "toposort": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.6.tgz", - "integrity": "sha1-wxdI5V0hDv/AD9zcfW5o19e7nOw=", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", "dev": true }, "tough-cookie": { @@ -10531,7 +10543,7 @@ "dev": true, "requires": { "arrify": "1.0.1", - "chalk": "2.4.0", + "chalk": "2.4.1", "diff": "3.5.0", "make-error": "1.3.4", "minimist": "1.2.0", @@ -10543,9 +10555,9 @@ }, "dependencies": { "chalk": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz", - "integrity": "sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { "ansi-styles": "3.2.1", @@ -10645,7 +10657,7 @@ "requires": { "babel-code-frame": "6.26.0", "builtin-modules": "1.1.1", - "chalk": "2.4.0", + "chalk": "2.4.1", "commander": "2.15.1", "diff": "3.5.0", "glob": "7.1.2", @@ -10654,13 +10666,13 @@ "resolve": "1.7.1", "semver": "5.5.0", "tslib": "1.9.0", - "tsutils": "2.26.1" + "tsutils": "2.26.2" }, "dependencies": { "chalk": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.0.tgz", - "integrity": "sha512-Wr/w0f4o9LuE7K53cD0qmbAMM+2XNLzR29vFn5hqko4sxGlUsyy363NvmyGIyk5tpe9cjTr9SJYbysEyPkRnFw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { "ansi-styles": "3.2.1", @@ -10693,9 +10705,9 @@ "optional": true }, "tsutils": { - "version": "2.26.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.26.1.tgz", - "integrity": "sha512-bnm9bcjOqOr1UljleL94wVCDlpa6KjfGaTkefeLch4GRafgDkROxPizbB/FxTEdI++5JqhxczRy/Qub0syNqZA==", + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.26.2.tgz", + "integrity": "sha512-uzwnhmrSbyinPCiwfzGsOY3IulBTwoky7r83HmZdz9QNCjhSCzavkh47KLWuU0zF2F2WbpmmzoJUIEiYyd+jEQ==", "dev": true, "requires": { "tslib": "1.9.0" @@ -10713,7 +10725,7 @@ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "5.1.2" } }, "tweetnacl": { @@ -10755,9 +10767,9 @@ "dev": true }, "uglify-js": { - "version": "3.3.22", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.22.tgz", - "integrity": "sha512-tqw96rL6/BG+7LM5VItdhDjTQmL5zG/I0b2RqWytlgeHe2eydZHuBHdA9vuGpCDhH/ZskNGcqDhivoR2xt8RIw==", + "version": "3.3.23", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.23.tgz", + "integrity": "sha512-Ks+KqLGDsYn4z+pU7JsKCzC0T3mPYl+rU+VcPZiQOazjE4Uqi4UCRY3qPMDbJi7ze37n1lDXj3biz1ik93vqvw==", "dev": true, "requires": { "commander": "2.15.1", @@ -10943,9 +10955,9 @@ } }, "upath": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.4.tgz", - "integrity": "sha512-d4SJySNBXDaQp+DPrziv3xGS6w3d2Xt69FijJr86zMPBy23JEloMCEOUBBzuN7xCtjLCnmB9tI/z7SBCahHBOw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.5.tgz", + "integrity": "sha512-qbKn90aDQ0YEwvXoLqj0oiuUYroLX2lVHZ+b+xwjozFasAOC4GneDq5+OaIG5Zj+jFmbz/uO+f7a9qxjktJQww==", "dev": true }, "upper-case": { @@ -11232,9 +11244,9 @@ } }, "watchpack": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.5.0.tgz", - "integrity": "sha512-RSlipNQB1u48cq0wH/BNfCu1tD/cJ8ydFIkNYhp9o+3d+8unClkIovpW5qpFPgmL9OE48wfAnlZydXByWP82AA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", "dev": true, "requires": { "chokidar": "2.0.3", @@ -11302,7 +11314,7 @@ "anymatch": "2.0.0", "async-each": "1.0.1", "braces": "2.3.2", - "fsevents": "1.2.2", + "fsevents": "1.2.3", "glob-parent": "3.1.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -11310,7 +11322,7 @@ "normalize-path": "2.1.1", "path-is-absolute": "1.0.1", "readdirp": "2.1.0", - "upath": "1.0.4" + "upath": "1.0.5" } }, "debug": { @@ -11685,7 +11697,7 @@ "acorn": "5.5.3", "acorn-dynamic-import": "2.0.2", "ajv": "6.4.0", - "ajv-keywords": "3.1.0", + "ajv-keywords": "3.2.0", "async": "2.6.0", "enhanced-resolve": "3.4.1", "escope": "3.6.0", @@ -11701,7 +11713,7 @@ "supports-color": "4.5.0", "tapable": "0.2.8", "uglifyjs-webpack-plugin": "0.4.6", - "watchpack": "1.5.0", + "watchpack": "1.6.0", "webpack-sources": "1.1.0", "yargs": "8.0.2" }, @@ -12082,7 +12094,7 @@ "anymatch": "2.0.0", "async-each": "1.0.1", "braces": "2.3.2", - "fsevents": "1.2.2", + "fsevents": "1.2.3", "glob-parent": "3.1.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -12090,7 +12102,7 @@ "normalize-path": "2.1.1", "path-is-absolute": "1.0.1", "readdirp": "2.1.0", - "upath": "1.0.4" + "upath": "1.0.5" } }, "expand-brackets": { @@ -12558,7 +12570,7 @@ "dev": true, "requires": { "async-limiter": "1.0.0", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "ultron": "1.1.1" } }, diff --git a/package.json b/package.json index 337b83f09f..0097673c17 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", - "@alfresco/adf-core": "2.4.0-d8e623531b7e75a39e773d32ac6d710354ca6d46", + "@alfresco/adf-content-services": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", + "@alfresco/adf-core": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -41,7 +41,7 @@ "@mat-datetimepicker/core": "1.0.1", "@mat-datetimepicker/moment": "1.0.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-6aeb75354b9b0ddb74444bfb449549ec21c123de", + "alfresco-js-api": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", "core-js": "2.5.3", "hammerjs": "2.0.8", "moment-es6": "1.0.0", diff --git a/src/app.config.json b/src/app.config.json index 26f08d7ae1..f12cd56e89 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -166,34 +166,37 @@ { "field": "modifier", "mincount": 1, "label": "Modifier" }, { "field": "created", "mincount": 1, "label": "Created" } ], - "facetQueries": [ - { "query": "created:2018", "label": "Created This Year" }, - { "query": "content.mimetype", "label": "Type" }, - { - "query": "content.size:[0 TO 10240]", - "label": "Size: xtra small" - }, - { - "query": "content.size:[10240 TO 102400]", - "label": "Size: small" - }, - { - "query": "content.size:[102400 TO 1048576]", - "label": "Size: medium" - }, - { - "query": "content.size:[1048576 TO 16777216]", - "label": "Size: large" - }, - { - "query": "content.size:[16777216 TO 134217728]", - "label": "Size: xtra large" - }, - { - "query": "content.size:[134217728 TO MAX]", - "label": "Size: XX large" - } - ], + "facetQueries": { + "label": "My facet queries", + "queries": [ + { "query": "created:2018", "label": "Created This Year" }, + { "query": "content.mimetype", "label": "Type" }, + { + "query": "content.size:[0 TO 10240]", + "label": "Size: xtra small" + }, + { + "query": "content.size:[10240 TO 102400]", + "label": "Size: small" + }, + { + "query": "content.size:[102400 TO 1048576]", + "label": "Size: medium" + }, + { + "query": "content.size:[1048576 TO 16777216]", + "label": "Size: large" + }, + { + "query": "content.size:[16777216 TO 134217728]", + "label": "Size: xtra large" + }, + { + "query": "content.size:[134217728 TO MAX]", + "label": "Size: XX large" + } + ] + }, "categories": [ { "id": "queryName", diff --git a/src/app/ui/application.scss b/src/app/ui/application.scss index b5d8072e62..89f484547f 100644 --- a/src/app/ui/application.scss +++ b/src/app/ui/application.scss @@ -23,12 +23,10 @@ ng-component { @import './overrides/adf-login'; @import './overrides/adf-sidenav-layout'; -@import './overrides/adf-viewer'; @import './overrides/alfresco-document-list'; @import './overrides/alfresco-upload-drag-area'; @import './overrides/alfresco-upload-button'; @import './overrides/alfresco-upload-dialog'; @import './overrides/toolbar'; @import './overrides/adf-viewer-more-actions'; -@import './overrides/breadcrumb'; @import './overrides/adf-info-drawer'; diff --git a/src/app/ui/overrides/_adf-viewer.scss b/src/app/ui/overrides/_adf-viewer.scss deleted file mode 100644 index b8e549685c..0000000000 --- a/src/app/ui/overrides/_adf-viewer.scss +++ /dev/null @@ -1,6 +0,0 @@ - -@import 'mixins'; - -.adf-viewer-content>div { - min-height: 0px !important; -} \ No newline at end of file diff --git a/src/app/ui/overrides/_breadcrumb.scss b/src/app/ui/overrides/_breadcrumb.scss deleted file mode 100644 index 010468714c..0000000000 --- a/src/app/ui/overrides/_breadcrumb.scss +++ /dev/null @@ -1,10 +0,0 @@ -@import 'variables'; - -.adf-breadcrumb { - color: $alfresco-secondary-text-color; - width: 0; - - &-item:first-child:nth-last-child(1) { - opacity: 1; - } -} From b3ae122c4c7569724bf9e9278d5cb1597d8111ef Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 4 May 2018 18:14:45 +0300 Subject: [PATCH 019/179] font config (#348) --- src/app/ui/theme.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/ui/theme.scss b/src/app/ui/theme.scss index 96302e8aac..9deea7cda5 100644 --- a/src/app/ui/theme.scss +++ b/src/app/ui/theme.scss @@ -5,7 +5,7 @@ @import 'custom-theme'; -@include mat-core(); +@include mat-core($alfresco-typography); $primary: mat-palette($alfresco-accent-orange); $accent: mat-palette($alfresco-ecm-blue); From 9e264f3fb031abe1074c472dddfc096b2d57e3eb Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 4 May 2018 20:39:26 +0300 Subject: [PATCH 020/179] [ACA-1317] Use ADF component for "New" side navigation actions (#347) * adf-sidebar-action-menu * update --- e2e/components/sidenav/sidenav.ts | 2 +- .../components/sidenav/sidenav.component.html | 105 ++++++++---------- .../components/sidenav/sidenav.component.scss | 17 +-- .../sidenav/sidenav.component.theme.scss | 5 +- src/app/ui/application.scss | 2 + .../overrides/_adf-sidebar-action-menu.scss | 39 +++++++ .../ui/overrides/_alfresco-upload-button.scss | 7 +- 7 files changed, 102 insertions(+), 75 deletions(-) create mode 100644 src/app/ui/overrides/_adf-sidebar-action-menu.scss diff --git a/e2e/components/sidenav/sidenav.ts b/e2e/components/sidenav/sidenav.ts index 53d4baf84e..3c14615b6a 100755 --- a/e2e/components/sidenav/sidenav.ts +++ b/e2e/components/sidenav/sidenav.ts @@ -33,7 +33,7 @@ export class Sidenav extends Component { link: '.sidenav-menu__item', label: '.menu__item--label', activeLink: '.menu__item--active', - newButton: '.sidenav__section--new__button' + newButton: '.adf-sidebar-action-menu-button' }; links: ElementArrayFinder = this.component.all(by.css(Sidenav.selectors.link)); diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index 7fb3f30b57..2dc6c0af38 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -1,64 +1,53 @@
-
- - - - - - +
+ + arrow_drop_down +
+ queue +
+
+ - - + + - - - + + +
+
diff --git a/src/app/components/sidenav/sidenav.component.scss b/src/app/components/sidenav/sidenav.component.scss index 724a6ee3ff..48df44e8fe 100644 --- a/src/app/components/sidenav/sidenav.component.scss +++ b/src/app/components/sidenav/sidenav.component.scss @@ -8,8 +8,10 @@ border-bottom: 0; } - .section--new--mini { + &_action-menu { display: flex; + padding: 16px 24px; + height: 40px; justify-content: center; align-items: center; } @@ -17,19 +19,6 @@ &__section { padding: 8px 14px; position: relative; - - &--new { - padding: 16px 24px; - height: 40px; - } - - &--new__button { - width: 100%; - } - - &--new__button.mat-raised-button { - box-shadow: none !important; - } } &-menu { diff --git a/src/app/components/sidenav/sidenav.component.theme.scss b/src/app/components/sidenav/sidenav.component.theme.scss index 8941378c3c..9ec93afaec 100644 --- a/src/app/components/sidenav/sidenav.component.theme.scss +++ b/src/app/components/sidenav/sidenav.component.theme.scss @@ -10,7 +10,10 @@ @include angular-material-theme($theme); background-color: mat-color($background, background); - border-right: $border; + + .adf-sidebar-action-menu-button { + background-color: mat-color($accent); + } &__section { border-bottom: $border; diff --git a/src/app/ui/application.scss b/src/app/ui/application.scss index 89f484547f..c179506b51 100644 --- a/src/app/ui/application.scss +++ b/src/app/ui/application.scss @@ -30,3 +30,5 @@ ng-component { @import './overrides/toolbar'; @import './overrides/adf-viewer-more-actions'; @import './overrides/adf-info-drawer'; +@import './overrides/_adf-sidebar-action-menu'; + diff --git a/src/app/ui/overrides/_adf-sidebar-action-menu.scss b/src/app/ui/overrides/_adf-sidebar-action-menu.scss new file mode 100644 index 0000000000..35dc19ae34 --- /dev/null +++ b/src/app/ui/overrides/_adf-sidebar-action-menu.scss @@ -0,0 +1,39 @@ +.adf-sidebar-action-menu-options div .mat-menu-item { + display: flex; + flex-direction: row; + align-items: center; +} + +.mat-menu-item[disabled], +.mat-menu-item[disabled]:hover { + color: rgba(0, 0, 0, 0.38); +} + +.mat-menu-panel.adf-sidebar-action-menu-panel { + max-width: 290px !important; +} + +.adf-sidebar-action-menu-panel { + width: 290px; + display: flex; + align-items: center; + justify-content: center; +} + +.adf-sidebar-action-menu-panel .mat-menu-content { + width: 100%; +} + +.adf-sidebar-action-menu-icon { + margin: 0; +} + +.adf-sidebar-action-menu-icon div[sidebar-menu-expand-icon] { + display: flex; + align-items: center; + justify-content: center; +} + +.adf-sidebar-action-menu { + width: 100%; +} diff --git a/src/app/ui/overrides/_alfresco-upload-button.scss b/src/app/ui/overrides/_alfresco-upload-button.scss index e3dbbfd004..896211be37 100644 --- a/src/app/ui/overrides/_alfresco-upload-button.scss +++ b/src/app/ui/overrides/_alfresco-upload-button.scss @@ -38,7 +38,12 @@ adf-upload-button { font-size: 16px; font-weight: normal; text-align: left; - margin-left: 18px; + margin-left: 12px; color: $alfresco-primary-text-color; } + + &:hover label { + color: #ff9800; + opacity: inherit; + } } From eb463c7635bb491b6a24adaf5acb85bbc95ea921 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 10 May 2018 11:33:31 +0300 Subject: [PATCH 021/179] use title binding over attribute style (#351) --- src/app/components/favorites/favorites.component.html | 2 +- src/app/components/libraries/libraries.component.html | 2 +- src/app/components/recent-files/recent-files.component.html | 2 +- src/app/components/shared-files/shared-files.component.html | 2 +- src/app/components/trashcan/trashcan.component.html | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 3378d3ed67..8ef804c297 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -114,7 +114,7 @@ diff --git a/src/app/components/libraries/libraries.component.html b/src/app/components/libraries/libraries.component.html index 60c2798281..160cebc8ed 100644 --- a/src/app/components/libraries/libraries.component.html +++ b/src/app/components/libraries/libraries.component.html @@ -23,7 +23,7 @@ diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 1d993701ba..32b0db5f2f 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -109,7 +109,7 @@ diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 7e85ca8045..fe10ad64a5 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -114,7 +114,7 @@ diff --git a/src/app/components/trashcan/trashcan.component.html b/src/app/components/trashcan/trashcan.component.html index 2f36d7f770..c762a0afa4 100644 --- a/src/app/components/trashcan/trashcan.component.html +++ b/src/app/components/trashcan/trashcan.component.html @@ -42,7 +42,7 @@ + [title]="'APP.BROWSE.TRASHCAN.EMPTY_STATE.TITLE'">

{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.FIRST_TEXT' | translate }}

{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.SECOND_TEXT' | translate }}

From 3ca63b84338ffdfd24dfe0c1a74c6716945e2b82 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 10 May 2018 12:11:45 +0300 Subject: [PATCH 022/179] check if file is selected (#350) --- src/app/components/files/files.component.html | 2 +- src/app/components/recent-files/recent-files.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index 19c6925b4d..073bec5bd7 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -93,7 +93,7 @@
diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index 7b1539f02c..5d0c6dfa3f 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -70,50 +70,6 @@ describe('PageComponent', () => { }); }); - describe('filesOnlySelected()', () => { - it('return true if only files are selected', () => { - const selected = [ { entry: { isFile: true } }, { entry: { isFile: true } } ]; - expect(component.filesOnlySelected(selected)).toBe(true); - }); - - it('return false if selection contains others types', () => { - const selected = [ { entry: { isFile: true } }, { entry: { isFolder: true } } ]; - expect(component.filesOnlySelected(selected)).toBe(false); - }); - - it('return false if selection contains no files', () => { - const selected = [ { entry: { isFolder: true } } ]; - expect(component.filesOnlySelected(selected)).toBe(false); - }); - - it('return false no selection', () => { - const selected = []; - expect(component.filesOnlySelected(selected)).toBe(false); - }); - }); - - describe('foldersOnlySelected()', () => { - it('return true if only folders are selected', () => { - const selected = [ { entry: { isFolder: true } }, { entry: { isFolder: true } } ]; - expect(component.foldersOnlySelected(selected)).toBe(true); - }); - - it('return false if selection contains others types', () => { - const selected = [ { entry: { isFile: true } }, { entry: { isFolder: true } } ]; - expect(component.foldersOnlySelected(selected)).toBe(false); - }); - - it('return false if selection contains no files', () => { - const selected = [ { entry: { isFile: true } } ]; - expect(component.foldersOnlySelected(selected)).toBe(false); - }); - - it('return false no selection', () => { - const selected = []; - expect(component.foldersOnlySelected(selected)).toBe(false); - }); - }); - describe('isFileSelected()', () => { it('returns true if selected node is file', () => { const selection = [ { entry: { isFile: true } } ]; @@ -131,135 +87,20 @@ describe('PageComponent', () => { }); }); - describe('canEditFolder()', () => { + describe('isFolderSelected()', () => { it('returns true if selected node is folder', () => { const selection = [ { entry: { isFolder: true } } ]; - spyOn(component, 'nodeHasPermission').and.returnValue(true); - - expect(component.canEditFolder(selection)).toBe(true); + expect(component.isFolderSelected(selection)).toBe(true); }); it('returns false if selected node is file', () => { const selection = [ { entry: { isFile: true } } ]; - expect(component.canEditFolder(selection)).toBe(false); + expect(component.isFolderSelected(selection)).toBe(false); }); it('returns false if there are more than one selections', () => { const selection = [ { entry: { isFolder: true } }, { entry: { isFolder: true } } ]; - expect(component.canEditFolder(selection)).toBe(false); - }); - - it('returns false folder dows not have edit permission', () => { - spyOn(component, 'nodeHasPermission').and.returnValue(false); - const selection = [ { entry: { isFolder: true } } ]; - - expect(component.canEditFolder(selection)).toBe(false); - }); - }); - - describe('canDelete()', () => { - it('returns false if node has no delete permission', () => { - const selection = [ { entry: { } } ]; - spyOn(component, 'nodeHasPermission').and.returnValue(false); - - expect(component.canDelete(selection)).toBe(false); - }); - - it('returns true if node has delete permission', () => { - const selection = [ { entry: { } } ]; - spyOn(component, 'nodeHasPermission').and.returnValue(true); - - expect(component.canDelete(selection)).toBe(true); - }); - }); - - describe('canMove()', () => { - it('returns true if node can be deleted', () => { - const selection = [ { entry: { } } ]; - spyOn(component, 'canDelete').and.returnValue(true); - - expect(component.canMove(selection)).toBe(true); - }); - - it('returns false if node can not be deleted', () => { - const selection = [ { entry: { } } ]; - spyOn(component, 'canDelete').and.returnValue(false); - - expect(component.canMove(selection)).toBe(false); - }); - }); - - describe('canPreviewFile()', () => { - it('it returns true if node is file', () => { - const selection = [{ entry: { isFile: true } }]; - - expect(component.canPreviewFile(selection)).toBe(true); - }); - - it('it returns false if node is folder', () => { - const selection = [{ entry: { isFolder: true } }]; - - expect(component.canPreviewFile(selection)).toBe(false); - }); - }); - - describe('canShareFile()', () => { - it('it returns true if node is file', () => { - const selection = [{ entry: { isFile: true } }]; - - expect(component.canShareFile(selection)).toBe(true); - }); - - it('it returns false if node is folder', () => { - const selection = [{ entry: { isFolder: true } }]; - - expect(component.canShareFile(selection)).toBe(false); - }); - }); - - describe('canDownloadFile()', () => { - it('it returns true if node is file', () => { - const selection = [{ entry: { isFile: true } }]; - - expect(component.canDownloadFile(selection)).toBe(true); - }); - - it('it returns false if node is folder', () => { - const selection = [{ entry: { isFolder: true } }]; - - expect(component.canDownloadFile(selection)).toBe(false); - }); - }); - - describe('nodeHasPermission()', () => { - it('returns true is has permission', () => { - const node = { allowableOperations: ['some-operation'] }; - - expect(component.nodeHasPermission(node, 'some-operation')).toBe(true); - }); - - it('returns true is has permission', () => { - const node = { allowableOperations: ['other-operation'] }; - - expect(component.nodeHasPermission(node, 'some-operation')).toBe(false); - }); - }); - - describe('canUpdate()', () => { - it('should return true if node can be edited', () => { - const selection = [ { entry: { - allowableOperations: ['update'] - } } ]; - - expect(component.canUpdate(selection)).toBe(true); - }); - - it(`should return false if node cannot be edited`, () => { - const selection = [ { entry: { - allowableOperations: ['other-permission'] - } } ]; - - expect(component.canUpdate(selection)).toBe(false); + expect(component.isFolderSelected(selection)).toBe(false); }); }); }); diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 2cc52f67ec..48e1021304 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -49,20 +49,6 @@ export abstract class PageComponent { return selection && selection.length > 0; } - filesOnlySelected(selection: Array): boolean { - if (this.hasSelection(selection)) { - return selection.every(entity => entity.entry && entity.entry.isFile); - } - return false; - } - - foldersOnlySelected(selection: Array): boolean { - if (this.hasSelection(selection)) { - return selection.every(entity => entity.entry && entity.entry.isFolder); - } - return false; - } - isFileSelected(selection: Array): boolean { if (selection && selection.length === 1) { const entry = selection[0].entry; @@ -74,58 +60,14 @@ export abstract class PageComponent { return false; } - canEditFolder(selection: Array): boolean { + isFolderSelected(selection: Array): boolean { if (selection && selection.length === 1) { const entry = selection[0].entry; if (entry && entry.isFolder) { - return this.nodeHasPermission(entry, 'update'); - } - } - return false; - } - - canDelete(selection: Array = []): boolean { - return selection.every(node => node.entry && this.nodeHasPermission(node.entry, 'delete')); - } - - canMove(selection: Array): boolean { - return this.canDelete(selection); - } - - canUpdate(selection: Array = []): boolean { - return selection.every(node => node.entry && this.nodeHasPermission(node.entry, 'update')); - } - - canPreviewFile(selection: Array): boolean { - return this.isFileSelected(selection); - } - - canShareFile(selection: Array): boolean { - return this.isFileSelected(selection); - } - - canDownloadFile(selection: Array): boolean { - return this.isFileSelected(selection); - } - - canUpdateFile(selection: Array): boolean { - return this.isFileSelected(selection) && this.nodeHasPermission(selection[0].entry, 'update'); - } - - canManageVersions(selection: Array): boolean { - return this.canUpdateFile(selection); - } - - nodeHasPermission(node: MinimalNodeEntryEntity, permission: string): boolean { - if (node && permission) { - const { allowableOperations = [] } = (node || {}); - - if (allowableOperations.indexOf(permission) > -1) { return true; } } - return false; } diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 9d88c729cd..980803be4f 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -8,7 +8,7 @@
diff --git a/src/app/components/recent-files/recent-files.component.spec.ts b/src/app/components/recent-files/recent-files.component.spec.ts index 62f681d2cd..deab9387f0 100644 --- a/src/app/components/recent-files/recent-files.component.spec.ts +++ b/src/app/components/recent-files/recent-files.component.spec.ts @@ -43,6 +43,7 @@ import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { AppConfigPipe } from '../../common/pipes/app-config.pipe'; +import { NodePermissionService } from '../../common/services/node-permission.service'; import { RecentFilesComponent } from './recent-files.component'; @@ -96,6 +97,7 @@ describe('RecentFiles Routed Component', () => { LogService, NotificationService, ContentManagementService, + NodePermissionService, ContentService, NodesApiService, DocumentListService, diff --git a/src/app/components/recent-files/recent-files.component.ts b/src/app/components/recent-files/recent-files.component.ts index a62b3e4f20..2d2dfe455f 100644 --- a/src/app/components/recent-files/recent-files.component.ts +++ b/src/app/components/recent-files/recent-files.component.ts @@ -32,6 +32,7 @@ import { DocumentListComponent } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; import { PageComponent } from '../page.component'; +import { NodePermissionService } from '../../common/services/node-permission.service'; @Component({ templateUrl: './recent-files.component.html' @@ -49,6 +50,7 @@ export class RecentFilesComponent extends PageComponent implements OnInit, OnDes private router: Router, private route: ActivatedRoute, private content: ContentManagementService, + public permission: NodePermissionService, preferences: UserPreferencesService) { super(preferences); diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index fe10ad64a5..063e55b3c9 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -7,7 +7,7 @@
diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 980803be4f..06f5c8529a 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -177,8 +177,8 @@
From 8a222bcb89b1983a5e5c5dd0f0f64add73040c01 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 10 May 2018 22:07:02 +0100 Subject: [PATCH 025/179] latest adf alpha (#353) * latest adf alpha * fix test * try using instant translation for page titles * upgrade to latest alpha * update app config * upgrade to adf app config pipe * update libs * update libs * update config file * fix code after upgrade * upgrade e2e * upgrade libs * update libs * fix e2e --- .angular-cli.json | 3 +- e2e/components/data-table/data-table.ts | 6 +- package-lock.json | 4322 ++++++++--------- package.json | 4 +- src/app.config.json | 9 +- src/app/app.component.ts | 7 +- src/app/app.module.ts | 4 - src/app/common/pipes/app-config.pipe.ts | 39 - .../empty-folder/empty-folder.component.html | 6 - .../empty-folder/empty-folder.component.scss | 29 - .../empty-folder.component.spec.ts | 33 - .../empty-folder/empty-folder.component.ts | 22 - .../favorites/favorites.component.html | 6 +- .../favorites/favorites.component.spec.ts | 3 +- src/app/components/files/files.component.html | 2 +- .../components/files/files.component.spec.ts | 3 +- .../libraries/libraries.component.html | 6 +- .../libraries/libraries.component.spec.ts | 3 +- src/app/components/login/login.component.html | 2 +- .../components/login/login.component.spec.ts | 5 +- .../recent-files/recent-files.component.html | 6 +- .../recent-files.component.spec.ts | 3 +- .../shared-files/shared-files.component.html | 6 +- .../shared-files.component.spec.ts | 3 +- .../trashcan/trashcan.component.html | 10 +- .../trashcan/trashcan.component.spec.ts | 3 +- src/app/ui/application.scss | 1 - src/app/ui/overrides/_adf-login.scss | 5 - .../ui/overrides/_alfresco-document-list.scss | 7 - 29 files changed, 2205 insertions(+), 2353 deletions(-) delete mode 100644 src/app/common/pipes/app-config.pipe.ts delete mode 100644 src/app/components/empty-folder/empty-folder.component.html delete mode 100644 src/app/components/empty-folder/empty-folder.component.scss delete mode 100644 src/app/components/empty-folder/empty-folder.component.spec.ts delete mode 100644 src/app/components/empty-folder/empty-folder.component.ts delete mode 100644 src/app/ui/overrides/_adf-login.scss diff --git a/.angular-cli.json b/.angular-cli.json index 144b4545c2..035ee99398 100644 --- a/.angular-cli.json +++ b/.angular-cli.json @@ -46,7 +46,8 @@ "scripts": [ "../node_modules/pdfjs-dist/build/pdf.js", "../node_modules/pdfjs-dist/lib/shared/compatibility.js", - "../node_modules/pdfjs-dist/web/pdf_viewer.js" + "../node_modules/pdfjs-dist/web/pdf_viewer.js", + "../node_modules/moment/min/moment.min.js" ], "environmentSource": "environments/environment.ts", "environments": { diff --git a/e2e/components/data-table/data-table.ts b/e2e/components/data-table/data-table.ts index 1bf8de8167..2939adebe2 100755 --- a/e2e/components/data-table/data-table.ts +++ b/e2e/components/data-table/data-table.ts @@ -50,9 +50,9 @@ export class DataTable extends Component { emptyListContainer: 'div.adf-no-content-container', emptyFolderDragAndDrop: '.adf-empty-list_template .adf-empty-folder', - emptyListTitle: '.app-empty-folder__title', - emptyListSubtitle: '.app-empty-folder__subtitle', - emptyListText: '.app-empty-folder__text' + emptyListTitle: '.adf-empty-content__title', + emptyListSubtitle: '.adf-empty-content__subtitle', + emptyListText: '.adf-empty-content__text' }; head: ElementFinder = this.component.element(by.css(DataTable.selectors.head)); diff --git a/package-lock.json b/package-lock.json index 5f3b0873b4..0f7b89dfc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1.tgz", - "integrity": "sha512-CdlWq86julMSMo0BX0rZ0FKYVa261ZtQb6T1f+XkqwnQtv6QSPv4dEQcvF0f3IWXOpc3LcxOBcVhWq4DBNQsOQ==", + "version": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5.tgz", + "integrity": "sha512-yecP7jB8oNJycCA5yY8jUgIYBOx35zAGQiIR5jGgpmsOC3QBTUx6pbAtRe5goi7TDZ0EWgrbPzvkxJFRKgnZ4Q==", "requires": { - "@alfresco/adf-core": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", + "@alfresco/adf-core": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -36,7 +36,7 @@ "reflect-metadata": "0.1.10", "rxjs": "5.5.2", "systemjs": "0.19.27", - "tslib": "1.9.0", + "tslib": "^1.7.1", "zone.js": "0.8.14" }, "dependencies": { @@ -50,7 +50,7 @@ "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz", "integrity": "sha1-hYXGUWquIU1ZCXXo+ys8PzrxTO8=", "requires": { - "node-ensure": "0.0.0" + "node-ensure": "^0.0.0" } }, "zone.js": { @@ -61,9 +61,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1.tgz", - "integrity": "sha512-nsM0k0WCq5s/awvj2o5BxCXTv1RmOLKwcBiW/kw/daCWMrLSESt1Et3YEKm/A1axKPB0aT3xkdTqIkuADjcWKA==", + "version": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5.tgz", + "integrity": "sha512-UyLiCax5XK665cjgXLArmQZ2lS62oSlOGdxie1ZR+M4ez6cMPHcSqMm35pGWrSsmX00yc3Ka558izBOmRKYeFw==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -91,7 +91,7 @@ "reflect-metadata": "0.1.10", "rxjs": "5.5.2", "systemjs": "0.19.27", - "tslib": "1.9.0", + "tslib": "^1.7.1", "zone.js": "0.8.14" }, "dependencies": { @@ -105,7 +105,7 @@ "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-1.5.404.tgz", "integrity": "sha1-hYXGUWquIU1ZCXXo+ys8PzrxTO8=", "requires": { - "node-ensure": "0.0.0" + "node-ensure": "^0.0.0" } }, "zone.js": { @@ -121,10 +121,10 @@ "integrity": "sha512-U0BCZtThq5rUfY08shHXpxe8ZhSsiYB/cJjUvAWRTs/ORrs8pbngS6xwseQws8d/vHoVrtqGD9GU9h8AmFRERQ==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "source-map": "0.5.7", - "typescript": "2.6.2", - "webpack-sources": "1.1.0" + "loader-utils": "^1.1.0", + "source-map": "^0.5.6", + "typescript": "~2.6.2", + "webpack-sources": "^1.0.1" }, "dependencies": { "typescript": { @@ -141,10 +141,10 @@ "integrity": "sha512-zABk/iP7YX5SVbmK4e+IX7j2d0D37MQJQiKgWdV3JzfvVJhNJzddiirtT980pIafoq+KyvTgVwXtc+vnux0oeQ==", "dev": true, "requires": { - "ajv": "5.5.2", - "chokidar": "1.7.0", - "rxjs": "5.5.10", - "source-map": "0.5.7" + "ajv": "~5.5.1", + "chokidar": "^1.7.0", + "rxjs": "^5.5.6", + "source-map": "^0.5.6" }, "dependencies": { "ajv": { @@ -153,10 +153,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "rxjs": { @@ -182,8 +182,8 @@ "integrity": "sha512-B6zZoqvHaTJy+vVdA6EtlxnCdGMa5elCa4j9lQLC3JI8DLvMXUWkCIPVbPzJ/GSRR9nsKWpvYMYaJyfBDUqfhw==", "dev": true, "requires": { - "@ngtools/json-schema": "1.2.0", - "rxjs": "5.5.10" + "@ngtools/json-schema": "^1.1.0", + "rxjs": "^5.5.6" }, "dependencies": { "rxjs": { @@ -208,7 +208,7 @@ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-5.1.1.tgz", "integrity": "sha512-PHLBWDnAzr5b5l52pk5ZYmv/6m0YUe2ICwu5dmbS0d8Kf5dXadMphAWCDbljMF+djGyZeFq2/dQ/t7ygYl3YuA==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/cdk": { @@ -216,7 +216,7 @@ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-5.0.1.tgz", "integrity": "sha512-uK4Vyaf06J8KqePzq35BxMHRGolt35EnbZf9wjCs7eYaghbQ7Pk2xUGoynu5Lj1wAOn5N1/C1nT2/aAH/EE2rw==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/cli": { @@ -232,58 +232,58 @@ "@ngtools/webpack": "1.10.2", "@schematics/angular": "0.3.2", "@schematics/package-update": "0.3.2", - "ajv": "6.4.0", - "autoprefixer": "7.2.6", - "cache-loader": "1.2.2", - "chalk": "2.2.2", - "circular-dependency-plugin": "4.4.0", - "clean-css": "4.1.11", - "common-tags": "1.7.2", - "copy-webpack-plugin": "4.4.3", - "core-object": "3.1.5", - "denodeify": "1.2.1", - "ember-cli-string-utils": "1.1.0", - "extract-text-webpack-plugin": "3.0.2", - "file-loader": "1.1.11", - "fs-extra": "4.0.3", - "glob": "7.1.2", - "html-webpack-plugin": "2.30.1", - "istanbul-instrumenter-loader": "3.0.1", - "karma-source-map-support": "1.2.0", - "less": "2.7.3", - "less-loader": "4.1.0", - "license-webpack-plugin": "1.3.1", + "ajv": "^6.1.1", + "autoprefixer": "^7.2.3", + "cache-loader": "^1.2.0", + "chalk": "~2.2.0", + "circular-dependency-plugin": "^4.2.1", + "clean-css": "^4.1.11", + "common-tags": "^1.3.1", + "copy-webpack-plugin": "~4.4.1", + "core-object": "^3.1.0", + "denodeify": "^1.2.1", + "ember-cli-string-utils": "^1.0.0", + "extract-text-webpack-plugin": "^3.0.2", + "file-loader": "^1.1.5", + "fs-extra": "^4.0.0", + "glob": "^7.0.3", + "html-webpack-plugin": "^2.29.0", + "istanbul-instrumenter-loader": "^3.0.0", + "karma-source-map-support": "^1.2.0", + "less": "^2.7.2", + "less-loader": "^4.0.5", + "license-webpack-plugin": "^1.0.0", "loader-utils": "1.1.0", - "lodash": "4.17.10", - "memory-fs": "0.4.1", - "minimatch": "3.0.4", - "node-modules-path": "1.0.1", - "node-sass": "4.9.0", - "nopt": "4.0.1", - "opn": "5.1.0", - "portfinder": "1.0.13", - "postcss": "6.0.22", - "postcss-import": "11.1.0", - "postcss-loader": "2.1.4", - "postcss-url": "7.3.2", - "raw-loader": "0.5.1", - "resolve": "1.7.1", - "rxjs": "5.5.10", - "sass-loader": "6.0.7", - "semver": "5.5.0", - "silent-error": "1.1.0", - "source-map-support": "0.4.18", - "style-loader": "0.19.1", - "stylus": "0.54.5", - "stylus-loader": "3.0.2", - "uglifyjs-webpack-plugin": "1.2.5", - "url-loader": "0.6.2", - "webpack": "3.11.0", - "webpack-dev-middleware": "1.12.2", - "webpack-dev-server": "2.11.2", - "webpack-merge": "4.1.2", - "webpack-sources": "1.1.0", - "webpack-subresource-integrity": "1.0.4" + "lodash": "^4.11.1", + "memory-fs": "^0.4.1", + "minimatch": "^3.0.4", + "node-modules-path": "^1.0.0", + "node-sass": "^4.7.2", + "nopt": "^4.0.1", + "opn": "~5.1.0", + "portfinder": "~1.0.12", + "postcss": "^6.0.16", + "postcss-import": "^11.0.0", + "postcss-loader": "^2.0.10", + "postcss-url": "^7.1.2", + "raw-loader": "^0.5.1", + "resolve": "^1.1.7", + "rxjs": "^5.5.6", + "sass-loader": "^6.0.6", + "semver": "^5.1.0", + "silent-error": "^1.0.0", + "source-map-support": "^0.4.1", + "style-loader": "^0.19.1", + "stylus": "^0.54.5", + "stylus-loader": "^3.0.1", + "uglifyjs-webpack-plugin": "^1.1.8", + "url-loader": "^0.6.2", + "webpack": "~3.11.0", + "webpack-dev-middleware": "~1.12.0", + "webpack-dev-server": "~2.11.0", + "webpack-merge": "^4.1.0", + "webpack-sources": "^1.0.0", + "webpack-subresource-integrity": "^1.0.1" }, "dependencies": { "rxjs": { @@ -308,7 +308,7 @@ "resolved": "https://registry.npmjs.org/@angular/common/-/common-5.1.1.tgz", "integrity": "sha512-SFRzdDthoiKaMLuV+TAwjKXFWwTRFGuidlWC3BhUf8/HzNSePAdvfdQcqbEaE5buMn403OV105S9Tyx5tILQeA==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/compiler": { @@ -316,7 +316,7 @@ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-5.1.1.tgz", "integrity": "sha512-k4J2kRiBjtjkDcDut2JVUpqQGLJWd8j3Don+swzZHuEklbLmsVRGM6u/fmH0K9TMwKHtC5Ycap8kj4bWXUYfwg==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/compiler-cli": { @@ -325,10 +325,10 @@ "integrity": "sha512-X3n1V0fAsZzJDRLM2OPiOri8rrQ2ILFS0VDqPdHMa1HbpF0ZKe1Yyux2rhGSbS83a1Eanx6RqfDkrUalKEprbw==", "dev": true, "requires": { - "chokidar": "1.7.0", - "minimist": "1.2.0", - "reflect-metadata": "0.1.10", - "tsickle": "0.25.6" + "chokidar": "^1.4.2", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "tsickle": "^0.25.5" }, "dependencies": { "minimist": { @@ -344,7 +344,7 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-5.1.1.tgz", "integrity": "sha512-8HJ0lNM5Z+pf+JfOl5mAWgNfrdtnMhVcEGCEniJAQweKOfYCziuyB0ALkX/Q6jGmd2IshR36SarwCYEc5ttt/w==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/flex-layout": { @@ -352,7 +352,7 @@ "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-2.0.0-beta.12.tgz", "integrity": "sha512-QTOKZxehYTh8fj64V/pNVWNbfNtebSbssyMIXiGJuHTzfyF7GYdRmtjoR2pNpllycz3rE5NYX77EB140Y6BCnw==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/forms": { @@ -360,7 +360,7 @@ "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-5.1.1.tgz", "integrity": "sha512-4iN/8N0DgnV82XIb/8PqlFIGrog8BHJlzQ9sdAlpT29biPFezFpqpsXkjLBouBc7oBFTgoyXMgWDj8IGRmwLGQ==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/http": { @@ -368,7 +368,7 @@ "resolved": "https://registry.npmjs.org/@angular/http/-/http-5.1.1.tgz", "integrity": "sha512-oeiLX00TaFlGS5Y4EAGnxxVitN8T9X8olhSC+XDDAAL3JHTAyh4dj7me8vNZk1VaqPFa9AXu4D34vu1Zsm0c1g==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/language-service": { @@ -382,7 +382,7 @@ "resolved": "https://registry.npmjs.org/@angular/material/-/material-5.0.1.tgz", "integrity": "sha512-k95i58ZIVneLE61a5JliM10NSasy9P5C2JJUESo3s/rxt9dq/9XOWpUvNCy49OHYBRFJBlsyrLM6E2V7/tmq4w==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/material-moment-adapter": { @@ -390,7 +390,7 @@ "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-5.0.1.tgz", "integrity": "sha512-SyFsoxnwXHAR4zLkFh7Z4NmxZANyBoLGAomVZRi2r9w1prc+kbaCaJ7LYjI6zM7Su4ltSQx0libbat1ppgow2w==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/platform-browser": { @@ -398,7 +398,7 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-5.1.1.tgz", "integrity": "sha512-QpkNXoO2pqURQJxXPhZo6RFeirKbr56O0SwoMpYfXGGN1qEIicoWZHobCUTp7/jvjx5Xjc7886Fvu/qJrE7wVA==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/platform-browser-dynamic": { @@ -406,7 +406,7 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-5.1.1.tgz", "integrity": "sha512-xnin1eK5nF7EO4tYZvRlhT28DyhL3p4NKWsZQwfqyBwSF0T2mJ1vjhjCZVT0MmaOyt5D+0eUkHIhBDqeZyBMMQ==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@angular/router": { @@ -414,7 +414,7 @@ "resolved": "https://registry.npmjs.org/@angular/router/-/router-5.1.1.tgz", "integrity": "sha512-96mBZS1b1Dt7HFOGKh5zI/1U6F3zT4cdjIaBmcCKkbyKhs3WRAPXxxCkuCwr6lWmBeQt4iEvSdXiHQbD0iCG7Q==", "requires": { - "tslib": "1.9.0" + "tslib": "^1.7.1" } }, "@mat-datetimepicker/core": { @@ -439,14 +439,14 @@ "integrity": "sha512-3u2zg2rarG3qNLSukBClGADWuq/iNn5SQtlSeAbfKzwBeyLGbF0gN1z1tVx1Bcr8YwFzR6NdRePQmJGcoqq1fg==", "dev": true, "requires": { - "chalk": "2.2.2", - "enhanced-resolve": "3.4.1", - "loader-utils": "1.1.0", - "magic-string": "0.22.5", - "semver": "5.5.0", - "source-map": "0.5.7", - "tree-kill": "1.2.0", - "webpack-sources": "1.1.0" + "chalk": "~2.2.0", + "enhanced-resolve": "^3.1.0", + "loader-utils": "^1.0.2", + "magic-string": "^0.22.3", + "semver": "^5.3.0", + "source-map": "^0.5.6", + "tree-kill": "^1.0.0", + "webpack-sources": "^1.1.0" } }, "@ngx-translate/core": { @@ -460,7 +460,7 @@ "integrity": "sha512-Elrk0BA951s0ScFZU0AWrpUeJBYVR52DZ1QTIO5R0AhwEd1PW4olI8szPLGQlVW5Sd6H0FA/fyFLIvn2r9v6Rw==", "dev": true, "requires": { - "typescript": "2.6.2" + "typescript": "~2.6.2" }, "dependencies": { "typescript": { @@ -477,9 +477,9 @@ "integrity": "sha512-7aVP4994Hu8vRdTTohXkfGWEwLhrdNP3EZnWyBootm5zshWqlQojUGweZe5zwewsKcixeVOiy2YtW+aI4aGSLA==", "dev": true, "requires": { - "rxjs": "5.5.10", - "semver": "5.5.0", - "semver-intersect": "1.3.1" + "rxjs": "^5.5.6", + "semver": "^5.3.0", + "semver-intersect": "^1.1.2" }, "dependencies": { "rxjs": { @@ -511,7 +511,7 @@ "integrity": "sha512-hYDVmQZT5VA2kigd4H4bv7vl/OhlympwREUemqBdOqtrYTo5Ytm12a5W5/nGgGYdanGVxj0x/VhZ7J3hOg/YKg==", "dev": true, "requires": { - "@types/jasmine": "2.8.7" + "@types/jasmine": "*" } }, "@types/node": { @@ -556,7 +556,7 @@ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "dev": true, "requires": { - "mime-types": "2.1.18", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -572,7 +572,7 @@ "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", "dev": true, "requires": { - "acorn": "4.0.13" + "acorn": "^4.0.3" }, "dependencies": { "acorn": { @@ -608,8 +608,8 @@ "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", "dev": true, "requires": { - "extend": "3.0.1", - "semver": "5.0.3" + "extend": "~3.0.0", + "semver": "~5.0.1" }, "dependencies": { "semver": { @@ -625,10 +625,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", "requires": { - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1", - "uri-js": "3.0.2" + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0", + "uri-js": "^3.0.2" } }, "ajv-keywords": { @@ -651,9 +651,9 @@ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, "amdefine": { @@ -669,11 +669,11 @@ "dev": true, "optional": true, "requires": { - "bitsyntax": "0.0.4", - "bluebird": "3.5.1", + "bitsyntax": "~0.0.4", + "bluebird": "^3.4.6", "buffer-more-ints": "0.0.2", - "readable-stream": "1.1.14", - "safe-buffer": "5.1.2" + "readable-stream": "1.x >=1.1.9", + "safe-buffer": "^5.0.1" }, "dependencies": { "isarray": { @@ -690,10 +690,10 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "string_decoder": { @@ -723,7 +723,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.1" + "color-convert": "^1.9.0" }, "dependencies": { "color-convert": { @@ -732,7 +732,7 @@ "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "^1.1.1" } } } @@ -743,8 +743,8 @@ "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", "dev": true, "requires": { - "micromatch": "2.3.11", - "normalize-path": "2.1.1" + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" } }, "app-root-path": { @@ -759,7 +759,7 @@ "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", "dev": true, "requires": { - "default-require-extensions": "1.0.0" + "default-require-extensions": "^1.0.0" } }, "aproba": { @@ -774,8 +774,8 @@ "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.6" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "argparse": { @@ -784,7 +784,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "arr-diff": { @@ -793,7 +793,7 @@ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "arr-flatten": { @@ -826,8 +826,8 @@ "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", "dev": true, "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.11.0" + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" } }, "array-slice": { @@ -842,7 +842,7 @@ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -888,9 +888,9 @@ "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "requires": { - "bn.js": "4.11.8", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "assert": { @@ -927,7 +927,7 @@ "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", "dev": true, "requires": { - "lodash": "4.17.10" + "lodash": "^4.14.0" } }, "async-each": { @@ -966,12 +966,12 @@ "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", "dev": true, "requires": { - "browserslist": "2.11.3", - "caniuse-lite": "1.0.30000833", - "normalize-range": "0.1.2", - "num2fraction": "1.2.2", - "postcss": "6.0.22", - "postcss-value-parser": "3.3.0" + "browserslist": "^2.11.3", + "caniuse-lite": "^1.0.30000805", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^6.0.17", + "postcss-value-parser": "^3.2.3" } }, "aws-sign2": { @@ -1013,7 +1013,7 @@ "dev": true, "optional": true, "requires": { - "debug": "2.6.9" + "debug": "^2.2.0" } } } @@ -1024,9 +1024,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "ansi-styles": { @@ -1041,11 +1041,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "supports-color": { @@ -1062,14 +1062,14 @@ "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", "dev": true, "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.10", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" } }, "babel-messages": { @@ -1078,7 +1078,7 @@ "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" } }, "babel-runtime": { @@ -1087,8 +1087,8 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { - "core-js": "2.5.3", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { @@ -1097,11 +1097,11 @@ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.10" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -1110,15 +1110,15 @@ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.10" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" }, "dependencies": { "debug": { @@ -1138,10 +1138,10 @@ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.10", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { @@ -1167,13 +1167,13 @@ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { @@ -1182,7 +1182,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -1191,7 +1191,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -1200,7 +1200,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -1209,9 +1209,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "isobject": { @@ -1259,7 +1259,7 @@ "dev": true, "optional": true, "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "better-assert": { @@ -1299,7 +1299,7 @@ "dev": true, "optional": true, "requires": { - "readable-stream": "2.0.6" + "readable-stream": "~2.0.5" }, "dependencies": { "process-nextick-args": { @@ -1316,12 +1316,12 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -1346,7 +1346,7 @@ "dev": true, "optional": true, "requires": { - "inherits": "2.0.3" + "inherits": "~2.0.0" } }, "blocking-proxy": { @@ -1355,7 +1355,7 @@ "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", "dev": true, "requires": { - "minimist": "1.2.0" + "minimist": "^1.2.0" }, "dependencies": { "minimist": { @@ -1385,15 +1385,15 @@ "dev": true, "requires": { "bytes": "3.0.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", + "depd": "~1.1.1", + "http-errors": "~1.6.2", "iconv-lite": "0.4.19", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.5.1", "raw-body": "2.3.2", - "type-is": "1.6.16" + "type-is": "~1.6.15" }, "dependencies": { "debug": { @@ -1413,12 +1413,12 @@ "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", "dev": true, "requires": { - "array-flatten": "2.1.1", - "deep-equal": "1.0.1", - "dns-equal": "1.0.0", - "dns-txt": "2.0.2", - "multicast-dns": "6.2.3", - "multicast-dns-service-types": "1.1.0" + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" } }, "boolbase": { @@ -1433,7 +1433,7 @@ "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" } }, "brace-expansion": { @@ -1441,7 +1441,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -1451,9 +1451,9 @@ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "brorand": { @@ -1468,12 +1468,12 @@ "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "browserify-cipher": { @@ -1482,9 +1482,9 @@ "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { - "browserify-aes": "1.2.0", - "browserify-des": "1.0.1", - "evp_bytestokey": "1.0.3" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, "browserify-des": { @@ -1493,9 +1493,9 @@ "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "des.js": "1.0.0", - "inherits": "2.0.3" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1" } }, "browserify-rsa": { @@ -1504,8 +1504,8 @@ "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { - "bn.js": "4.11.8", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" } }, "browserify-sign": { @@ -1514,13 +1514,13 @@ "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", "dev": true, "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "elliptic": "6.4.0", - "inherits": "2.0.3", - "parse-asn1": "5.1.1" + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" } }, "browserify-zlib": { @@ -1529,7 +1529,7 @@ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "requires": { - "pako": "1.0.6" + "pako": "~1.0.5" } }, "browserslist": { @@ -1538,8 +1538,8 @@ "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", "dev": true, "requires": { - "caniuse-lite": "1.0.30000833", - "electron-to-chromium": "1.3.45" + "caniuse-lite": "^1.0.30000792", + "electron-to-chromium": "^1.3.30" } }, "buffer": { @@ -1548,9 +1548,9 @@ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { - "base64-js": "1.3.0", - "ieee754": "1.1.11", - "isarray": "1.0.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, "buffer-from": { @@ -1626,19 +1626,19 @@ "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", "dev": true, "requires": { - "bluebird": "3.5.1", - "chownr": "1.0.1", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "lru-cache": "4.1.2", - "mississippi": "2.0.0", - "mkdirp": "0.5.1", - "move-concurrently": "1.0.1", - "promise-inflight": "1.0.1", - "rimraf": "2.6.2", - "ssri": "5.3.0", - "unique-filename": "1.1.0", - "y18n": "4.0.0" + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" } }, "cache-base": { @@ -1647,15 +1647,15 @@ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" }, "dependencies": { "isobject": { @@ -1672,10 +1672,10 @@ "integrity": "sha512-rsGh4SIYyB9glU+d0OcHwiXHXBoUgDhHZaQ1KAbiXqfz1CDPxtTboh1gPbJ0q2qdO8a9lfcjgC5CJ2Ms32y5bw==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "mkdirp": "0.5.1", - "neo-async": "2.5.1", - "schema-utils": "0.4.5" + "loader-utils": "^1.1.0", + "mkdirp": "^0.5.1", + "neo-async": "^2.5.0", + "schema-utils": "^0.4.2" } }, "callsite": { @@ -1690,8 +1690,8 @@ "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", "dev": true, "requires": { - "no-case": "2.3.2", - "upper-case": "1.1.3" + "no-case": "^2.2.0", + "upper-case": "^1.1.1" } }, "camelcase": { @@ -1706,8 +1706,8 @@ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" } }, "caniuse-lite": { @@ -1728,8 +1728,8 @@ "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "chalk": { @@ -1738,9 +1738,9 @@ "integrity": "sha512-LvixLAQ4MYhbf7hgL4o5PeK32gJKvVzDRiSNIApDofQvyhl8adgG2lJVXn4+ekQoK7HL9RF8lqxwerpe0x2pCw==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" } }, "chart.js": { @@ -1748,8 +1748,8 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.5.0.tgz", "integrity": "sha1-/m51Gok3afVucr7lrZEgfhxZKVc=", "requires": { - "chartjs-color": "2.2.0", - "moment": "2.20.1" + "chartjs-color": "^2.0.0", + "moment": "^2.10.6" } }, "chartjs-color": { @@ -1757,8 +1757,8 @@ "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz", "integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=", "requires": { - "chartjs-color-string": "0.5.0", - "color-convert": "0.5.3" + "chartjs-color-string": "^0.5.0", + "color-convert": "^0.5.3" } }, "chartjs-color-string": { @@ -1766,7 +1766,7 @@ "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz", "integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==", "requires": { - "color-name": "1.1.3" + "color-name": "^1.0.0" } }, "chokidar": { @@ -1775,15 +1775,15 @@ "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", "dev": true, "requires": { - "anymatch": "1.3.2", - "async-each": "1.0.1", - "fsevents": "1.2.3", - "glob-parent": "2.0.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "2.0.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0" + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" } }, "chownr": { @@ -1798,8 +1798,8 @@ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "circular-dependency-plugin": { @@ -1820,10 +1820,10 @@ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -1832,7 +1832,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "isobject": { @@ -1849,7 +1849,7 @@ "integrity": "sha1-Ls3xRaujj1R0DybO/Q/z4D4SXWo=", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "0.5.x" } }, "cliui": { @@ -1858,9 +1858,9 @@ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" } }, "clone": { @@ -1875,10 +1875,10 @@ "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", "dev": true, "requires": { - "for-own": "1.0.0", - "is-plain-object": "2.0.4", - "kind-of": "6.0.2", - "shallow-clone": "1.0.0" + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.0", + "shallow-clone": "^1.0.0" }, "dependencies": { "for-own": { @@ -1887,7 +1887,7 @@ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "kind-of": { @@ -1910,14 +1910,14 @@ "integrity": "sha512-MGMkPS5d9AqQEXTZ4grn/syl/7VvOehgWTeU2B41E22q767QolclfdfadKAndL287cIPEOEdwh9JBqCwQJLtFw==", "dev": true, "requires": { - "bluebird": "3.5.1", - "commander": "2.15.1", - "joi": "12.0.0", - "lcov-parse": "1.0.0", - "lodash": "4.17.10", - "log-driver": "1.2.7", - "request": "2.85.0", - "request-promise": "4.2.2" + "bluebird": "^3.5.x", + "commander": "^2.x", + "joi": "^12.x", + "lcov-parse": "^1.x", + "lodash": "^4.17.4", + "log-driver": "^1.x", + "request": "^2.83.0", + "request-promise": "^4.x" }, "dependencies": { "ajv": { @@ -1926,10 +1926,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "assert-plus": { @@ -1950,7 +1950,7 @@ "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "dev": true, "requires": { - "hoek": "4.2.1" + "hoek": "4.x.x" } }, "cryptiles": { @@ -1959,7 +1959,7 @@ "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "dev": true, "requires": { - "boom": "5.2.0" + "boom": "5.x.x" }, "dependencies": { "boom": { @@ -1968,7 +1968,7 @@ "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", "dev": true, "requires": { - "hoek": "4.2.1" + "hoek": "4.x.x" } } } @@ -1985,8 +1985,8 @@ "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "dev": true, "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.1.0", + "har-schema": "^2.0.0" } }, "hawk": { @@ -1995,10 +1995,10 @@ "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", "dev": true, "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.1", - "sntp": "2.1.0" + "boom": "4.x.x", + "cryptiles": "3.x.x", + "hoek": "4.x.x", + "sntp": "2.x.x" } }, "hoek": { @@ -2013,9 +2013,9 @@ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "dev": true, "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.14.1" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "performance-now": { @@ -2030,28 +2030,28 @@ "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", "dev": true, "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.2", - "stringstream": "0.0.5", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "hawk": "~6.0.2", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "stringstream": "~0.0.5", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" } }, "sntp": { @@ -2060,7 +2060,7 @@ "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", "dev": true, "requires": { - "hoek": "4.2.1" + "hoek": "4.x.x" } } } @@ -2077,12 +2077,12 @@ "integrity": "sha512-RLMrtLwrBS0dfo2/KTP+2NHofCpzcuh0bEp/A/naqvQonbUL4AW/qWQdbpn8dMNudtpmzEx9eS8KEpGdVPg1BA==", "dev": true, "requires": { - "app-root-path": "2.0.1", - "css-selector-tokenizer": "0.7.0", - "cssauron": "1.4.0", - "semver-dsl": "1.0.1", - "source-map": "0.5.7", - "sprintf-js": "1.0.3" + "app-root-path": "^2.0.1", + "css-selector-tokenizer": "^0.7.0", + "cssauron": "^1.4.0", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.0.3" } }, "collection-visit": { @@ -2091,8 +2091,8 @@ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color-convert": { @@ -2117,7 +2117,7 @@ "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", "dev": true, "requires": { - "lodash": "4.17.10" + "lodash": "^4.5.0" } }, "combined-stream": { @@ -2125,7 +2125,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { @@ -2140,7 +2140,7 @@ "integrity": "sha512-joj9ZlUOjCrwdbmiLqafeUSgkUM74NqhLsZtSqDmhKudaIY197zTrb8JMl31fMnCUuxwFT23eC/oWvrZzDLRJQ==", "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.26.0" } }, "commondir": { @@ -2178,7 +2178,7 @@ "integrity": "sha1-DRAgq5JLL9tNYnmHXH1tq6a6p6k=", "dev": true, "requires": { - "mime-db": "1.33.0" + "mime-db": ">= 1.33.0 < 2" } }, "compression": { @@ -2187,13 +2187,13 @@ "integrity": "sha1-qv+81qr4VLROuygDU9WtFlH1mmk=", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.4", "bytes": "3.0.0", - "compressible": "2.0.13", + "compressible": "~2.0.13", "debug": "2.6.9", - "on-headers": "1.0.1", + "on-headers": "~1.0.1", "safe-buffer": "5.1.1", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "debug": { @@ -2224,10 +2224,10 @@ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "buffer-from": "1.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "connect": { @@ -2238,7 +2238,7 @@ "requires": { "debug": "2.6.9", "finalhandler": "1.1.0", - "parseurl": "1.3.2", + "parseurl": "~1.3.2", "utils-merge": "1.0.1" }, "dependencies": { @@ -2258,12 +2258,12 @@ "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.3.1", - "unpipe": "1.0.0" + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" } }, "statuses": { @@ -2286,7 +2286,7 @@ "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", "dev": true, "requires": { - "date-now": "0.1.4" + "date-now": "^0.1.4" } }, "console-control-strings": { @@ -2342,12 +2342,12 @@ "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "dev": true, "requires": { - "aproba": "1.2.0", - "fs-write-stream-atomic": "1.0.10", - "iferr": "0.1.5", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" } }, "copy-descriptor": { @@ -2362,14 +2362,14 @@ "integrity": "sha512-v4THQ24Tks2NkyOvZuFDgZVfDD9YaA9rwYLZTrWg2GHIA8lrH5DboEyeoorh5Skki+PUbgSmnsCwhMWqYrQZrA==", "dev": true, "requires": { - "cacache": "10.0.4", - "find-cache-dir": "1.0.0", - "globby": "7.1.1", - "is-glob": "4.0.0", - "loader-utils": "1.1.0", - "minimatch": "3.0.4", - "p-limit": "1.2.0", - "serialize-javascript": "1.5.0" + "cacache": "^10.0.1", + "find-cache-dir": "^1.0.0", + "globby": "^7.1.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "minimatch": "^3.0.4", + "p-limit": "^1.0.0", + "serialize-javascript": "^1.4.0" }, "dependencies": { "is-extglob": { @@ -2384,7 +2384,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } } } @@ -2400,7 +2400,7 @@ "integrity": "sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg==", "dev": true, "requires": { - "chalk": "2.2.2" + "chalk": "^2.0.0" } }, "core-util-is": { @@ -2414,13 +2414,13 @@ "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", "dev": true, "requires": { - "is-directory": "0.3.1", - "js-yaml": "3.11.0", - "minimist": "1.2.0", - "object-assign": "4.1.1", - "os-homedir": "1.0.2", - "parse-json": "2.2.0", - "require-from-string": "1.2.1" + "is-directory": "^0.3.1", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "require-from-string": "^1.1.0" }, "dependencies": { "minimist": { @@ -2437,8 +2437,8 @@ "integrity": "sha512-iZvCCg8XqHQZ1ioNBTzXS/cQSkqkqcPs8xSX4upNB+DAk9Ht3uzQf2J32uAHNCne8LDmKr29AgZrEs4oIrwLuQ==", "dev": true, "requires": { - "bn.js": "4.11.8", - "elliptic": "6.4.0" + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" } }, "create-hash": { @@ -2447,11 +2447,11 @@ "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.3", - "md5.js": "1.3.4", - "ripemd160": "2.0.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, "create-hmac": { @@ -2460,12 +2460,12 @@ "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "inherits": "2.0.3", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "cross-spawn": { @@ -2475,8 +2475,8 @@ "dev": true, "optional": true, "requires": { - "lru-cache": "4.1.2", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "which": "^1.2.9" } }, "cryptiles": { @@ -2485,7 +2485,7 @@ "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", "dev": true, "requires": { - "boom": "2.10.1" + "boom": "2.x.x" } }, "crypto-browserify": { @@ -2494,17 +2494,17 @@ "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, "requires": { - "browserify-cipher": "1.0.1", - "browserify-sign": "4.0.4", - "create-ecdh": "4.0.1", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "diffie-hellman": "5.0.3", - "inherits": "2.0.3", - "pbkdf2": "3.0.16", - "public-encrypt": "4.0.2", - "randombytes": "2.0.6", - "randomfill": "1.0.4" + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" } }, "css-parse": { @@ -2519,10 +2519,10 @@ "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "dev": true, "requires": { - "boolbase": "1.0.0", - "css-what": "2.1.0", + "boolbase": "~1.0.0", + "css-what": "2.1", "domutils": "1.5.1", - "nth-check": "1.0.1" + "nth-check": "~1.0.1" } }, "css-selector-tokenizer": { @@ -2531,9 +2531,9 @@ "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", "dev": true, "requires": { - "cssesc": "0.1.0", - "fastparse": "1.1.1", - "regexpu-core": "1.0.0" + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" } }, "css-what": { @@ -2548,7 +2548,7 @@ "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", "dev": true, "requires": { - "through": "2.3.8" + "through": "X.X.X" } }, "cssesc": { @@ -2569,7 +2569,7 @@ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "dev": true, "requires": { - "array-find-index": "1.0.2" + "array-find-index": "^1.0.1" } }, "custom-event": { @@ -2589,7 +2589,7 @@ "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=", "requires": { - "es5-ext": "0.10.42" + "es5-ext": "~0.10.2" } }, "dashdash": { @@ -2598,7 +2598,7 @@ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" }, "dependencies": { "assert-plus": { @@ -2667,7 +2667,7 @@ "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "dev": true, "requires": { - "strip-bom": "2.0.0" + "strip-bom": "^2.0.0" } }, "define-properties": { @@ -2676,8 +2676,8 @@ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", "dev": true, "requires": { - "foreach": "2.0.5", - "object-keys": "1.0.11" + "foreach": "^2.0.5", + "object-keys": "^1.0.8" } }, "define-property": { @@ -2686,8 +2686,8 @@ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -2696,7 +2696,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -2705,7 +2705,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -2714,9 +2714,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "isobject": { @@ -2740,9 +2740,9 @@ "dev": true, "optional": true, "requires": { - "ast-types": "0.11.3", - "escodegen": "1.9.1", - "esprima": "3.1.3" + "ast-types": "0.x.x", + "escodegen": "1.x.x", + "esprima": "3.x.x" }, "dependencies": { "esprima": { @@ -2760,12 +2760,12 @@ "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", "dev": true, "requires": { - "globby": "6.1.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "p-map": "1.2.0", - "pify": "3.0.0", - "rimraf": "2.6.2" + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" }, "dependencies": { "globby": { @@ -2774,11 +2774,11 @@ "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { - "array-union": "1.0.2", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { "pify": { @@ -2820,8 +2820,8 @@ "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", "dev": true, "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "destroy": { @@ -2836,7 +2836,7 @@ "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "dev": true, "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "detect-node": { @@ -2863,9 +2863,9 @@ "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { - "bn.js": "4.11.8", - "miller-rabin": "4.0.1", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" } }, "dir-glob": { @@ -2874,8 +2874,8 @@ "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", "dev": true, "requires": { - "arrify": "1.0.1", - "path-type": "3.0.0" + "arrify": "^1.0.1", + "path-type": "^3.0.0" } }, "dns-equal": { @@ -2890,8 +2890,8 @@ "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", "dev": true, "requires": { - "ip": "1.1.5", - "safe-buffer": "5.1.2" + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" } }, "dns-txt": { @@ -2900,7 +2900,7 @@ "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", "dev": true, "requires": { - "buffer-indexof": "1.1.1" + "buffer-indexof": "^1.0.0" } }, "dom-converter": { @@ -2909,7 +2909,7 @@ "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=", "dev": true, "requires": { - "utila": "0.3.3" + "utila": "~0.3" }, "dependencies": { "utila": { @@ -2926,10 +2926,10 @@ "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", "dev": true, "requires": { - "custom-event": "1.0.1", - "ent": "2.2.0", - "extend": "3.0.1", - "void-elements": "2.0.1" + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" } }, "dom-serializer": { @@ -2938,8 +2938,8 @@ "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "dev": true, "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.1" + "domelementtype": "~1.1.1", + "entities": "~1.1.1" }, "dependencies": { "domelementtype": { @@ -2968,7 +2968,7 @@ "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", "dev": true, "requires": { - "domelementtype": "1.3.0" + "domelementtype": "1" } }, "domutils": { @@ -2977,8 +2977,8 @@ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "dev": true, "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" + "dom-serializer": "0", + "domelementtype": "1" } }, "double-ended-queue": { @@ -2994,10 +2994,10 @@ "integrity": "sha512-JzYSLYMhoVVBe8+mbHQ4KgpvHpm0DZpJuL8PY93Vyv1fW7jYJ90LoXa1di/CVbJM+TgMs91rbDapE/RNIfnJsA==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "stream-shift": "1.0.0" + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" } }, "ecc-jsbn": { @@ -3007,7 +3007,7 @@ "dev": true, "optional": true, "requires": { - "jsbn": "0.1.1" + "jsbn": "~0.1.0" } }, "ee-first": { @@ -3034,13 +3034,13 @@ "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", "dev": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0", - "hash.js": "1.1.3", - "hmac-drbg": "1.0.1", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" } }, "ember-cli-string-utils": { @@ -3066,7 +3066,7 @@ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { - "once": "1.4.0" + "once": "^1.4.0" } }, "engine.io": { @@ -3075,13 +3075,13 @@ "integrity": "sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA==", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.4", "base64id": "1.0.0", "cookie": "0.3.1", - "debug": "3.1.0", - "engine.io-parser": "2.1.2", - "uws": "9.14.0", - "ws": "3.3.3" + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "uws": "~9.14.0", + "ws": "~3.3.1" } }, "engine.io-client": { @@ -3092,14 +3092,14 @@ "requires": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", - "debug": "3.1.0", - "engine.io-parser": "2.1.2", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", "has-cors": "1.1.0", "indexof": "0.0.1", "parseqs": "0.0.5", "parseuri": "0.0.5", - "ws": "3.3.3", - "xmlhttprequest-ssl": "1.5.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", "yeast": "0.1.2" } }, @@ -3110,10 +3110,10 @@ "dev": true, "requires": { "after": "0.8.2", - "arraybuffer.slice": "0.0.7", + "arraybuffer.slice": "~0.0.7", "base64-arraybuffer": "0.1.5", "blob": "0.0.4", - "has-binary2": "1.0.2" + "has-binary2": "~1.0.2" } }, "enhanced-resolve": { @@ -3122,10 +3122,10 @@ "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "memory-fs": "0.4.1", - "object-assign": "4.1.1", - "tapable": "0.2.8" + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "object-assign": "^4.0.1", + "tapable": "^0.2.7" } }, "ent": { @@ -3146,7 +3146,7 @@ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "dev": true, "requires": { - "prr": "1.0.1" + "prr": "~1.0.1" } }, "error-ex": { @@ -3155,7 +3155,7 @@ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "es-abstract": { @@ -3164,11 +3164,11 @@ "integrity": "sha512-ZnQrE/lXTTQ39ulXZ+J1DTFazV9qBy61x2bY071B+qGco8Z8q1QddsLdt/EF8Ai9hcWH72dWS0kFqXLxOxqslA==", "dev": true, "requires": { - "es-to-primitive": "1.1.1", - "function-bind": "1.1.1", - "has": "1.0.1", - "is-callable": "1.1.3", - "is-regex": "1.0.4" + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" } }, "es-to-primitive": { @@ -3177,9 +3177,9 @@ "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", "dev": true, "requires": { - "is-callable": "1.1.3", - "is-date-object": "1.0.1", - "is-symbol": "1.0.1" + "is-callable": "^1.1.1", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.1" } }, "es5-ext": { @@ -3187,9 +3187,9 @@ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.42.tgz", "integrity": "sha512-AJxO1rmPe1bDEfSR6TJ/FgMFYuTBhR5R57KW58iCkYACMyFbrkqVyzXSurYoScDGvgyMpk7uRF/lPUPPTmsRSA==", "requires": { - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1", - "next-tick": "1.0.0" + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "1" } }, "es6-iterator": { @@ -3197,9 +3197,9 @@ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "requires": { - "d": "1.0.0", - "es5-ext": "0.10.42", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" }, "dependencies": { "d": { @@ -3207,7 +3207,7 @@ "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "requires": { - "es5-ext": "0.10.42" + "es5-ext": "^0.10.9" } } } @@ -3218,12 +3218,12 @@ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.42", - "es6-iterator": "2.0.3", - "es6-set": "0.1.5", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" }, "dependencies": { "d": { @@ -3232,7 +3232,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.42" + "es5-ext": "^0.10.9" } }, "event-emitter": { @@ -3241,8 +3241,8 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.42" + "d": "1", + "es5-ext": "~0.10.14" } } } @@ -3259,11 +3259,11 @@ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.42", - "es6-iterator": "2.0.3", + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" + "event-emitter": "~0.3.5" }, "dependencies": { "d": { @@ -3272,7 +3272,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.42" + "es5-ext": "^0.10.9" } }, "event-emitter": { @@ -3281,8 +3281,8 @@ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.42" + "d": "1", + "es5-ext": "~0.10.14" } } } @@ -3292,8 +3292,8 @@ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "requires": { - "d": "1.0.0", - "es5-ext": "0.10.42" + "d": "1", + "es5-ext": "~0.10.14" }, "dependencies": { "d": { @@ -3301,7 +3301,7 @@ "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "requires": { - "es5-ext": "0.10.42" + "es5-ext": "^0.10.9" } } } @@ -3312,10 +3312,10 @@ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { - "d": "1.0.0", - "es5-ext": "0.10.42", - "es6-iterator": "2.0.3", - "es6-symbol": "3.1.1" + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" }, "dependencies": { "d": { @@ -3324,7 +3324,7 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { - "es5-ext": "0.10.42" + "es5-ext": "^0.10.9" } } } @@ -3348,11 +3348,11 @@ "dev": true, "optional": true, "requires": { - "esprima": "3.1.3", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.6.1" + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" }, "dependencies": { "esprima": { @@ -3377,10 +3377,10 @@ "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", "dev": true, "requires": { - "es6-map": "0.1.5", - "es6-weak-map": "2.0.2", - "esrecurse": "4.2.1", - "estraverse": "4.2.0" + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "esprima": { @@ -3395,7 +3395,7 @@ "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { - "estraverse": "4.2.0" + "estraverse": "^4.1.0" } }, "estraverse": { @@ -3426,8 +3426,8 @@ "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz", "integrity": "sha1-jWPd+0z+H647MsomXExyAiIIC7U=", "requires": { - "d": "0.1.1", - "es5-ext": "0.10.42" + "d": "~0.1.1", + "es5-ext": "~0.10.7" } }, "eventemitter3": { @@ -3448,7 +3448,7 @@ "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", "dev": true, "requires": { - "original": "1.0.0" + "original": ">=0.0.5" } }, "evp_bytestokey": { @@ -3457,8 +3457,8 @@ "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { - "md5.js": "1.3.4", - "safe-buffer": "5.1.2" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, "execa": { @@ -3467,13 +3467,13 @@ "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, "dependencies": { "cross-spawn": { @@ -3482,9 +3482,9 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { - "lru-cache": "4.1.2", - "shebang-command": "1.2.0", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } } } @@ -3501,9 +3501,9 @@ "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", "dev": true, "requires": { - "array-slice": "0.2.3", - "array-unique": "0.2.1", - "braces": "0.1.5" + "array-slice": "^0.2.3", + "array-unique": "^0.2.1", + "braces": "^0.1.2" }, "dependencies": { "braces": { @@ -3512,7 +3512,7 @@ "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", "dev": true, "requires": { - "expand-range": "0.1.1" + "expand-range": "^0.1.0" } }, "expand-range": { @@ -3521,8 +3521,8 @@ "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", "dev": true, "requires": { - "is-number": "0.1.1", - "repeat-string": "0.2.2" + "is-number": "^0.1.1", + "repeat-string": "^0.2.2" } }, "is-number": { @@ -3545,7 +3545,7 @@ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "expand-range": { @@ -3554,7 +3554,7 @@ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { - "fill-range": "2.2.3" + "fill-range": "^2.1.0" } }, "express": { @@ -3563,36 +3563,36 @@ "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.2", "content-disposition": "0.5.2", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "finalhandler": "1.1.1", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.3", + "proxy-addr": "~2.0.3", "qs": "6.5.1", - "range-parser": "1.2.0", + "range-parser": "~1.2.0", "safe-buffer": "5.1.1", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.16", + "statuses": "~1.4.0", + "type-is": "~1.6.16", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "array-flatten": { @@ -3629,8 +3629,8 @@ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -3639,7 +3639,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -3650,7 +3650,7 @@ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "extract-text-webpack-plugin": { @@ -3659,10 +3659,10 @@ "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", "dev": true, "requires": { - "async": "2.6.0", - "loader-utils": "1.1.0", - "schema-utils": "0.3.0", - "webpack-sources": "1.1.0" + "async": "^2.4.1", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0", + "webpack-sources": "^1.0.1" }, "dependencies": { "ajv": { @@ -3671,10 +3671,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "schema-utils": { @@ -3683,7 +3683,7 @@ "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", "dev": true, "requires": { - "ajv": "5.5.2" + "ajv": "^5.0.0" } } } @@ -3723,7 +3723,7 @@ "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", "dev": true, "requires": { - "websocket-driver": "0.7.0" + "websocket-driver": ">=0.5.1" } }, "file-loader": { @@ -3732,8 +3732,8 @@ "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "schema-utils": "0.4.5" + "loader-utils": "^1.0.2", + "schema-utils": "^0.4.5" } }, "file-uri-to-path": { @@ -3755,8 +3755,8 @@ "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", "dev": true, "requires": { - "glob": "7.1.2", - "minimatch": "3.0.4" + "glob": "^7.0.3", + "minimatch": "^3.0.3" } }, "fill-range": { @@ -3765,11 +3765,11 @@ "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", "dev": true, "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^1.1.3", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" } }, "finalhandler": { @@ -3779,12 +3779,12 @@ "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.4.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" }, "dependencies": { "debug": { @@ -3804,9 +3804,9 @@ "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", "dev": true, "requires": { - "commondir": "1.0.1", - "make-dir": "1.2.0", - "pkg-dir": "2.0.0" + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" } }, "find-up": { @@ -3815,7 +3815,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } }, "flush-write-stream": { @@ -3824,8 +3824,8 @@ "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" } }, "follow-redirects": { @@ -3834,7 +3834,7 @@ "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", "dev": true, "requires": { - "debug": "3.1.0" + "debug": "^3.1.0" } }, "for-in": { @@ -3849,7 +3849,7 @@ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "foreach": { @@ -3869,9 +3869,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.18" + "mime-types": "^2.1.12" } }, "formidable": { @@ -3891,7 +3891,7 @@ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fresh": { @@ -3906,8 +3906,8 @@ "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" } }, "fs-access": { @@ -3916,7 +3916,7 @@ "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", "dev": true, "requires": { - "null-check": "1.0.0" + "null-check": "^1.0.0" } }, "fs-extra": { @@ -3925,9 +3925,9 @@ "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "4.0.0", - "universalify": "0.1.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "fs-write-stream-atomic": { @@ -3936,10 +3936,10 @@ "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "2.3.6" + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" } }, "fs.realpath": { @@ -3955,8 +3955,8 @@ "dev": true, "optional": true, "requires": { - "nan": "2.10.0", - "node-pre-gyp": "0.9.1" + "nan": "^2.9.2", + "node-pre-gyp": "^0.9.0" }, "dependencies": { "abbrev": { @@ -3982,8 +3982,8 @@ "dev": true, "optional": true, "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.6" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" } }, "balanced-match": { @@ -3996,7 +3996,7 @@ "bundled": true, "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -4060,7 +4060,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "fs.realpath": { @@ -4075,14 +4075,14 @@ "dev": true, "optional": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, "glob": { @@ -4091,12 +4091,12 @@ "dev": true, "optional": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "has-unicode": { @@ -4111,7 +4111,7 @@ "dev": true, "optional": true, "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "^2.1.0" } }, "ignore-walk": { @@ -4120,7 +4120,7 @@ "dev": true, "optional": true, "requires": { - "minimatch": "3.0.4" + "minimatch": "^3.0.4" } }, "inflight": { @@ -4129,8 +4129,8 @@ "dev": true, "optional": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -4149,7 +4149,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "isarray": { @@ -4163,7 +4163,7 @@ "bundled": true, "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -4176,8 +4176,8 @@ "bundled": true, "dev": true, "requires": { - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" } }, "minizlib": { @@ -4186,7 +4186,7 @@ "dev": true, "optional": true, "requires": { - "minipass": "2.2.4" + "minipass": "^2.2.1" } }, "mkdirp": { @@ -4209,9 +4209,9 @@ "dev": true, "optional": true, "requires": { - "debug": "2.6.9", - "iconv-lite": "0.4.21", - "sax": "1.2.4" + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" } }, "node-pre-gyp": { @@ -4220,16 +4220,16 @@ "dev": true, "optional": true, "requires": { - "detect-libc": "1.0.3", - "mkdirp": "0.5.1", - "needle": "2.2.0", - "nopt": "4.0.1", - "npm-packlist": "1.1.10", - "npmlog": "4.1.2", - "rc": "1.2.6", - "rimraf": "2.6.2", - "semver": "5.5.0", - "tar": "4.4.1" + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" } }, "nopt": { @@ -4238,8 +4238,8 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "npm-bundled": { @@ -4254,8 +4254,8 @@ "dev": true, "optional": true, "requires": { - "ignore-walk": "3.0.1", - "npm-bundled": "1.0.3" + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" } }, "npmlog": { @@ -4264,10 +4264,10 @@ "dev": true, "optional": true, "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { @@ -4286,7 +4286,7 @@ "bundled": true, "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-homedir": { @@ -4307,8 +4307,8 @@ "dev": true, "optional": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "path-is-absolute": { @@ -4329,10 +4329,10 @@ "dev": true, "optional": true, "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.5", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, "dependencies": { "minimist": { @@ -4349,13 +4349,13 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "rimraf": { @@ -4364,7 +4364,7 @@ "dev": true, "optional": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "safe-buffer": { @@ -4407,9 +4407,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -4418,7 +4418,7 @@ "dev": true, "optional": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -4426,7 +4426,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { @@ -4441,13 +4441,13 @@ "dev": true, "optional": true, "requires": { - "chownr": "1.0.1", - "fs-minipass": "1.2.5", - "minipass": "2.2.4", - "minizlib": "1.1.0", - "mkdirp": "0.5.1", - "safe-buffer": "5.1.1", - "yallist": "3.0.2" + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" } }, "util-deprecate": { @@ -4462,7 +4462,7 @@ "dev": true, "optional": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2" } }, "wrappy": { @@ -4483,10 +4483,10 @@ "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.2" + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" } }, "ftp": { @@ -4496,7 +4496,7 @@ "dev": true, "optional": true, "requires": { - "readable-stream": "1.1.14", + "readable-stream": "1.1.x", "xregexp": "2.0.0" }, "dependencies": { @@ -4514,10 +4514,10 @@ "dev": true, "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "string_decoder": { @@ -4541,14 +4541,14 @@ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, "gaze": { @@ -4558,7 +4558,7 @@ "dev": true, "optional": true, "requires": { - "globule": "1.2.0" + "globule": "^1.0.0" } }, "generate-function": { @@ -4575,7 +4575,7 @@ "dev": true, "optional": true, "requires": { - "is-property": "1.0.2" + "is-property": "^1.0.0" } }, "get-caller-file": { @@ -4603,12 +4603,12 @@ "dev": true, "optional": true, "requires": { - "data-uri-to-buffer": "1.2.0", - "debug": "2.6.9", - "extend": "3.0.1", - "file-uri-to-path": "1.0.0", - "ftp": "0.3.10", - "readable-stream": "2.3.6" + "data-uri-to-buffer": "1", + "debug": "2", + "extend": "3", + "file-uri-to-path": "1", + "ftp": "~0.3.10", + "readable-stream": "2" }, "dependencies": { "debug": { @@ -4635,7 +4635,7 @@ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" }, "dependencies": { "assert-plus": { @@ -4652,12 +4652,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "glob-base": { @@ -4666,8 +4666,8 @@ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "dev": true, "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" } }, "glob-parent": { @@ -4676,7 +4676,7 @@ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, "requires": { - "is-glob": "2.0.1" + "is-glob": "^2.0.0" } }, "globals": { @@ -4691,12 +4691,12 @@ "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", "dev": true, "requires": { - "array-union": "1.0.2", - "dir-glob": "2.0.0", - "glob": "7.1.2", - "ignore": "3.3.8", - "pify": "3.0.0", - "slash": "1.0.0" + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" } }, "globule": { @@ -4706,9 +4706,9 @@ "dev": true, "optional": true, "requires": { - "glob": "7.1.2", - "lodash": "4.17.10", - "minimatch": "3.0.4" + "glob": "~7.1.1", + "lodash": "~4.17.4", + "minimatch": "~3.0.2" } }, "graceful-fs": { @@ -4734,10 +4734,10 @@ "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" }, "dependencies": { "async": { @@ -4760,8 +4760,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" } }, @@ -4771,7 +4771,7 @@ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } }, "uglify-js": { @@ -4781,9 +4781,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { "source-map": { @@ -4802,9 +4802,9 @@ "dev": true, "optional": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" } } @@ -4822,8 +4822,8 @@ "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", "dev": true, "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" + "ajv": "^4.9.1", + "har-schema": "^1.0.5" }, "dependencies": { "ajv": { @@ -4832,8 +4832,8 @@ "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "dev": true, "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" } } } @@ -4844,7 +4844,7 @@ "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.0.2" } }, "has-ansi": { @@ -4853,7 +4853,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-binary2": { @@ -4897,9 +4897,9 @@ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" }, "dependencies": { "isobject": { @@ -4916,8 +4916,8 @@ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "is-number": { @@ -4926,7 +4926,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -4935,7 +4935,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4946,7 +4946,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4957,8 +4957,8 @@ "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "hash.js": { @@ -4967,8 +4967,8 @@ "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", "dev": true, "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" } }, "hawk": { @@ -4977,10 +4977,10 @@ "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", "dev": true, "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" } }, "he": { @@ -4996,8 +4996,8 @@ "dev": true, "optional": true, "requires": { - "lodash": "4.17.10", - "request": "2.81.0" + "lodash": "^4.0.0", + "request": "^2.0.0" } }, "hmac-drbg": { @@ -5006,9 +5006,9 @@ "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "dev": true, "requires": { - "hash.js": "1.1.3", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, "hoek": { @@ -5023,7 +5023,7 @@ "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", "dev": true, "requires": { - "parse-passwd": "1.0.0" + "parse-passwd": "^1.0.0" } }, "hosted-git-info": { @@ -5038,10 +5038,10 @@ "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", "dev": true, "requires": { - "inherits": "2.0.3", - "obuf": "1.1.2", - "readable-stream": "2.3.6", - "wbuf": "1.7.3" + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" } }, "html-entities": { @@ -5056,13 +5056,13 @@ "integrity": "sha512-OZa4rfb6tZOZ3Z8Xf0jKxXkiDcFWldQePGYFDcgKqES2sXeWaEv9y6QQvWUtX3ySI3feApQi5uCsHLINQ6NoAw==", "dev": true, "requires": { - "camel-case": "3.0.0", - "clean-css": "4.1.11", - "commander": "2.15.1", - "he": "1.1.1", - "param-case": "2.1.1", - "relateurl": "0.2.7", - "uglify-js": "3.3.23" + "camel-case": "3.0.x", + "clean-css": "4.1.x", + "commander": "2.15.x", + "he": "1.1.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.3.x" } }, "html-webpack-plugin": { @@ -5071,12 +5071,12 @@ "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=", "dev": true, "requires": { - "bluebird": "3.5.1", - "html-minifier": "3.5.15", - "loader-utils": "0.2.17", - "lodash": "4.17.10", - "pretty-error": "2.1.1", - "toposort": "1.0.7" + "bluebird": "^3.4.7", + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "toposort": "^1.0.0" }, "dependencies": { "loader-utils": { @@ -5085,10 +5085,10 @@ "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", "dev": true, "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1", - "object-assign": "4.1.1" + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" } } } @@ -5099,10 +5099,10 @@ "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", "dev": true, "requires": { - "domelementtype": "1.3.0", - "domhandler": "2.1.0", - "domutils": "1.1.6", - "readable-stream": "1.0.34" + "domelementtype": "1", + "domhandler": "2.1", + "domutils": "1.1", + "readable-stream": "1.0" }, "dependencies": { "domutils": { @@ -5111,7 +5111,7 @@ "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", "dev": true, "requires": { - "domelementtype": "1.3.0" + "domelementtype": "1" } }, "isarray": { @@ -5126,10 +5126,10 @@ "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "string_decoder": { @@ -5152,10 +5152,10 @@ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.4.0" + "statuses": ">= 1.4.0 < 2" } }, "http-parser-js": { @@ -5170,9 +5170,9 @@ "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "dev": true, "requires": { - "eventemitter3": "3.1.0", - "follow-redirects": "1.4.1", - "requires-port": "1.0.0" + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" } }, "http-proxy-agent": { @@ -5181,9 +5181,9 @@ "integrity": "sha1-zBzjjkU7+YSg93AtLdWcc9CBKEo=", "dev": true, "requires": { - "agent-base": "2.1.1", - "debug": "2.6.9", - "extend": "3.0.1" + "agent-base": "2", + "debug": "2", + "extend": "3" }, "dependencies": { "debug": { @@ -5203,10 +5203,10 @@ "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", "dev": true, "requires": { - "http-proxy": "1.17.0", - "is-glob": "3.1.0", - "lodash": "4.17.10", - "micromatch": "2.3.11" + "http-proxy": "^1.16.2", + "is-glob": "^3.1.0", + "lodash": "^4.17.2", + "micromatch": "^2.3.11" }, "dependencies": { "is-extglob": { @@ -5221,7 +5221,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -5232,9 +5232,9 @@ "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", "dev": true, "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.14.1" + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "httpntlm": { @@ -5243,8 +5243,8 @@ "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", "dev": true, "requires": { - "httpreq": "0.4.24", - "underscore": "1.7.0" + "httpreq": ">=0.4.22", + "underscore": "~1.7.0" } }, "httpreq": { @@ -5265,9 +5265,9 @@ "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", "dev": true, "requires": { - "agent-base": "2.1.1", - "debug": "2.6.9", - "extend": "3.0.1" + "agent-base": "2", + "debug": "2", + "extend": "3" }, "dependencies": { "debug": { @@ -5324,8 +5324,8 @@ "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", "dev": true, "requires": { - "pkg-dir": "2.0.0", - "resolve-cwd": "2.0.0" + "pkg-dir": "^2.0.0", + "resolve-cwd": "^2.0.0" } }, "imurmurhash": { @@ -5347,7 +5347,7 @@ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "indexof": { @@ -5369,8 +5369,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -5390,7 +5390,7 @@ "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", "dev": true, "requires": { - "meow": "3.7.0" + "meow": "^3.3.0" } }, "interpret": { @@ -5405,7 +5405,7 @@ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { - "loose-envify": "1.3.1" + "loose-envify": "^1.0.0" } }, "invert-kv": { @@ -5432,7 +5432,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-arrayish": { @@ -5447,7 +5447,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { - "binary-extensions": "1.11.0" + "binary-extensions": "^1.0.0" } }, "is-buffer": { @@ -5462,7 +5462,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-callable": { @@ -5477,7 +5477,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-date-object": { @@ -5492,9 +5492,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { @@ -5523,7 +5523,7 @@ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "dev": true, "requires": { - "is-primitive": "2.0.0" + "is-primitive": "^2.0.0" } }, "is-extendable": { @@ -5544,7 +5544,7 @@ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-fullwidth-code-point": { @@ -5553,7 +5553,7 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-glob": { @@ -5562,7 +5562,7 @@ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-my-ip-valid": { @@ -5579,11 +5579,11 @@ "dev": true, "optional": true, "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "is-my-ip-valid": "1.0.0", - "jsonpointer": "4.0.1", - "xtend": "4.0.1" + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" } }, "is-number": { @@ -5592,7 +5592,7 @@ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-odd": { @@ -5601,7 +5601,7 @@ "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", "dev": true, "requires": { - "is-number": "4.0.0" + "is-number": "^4.0.0" }, "dependencies": { "is-number": { @@ -5624,7 +5624,7 @@ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "requires": { - "is-path-inside": "1.0.1" + "is-path-inside": "^1.0.0" } }, "is-path-inside": { @@ -5633,7 +5633,7 @@ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.1" } }, "is-plain-object": { @@ -5642,7 +5642,7 @@ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" }, "dependencies": { "isobject": { @@ -5678,7 +5678,7 @@ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, "requires": { - "has": "1.0.1" + "has": "^1.0.1" } }, "is-stream": { @@ -5734,7 +5734,7 @@ "integrity": "sha512-zfRhJn9rFSGhzU5tGZqepRSAj3+g6oTOHxMGGriWNJZzyLPUK8H7VHpqKntegnW8KLyGA9zwuNaCoopl40LTpg==", "dev": true, "requires": { - "punycode": "2.1.0" + "punycode": "2.x.x" } }, "isexe": { @@ -5764,18 +5764,18 @@ "integrity": "sha512-duj6AlLcsWNwUpfyfHt0nWIeRiZpuShnP40YTxOGQgtaN8fd6JYSxsvxUphTDy8V5MfDXo4s/xVCIIvVCO808g==", "dev": true, "requires": { - "async": "2.6.0", - "compare-versions": "3.1.0", - "fileset": "2.0.3", - "istanbul-lib-coverage": "1.2.0", - "istanbul-lib-hook": "1.2.0", - "istanbul-lib-instrument": "1.10.1", - "istanbul-lib-report": "1.1.4", - "istanbul-lib-source-maps": "1.2.4", - "istanbul-reports": "1.3.0", - "js-yaml": "3.11.0", - "mkdirp": "0.5.1", - "once": "1.4.0" + "async": "^2.1.4", + "compare-versions": "^3.1.0", + "fileset": "^2.0.2", + "istanbul-lib-coverage": "^1.2.0", + "istanbul-lib-hook": "^1.2.0", + "istanbul-lib-instrument": "^1.10.1", + "istanbul-lib-report": "^1.1.4", + "istanbul-lib-source-maps": "^1.2.4", + "istanbul-reports": "^1.3.0", + "js-yaml": "^3.7.0", + "mkdirp": "^0.5.1", + "once": "^1.4.0" } }, "istanbul-instrumenter-loader": { @@ -5784,10 +5784,10 @@ "integrity": "sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w==", "dev": true, "requires": { - "convert-source-map": "1.5.1", - "istanbul-lib-instrument": "1.10.1", - "loader-utils": "1.1.0", - "schema-utils": "0.3.0" + "convert-source-map": "^1.5.0", + "istanbul-lib-instrument": "^1.7.3", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0" }, "dependencies": { "ajv": { @@ -5796,10 +5796,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "schema-utils": { @@ -5808,7 +5808,7 @@ "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", "dev": true, "requires": { - "ajv": "5.5.2" + "ajv": "^5.0.0" } } } @@ -5825,7 +5825,7 @@ "integrity": "sha512-p3En6/oGkFQV55Up8ZPC2oLxvgSxD8CzA0yBrhRZSh3pfv3OFj9aSGVC0yoerAi/O4u7jUVnOGVX1eVFM+0tmQ==", "dev": true, "requires": { - "append-transform": "0.4.0" + "append-transform": "^0.4.0" } }, "istanbul-lib-instrument": { @@ -5834,13 +5834,13 @@ "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", "dev": true, "requires": { - "babel-generator": "6.26.1", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "istanbul-lib-coverage": "1.2.0", - "semver": "5.5.0" + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.0", + "semver": "^5.3.0" } }, "istanbul-lib-report": { @@ -5849,10 +5849,10 @@ "integrity": "sha512-Azqvq5tT0U09nrncK3q82e/Zjkxa4tkFZv7E6VcqP0QCPn6oNljDPfrZEC/umNXds2t7b8sRJfs6Kmpzt8m2kA==", "dev": true, "requires": { - "istanbul-lib-coverage": "1.2.0", - "mkdirp": "0.5.1", - "path-parse": "1.0.5", - "supports-color": "3.2.3" + "istanbul-lib-coverage": "^1.2.0", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" }, "dependencies": { "has-flag": { @@ -5867,7 +5867,7 @@ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } } } @@ -5878,11 +5878,11 @@ "integrity": "sha512-UzuK0g1wyQijiaYQxj/CdNycFhAd2TLtO2obKQMTZrZ1jzEMRY3rvpASEKkaxbRR6brvdovfA03znPa/pXcejg==", "dev": true, "requires": { - "debug": "3.1.0", - "istanbul-lib-coverage": "1.2.0", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "source-map": "0.5.7" + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.2.0", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" } }, "istanbul-reports": { @@ -5891,7 +5891,7 @@ "integrity": "sha512-y2Z2IMqE1gefWUaVjrBm0mSKvUkaBy9Vqz8iwr/r40Y9hBbIteH5wqHG/9DLTfJ9xUnUT2j7A3+VVJ6EaYBllA==", "dev": true, "requires": { - "handlebars": "4.0.11" + "handlebars": "^4.0.3" } }, "items": { @@ -5906,9 +5906,9 @@ "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", "dev": true, "requires": { - "exit": "0.1.2", - "glob": "7.1.2", - "jasmine-core": "2.8.0" + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" } }, "jasmine-core": { @@ -5923,8 +5923,8 @@ "integrity": "sha1-9C1XjplmlhY0MdkRwxZ5cZ+0Ozs=", "dev": true, "requires": { - "mkdirp": "0.5.1", - "xmldom": "0.1.27" + "mkdirp": "^0.5.1", + "xmldom": "^0.1.22" } }, "jasmine-spec-reporter": { @@ -5942,9 +5942,9 @@ "integrity": "sha1-lARqq7x0rQpLdGvNTcMFB1h7Z+M=", "dev": true, "requires": { - "fs-extra": "0.26.7", - "mkdirp": "0.5.1", - "q": "1.5.1" + "fs-extra": "^0.26.5", + "mkdirp": "^0.5.1", + "q": "^1.4.1" }, "dependencies": { "fs-extra": { @@ -5953,11 +5953,11 @@ "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "2.4.0", - "klaw": "1.3.1", - "path-is-absolute": "1.0.1", - "rimraf": "2.6.2" + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" } }, "jsonfile": { @@ -5966,7 +5966,7 @@ "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.6" } } } @@ -5983,9 +5983,9 @@ "integrity": "sha512-z0FNlV4NGgjQN1fdtHYXf5kmgludM65fG/JlXzU6+rwkt9U5UWuXVYnXa2FpK0u6+qBuCmrm5byPNuiiddAHvQ==", "dev": true, "requires": { - "hoek": "4.2.1", - "isemail": "3.1.2", - "topo": "2.0.2" + "hoek": "4.x.x", + "isemail": "3.x.x", + "topo": "2.x.x" }, "dependencies": { "hoek": { @@ -6015,8 +6015,8 @@ "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "jsbn": { @@ -6055,7 +6055,7 @@ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { - "jsonify": "0.0.0" + "jsonify": "~0.0.0" } }, "json-stringify-safe": { @@ -6081,7 +6081,7 @@ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.6" } }, "jsonify": { @@ -6123,11 +6123,11 @@ "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==", "dev": true, "requires": { - "core-js": "2.3.0", - "es6-promise": "3.0.2", - "lie": "3.1.1", - "pako": "1.0.6", - "readable-stream": "2.0.6" + "core-js": "~2.3.0", + "es6-promise": "~3.0.2", + "lie": "~3.1.0", + "pako": "~1.0.2", + "readable-stream": "~2.0.6" }, "dependencies": { "core-js": { @@ -6148,12 +6148,12 @@ "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" } }, "string_decoder": { @@ -6170,31 +6170,31 @@ "integrity": "sha1-TS25QChQpmVR+nhLAWT7CCTtjEs=", "dev": true, "requires": { - "bluebird": "3.5.1", - "body-parser": "1.18.2", - "chokidar": "1.7.0", - "colors": "1.1.2", - "combine-lists": "1.0.1", - "connect": "3.6.6", - "core-js": "2.5.3", - "di": "0.0.1", - "dom-serialize": "2.2.1", - "expand-braces": "0.1.2", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "http-proxy": "1.17.0", - "isbinaryfile": "3.0.2", - "lodash": "4.17.10", - "log4js": "2.5.3", - "mime": "1.6.0", - "minimatch": "3.0.4", - "optimist": "0.6.1", - "qjobs": "1.2.0", - "range-parser": "1.2.0", - "rimraf": "2.6.2", - "safe-buffer": "5.1.2", + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "chokidar": "^1.4.1", + "colors": "^1.1.0", + "combine-lists": "^1.0.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "expand-braces": "^0.1.1", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.4", + "log4js": "^2.3.9", + "mime": "^1.3.4", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", "socket.io": "2.0.4", - "source-map": "0.6.1", + "source-map": "^0.6.1", "tmp": "0.0.33", "useragent": "2.2.1" }, @@ -6213,8 +6213,8 @@ "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", "dev": true, "requires": { - "fs-access": "1.0.1", - "which": "1.3.0" + "fs-access": "^1.0.0", + "which": "^1.2.1" } }, "karma-cli": { @@ -6223,7 +6223,7 @@ "integrity": "sha1-rmw8WKMTodALRRZMRVubhs4X+WA=", "dev": true, "requires": { - "resolve": "1.7.1" + "resolve": "^1.1.6" } }, "karma-coverage-istanbul-reporter": { @@ -6232,8 +6232,8 @@ "integrity": "sha512-sQHexslLF+QHzaKfK8+onTYMyvSwv+p5cDayVxhpEELGa3z0QuB+l0IMsicIkkBNMOJKQaqueiRoW7iuo7lsog==", "dev": true, "requires": { - "istanbul-api": "1.3.1", - "minimatch": "3.0.4" + "istanbul-api": "^1.1.14", + "minimatch": "^3.0.4" } }, "karma-jasmine": { @@ -6248,7 +6248,7 @@ "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=", "dev": true, "requires": { - "karma-jasmine": "1.1.2" + "karma-jasmine": "^1.0.2" } }, "karma-source-map-support": { @@ -6257,7 +6257,7 @@ "integrity": "sha1-G/gee7SwiWJ6s1LsQXnhF8QGpUA=", "dev": true, "requires": { - "source-map-support": "0.4.18" + "source-map-support": "^0.4.1" } }, "killable": { @@ -6272,7 +6272,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "klaw": { @@ -6281,7 +6281,7 @@ "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.9" } }, "lazy-cache": { @@ -6296,7 +6296,7 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "lcov-parse": { @@ -6311,14 +6311,14 @@ "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", "dev": true, "requires": { - "errno": "0.1.7", - "graceful-fs": "4.1.11", - "image-size": "0.5.5", - "mime": "1.6.0", - "mkdirp": "0.5.1", - "promise": "7.3.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.2.11", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", "request": "2.81.0", - "source-map": "0.5.7" + "source-map": "^0.5.3" } }, "less-loader": { @@ -6327,9 +6327,9 @@ "integrity": "sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg==", "dev": true, "requires": { - "clone": "2.1.1", - "loader-utils": "1.1.0", - "pify": "3.0.0" + "clone": "^2.1.1", + "loader-utils": "^1.1.0", + "pify": "^3.0.0" } }, "levn": { @@ -6339,8 +6339,8 @@ "dev": true, "optional": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "libbase64": { @@ -6380,7 +6380,7 @@ "integrity": "sha512-NqAFodJdpBUuf1iD+Ij8hQvF0rCFKlO2KaieoQzAPhFgzLCtJnC7Z7x5gQbGNjoe++wOKAtAmwVEIBLqq2Yp1A==", "dev": true, "requires": { - "ejs": "2.5.9" + "ejs": "^2.5.7" } }, "lie": { @@ -6389,7 +6389,7 @@ "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", "dev": true, "requires": { - "immediate": "3.0.6" + "immediate": "~3.0.5" } }, "load-json-file": { @@ -6398,11 +6398,11 @@ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" }, "dependencies": { "pify": { @@ -6424,9 +6424,9 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1" + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0" } }, "locate-path": { @@ -6435,8 +6435,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, "lodash": { @@ -6483,19 +6483,19 @@ "integrity": "sha512-YL/qpTxYtK0iWWbuKCrevDZz5lh+OjyHHD+mICqpjnYGKdNRBvPeh/1uYjkKUemT1CSO4wwLOwphWMpKAnD9kw==", "dev": true, "requires": { - "amqplib": "0.5.2", - "axios": "0.15.3", - "circular-json": "0.5.3", - "date-format": "1.2.0", - "debug": "3.1.0", - "hipchat-notifier": "1.1.0", - "loggly": "1.1.1", - "mailgun-js": "0.7.15", - "nodemailer": "2.7.2", - "redis": "2.8.0", - "semver": "5.5.0", - "slack-node": "0.2.0", - "streamroller": "0.7.0" + "amqplib": "^0.5.2", + "axios": "^0.15.3", + "circular-json": "^0.5.1", + "date-format": "^1.2.0", + "debug": "^3.1.0", + "hipchat-notifier": "^1.1.0", + "loggly": "^1.1.0", + "mailgun-js": "^0.7.0", + "nodemailer": "^2.5.0", + "redis": "^2.7.1", + "semver": "^5.3.0", + "slack-node": "~0.2.0", + "streamroller": "^0.7.0" } }, "loggly": { @@ -6505,9 +6505,9 @@ "dev": true, "optional": true, "requires": { - "json-stringify-safe": "5.0.1", - "request": "2.75.0", - "timespan": "2.3.0" + "json-stringify-safe": "5.0.x", + "request": "2.75.x", + "timespan": "2.3.x" }, "dependencies": { "ansi-styles": { @@ -6531,11 +6531,11 @@ "dev": true, "optional": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "form-data": { @@ -6545,9 +6545,9 @@ "dev": true, "optional": true, "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.6", - "mime-types": "2.1.18" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.11" } }, "har-validator": { @@ -6557,10 +6557,10 @@ "dev": true, "optional": true, "requires": { - "chalk": "1.1.3", - "commander": "2.15.1", - "is-my-json-valid": "2.17.2", - "pinkie-promise": "2.0.1" + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" } }, "node-uuid": { @@ -6584,27 +6584,27 @@ "dev": true, "optional": true, "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.7.0", - "bl": "1.1.2", - "caseless": "0.11.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.0.0", - "har-validator": "2.0.6", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "node-uuid": "1.4.8", - "oauth-sign": "0.8.2", - "qs": "6.2.3", - "stringstream": "0.0.5", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.4.3" + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "bl": "~1.1.2", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.0.0", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "node-uuid": "~1.4.7", + "oauth-sign": "~0.8.1", + "qs": "~6.2.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1" } }, "supports-color": { @@ -6641,7 +6641,7 @@ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } }, "loud-rejection": { @@ -6650,8 +6650,8 @@ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "dev": true, "requires": { - "currently-unhandled": "0.4.1", - "signal-exit": "3.0.2" + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" } }, "lower-case": { @@ -6666,8 +6666,8 @@ "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "magic-string": { @@ -6676,7 +6676,7 @@ "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", "dev": true, "requires": { - "vlq": "0.2.3" + "vlq": "^0.2.2" } }, "mailcomposer": { @@ -6697,15 +6697,15 @@ "dev": true, "optional": true, "requires": { - "async": "2.1.5", - "debug": "2.2.0", - "form-data": "2.1.4", - "inflection": "1.10.0", - "is-stream": "1.1.0", - "path-proxy": "1.0.0", - "proxy-agent": "2.0.0", - "q": "1.4.1", - "tsscmp": "1.0.5" + "async": "~2.1.2", + "debug": "~2.2.0", + "form-data": "~2.1.1", + "inflection": "~1.10.0", + "is-stream": "^1.1.0", + "path-proxy": "~1.0.0", + "proxy-agent": "~2.0.0", + "q": "~1.4.0", + "tsscmp": "~1.0.0" }, "dependencies": { "async": { @@ -6715,7 +6715,7 @@ "dev": true, "optional": true, "requires": { - "lodash": "4.17.10" + "lodash": "^4.14.0" } }, "debug": { @@ -6735,9 +6735,9 @@ "dev": true, "optional": true, "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.6", - "mime-types": "2.1.18" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" } }, "ms": { @@ -6762,7 +6762,7 @@ "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "make-error": { @@ -6789,7 +6789,7 @@ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "md5.js": { @@ -6798,8 +6798,8 @@ "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", "dev": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "media-typer": { @@ -6814,7 +6814,7 @@ "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "memory-fs": { @@ -6823,8 +6823,8 @@ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "dev": true, "requires": { - "errno": "0.1.7", - "readable-stream": "2.3.6" + "errno": "^0.1.3", + "readable-stream": "^2.0.1" } }, "meow": { @@ -6833,16 +6833,16 @@ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.6.0", - "map-obj": "1.0.1", - "minimist": "1.2.0", - "normalize-package-data": "2.4.0", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" }, "dependencies": { "minimist": { @@ -6870,19 +6870,19 @@ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } }, "miller-rabin": { @@ -6891,8 +6891,8 @@ "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "requires": { - "bn.js": "4.11.8", - "brorand": "1.1.0" + "bn.js": "^4.0.0", + "brorand": "^1.0.1" } }, "mime": { @@ -6910,7 +6910,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } }, "mimic-fn": { @@ -6936,7 +6936,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -6951,16 +6951,16 @@ "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", "dev": true, "requires": { - "concat-stream": "1.6.2", - "duplexify": "3.5.4", - "end-of-stream": "1.4.1", - "flush-write-stream": "1.0.3", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "2.0.1", - "pumpify": "1.4.0", - "stream-each": "1.2.2", - "through2": "2.0.3" + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" } }, "mixin-deep": { @@ -6969,8 +6969,8 @@ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -6979,7 +6979,7 @@ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -6990,8 +6990,8 @@ "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", "dev": true, "requires": { - "for-in": "0.1.8", - "is-extendable": "0.1.1" + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" }, "dependencies": { "for-in": { @@ -7021,7 +7021,7 @@ "resolved": "https://registry.npmjs.org/moment-es6/-/moment-es6-1.0.0.tgz", "integrity": "sha1-VS/PQF1iVlsKH+hObB5peseTMt8=", "requires": { - "moment": "2.20.1" + "moment": "*" } }, "move-concurrently": { @@ -7030,12 +7030,12 @@ "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "dev": true, "requires": { - "aproba": "1.2.0", - "copy-concurrently": "1.0.5", - "fs-write-stream-atomic": "1.0.10", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" } }, "ms": { @@ -7049,8 +7049,8 @@ "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", "dev": true, "requires": { - "dns-packet": "1.3.1", - "thunky": "1.0.2" + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" } }, "multicast-dns-service-types": { @@ -7072,18 +7072,18 @@ "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-odd": "2.0.0", - "is-windows": "1.0.2", - "kind-of": "6.0.2", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-odd": "^2.0.0", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "arr-diff": { @@ -7135,7 +7135,7 @@ "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-1.6.0.tgz", "integrity": "sha512-9w0WH69x5/nuqC1og2WaY39NbaBqTGIP1+5gZaH7/KPN6UEPonNg/pYnsIVklLj1DWPWXKa8+XXIJZ1jy5nLxg==", "requires": { - "chart.js": "2.7.2" + "chart.js": "^2.6.0" }, "dependencies": { "chart.js": { @@ -7143,8 +7143,8 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.2.tgz", "integrity": "sha512-90wl3V9xRZ8tnMvMlpcW+0Yg13BelsGS9P9t0ClaDxv/hdypHDr/YAGf+728m11P5ljwyB0ZHfPKCapZFqSqYA==", "requires": { - "chartjs-color": "2.2.0", - "moment": "2.20.1" + "chartjs-color": "^2.1.0", + "moment": "^2.10.2" } } } @@ -7155,7 +7155,7 @@ "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "dev": true, "requires": { - "lower-case": "1.1.4" + "lower-case": "^1.1.1" } }, "node-ensure": { @@ -7176,19 +7176,19 @@ "dev": true, "optional": true, "requires": { - "fstream": "1.0.11", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "npmlog": "4.1.2", - "osenv": "0.1.5", - "request": "2.81.0", - "rimraf": "2.6.2", - "semver": "5.3.0", - "tar": "2.2.1", - "which": "1.3.0" + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "2", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" }, "dependencies": { "nopt": { @@ -7198,7 +7198,7 @@ "dev": true, "optional": true, "requires": { - "abbrev": "1.1.1" + "abbrev": "1" } }, "semver": { @@ -7216,28 +7216,28 @@ "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", "dev": true, "requires": { - "assert": "1.4.1", - "browserify-zlib": "0.2.0", - "buffer": "4.9.1", - "console-browserify": "1.1.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.12.0", - "domain-browser": "1.2.0", - "events": "1.1.1", - "https-browserify": "1.0.0", - "os-browserify": "0.3.0", + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^1.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", "path-browserify": "0.0.0", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "readable-stream": "2.3.6", - "stream-browserify": "2.0.1", - "stream-http": "2.8.1", - "string_decoder": "1.1.1", - "timers-browserify": "2.0.10", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", "tty-browserify": "0.0.0", - "url": "0.11.0", - "util": "0.10.3", + "url": "^0.11.0", + "util": "^0.10.3", "vm-browserify": "0.0.4" }, "dependencies": { @@ -7261,9 +7261,9 @@ "integrity": "sha1-4L623aeyDMC2enhHzxLF/EGcN8M=", "dev": true, "requires": { - "debug": "2.2.0", - "follow-redirects": "1.4.1", - "xml2js": "0.4.19" + "debug": "~2.2.0", + "follow-redirects": ">=1.2.0", + "xml2js": ">=0.2.4" }, "dependencies": { "debug": { @@ -7290,25 +7290,25 @@ "dev": true, "optional": true, "requires": { - "async-foreach": "0.1.3", - "chalk": "1.1.3", - "cross-spawn": "3.0.1", - "gaze": "1.1.2", - "get-stdin": "4.0.1", - "glob": "7.1.2", - "in-publish": "2.0.0", - "lodash.assign": "4.2.0", - "lodash.clonedeep": "4.5.0", - "lodash.mergewith": "4.6.1", - "meow": "3.7.0", - "mkdirp": "0.5.1", - "nan": "2.10.0", - "node-gyp": "3.6.2", - "npmlog": "4.1.2", - "request": "2.79.0", - "sass-graph": "2.2.4", - "stdout-stream": "1.4.0", - "true-case-path": "1.0.2" + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash.assign": "^4.2.0", + "lodash.clonedeep": "^4.3.2", + "lodash.mergewith": "^4.6.0", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.10.0", + "node-gyp": "^3.3.1", + "npmlog": "^4.0.0", + "request": "~2.79.0", + "sass-graph": "^2.2.4", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" }, "dependencies": { "ansi-styles": { @@ -7330,11 +7330,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "form-data": { @@ -7344,9 +7344,9 @@ "dev": true, "optional": true, "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.6", - "mime-types": "2.1.18" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" } }, "har-validator": { @@ -7356,10 +7356,10 @@ "dev": true, "optional": true, "requires": { - "chalk": "1.1.3", - "commander": "2.15.1", - "is-my-json-valid": "2.17.2", - "pinkie-promise": "2.0.1" + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" } }, "qs": { @@ -7376,26 +7376,26 @@ "dev": true, "optional": true, "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.7.0", - "caseless": "0.11.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "2.0.6", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "oauth-sign": "0.8.2", - "qs": "6.3.2", - "stringstream": "0.0.5", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.4.3", - "uuid": "3.2.1" + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "qs": "~6.3.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1", + "uuid": "^3.0.0" } }, "supports-color": { @@ -7436,8 +7436,8 @@ "dev": true, "optional": true, "requires": { - "ip": "1.1.5", - "smart-buffer": "1.1.15" + "ip": "^1.1.2", + "smart-buffer": "^1.0.4" } } } @@ -7504,8 +7504,8 @@ "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "requires": { - "abbrev": "1.1.1", - "osenv": "0.1.5" + "abbrev": "1", + "osenv": "^0.1.4" } }, "normalize-package-data": { @@ -7514,10 +7514,10 @@ "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { - "hosted-git-info": "2.6.0", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "normalize-path": { @@ -7526,7 +7526,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } }, "normalize-range": { @@ -7541,7 +7541,7 @@ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "npmlog": { @@ -7550,10 +7550,10 @@ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "nth-check": { @@ -7562,7 +7562,7 @@ "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", "dev": true, "requires": { - "boolbase": "1.0.0" + "boolbase": "~1.0.0" } }, "null-check": { @@ -7607,9 +7607,9 @@ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "dev": true, "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -7618,7 +7618,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -7635,7 +7635,7 @@ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" }, "dependencies": { "isobject": { @@ -7652,8 +7652,8 @@ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" } }, "object.pick": { @@ -7662,7 +7662,7 @@ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" }, "dependencies": { "isobject": { @@ -7700,7 +7700,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "opn": { @@ -7709,7 +7709,7 @@ "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", "dev": true, "requires": { - "is-wsl": "1.1.0" + "is-wsl": "^1.1.0" } }, "optimist": { @@ -7718,8 +7718,8 @@ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { - "minimist": "0.0.8", - "wordwrap": "0.0.2" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" } }, "optionator": { @@ -7729,12 +7729,12 @@ "dev": true, "optional": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" }, "dependencies": { "wordwrap": { @@ -7758,7 +7758,7 @@ "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=", "dev": true, "requires": { - "url-parse": "1.0.5" + "url-parse": "1.0.x" }, "dependencies": { "url-parse": { @@ -7767,8 +7767,8 @@ "integrity": "sha1-CFSGBCKv3P7+tsllxmLUgAFpkns=", "dev": true, "requires": { - "querystringify": "0.0.4", - "requires-port": "1.0.0" + "querystringify": "0.0.x", + "requires-port": "1.0.x" } } } @@ -7791,7 +7791,7 @@ "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { - "lcid": "1.0.0" + "lcid": "^1.0.0" } }, "os-tmpdir": { @@ -7806,8 +7806,8 @@ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "p-finally": { @@ -7822,7 +7822,7 @@ "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", "dev": true, "requires": { - "p-try": "1.0.0" + "p-try": "^1.0.0" } }, "p-locate": { @@ -7831,7 +7831,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "1.2.0" + "p-limit": "^1.1.0" } }, "p-map": { @@ -7853,15 +7853,15 @@ "dev": true, "optional": true, "requires": { - "agent-base": "2.1.1", - "debug": "2.6.9", - "extend": "3.0.1", - "get-uri": "2.0.1", - "http-proxy-agent": "1.0.0", - "https-proxy-agent": "1.0.0", - "pac-resolver": "2.0.0", - "raw-body": "2.3.2", - "socks-proxy-agent": "2.1.1" + "agent-base": "2", + "debug": "2", + "extend": "3", + "get-uri": "2", + "http-proxy-agent": "1", + "https-proxy-agent": "1", + "pac-resolver": "~2.0.0", + "raw-body": "2", + "socks-proxy-agent": "2" }, "dependencies": { "debug": { @@ -7883,11 +7883,11 @@ "dev": true, "optional": true, "requires": { - "co": "3.0.6", - "degenerator": "1.0.4", + "co": "~3.0.6", + "degenerator": "~1.0.2", "ip": "1.0.1", - "netmask": "1.0.6", - "thunkify": "2.1.2" + "netmask": "~1.0.4", + "thunkify": "~2.1.1" }, "dependencies": { "co": { @@ -7918,9 +7918,9 @@ "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", "dev": true, "requires": { - "cyclist": "0.2.2", - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" } }, "param-case": { @@ -7929,7 +7929,7 @@ "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", "dev": true, "requires": { - "no-case": "2.3.2" + "no-case": "^2.2.0" } }, "parse-asn1": { @@ -7938,11 +7938,11 @@ "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "dev": true, "requires": { - "asn1.js": "4.10.1", - "browserify-aes": "1.2.0", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "pbkdf2": "3.0.16" + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3" } }, "parse-glob": { @@ -7951,10 +7951,10 @@ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "dev": true, "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" } }, "parse-json": { @@ -7963,7 +7963,7 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "1.3.1" + "error-ex": "^1.2.0" } }, "parse-passwd": { @@ -7978,7 +7978,7 @@ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseuri": { @@ -7987,7 +7987,7 @@ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseurl": { @@ -8051,7 +8051,7 @@ "dev": true, "optional": true, "requires": { - "inflection": "1.3.8" + "inflection": "~1.3.0" }, "dependencies": { "inflection": { @@ -8075,7 +8075,7 @@ "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "pify": "3.0.0" + "pify": "^3.0.0" } }, "pbkdf2": { @@ -8084,11 +8084,11 @@ "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", "dev": true, "requires": { - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "ripemd160": "2.0.2", - "safe-buffer": "5.1.2", - "sha.js": "2.4.11" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "pdfjs-dist": { @@ -8096,8 +8096,8 @@ "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.0.303.tgz", "integrity": "sha1-jABTDyQihmA7/L/dLukXwYK51EE=", "requires": { - "node-ensure": "0.0.0", - "worker-loader": "1.1.1" + "node-ensure": "^0.0.0", + "worker-loader": "^1.1.0" } }, "performance-now": { @@ -8124,7 +8124,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pkg-dir": { @@ -8133,7 +8133,7 @@ "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "2.1.0" + "find-up": "^2.1.0" } }, "portfinder": { @@ -8142,9 +8142,9 @@ "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=", "dev": true, "requires": { - "async": "1.5.2", - "debug": "2.6.9", - "mkdirp": "0.5.1" + "async": "^1.5.2", + "debug": "^2.2.0", + "mkdirp": "0.5.x" }, "dependencies": { "async": { @@ -8176,9 +8176,9 @@ "integrity": "sha512-Toc9lLoUASwGqxBSJGTVcOQiDqjK+Z2XlWBg+IgYwQMY9vA2f7iMpXVc1GpPcfTSyM5lkxNo0oDwDRO+wm7XHA==", "dev": true, "requires": { - "chalk": "2.4.1", - "source-map": "0.6.1", - "supports-color": "5.4.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" }, "dependencies": { "chalk": { @@ -8187,9 +8187,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "has-flag": { @@ -8210,7 +8210,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -8221,10 +8221,10 @@ "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", "dev": true, "requires": { - "postcss": "6.0.22", - "postcss-value-parser": "3.3.0", - "read-cache": "1.0.0", - "resolve": "1.7.1" + "postcss": "^6.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" } }, "postcss-load-config": { @@ -8233,10 +8233,10 @@ "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", "dev": true, "requires": { - "cosmiconfig": "2.2.2", - "object-assign": "4.1.1", - "postcss-load-options": "1.2.0", - "postcss-load-plugins": "2.3.0" + "cosmiconfig": "^2.1.0", + "object-assign": "^4.1.0", + "postcss-load-options": "^1.2.0", + "postcss-load-plugins": "^2.3.0" } }, "postcss-load-options": { @@ -8245,8 +8245,8 @@ "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", "dev": true, "requires": { - "cosmiconfig": "2.2.2", - "object-assign": "4.1.1" + "cosmiconfig": "^2.1.0", + "object-assign": "^4.1.0" } }, "postcss-load-plugins": { @@ -8255,8 +8255,8 @@ "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", "dev": true, "requires": { - "cosmiconfig": "2.2.2", - "object-assign": "4.1.1" + "cosmiconfig": "^2.1.1", + "object-assign": "^4.1.0" } }, "postcss-loader": { @@ -8265,10 +8265,10 @@ "integrity": "sha512-L2p654oK945B/gDFUGgOhh7uzj19RWoY1SVMeJVoKno1H2MdbQ0RppR/28JGju4pMb22iRC7BJ9aDzbxXSLf4A==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "postcss": "6.0.22", - "postcss-load-config": "1.2.0", - "schema-utils": "0.4.5" + "loader-utils": "^1.1.0", + "postcss": "^6.0.0", + "postcss-load-config": "^1.2.0", + "schema-utils": "^0.4.0" } }, "postcss-url": { @@ -8277,11 +8277,11 @@ "integrity": "sha512-QMV5mA+pCYZQcUEPQkmor9vcPQ2MT+Ipuu8qdi1gVxbNiIiErEGft+eny1ak19qALoBkccS5AHaCaCDzh7b9MA==", "dev": true, "requires": { - "mime": "1.6.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "postcss": "6.0.22", - "xxhashjs": "0.2.2" + "mime": "^1.4.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.0", + "postcss": "^6.0.1", + "xxhashjs": "^0.2.1" } }, "postcss-value-parser": { @@ -8308,8 +8308,8 @@ "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", "dev": true, "requires": { - "renderkid": "2.0.1", - "utila": "0.4.0" + "renderkid": "^2.0.1", + "utila": "~0.4" } }, "process": { @@ -8330,7 +8330,7 @@ "dev": true, "optional": true, "requires": { - "asap": "2.0.6" + "asap": "~2.0.3" } }, "promise-inflight": { @@ -8345,21 +8345,21 @@ "integrity": "sha512-AW9qJ0prx2QEMy1gnhJ1Sl1WBQL2R3fx/VnG09FEmWprPIQPK14t0B83OB/pAGddpxiDCAAV0KiNNLf2c2Y/lQ==", "dev": true, "requires": { - "@types/node": "6.0.107", - "@types/q": "0.0.32", - "@types/selenium-webdriver": "2.53.43", - "blocking-proxy": "1.0.1", - "chalk": "1.1.3", - "glob": "7.1.2", + "@types/node": "^6.0.46", + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "~2.53.39", + "blocking-proxy": "^1.0.0", + "chalk": "^1.1.3", + "glob": "^7.0.3", "jasmine": "2.8.0", - "jasminewd2": "2.2.0", - "optimist": "0.6.1", + "jasminewd2": "^2.1.0", + "optimist": "~0.6.0", "q": "1.4.1", - "saucelabs": "1.3.0", + "saucelabs": "~1.3.0", "selenium-webdriver": "3.6.0", - "source-map-support": "0.4.18", - "webdriver-js-extender": "1.0.0", - "webdriver-manager": "12.0.6" + "source-map-support": "~0.4.0", + "webdriver-js-extender": "^1.0.0", + "webdriver-manager": "^12.0.6" }, "dependencies": { "@types/node": { @@ -8392,11 +8392,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "del": { @@ -8405,13 +8405,13 @@ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" } }, "globby": { @@ -8420,12 +8420,12 @@ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "minimist": { @@ -8452,10 +8452,10 @@ "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", "dev": true, "requires": { - "jszip": "3.1.5", - "rimraf": "2.6.2", + "jszip": "^3.1.3", + "rimraf": "^2.5.4", "tmp": "0.0.30", - "xml2js": "0.4.19" + "xml2js": "^0.4.17" } }, "supports-color": { @@ -8470,7 +8470,7 @@ "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.1" } }, "webdriver-manager": { @@ -8479,17 +8479,17 @@ "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=", "dev": true, "requires": { - "adm-zip": "0.4.9", - "chalk": "1.1.3", - "del": "2.2.2", - "glob": "7.1.2", - "ini": "1.3.5", - "minimist": "1.2.0", - "q": "1.4.1", - "request": "2.81.0", - "rimraf": "2.6.2", - "semver": "5.5.0", - "xml2js": "0.4.19" + "adm-zip": "^0.4.7", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.78.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" } } } @@ -8500,7 +8500,7 @@ "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", "dev": true, "requires": { - "forwarded": "0.1.2", + "forwarded": "~0.1.2", "ipaddr.js": "1.6.0" } }, @@ -8511,14 +8511,14 @@ "dev": true, "optional": true, "requires": { - "agent-base": "2.1.1", - "debug": "2.6.9", - "extend": "3.0.1", - "http-proxy-agent": "1.0.0", - "https-proxy-agent": "1.0.0", - "lru-cache": "2.6.5", - "pac-proxy-agent": "1.1.0", - "socks-proxy-agent": "2.1.1" + "agent-base": "2", + "debug": "2", + "extend": "3", + "http-proxy-agent": "1", + "https-proxy-agent": "1", + "lru-cache": "~2.6.5", + "pac-proxy-agent": "1", + "socks-proxy-agent": "2" }, "dependencies": { "debug": { @@ -8558,11 +8558,11 @@ "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", "dev": true, "requires": { - "bn.js": "4.11.8", - "browserify-rsa": "4.0.1", - "create-hash": "1.2.0", - "parse-asn1": "5.1.1", - "randombytes": "2.0.6" + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1" } }, "pump": { @@ -8571,8 +8571,8 @@ "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "pumpify": { @@ -8581,9 +8581,9 @@ "integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==", "dev": true, "requires": { - "duplexify": "3.5.4", - "inherits": "2.0.3", - "pump": "2.0.1" + "duplexify": "^3.5.3", + "inherits": "^2.0.3", + "pump": "^2.0.0" } }, "punycode": { @@ -8632,8 +8632,8 @@ "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "is-number": { @@ -8642,7 +8642,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -8651,7 +8651,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -8662,7 +8662,7 @@ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -8673,7 +8673,7 @@ "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.1.0" } }, "randomfill": { @@ -8682,8 +8682,8 @@ "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "requires": { - "randombytes": "2.0.6", - "safe-buffer": "5.1.2" + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" } }, "range-parser": { @@ -8727,7 +8727,7 @@ "depd": "1.1.1", "inherits": "2.0.3", "setprototypeof": "1.0.3", - "statuses": "1.4.0" + "statuses": ">= 1.3.1 < 2" } }, "setprototypeof": { @@ -8750,7 +8750,7 @@ "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", "dev": true, "requires": { - "pify": "2.3.0" + "pify": "^2.3.0" }, "dependencies": { "pify": { @@ -8767,9 +8767,9 @@ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" }, "dependencies": { "path-type": { @@ -8778,9 +8778,9 @@ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pify": { @@ -8797,8 +8797,8 @@ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "dependencies": { "find-up": { @@ -8807,8 +8807,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "path-exists": { @@ -8817,7 +8817,7 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } } } @@ -8827,13 +8827,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "readdirp": { @@ -8842,10 +8842,10 @@ "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "readable-stream": "2.3.6", - "set-immediate-shim": "1.0.1" + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "readable-stream": "^2.0.2", + "set-immediate-shim": "^1.0.1" } }, "redent": { @@ -8854,8 +8854,8 @@ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "dev": true, "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" } }, "redis": { @@ -8865,9 +8865,9 @@ "dev": true, "optional": true, "requires": { - "double-ended-queue": "2.1.0-0", - "redis-commands": "1.3.5", - "redis-parser": "2.6.0" + "double-ended-queue": "^2.1.0-0", + "redis-commands": "^1.2.0", + "redis-parser": "^2.6.0" } }, "redis-commands": { @@ -8907,7 +8907,7 @@ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { - "is-equal-shallow": "0.1.3" + "is-equal-shallow": "^0.1.3" } }, "regex-not": { @@ -8916,8 +8916,8 @@ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "regexpu-core": { @@ -8926,9 +8926,9 @@ "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", "dev": true, "requires": { - "regenerate": "1.3.3", - "regjsgen": "0.2.0", - "regjsparser": "0.1.5" + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" } }, "regjsgen": { @@ -8943,7 +8943,7 @@ "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", "dev": true, "requires": { - "jsesc": "0.5.0" + "jsesc": "~0.5.0" }, "dependencies": { "jsesc": { @@ -8972,11 +8972,11 @@ "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=", "dev": true, "requires": { - "css-select": "1.2.0", - "dom-converter": "0.1.4", - "htmlparser2": "3.3.0", - "strip-ansi": "3.0.1", - "utila": "0.3.3" + "css-select": "^1.1.0", + "dom-converter": "~0.1", + "htmlparser2": "~3.3.0", + "strip-ansi": "^3.0.0", + "utila": "~0.3" }, "dependencies": { "utila": { @@ -9005,7 +9005,7 @@ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "request": { @@ -9014,28 +9014,28 @@ "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", "dev": true, "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.2", - "stringstream": "0.0.5", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" }, "dependencies": { "form-data": { @@ -9044,9 +9044,9 @@ "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", "dev": true, "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.6", - "mime-types": "2.1.18" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" } }, "qs": { @@ -9063,10 +9063,10 @@ "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", "dev": true, "requires": { - "bluebird": "3.5.1", + "bluebird": "^3.5.0", "request-promise-core": "1.1.1", - "stealthy-require": "1.1.1", - "tough-cookie": "2.3.4" + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" } }, "request-promise-core": { @@ -9075,7 +9075,7 @@ "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", "dev": true, "requires": { - "lodash": "4.17.10" + "lodash": "^4.13.1" } }, "requestretry": { @@ -9085,10 +9085,10 @@ "dev": true, "optional": true, "requires": { - "extend": "3.0.1", - "lodash": "4.17.10", - "request": "2.81.0", - "when": "3.7.8" + "extend": "^3.0.0", + "lodash": "^4.15.0", + "request": "^2.74.0", + "when": "^3.7.7" } }, "require-directory": { @@ -9121,7 +9121,7 @@ "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "resolve-cwd": { @@ -9130,7 +9130,7 @@ "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "dev": true, "requires": { - "resolve-from": "3.0.0" + "resolve-from": "^3.0.0" } }, "resolve-from": { @@ -9157,7 +9157,7 @@ "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "rimraf": { @@ -9166,7 +9166,7 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "ripemd160": { @@ -9175,8 +9175,8 @@ "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { - "hash-base": "3.0.4", - "inherits": "2.0.3" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "run-queue": { @@ -9185,7 +9185,7 @@ "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "dev": true, "requires": { - "aproba": "1.2.0" + "aproba": "^1.1.1" } }, "rx": { @@ -9199,7 +9199,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.2.tgz", "integrity": "sha512-oRYoIKWBU3Ic37fLA5VJu31VqQO4bWubRntcHSJ+cwaDQBwdnZ9x4zmhJfm/nFQ2E82/I4loSioHnACamrKGgA==", "requires": { - "symbol-observable": "1.2.0" + "symbol-observable": "^1.0.1" } }, "safe-buffer": { @@ -9213,7 +9213,7 @@ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "sass-graph": { @@ -9223,10 +9223,10 @@ "dev": true, "optional": true, "requires": { - "glob": "7.1.2", - "lodash": "4.17.10", - "scss-tokenizer": "0.2.3", - "yargs": "7.1.0" + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^7.0.0" } }, "sass-loader": { @@ -9235,11 +9235,11 @@ "integrity": "sha512-JoiyD00Yo1o61OJsoP2s2kb19L1/Y2p3QFcCdWdF6oomBGKVYuZyqHWemRBfQ2uGYsk+CH3eCguXNfpjzlcpaA==", "dev": true, "requires": { - "clone-deep": "2.0.2", - "loader-utils": "1.1.0", - "lodash.tail": "4.1.1", - "neo-async": "2.5.1", - "pify": "3.0.0" + "clone-deep": "^2.0.1", + "loader-utils": "^1.0.1", + "lodash.tail": "^4.1.1", + "neo-async": "^2.5.0", + "pify": "^3.0.0" } }, "saucelabs": { @@ -9248,7 +9248,7 @@ "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", "dev": true, "requires": { - "https-proxy-agent": "1.0.0" + "https-proxy-agent": "^1.0.0" } }, "sax": { @@ -9262,8 +9262,8 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", "requires": { - "ajv": "6.4.0", - "ajv-keywords": "3.2.0" + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" } }, "scss-tokenizer": { @@ -9273,8 +9273,8 @@ "dev": true, "optional": true, "requires": { - "js-base64": "2.4.3", - "source-map": "0.4.4" + "js-base64": "^2.1.8", + "source-map": "^0.4.2" }, "dependencies": { "source-map": { @@ -9284,7 +9284,7 @@ "dev": true, "optional": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -9301,10 +9301,10 @@ "integrity": "sha512-z88rdjHAv3jmTZ7KSGUkTvo4rGzcDGMq0oXWHNIDK96Gs31JKVdu9+FMtT4KBrVoibg8dUicJDok6GnqqttO5Q==", "dev": true, "requires": { - "jszip": "3.1.5", - "rimraf": "2.6.2", + "jszip": "^3.1.3", + "rimraf": "^2.5.4", "tmp": "0.0.30", - "xml2js": "0.4.19" + "xml2js": "^0.4.17" }, "dependencies": { "tmp": { @@ -9313,7 +9313,7 @@ "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.1" } } } @@ -9339,7 +9339,7 @@ "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", "dev": true, "requires": { - "semver": "5.5.0" + "semver": "^5.3.0" } }, "semver-intersect": { @@ -9348,7 +9348,7 @@ "integrity": "sha1-j6hKnhAovSOeRTDRo+GB5pjYhLo=", "dev": true, "requires": { - "semver": "5.5.0" + "semver": "^5.0.0" } }, "send": { @@ -9358,18 +9358,18 @@ "dev": true, "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.6.3", + "http-errors": "~1.6.2", "mime": "1.4.1", "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.4.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" }, "dependencies": { "debug": { @@ -9401,13 +9401,13 @@ "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.4", "batch": "0.6.1", "debug": "2.6.9", - "escape-html": "1.0.3", - "http-errors": "1.6.3", - "mime-types": "2.1.18", - "parseurl": "1.3.2" + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" }, "dependencies": { "debug": { @@ -9427,9 +9427,9 @@ "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "dev": true, "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", "send": "0.16.2" } }, @@ -9451,10 +9451,10 @@ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -9463,7 +9463,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -9486,8 +9486,8 @@ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.2" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "shallow-clone": { @@ -9496,9 +9496,9 @@ "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", "dev": true, "requires": { - "is-extendable": "0.1.1", - "kind-of": "5.1.0", - "mixin-object": "2.0.1" + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" }, "dependencies": { "kind-of": { @@ -9515,7 +9515,7 @@ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -9536,7 +9536,7 @@ "integrity": "sha1-IglwbxyFCp8dENDYQJGLRvJuG8k=", "dev": true, "requires": { - "debug": "2.6.9" + "debug": "^2.2.0" }, "dependencies": { "debug": { @@ -9557,7 +9557,7 @@ "dev": true, "optional": true, "requires": { - "requestretry": "1.13.0" + "requestretry": "^1.2.2" } }, "slash": { @@ -9588,14 +9588,14 @@ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.1", - "use": "3.1.0" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "dependencies": { "debug": { @@ -9613,7 +9613,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -9622,7 +9622,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -9633,9 +9633,9 @@ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -9644,7 +9644,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -9653,7 +9653,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -9662,7 +9662,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -9671,9 +9671,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "isobject": { @@ -9696,7 +9696,7 @@ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" } }, "sntp": { @@ -9705,7 +9705,7 @@ "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", "dev": true, "requires": { - "hoek": "2.16.3" + "hoek": "2.x.x" } }, "socket.io": { @@ -9714,11 +9714,11 @@ "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", "dev": true, "requires": { - "debug": "2.6.9", - "engine.io": "3.1.5", - "socket.io-adapter": "1.1.1", + "debug": "~2.6.6", + "engine.io": "~3.1.0", + "socket.io-adapter": "~1.1.0", "socket.io-client": "2.0.4", - "socket.io-parser": "3.1.3" + "socket.io-parser": "~3.1.1" }, "dependencies": { "debug": { @@ -9748,14 +9748,14 @@ "base64-arraybuffer": "0.1.5", "component-bind": "1.0.0", "component-emitter": "1.2.1", - "debug": "2.6.9", - "engine.io-client": "3.1.6", + "debug": "~2.6.4", + "engine.io-client": "~3.1.0", "has-cors": "1.1.0", "indexof": "0.0.1", "object-component": "0.0.3", "parseqs": "0.0.5", "parseuri": "0.0.5", - "socket.io-parser": "3.1.3", + "socket.io-parser": "~3.1.1", "to-array": "0.1.4" }, "dependencies": { @@ -9777,8 +9777,8 @@ "dev": true, "requires": { "component-emitter": "1.2.1", - "debug": "3.1.0", - "has-binary2": "1.0.2", + "debug": "~3.1.0", + "has-binary2": "~1.0.2", "isarray": "2.0.1" }, "dependencies": { @@ -9796,8 +9796,8 @@ "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", "dev": true, "requires": { - "faye-websocket": "0.10.0", - "uuid": "3.2.1" + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" } }, "sockjs-client": { @@ -9806,12 +9806,12 @@ "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=", "dev": true, "requires": { - "debug": "2.6.9", + "debug": "^2.6.6", "eventsource": "0.1.6", - "faye-websocket": "0.11.1", - "inherits": "2.0.3", - "json3": "3.3.2", - "url-parse": "1.4.0" + "faye-websocket": "~0.11.0", + "inherits": "^2.0.1", + "json3": "^3.3.2", + "url-parse": "^1.1.8" }, "dependencies": { "debug": { @@ -9829,7 +9829,7 @@ "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", "dev": true, "requires": { - "websocket-driver": "0.7.0" + "websocket-driver": ">=0.5.1" } } } @@ -9840,8 +9840,8 @@ "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=", "dev": true, "requires": { - "ip": "1.1.5", - "smart-buffer": "1.1.15" + "ip": "^1.1.4", + "smart-buffer": "^1.0.13" } }, "socks-proxy-agent": { @@ -9850,9 +9850,9 @@ "integrity": "sha512-sFtmYqdUK5dAMh85H0LEVFUCO7OhJJe1/z2x/Z6mxp3s7/QPf1RkZmpZy+BpuU0bEjcV9npqKjq9Y3kwFUjnxw==", "dev": true, "requires": { - "agent-base": "2.1.1", - "extend": "3.0.1", - "socks": "1.1.10" + "agent-base": "2", + "extend": "3", + "socks": "~1.1.5" } }, "source-list-map": { @@ -9873,11 +9873,11 @@ "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", "dev": true, "requires": { - "atob": "2.1.1", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" + "atob": "^2.0.0", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-support": { @@ -9886,7 +9886,7 @@ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "requires": { - "source-map": "0.5.7" + "source-map": "^0.5.6" } }, "source-map-url": { @@ -9901,8 +9901,8 @@ "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { @@ -9917,8 +9917,8 @@ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { @@ -9933,12 +9933,12 @@ "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", "dev": true, "requires": { - "debug": "2.6.9", - "handle-thing": "1.2.5", - "http-deceiver": "1.2.7", - "safe-buffer": "5.1.2", - "select-hose": "2.0.0", - "spdy-transport": "2.1.0" + "debug": "^2.6.8", + "handle-thing": "^1.2.5", + "http-deceiver": "^1.2.7", + "safe-buffer": "^5.0.1", + "select-hose": "^2.0.0", + "spdy-transport": "^2.0.18" }, "dependencies": { "debug": { @@ -9958,13 +9958,13 @@ "integrity": "sha512-bpUeGpZcmZ692rrTiqf9/2EUakI6/kXX1Rpe0ib/DyOzbiexVfXkw6GnvI9hVGvIwVaUhkaBojjCZwLNRGQg1g==", "dev": true, "requires": { - "debug": "2.6.9", - "detect-node": "2.0.3", - "hpack.js": "2.1.6", - "obuf": "1.1.2", - "readable-stream": "2.3.6", - "safe-buffer": "5.1.2", - "wbuf": "1.7.3" + "debug": "^2.6.8", + "detect-node": "^2.0.3", + "hpack.js": "^2.1.6", + "obuf": "^1.1.1", + "readable-stream": "^2.2.9", + "safe-buffer": "^5.0.1", + "wbuf": "^1.7.2" }, "dependencies": { "debug": { @@ -9984,7 +9984,7 @@ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "sprintf-js": { @@ -9999,14 +9999,14 @@ "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "dev": true, "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" }, "dependencies": { "assert-plus": { @@ -10023,7 +10023,7 @@ "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.1.1" } }, "static-extend": { @@ -10032,8 +10032,8 @@ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -10042,7 +10042,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -10060,7 +10060,7 @@ "dev": true, "optional": true, "requires": { - "readable-stream": "2.3.6" + "readable-stream": "^2.0.1" } }, "stealthy-require": { @@ -10075,8 +10075,8 @@ "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.6" + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" } }, "stream-each": { @@ -10085,8 +10085,8 @@ "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", "dev": true, "requires": { - "end-of-stream": "1.4.1", - "stream-shift": "1.0.0" + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" } }, "stream-http": { @@ -10095,11 +10095,11 @@ "integrity": "sha512-cQ0jo17BLca2r0GfRdZKYAGLU6JRoIWxqSOakUMuKOT6MOK7AAlE856L33QuDmAy/eeOrhLee3dZKX0Uadu93A==", "dev": true, "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.1" + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.3", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" } }, "stream-shift": { @@ -10114,10 +10114,10 @@ "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", "dev": true, "requires": { - "date-format": "1.2.0", - "debug": "3.1.0", - "mkdirp": "0.5.1", - "readable-stream": "2.3.6" + "date-format": "^1.2.0", + "debug": "^3.1.0", + "mkdirp": "^0.5.1", + "readable-stream": "^2.3.0" } }, "string-width": { @@ -10126,9 +10126,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -10136,7 +10136,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "stringstream": { @@ -10151,7 +10151,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -10160,7 +10160,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } }, "strip-eof": { @@ -10175,7 +10175,7 @@ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "dev": true, "requires": { - "get-stdin": "4.0.1" + "get-stdin": "^4.0.1" } }, "strip-json-comments": { @@ -10190,8 +10190,8 @@ "integrity": "sha512-IRE+ijgojrygQi3rsqT0U4dd+UcPCqcVvauZpCnQrGAlEe+FUIyrK93bUDScamesjP08JlQNsFJU+KmPedP5Og==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "schema-utils": "0.3.0" + "loader-utils": "^1.0.2", + "schema-utils": "^0.3.0" }, "dependencies": { "ajv": { @@ -10200,10 +10200,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "schema-utils": { @@ -10212,7 +10212,7 @@ "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", "dev": true, "requires": { - "ajv": "5.5.2" + "ajv": "^5.0.0" } } } @@ -10223,12 +10223,12 @@ "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", "dev": true, "requires": { - "css-parse": "1.7.0", - "debug": "3.1.0", - "glob": "7.0.6", - "mkdirp": "0.5.1", - "sax": "0.5.8", - "source-map": "0.1.43" + "css-parse": "1.7.x", + "debug": "*", + "glob": "7.0.x", + "mkdirp": "0.5.x", + "sax": "0.5.x", + "source-map": "0.1.x" }, "dependencies": { "glob": { @@ -10237,12 +10237,12 @@ "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "source-map": { @@ -10251,7 +10251,7 @@ "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -10262,9 +10262,9 @@ "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "lodash.clonedeep": "4.5.0", - "when": "3.6.4" + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" }, "dependencies": { "when": { @@ -10280,16 +10280,16 @@ "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.2.tgz", "integrity": "sha512-gVH4QfYHcY3P0f/BZzavLreHW3T1v7hG9B+hpMQotGQqurOvhv87GcMCd6LWySmBuf+BDR44TQd0aISjVHLeNQ==", "requires": { - "component-emitter": "1.2.1", - "cookiejar": "2.1.1", - "debug": "3.1.0", - "extend": "3.0.1", - "form-data": "2.3.2", - "formidable": "1.2.1", - "methods": "1.1.2", - "mime": "1.6.0", - "qs": "6.5.1", - "readable-stream": "2.3.6" + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.1.1", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.0.5" } }, "supports-color": { @@ -10298,7 +10298,7 @@ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { - "has-flag": "2.0.0" + "has-flag": "^2.0.0" } }, "symbol-observable": { @@ -10311,7 +10311,7 @@ "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-0.19.27.tgz", "integrity": "sha1-8XQNVlzmQ3GsDecHKk0eVHG6e6I=", "requires": { - "when": "3.7.8" + "when": "^3.7.5" } }, "tapable": { @@ -10327,9 +10327,9 @@ "dev": true, "optional": true, "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" } }, "through": { @@ -10344,8 +10344,8 @@ "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "dev": true, "requires": { - "readable-stream": "2.3.6", - "xtend": "4.0.1" + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" } }, "thunkify": { @@ -10373,7 +10373,7 @@ "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", "dev": true, "requires": { - "setimmediate": "1.0.5" + "setimmediate": "^1.0.4" } }, "timespan": { @@ -10389,7 +10389,7 @@ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.2" } }, "to-array": { @@ -10416,7 +10416,7 @@ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "to-regex": { @@ -10425,10 +10425,10 @@ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -10437,8 +10437,8 @@ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" }, "dependencies": { "is-number": { @@ -10447,7 +10447,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } } } @@ -10458,7 +10458,7 @@ "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", "dev": true, "requires": { - "hoek": "4.2.1" + "hoek": "4.x.x" }, "dependencies": { "hoek": { @@ -10481,7 +10481,7 @@ "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "dev": true, "requires": { - "punycode": "1.4.1" + "punycode": "^1.4.1" }, "dependencies": { "punycode": { @@ -10517,7 +10517,7 @@ "dev": true, "optional": true, "requires": { - "glob": "6.0.4" + "glob": "^6.0.4" }, "dependencies": { "glob": { @@ -10527,11 +10527,11 @@ "dev": true, "optional": true, "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } @@ -10542,16 +10542,16 @@ "integrity": "sha512-xcZH12oVg9PShKhy3UHyDmuDLV3y7iKwX25aMVPt1SIXSuAfWkFiGPEkg+th8R4YKW/QCxDoW7lJdb15lx6QWg==", "dev": true, "requires": { - "arrify": "1.0.1", - "chalk": "2.4.1", - "diff": "3.5.0", - "make-error": "1.3.4", - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "source-map-support": "0.5.5", - "tsconfig": "7.0.0", - "v8flags": "3.0.2", - "yn": "2.0.0" + "arrify": "^1.0.0", + "chalk": "^2.3.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.0", + "tsconfig": "^7.0.0", + "v8flags": "^3.0.0", + "yn": "^2.0.0" }, "dependencies": { "chalk": { @@ -10560,9 +10560,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "has-flag": { @@ -10589,8 +10589,8 @@ "integrity": "sha512-mR7/Nd5l1z6g99010shcXJiNEaf3fEtmLhRB/sBcQVJGodcHCULPp2y4Sfa43Kv2zq7T+Izmfp/WHCR6dYkQCA==", "dev": true, "requires": { - "buffer-from": "1.0.0", - "source-map": "0.6.1" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, "supports-color": { @@ -10599,7 +10599,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -10610,10 +10610,10 @@ "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", "dev": true, "requires": { - "@types/strip-bom": "3.0.0", + "@types/strip-bom": "^3.0.0", "@types/strip-json-comments": "0.0.30", - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1" + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" }, "dependencies": { "strip-bom": { @@ -10630,10 +10630,10 @@ "integrity": "sha1-tZXbFrI2chgk7u2ouyYjZbR+8zQ=", "dev": true, "requires": { - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "source-map": "0.5.7", - "source-map-support": "0.4.18" + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map": "^0.5.6", + "source-map-support": "^0.4.2" }, "dependencies": { "minimist": { @@ -10655,18 +10655,18 @@ "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "builtin-modules": "1.1.1", - "chalk": "2.4.1", - "commander": "2.15.1", - "diff": "3.5.0", - "glob": "7.1.2", - "js-yaml": "3.11.0", - "minimatch": "3.0.4", - "resolve": "1.7.1", - "semver": "5.5.0", - "tslib": "1.9.0", - "tsutils": "2.26.2" + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.12.1" }, "dependencies": { "chalk": { @@ -10675,9 +10675,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "has-flag": { @@ -10692,7 +10692,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -10710,7 +10710,7 @@ "integrity": "sha512-uzwnhmrSbyinPCiwfzGsOY3IulBTwoky7r83HmZdz9QNCjhSCzavkh47KLWuU0zF2F2WbpmmzoJUIEiYyd+jEQ==", "dev": true, "requires": { - "tslib": "1.9.0" + "tslib": "^1.8.1" } }, "tty-browserify": { @@ -10725,7 +10725,7 @@ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -10741,7 +10741,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "type-is": { @@ -10751,7 +10751,7 @@ "dev": true, "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.18" + "mime-types": "~2.1.18" } }, "typedarray": { @@ -10772,8 +10772,8 @@ "integrity": "sha512-Ks+KqLGDsYn4z+pU7JsKCzC0T3mPYl+rU+VcPZiQOazjE4Uqi4UCRY3qPMDbJi7ze37n1lDXj3biz1ik93vqvw==", "dev": true, "requires": { - "commander": "2.15.1", - "source-map": "0.6.1" + "commander": "~2.15.0", + "source-map": "~0.6.1" }, "dependencies": { "source-map": { @@ -10797,14 +10797,14 @@ "integrity": "sha512-hIQJ1yxAPhEA2yW/i7Fr+SXZVMp+VEI3d42RTHBgQd2yhp/1UdBcR3QEWPV5ahBxlqQDMEMTuTEvDHSFINfwSw==", "dev": true, "requires": { - "cacache": "10.0.4", - "find-cache-dir": "1.0.0", - "schema-utils": "0.4.5", - "serialize-javascript": "1.5.0", - "source-map": "0.6.1", - "uglify-es": "3.3.9", - "webpack-sources": "1.1.0", - "worker-farm": "1.6.0" + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "schema-utils": "^0.4.5", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "uglify-es": "^3.3.4", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" }, "dependencies": { "commander": { @@ -10825,8 +10825,8 @@ "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", "dev": true, "requires": { - "commander": "2.13.0", - "source-map": "0.6.1" + "commander": "~2.13.0", + "source-map": "~0.6.1" } } } @@ -10849,10 +10849,10 @@ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" }, "dependencies": { "extend-shallow": { @@ -10861,7 +10861,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "set-value": { @@ -10870,10 +10870,10 @@ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" } } } @@ -10884,7 +10884,7 @@ "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", "dev": true, "requires": { - "unique-slug": "2.0.0" + "unique-slug": "^2.0.0" } }, "unique-slug": { @@ -10893,7 +10893,7 @@ "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", "dev": true, "requires": { - "imurmurhash": "0.1.4" + "imurmurhash": "^0.1.4" } }, "universalify": { @@ -10914,8 +10914,8 @@ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -10924,9 +10924,9 @@ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -10971,7 +10971,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=", "requires": { - "punycode": "2.1.0" + "punycode": "^2.1.0" } }, "urix": { @@ -11004,9 +11004,9 @@ "integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==", "dev": true, "requires": { - "loader-utils": "1.1.0", - "mime": "1.6.0", - "schema-utils": "0.3.0" + "loader-utils": "^1.0.2", + "mime": "^1.4.1", + "schema-utils": "^0.3.0" }, "dependencies": { "ajv": { @@ -11015,10 +11015,10 @@ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "schema-utils": { @@ -11027,7 +11027,7 @@ "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", "dev": true, "requires": { - "ajv": "5.5.2" + "ajv": "^5.0.0" } } } @@ -11038,8 +11038,8 @@ "integrity": "sha512-ERuGxDiQ6Xw/agN4tuoCRbmwRuZP0cJ1lJxJubXr5Q/5cDa78+Dc4wfvtxzhzhkm5VvmW6Mf8EVj9SPGN4l8Lg==", "dev": true, "requires": { - "querystringify": "2.0.0", - "requires-port": "1.0.0" + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" }, "dependencies": { "querystringify": { @@ -11056,7 +11056,7 @@ "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.2" }, "dependencies": { "kind-of": { @@ -11073,8 +11073,8 @@ "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", "dev": true, "requires": { - "lru-cache": "2.2.4", - "tmp": "0.0.33" + "lru-cache": "2.2.x", + "tmp": "0.0.x" }, "dependencies": { "lru-cache": { @@ -11138,7 +11138,7 @@ "integrity": "sha512-6sgSKoFw1UpUPd3cFdF7QGnrH6tDeBgW1F3v9gy8gLY0mlbiBXq8soy8aQpY6xeeCjH5K+JvC62Acp7gtl7wWA==", "dev": true, "requires": { - "homedir-polyfill": "1.0.1" + "homedir-polyfill": "^1.0.1" } }, "validate-npm-package-license": { @@ -11147,8 +11147,8 @@ "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "dev": true, "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, "vary": { @@ -11163,9 +11163,9 @@ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" }, "dependencies": { "assert-plus": { @@ -11203,11 +11203,11 @@ "integrity": "sha512-hDwJ674+7dfiiK/cxtYCwPxlnjXDjto/pCz1PF02sXUhqCqCWsgvxZln0699PReWqXXgkxqkF6DDo5Rj9sjNvw==", "dev": true, "requires": { - "core-js": "2.5.3", - "joi": "9.2.0", - "minimist": "1.2.0", - "request": "2.81.0", - "rx": "4.1.0" + "core-js": "^2.4.1", + "joi": "^9.2.0", + "minimist": "^1.2.0", + "request": "^2.78.0", + "rx": "^4.1.0" }, "dependencies": { "hoek": { @@ -11228,11 +11228,11 @@ "integrity": "sha1-M4WseQGSEwy+Iw6ALsAskhW7/to=", "dev": true, "requires": { - "hoek": "4.2.1", - "isemail": "2.2.1", - "items": "2.1.1", - "moment": "2.20.1", - "topo": "2.0.2" + "hoek": "4.x.x", + "isemail": "2.x.x", + "items": "2.x.x", + "moment": "2.x.x", + "topo": "2.x.x" } }, "minimist": { @@ -11249,9 +11249,9 @@ "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", "dev": true, "requires": { - "chokidar": "2.0.3", - "graceful-fs": "4.1.11", - "neo-async": "2.5.1" + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" }, "dependencies": { "anymatch": { @@ -11260,8 +11260,8 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" } }, "arr-diff": { @@ -11282,16 +11282,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.2", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -11300,7 +11300,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -11311,18 +11311,18 @@ "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", "dev": true, "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.2.3", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0", - "upath": "1.0.5" + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.1.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.0" } }, "debug": { @@ -11340,13 +11340,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -11355,7 +11355,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -11364,7 +11364,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -11373,7 +11373,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -11382,7 +11382,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -11393,7 +11393,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -11402,7 +11402,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -11413,9 +11413,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" } }, "kind-of": { @@ -11432,14 +11432,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -11448,7 +11448,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -11457,7 +11457,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -11468,10 +11468,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -11480,7 +11480,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -11491,8 +11491,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -11501,7 +11501,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -11512,7 +11512,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -11521,7 +11521,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -11530,9 +11530,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "is-extglob": { @@ -11547,7 +11547,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-number": { @@ -11556,7 +11556,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -11565,7 +11565,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -11588,19 +11588,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.9", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } } } @@ -11611,7 +11611,7 @@ "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, "requires": { - "minimalistic-assert": "1.0.1" + "minimalistic-assert": "^1.0.0" } }, "web-animations-js": { @@ -11625,8 +11625,8 @@ "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=", "dev": true, "requires": { - "@types/selenium-webdriver": "2.53.43", - "selenium-webdriver": "2.53.3" + "@types/selenium-webdriver": "^2.53.35", + "selenium-webdriver": "^2.53.2" }, "dependencies": { "@types/selenium-webdriver": { @@ -11648,9 +11648,9 @@ "dev": true, "requires": { "adm-zip": "0.4.4", - "rimraf": "2.6.2", + "rimraf": "^2.2.8", "tmp": "0.0.24", - "ws": "1.1.5", + "ws": "^1.0.1", "xml2js": "0.4.4" } }, @@ -11672,8 +11672,8 @@ "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", "dev": true, "requires": { - "options": "0.0.6", - "ultron": "1.0.2" + "options": ">=0.0.5", + "ultron": "1.0.x" } }, "xml2js": { @@ -11682,8 +11682,8 @@ "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", "dev": true, "requires": { - "sax": "0.6.1", - "xmlbuilder": "9.0.7" + "sax": "0.6.x", + "xmlbuilder": ">=1.0.0" } } } @@ -11694,28 +11694,28 @@ "integrity": "sha512-3kOFejWqj5ISpJk4Qj/V7w98h9Vl52wak3CLiw/cDOfbVTq7FeoZ0SdoHHY9PYlHr50ZS42OfvzE2vB4nncKQg==", "dev": true, "requires": { - "acorn": "5.5.3", - "acorn-dynamic-import": "2.0.2", - "ajv": "6.4.0", - "ajv-keywords": "3.2.0", - "async": "2.6.0", - "enhanced-resolve": "3.4.1", - "escope": "3.6.0", - "interpret": "1.1.0", - "json-loader": "0.5.7", - "json5": "0.5.1", - "loader-runner": "2.3.0", - "loader-utils": "1.1.0", - "memory-fs": "0.4.1", - "mkdirp": "0.5.1", - "node-libs-browser": "2.1.0", - "source-map": "0.5.7", - "supports-color": "4.5.0", - "tapable": "0.2.8", - "uglifyjs-webpack-plugin": "0.4.6", - "watchpack": "1.6.0", - "webpack-sources": "1.1.0", - "yargs": "8.0.2" + "acorn": "^5.0.0", + "acorn-dynamic-import": "^2.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "async": "^2.1.2", + "enhanced-resolve": "^3.4.0", + "escope": "^3.6.0", + "interpret": "^1.0.0", + "json-loader": "^0.5.4", + "json5": "^0.5.1", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "mkdirp": "~0.5.0", + "node-libs-browser": "^2.0.0", + "source-map": "^0.5.3", + "supports-color": "^4.2.1", + "tapable": "^0.2.7", + "uglifyjs-webpack-plugin": "^0.4.6", + "watchpack": "^1.4.0", + "webpack-sources": "^1.0.1", + "yargs": "^8.0.2" }, "dependencies": { "ansi-regex": { @@ -11736,8 +11736,8 @@ "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" } }, @@ -11747,10 +11747,10 @@ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" } }, "os-locale": { @@ -11759,9 +11759,9 @@ "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, "path-type": { @@ -11770,7 +11770,7 @@ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "pify": "2.3.0" + "pify": "^2.0.0" } }, "pify": { @@ -11785,9 +11785,9 @@ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" } }, "read-pkg-up": { @@ -11796,8 +11796,8 @@ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" } }, "string-width": { @@ -11806,8 +11806,8 @@ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, "dependencies": { "is-fullwidth-code-point": { @@ -11822,7 +11822,7 @@ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -11839,9 +11839,9 @@ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { "yargs": { @@ -11850,9 +11850,9 @@ "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" } } @@ -11864,9 +11864,9 @@ "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", "dev": true, "requires": { - "source-map": "0.5.7", - "uglify-js": "2.8.29", - "webpack-sources": "1.1.0" + "source-map": "^0.5.6", + "uglify-js": "^2.8.29", + "webpack-sources": "^1.0.1" } }, "which-module": { @@ -11887,19 +11887,19 @@ "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", "dev": true, "requires": { - "camelcase": "4.1.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "read-pkg-up": "2.0.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "7.0.0" + "camelcase": "^4.1.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "read-pkg-up": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^7.0.0" }, "dependencies": { "camelcase": { @@ -11914,9 +11914,9 @@ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" }, "dependencies": { "string-width": { @@ -11925,9 +11925,9 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -11940,7 +11940,7 @@ "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", "dev": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" }, "dependencies": { "camelcase": { @@ -11959,8 +11959,8 @@ "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=", "dev": true, "requires": { - "source-list-map": "0.1.8", - "source-map": "0.4.4" + "source-list-map": "~0.1.7", + "source-map": "~0.4.1" }, "dependencies": { "source-list-map": { @@ -11975,7 +11975,7 @@ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -11986,11 +11986,11 @@ "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==", "dev": true, "requires": { - "memory-fs": "0.4.1", - "mime": "1.6.0", - "path-is-absolute": "1.0.1", - "range-parser": "1.2.0", - "time-stamp": "2.0.0" + "memory-fs": "~0.4.1", + "mime": "^1.5.0", + "path-is-absolute": "^1.0.0", + "range-parser": "^1.0.3", + "time-stamp": "^2.0.0" } }, "webpack-dev-server": { @@ -12000,30 +12000,30 @@ "dev": true, "requires": { "ansi-html": "0.0.7", - "array-includes": "3.0.3", - "bonjour": "3.5.0", - "chokidar": "2.0.3", - "compression": "1.7.2", - "connect-history-api-fallback": "1.5.0", - "debug": "3.1.0", - "del": "3.0.0", - "express": "4.16.3", - "html-entities": "1.2.1", - "http-proxy-middleware": "0.17.4", - "import-local": "1.0.0", + "array-includes": "^3.0.3", + "bonjour": "^3.5.0", + "chokidar": "^2.0.0", + "compression": "^1.5.2", + "connect-history-api-fallback": "^1.3.0", + "debug": "^3.1.0", + "del": "^3.0.0", + "express": "^4.16.2", + "html-entities": "^1.2.0", + "http-proxy-middleware": "~0.17.4", + "import-local": "^1.0.0", "internal-ip": "1.2.0", - "ip": "1.1.5", - "killable": "1.0.0", - "loglevel": "1.6.1", - "opn": "5.1.0", - "portfinder": "1.0.13", - "selfsigned": "1.10.2", - "serve-index": "1.9.1", + "ip": "^1.1.5", + "killable": "^1.0.0", + "loglevel": "^1.4.1", + "opn": "^5.1.0", + "portfinder": "^1.0.9", + "selfsigned": "^1.9.1", + "serve-index": "^1.7.2", "sockjs": "0.3.19", "sockjs-client": "1.1.4", - "spdy": "3.4.7", - "strip-ansi": "3.0.1", - "supports-color": "5.4.0", + "spdy": "^3.4.1", + "strip-ansi": "^3.0.0", + "supports-color": "^5.1.0", "webpack-dev-middleware": "1.12.2", "yargs": "6.6.0" }, @@ -12034,8 +12034,8 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" } }, "arr-diff": { @@ -12056,16 +12056,16 @@ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.2", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -12074,7 +12074,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -12091,18 +12091,18 @@ "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", "dev": true, "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.1", - "braces": "2.3.2", - "fsevents": "1.2.3", - "glob-parent": "3.1.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "4.0.0", - "normalize-path": "2.1.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0", - "upath": "1.0.5" + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.1.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.0" } }, "expand-brackets": { @@ -12111,13 +12111,13 @@ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "debug": { @@ -12135,7 +12135,7 @@ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -12144,7 +12144,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -12153,7 +12153,7 @@ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -12162,7 +12162,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -12173,7 +12173,7 @@ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -12182,7 +12182,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -12193,9 +12193,9 @@ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" } }, "kind-of": { @@ -12212,14 +12212,14 @@ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -12228,7 +12228,7 @@ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -12237,7 +12237,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -12248,10 +12248,10 @@ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -12260,7 +12260,7 @@ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -12271,8 +12271,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -12281,7 +12281,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -12298,7 +12298,7 @@ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -12307,7 +12307,7 @@ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -12316,9 +12316,9 @@ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "is-extglob": { @@ -12333,7 +12333,7 @@ "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-number": { @@ -12342,7 +12342,7 @@ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -12351,7 +12351,7 @@ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -12374,19 +12374,19 @@ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.9", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, "supports-color": { @@ -12395,7 +12395,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "y18n": { @@ -12410,19 +12410,19 @@ "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", "dev": true, "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "y18n": "3.2.1", - "yargs-parser": "4.2.1" + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^4.2.0" } }, "yargs-parser": { @@ -12431,7 +12431,7 @@ "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", "dev": true, "requires": { - "camelcase": "3.0.0" + "camelcase": "^3.0.0" } } } @@ -12442,7 +12442,7 @@ "integrity": "sha512-/0QYwW/H1N/CdXYA2PNPVbsxO3u2Fpz34vs72xm03SRfg6bMNGfMJIQEpQjKRvkG2JvT6oRJFpDtSrwbX8Jzvw==", "dev": true, "requires": { - "lodash": "4.17.10" + "lodash": "^4.17.5" } }, "webpack-sources": { @@ -12451,8 +12451,8 @@ "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", "dev": true, "requires": { - "source-list-map": "2.0.0", - "source-map": "0.6.1" + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" }, "dependencies": { "source-map": { @@ -12469,7 +12469,7 @@ "integrity": "sha1-j6yKfo61n8ahZ2ioXJ2U7n+dDts=", "dev": true, "requires": { - "webpack-core": "0.6.9" + "webpack-core": "^0.6.8" } }, "websocket-driver": { @@ -12478,8 +12478,8 @@ "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", "dev": true, "requires": { - "http-parser-js": "0.4.12", - "websocket-extensions": "0.1.3" + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { @@ -12499,7 +12499,7 @@ "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-module": { @@ -12514,7 +12514,7 @@ "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2" } }, "window-size": { @@ -12535,7 +12535,7 @@ "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", "dev": true, "requires": { - "errno": "0.1.7" + "errno": "~0.1.7" } }, "worker-loader": { @@ -12543,8 +12543,8 @@ "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-1.1.1.tgz", "integrity": "sha512-qJZLVS/jMCBITDzPo/RuweYSIG8VJP5P67mP/71alGyTZRe1LYJFdwLjLalY3T5ifx0bMDRD3OB6P2p1escvlg==", "requires": { - "loader-utils": "1.1.0", - "schema-utils": "0.4.5" + "loader-utils": "^1.0.0", + "schema-utils": "^0.4.0" } }, "wrap-ansi": { @@ -12553,8 +12553,8 @@ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" } }, "wrappy": { @@ -12569,9 +12569,9 @@ "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, "requires": { - "async-limiter": "1.0.0", - "safe-buffer": "5.1.2", - "ultron": "1.1.1" + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" } }, "xml2js": { @@ -12580,8 +12580,8 @@ "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", "dev": true, "requires": { - "sax": "1.2.4", - "xmlbuilder": "9.0.7" + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" }, "dependencies": { "sax": { @@ -12629,7 +12629,7 @@ "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", "dev": true, "requires": { - "cuint": "0.2.2" + "cuint": "^0.2.2" } }, "y18n": { @@ -12651,19 +12651,19 @@ "dev": true, "optional": true, "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "y18n": "3.2.1", - "yargs-parser": "5.0.0" + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" }, "dependencies": { "camelcase": { @@ -12689,7 +12689,7 @@ "dev": true, "optional": true, "requires": { - "camelcase": "3.0.0" + "camelcase": "^3.0.0" }, "dependencies": { "camelcase": { diff --git a/package.json b/package.json index 0097673c17..f6e62794b0 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", - "@alfresco/adf-core": "2.4.0-5096baa758e7c50a6b1e02a83e079691ee6615d1", + "@alfresco/adf-content-services": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", + "@alfresco/adf-core": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", diff --git a/src/app.config.json b/src/app.config.json index f12cd56e89..7fe0ce8710 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -168,6 +168,7 @@ ], "facetQueries": { "label": "My facet queries", + "pageSize": 5, "queries": [ { "query": "created:2018", "label": "Created This Year" }, { "query": "content.mimetype", "label": "Type" }, @@ -219,6 +220,7 @@ "component": { "selector": "check-list", "settings": { + "pageSize": 5, "operator": "OR", "options": [ { "name": "Folder", "value": "TYPE:'cm:folder'" }, @@ -249,7 +251,8 @@ "component": { "selector": "number-range", "settings": { - "field": "cm:content.size" + "field": "cm:content.size", + "format": "[{FROM} TO {TO}]" } } }, @@ -260,7 +263,8 @@ "component": { "selector": "date-range", "settings": { - "field": "cm:created" + "field": "cm:created", + "dateFormat": "DD-MMM-YY" } } }, @@ -272,6 +276,7 @@ "selector": "radio", "settings": { "field": null, + "pageSize": 5, "options": [ { "name": "None", "value": "", "default": true }, { diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 4399601878..c08f4cb1e5 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -62,10 +62,9 @@ export class AppComponent implements OnInit { const data: any = snapshot.data || {}; if (data.i18nTitle) { - this.translateService.translate - .stream(data.i18nTitle) - .subscribe((title) => pageTitle.setTitle(title)); - + pageTitle.setTitle( + this.translateService.instant(data.i18nTitle) + ); } else { pageTitle.setTitle(data.title || ''); } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f286904467..6738d4bffc 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -50,7 +50,6 @@ import { SearchInputComponent } from './components/search-input/search-input.com import { SidenavComponent } from './components/sidenav/sidenav.component'; import { AboutComponent } from './components/about/about.component'; import { LocationLinkComponent } from './components/location-link/location-link.component'; -import { EmptyFolderComponent } from './components/empty-folder/empty-folder.component'; import { NodeCopyDirective } from './common/directives/node-copy.directive'; import { NodeDeleteDirective } from './common/directives/node-delete.directive'; import { NodeMoveDirective } from './common/directives/node-move.directive'; @@ -59,7 +58,6 @@ import { NodePermanentDeleteDirective } from './common/directives/node-permanent import { NodeUnshareDirective } from './common/directives/node-unshare.directive'; import { NodeInfoDirective } from './common/directives/node-info.directive'; import { NodeVersionsDirective } from './common/directives/node-versions.directive'; -import { AppConfigPipe } from './common/pipes/app-config.pipe'; import { VersionManagerDialogAdapterComponent } from './components/versions-dialog/version-manager-dialog-adapter.component'; import { BrowsingFilesService } from './common/services/browsing-files.service'; import { ContentManagementService } from './common/services/content-management.service'; @@ -104,7 +102,6 @@ import { SearchComponent } from './components/search/search.component'; PreviewComponent, AboutComponent, LocationLinkComponent, - EmptyFolderComponent, NodeCopyDirective, NodeDeleteDirective, NodeMoveDirective, @@ -113,7 +110,6 @@ import { SearchComponent } from './components/search/search.component'; NodeUnshareDirective, NodeInfoDirective, NodeVersionsDirective, - AppConfigPipe, VersionManagerDialogAdapterComponent, SearchComponent ], diff --git a/src/app/common/pipes/app-config.pipe.ts b/src/app/common/pipes/app-config.pipe.ts deleted file mode 100644 index 46470d69a9..0000000000 --- a/src/app/common/pipes/app-config.pipe.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2018 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Pipe, PipeTransform } from '@angular/core'; -import { AppConfigService } from '@alfresco/adf-core'; - -@Pipe({ - name: 'appConfig', - pure: true -}) -export class AppConfigPipe implements PipeTransform { - constructor(private config: AppConfigService) {} - - transform(value: string, fallback: any): any { - return this.config.get(value, fallback); - } -} diff --git a/src/app/components/empty-folder/empty-folder.component.html b/src/app/components/empty-folder/empty-folder.component.html deleted file mode 100644 index 43ecf6bf83..0000000000 --- a/src/app/components/empty-folder/empty-folder.component.html +++ /dev/null @@ -1,6 +0,0 @@ -
- {{ icon }} -

{{ title | translate }}

-

{{ subtitle | translate }}

- -
diff --git a/src/app/components/empty-folder/empty-folder.component.scss b/src/app/components/empty-folder/empty-folder.component.scss deleted file mode 100644 index 2da90ab1ca..0000000000 --- a/src/app/components/empty-folder/empty-folder.component.scss +++ /dev/null @@ -1,29 +0,0 @@ -@import 'variables'; - -.app-empty-folder { - color: $alfresco-secondary-text-color; - display: flex; - flex-direction: column; - align-items: center; - - &__icon { - font-size: 52px; - height: 52px; - width: 52px; - } - - p { - line-height: 0; - } - - &__title { - font-size: 18px; - font-weight: 600; - } - - &__subtitle, - &__text { - font-size: 14px; - font-weight: 300; - } -} diff --git a/src/app/components/empty-folder/empty-folder.component.spec.ts b/src/app/components/empty-folder/empty-folder.component.spec.ts deleted file mode 100644 index 32e4d5571a..0000000000 --- a/src/app/components/empty-folder/empty-folder.component.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatIconModule } from '@angular/material'; -import { TranslateModule } from '@ngx-translate/core'; - -import { EmptyFolderComponent } from './empty-folder.component'; - -describe('EmptyFolderComponent', () => { - let component: EmptyFolderComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - MatIconModule, - TranslateModule.forRoot() - ], - declarations: [ - EmptyFolderComponent - ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(EmptyFolderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/components/empty-folder/empty-folder.component.ts b/src/app/components/empty-folder/empty-folder.component.ts deleted file mode 100644 index 4e137d1de1..0000000000 --- a/src/app/components/empty-folder/empty-folder.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Component, Input, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; - -@Component({ - selector: 'app-empty-folder', - templateUrl: './empty-folder.component.html', - styleUrls: ['./empty-folder.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None, - // tslint:disable-next-line:use-host-property-decorator - host: { class: 'app-empty-folder' } -}) -export class EmptyFolderComponent { - - @Input() - icon = 'cake'; - - @Input() - title = ''; - - @Input() - subtitle = ''; -} diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index c09577a5da..37679d2319 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -112,11 +112,11 @@ - - + @@ -170,7 +170,7 @@ diff --git a/src/app/components/favorites/favorites.component.spec.ts b/src/app/components/favorites/favorites.component.spec.ts index 13f571a1d0..0dd7255915 100644 --- a/src/app/components/favorites/favorites.component.spec.ts +++ b/src/app/components/favorites/favorites.component.spec.ts @@ -35,7 +35,7 @@ import { UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, AuthenticationService, TimeAgoPipe, NodeNameTooltipPipe, - NodeFavoriteDirective, DataTableComponent + NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; @@ -46,7 +46,6 @@ import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { NodePermissionService } from '../../common/services/node-permission.service'; -import { AppConfigPipe } from '../../common/pipes/app-config.pipe'; import { FavoritesComponent } from './favorites.component'; diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index 195bcf44fe..8107da7fd4 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -171,7 +171,7 @@ diff --git a/src/app/components/files/files.component.spec.ts b/src/app/components/files/files.component.spec.ts index edefece616..063e0499eb 100644 --- a/src/app/components/files/files.component.spec.ts +++ b/src/app/components/files/files.component.spec.ts @@ -37,7 +37,7 @@ import { UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, AuthenticationService, TimeAgoPipe, NodeNameTooltipPipe, FileSizePipe, NodeFavoriteDirective, - DataTableComponent, UploadService + DataTableComponent, UploadService, AppConfigPipe } from '@alfresco/adf-core'; import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; import { MatMenuModule, MatSnackBarModule, MatIconModule, MatDialogModule } from '@angular/material'; @@ -47,7 +47,6 @@ import { BrowsingFilesService } from '../../common/services/browsing-files.servi import { NodeActionsService } from '../../common/services/node-actions.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { NodeInfoDirective } from '../../common/directives/node-info.directive'; -import { AppConfigPipe } from '../../common/pipes/app-config.pipe'; import { FilesComponent } from './files.component'; diff --git a/src/app/components/libraries/libraries.component.html b/src/app/components/libraries/libraries.component.html index 160cebc8ed..3a11a47673 100644 --- a/src/app/components/libraries/libraries.component.html +++ b/src/app/components/libraries/libraries.component.html @@ -21,11 +21,11 @@ - - + @@ -67,7 +67,7 @@ diff --git a/src/app/components/libraries/libraries.component.spec.ts b/src/app/components/libraries/libraries.component.spec.ts index a040082009..ec4a7d74b0 100644 --- a/src/app/components/libraries/libraries.component.spec.ts +++ b/src/app/components/libraries/libraries.component.spec.ts @@ -34,7 +34,7 @@ import { NodesApiService, AlfrescoApiService, ContentService, UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, AuthenticationService, - TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent + TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; import { TranslateModule } from '@ngx-translate/core'; @@ -42,7 +42,6 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ShareDataTableAdapter } from '@alfresco/adf-content-services'; -import { AppConfigPipe } from '../../common/pipes/app-config.pipe'; import { LibrariesComponent } from './libraries.component'; diff --git a/src/app/components/login/login.component.html b/src/app/components/login/login.component.html index d6aa3fc8c0..e5a80250b8 100644 --- a/src/app/components/login/login.component.html +++ b/src/app/components/login/login.component.html @@ -1,5 +1,5 @@ { let fixture: ComponentFixture; @@ -82,7 +81,7 @@ describe('LoginComponent', () => { beforeEach(() => { spyOn(userPreference, 'setStoragePrefix'); spyOn(router, 'navigateByUrl'); - spyOn(auth, 'getRedirectUrl').and.returnValue('/some-url'); + spyOn(auth, 'getRedirect').and.returnValue('/some-url'); spyOn(location, 'forward'); }); diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 06f5c8529a..e20c81d00b 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -107,11 +107,11 @@ - - + @@ -158,7 +158,7 @@ diff --git a/src/app/components/recent-files/recent-files.component.spec.ts b/src/app/components/recent-files/recent-files.component.spec.ts index deab9387f0..f8b1af991d 100644 --- a/src/app/components/recent-files/recent-files.component.spec.ts +++ b/src/app/components/recent-files/recent-files.component.spec.ts @@ -33,7 +33,7 @@ import { NodesApiService, AlfrescoApiService, ContentService, UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, AuthenticationService, - TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent + TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; import { TranslateModule } from '@ngx-translate/core'; @@ -42,7 +42,6 @@ import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/materi import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodeInfoDirective } from '../../common/directives/node-info.directive'; -import { AppConfigPipe } from '../../common/pipes/app-config.pipe'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { RecentFilesComponent } from './recent-files.component'; diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 063e55b3c9..9bbf5a8def 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -112,11 +112,11 @@ - - + @@ -175,7 +175,7 @@ diff --git a/src/app/components/shared-files/shared-files.component.spec.ts b/src/app/components/shared-files/shared-files.component.spec.ts index 6a1030df89..8bcc220910 100644 --- a/src/app/components/shared-files/shared-files.component.spec.ts +++ b/src/app/components/shared-files/shared-files.component.spec.ts @@ -33,7 +33,7 @@ import { NodesApiService, AlfrescoApiService, ContentService, UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, AuthenticationService, - TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent + TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; import { TranslateModule } from '@ngx-translate/core'; @@ -43,7 +43,6 @@ import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { NodePermissionService } from '../../common/services/node-permission.service'; -import { AppConfigPipe } from '../../common/pipes/app-config.pipe'; import { SharedFilesComponent } from './shared-files.component'; diff --git a/src/app/components/trashcan/trashcan.component.html b/src/app/components/trashcan/trashcan.component.html index c762a0afa4..f475d16f18 100644 --- a/src/app/components/trashcan/trashcan.component.html +++ b/src/app/components/trashcan/trashcan.component.html @@ -40,12 +40,12 @@ - -

{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.FIRST_TEXT' | translate }}

-

{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.SECOND_TEXT' | translate }}

-
+

{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.FIRST_TEXT' | translate }}

+

{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.SECOND_TEXT' | translate }}

+
@@ -99,7 +99,7 @@ diff --git a/src/app/components/trashcan/trashcan.component.spec.ts b/src/app/components/trashcan/trashcan.component.spec.ts index df6b8a0781..1e9dfa7bf9 100644 --- a/src/app/components/trashcan/trashcan.component.spec.ts +++ b/src/app/components/trashcan/trashcan.component.spec.ts @@ -33,7 +33,7 @@ import { UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, AuthenticationService, TimeAgoPipe, NodeNameTooltipPipe, - NodeFavoriteDirective, DataTableComponent + NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; import { TranslateModule } from '@ngx-translate/core'; @@ -42,7 +42,6 @@ import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/materi import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodeInfoDirective } from '../../common/directives/node-info.directive'; -import { AppConfigPipe } from '../../common/pipes/app-config.pipe'; import { TrashcanComponent } from './trashcan.component'; diff --git a/src/app/ui/application.scss b/src/app/ui/application.scss index c179506b51..e4ac8ee9af 100644 --- a/src/app/ui/application.scss +++ b/src/app/ui/application.scss @@ -21,7 +21,6 @@ ng-component { @import 'layout'; -@import './overrides/adf-login'; @import './overrides/adf-sidenav-layout'; @import './overrides/alfresco-document-list'; @import './overrides/alfresco-upload-drag-area'; diff --git a/src/app/ui/overrides/_adf-login.scss b/src/app/ui/overrides/_adf-login.scss deleted file mode 100644 index 3d8305f0a2..0000000000 --- a/src/app/ui/overrides/_adf-login.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import 'mixins'; - -adf-login { - @include flex-column; -} \ No newline at end of file diff --git a/src/app/ui/overrides/_alfresco-document-list.scss b/src/app/ui/overrides/_alfresco-document-list.scss index 94f837fa8a..55e9d2293c 100644 --- a/src/app/ui/overrides/_alfresco-document-list.scss +++ b/src/app/ui/overrides/_alfresco-document-list.scss @@ -75,16 +75,9 @@ adf-datatable { } .adf-document-list--empty { - .adf-data-table { - @include flex-column; - justify-content: center; - align-items: center; - } - .adf-data-table .adf-datatable-row:hover, .adf-data-table .adf-datatable-row:focus { background-color: unset; - cursor: default; } } From 6ec7096dd41b9fedfa0770c99e2ebdcfd0191c11 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 11 May 2018 12:51:35 +0100 Subject: [PATCH 026/179] upgrade to latest ADF alpha --- package-lock.json | 14 +++++++------- package.json | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f7b89dfc3..df7be44db3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5.tgz", - "integrity": "sha512-yecP7jB8oNJycCA5yY8jUgIYBOx35zAGQiIR5jGgpmsOC3QBTUx6pbAtRe5goi7TDZ0EWgrbPzvkxJFRKgnZ4Q==", + "version": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f.tgz", + "integrity": "sha512-NsfU+FOe52lgXD+qU+0ynkGJBNTZInQIRlKl1n5x/2JEExFBaHV1gGYO7JhFTxWdZg9hNpZGQN/fY5J4Ey/AhA==", "requires": { - "@alfresco/adf-core": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", + "@alfresco/adf-core": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -61,9 +61,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5.tgz", - "integrity": "sha512-UyLiCax5XK665cjgXLArmQZ2lS62oSlOGdxie1ZR+M4ez6cMPHcSqMm35pGWrSsmX00yc3Ka558izBOmRKYeFw==", + "version": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f.tgz", + "integrity": "sha512-eLNvztTWrYMp93iaOJ+XM4EvBOCou0ofNSv2ffDfFZyqEPeO+sliRcPcaVtBc6jRfOH6l9GBAKzS5KOx10hOMA==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", diff --git a/package.json b/package.json index f6e62794b0..7660f963ac 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", - "@alfresco/adf-core": "2.4.0-589af266d4d41dac4659880c1a12a96f1f0338b5", + "@alfresco/adf-content-services": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", + "@alfresco/adf-core": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", From daf7d65c03e146dd3f7b34b7b222a1dee4c09995 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 11 May 2018 18:40:46 +0100 Subject: [PATCH 027/179] update docker settings (#355) --- .env | 5 ---- Dockerfile | 2 +- docker-compose.yml | 29 ++++++++---------- docker-compose/.env | 5 ---- docker-compose/docker-compose.yml | 15 ++++------ docker-compose/proxy/Dockerfile | 4 --- docker-compose/proxy/nginx.conf | 49 ------------------------------- 7 files changed, 19 insertions(+), 90 deletions(-) delete mode 100644 .env delete mode 100644 docker-compose/.env delete mode 100644 docker-compose/proxy/Dockerfile delete mode 100644 docker-compose/proxy/nginx.conf diff --git a/.env b/.env deleted file mode 100644 index 48d0b390fa..0000000000 --- a/.env +++ /dev/null @@ -1,5 +0,0 @@ -ALFRESCO_TAG=6.0.5-ea -SHARE_TAG=6.0.a -SOLR6_TAG=1.1.1 -POSTGRES_TAG=10.1 -ACA_TAG=latest diff --git a/Dockerfile b/Dockerfile index 423c400990..3ce9f8c7bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM nginx:alpine -LABEL version="1.2" +LABEL version="1.3" LABEL maintainer="Denys Vuika " COPY nginx.conf /etc/nginx/nginx.conf diff --git a/docker-compose.yml b/docker-compose.yml index 40bf2a1311..720c0b1def 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,13 +2,10 @@ version: "3" services: alfresco: - image: alfresco/alfresco-content-repository-community:${ALFRESCO_TAG} + image: alfresco/alfresco-content-repository-community:6.0.5-ea depends_on: - postgres environment: - CATALINA_OPTS : " - -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n - " JAVA_OPTS : " -Ddb.driver=org.postgresql.Driver -Ddb.username=alfresco @@ -19,15 +16,15 @@ services: -Dsolr.secureComms=none -Dsolr.base.url=/solr -Dindex.subsystem.name=solr6 + -Ddeployment.method=DOCKER_COMPOSE " networks: - internal ports: - 8080:8080 #Browser port - - 8000:8000 #Debug port share: - image: alfresco/alfresco-share:${SHARE_TAG} + image: alfresco/alfresco-share:6.0.a depends_on: - alfresco environment: @@ -39,7 +36,7 @@ services: - 8081:8080 postgres: - image: postgres:${POSTGRES_TAG} + image: postgres:10.1 environment: - POSTGRES_PASSWORD=alfresco - POSTGRES_USER=alfresco @@ -50,7 +47,7 @@ services: - 5432:5432 solr6: - image: alfresco/alfresco-search-services:${SOLR6_TAG} + image: alfresco/alfresco-search-services:1.1.1 depends_on: - alfresco environment: @@ -68,7 +65,7 @@ services: - 8983:8983 #Browser port content-app: - image: alfresco/alfresco-content-app:${ACA_TAG} + image: alfresco/alfresco-content-app:latest build: . depends_on: - alfresco @@ -81,17 +78,15 @@ services: # - ./nginx.conf:/etc/nginx/conf.d/default.conf proxy: - #image: nginx - image: alfresco/alfresco-content-app-proxy - build: ./docker-compose/proxy + image: nginx depends_on: - - content-app - # volumes: - # - ./docker-compose/nginx.conf:/etc/nginx/conf.d/default.conf + - content-app + volumes: + - ./docker-compose/nginx.conf:/etc/nginx/conf.d/default.conf networks: - - internal + - internal ports: - - 3000:80 + - 3000:80 networks: internal: diff --git a/docker-compose/.env b/docker-compose/.env deleted file mode 100644 index 8d75501a29..0000000000 --- a/docker-compose/.env +++ /dev/null @@ -1,5 +0,0 @@ -ALFRESCO_TAG=6.0.5-ea -SHARE_TAG=6.0.a -SOLR6_TAG=1.1.1 -POSTGRES_TAG=10.1 -ACA_TAG=master diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml index b6153d7185..752b410538 100644 --- a/docker-compose/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -2,13 +2,10 @@ version: "3" services: alfresco: - image: alfresco/alfresco-content-repository-community:${ALFRESCO_TAG} + image: alfresco/alfresco-content-repository-community:6.0.5-ea depends_on: - postgres environment: - CATALINA_OPTS : " - -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n - " JAVA_OPTS : " -Ddb.driver=org.postgresql.Driver -Ddb.username=alfresco @@ -19,15 +16,15 @@ services: -Dsolr.secureComms=none -Dsolr.base.url=/solr -Dindex.subsystem.name=solr6 + -Ddeployment.method=DOCKER_COMPOSE " networks: - internal ports: - 8080:8080 #Browser port - - 8000:8000 #Debug port share: - image: alfresco/alfresco-share:${SHARE_TAG} + image: alfresco/alfresco-share:6.0.a depends_on: - alfresco environment: @@ -39,7 +36,7 @@ services: - 8081:8080 postgres: - image: postgres:${POSTGRES_TAG} + image: postgres:10.1 environment: - POSTGRES_PASSWORD=alfresco - POSTGRES_USER=alfresco @@ -50,7 +47,7 @@ services: - 5432:5432 solr6: - image: alfresco/alfresco-search-services:${SOLR6_TAG} + image: alfresco/alfresco-search-services:1.1.1 depends_on: - alfresco environment: @@ -68,7 +65,7 @@ services: - 8983:8983 #Browser port content-app: - image: alfresco/alfresco-content-app:${ACA_TAG} + image: alfresco/alfresco-content-app:master depends_on: - alfresco networks: diff --git a/docker-compose/proxy/Dockerfile b/docker-compose/proxy/Dockerfile deleted file mode 100644 index e9319ec4ab..0000000000 --- a/docker-compose/proxy/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM nginx:alpine -LABEL version="1.2" -LABEL maintainer="Denys Vuika " -COPY nginx.conf /etc/nginx/nginx.conf diff --git a/docker-compose/proxy/nginx.conf b/docker-compose/proxy/nginx.conf deleted file mode 100644 index 3a53f3e3f2..0000000000 --- a/docker-compose/proxy/nginx.conf +++ /dev/null @@ -1,49 +0,0 @@ -events { - worker_connections 1024; -} - -http { - server { - listen *:80; - - set $allowOriginSite *; - proxy_pass_request_headers on; - proxy_pass_header Set-Cookie; - - location / { - proxy_pass http://content-app; - - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_redirect off; - proxy_buffering off; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass_header Set-Cookie; - } - - location /alfresco/ { - proxy_pass http://alfresco:8080; - - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_redirect off; - proxy_buffering off; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass_header Set-Cookie; - } - - location /share/ { - proxy_pass http://share:8080; - - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_redirect off; - proxy_buffering off; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass_header Set-Cookie; - } - } -} From e1ea9fbfc18eb6591b33db3a026277a2183101c9 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 14 May 2018 04:12:45 +0100 Subject: [PATCH 028/179] core electron integration (#356) * core electron integration * test fixes --- package-lock.json | 8 +++++ package.json | 2 ++ src/app/app.component.ts | 32 +++++++++++++++++-- src/app/app.module.ts | 4 ++- .../components/sidenav/sidenav.component.html | 17 +++++++++- .../sidenav/sidenav.component.spec.ts | 4 ++- .../components/sidenav/sidenav.component.ts | 11 ++++++- 7 files changed, 71 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index df7be44db3..8dcd5cc651 100644 --- a/package-lock.json +++ b/package-lock.json @@ -427,6 +427,14 @@ "resolved": "https://registry.npmjs.org/@mat-datetimepicker/moment/-/moment-1.0.1.tgz", "integrity": "sha1-YYUwbd/QeTBlq9XbBjKpQZgjdPQ=" }, + "@ngstack/electron": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@ngstack/electron/-/electron-0.1.0.tgz", + "integrity": "sha512-uqBNDkeATuZQm1eVXjB3rok9zFLMaJzfNl1tVnlqMwfaGA9FIe90nquvIZnL/scHbno89weGGxg4JeHLgsRMLA==", + "requires": { + "tslib": "^1.7.1" + } + }, "@ngtools/json-schema": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.2.0.tgz", diff --git a/package.json b/package.json index 7660f963ac..a94d76c2da 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "build:prod": "npm run server-versions && ng build --prod", "build:dev": "npm run server-versions && ng build", "build:tomcat": "npm run server-versions && ng build --base-href ./", + "build:electron": "npm run server-versions && ng build --base-href ./", "test": "ng test --code-coverage", "test:ci": "ng test --code-coverage --single-run --no-progress && cat ./coverage/lcov.info | ./node_modules/.bin/codacy-coverage && rm -rf ./coverage", "lint": "ng lint", @@ -40,6 +41,7 @@ "@angular/router": "5.1.1", "@mat-datetimepicker/core": "1.0.1", "@mat-datetimepicker/moment": "1.0.1", + "@ngstack/electron": "0.1.0", "@ngx-translate/core": "9.1.1", "alfresco-js-api": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", "core-js": "2.5.3", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index c08f4cb1e5..61548951ca 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -23,9 +23,13 @@ * along with Alfresco. If not, see . */ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, EventEmitter } from '@angular/core'; import { Router, ActivatedRoute, NavigationEnd } from '@angular/router'; -import { TranslationService, PageTitleService, UserPreferencesService, AppConfigService } from '@alfresco/adf-core'; +import { + TranslationService, PageTitleService, UserPreferencesService, AppConfigService, + FileModel, UploadService +} from '@alfresco/adf-core'; +import { ElectronService } from '@ngstack/electron'; @Component({ selector: 'app-root', @@ -39,7 +43,9 @@ export class AppComponent implements OnInit { private pageTitle: PageTitleService, private translateService: TranslationService, preferences: UserPreferencesService, - config: AppConfigService) { + config: AppConfigService, + private electronService: ElectronService, + private uploadService: UploadService) { // TODO: remove once ADF 2.3.0 is out (needs bug fixes) preferences.defaults.supportedPageSizes = config.get('pagination.supportedPageSizes'); preferences.defaults.paginationSize = config.get('pagination.size'); @@ -69,5 +75,25 @@ export class AppComponent implements OnInit { pageTitle.setTitle(data.title || ''); } }); + + this.electronService.on('app:navigateRoute', (event: any, ...args: string[]) => { + this.router.navigate([...args]); + }); + + this.electronService.on('app:upload', (event: any, files: any[] = []) => { + const models = files.map(fileInfo => { + const file = new File([fileInfo.data], fileInfo.name); + + return new FileModel(file, { + path: fileInfo.path, + parentId: fileInfo.parentId + }); + }); + + if (models.length > 0) { + this.uploadService.addToQueue(...models); + this.uploadService.uploadFilesInTheQueue(new EventEmitter()); + } + }); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 6738d4bffc..519b51d765 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -30,6 +30,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { TRANSLATION_PROVIDER, CoreModule } from '@alfresco/adf-core'; import { ContentModule } from '@alfresco/adf-content-services'; +import { ElectronModule } from '@ngstack/electron'; import { AppComponent } from './app.component'; import { APP_ROUTES } from './app.routes'; @@ -82,7 +83,8 @@ import { SearchComponent } from './components/search/search.component'; MatDialogModule, MatInputModule, CoreModule, - ContentModule + ContentModule, + ElectronModule ], declarations: [ AppComponent, diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index 2dc6c0af38..174af8aa7f 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -35,6 +35,7 @@ + +
@@ -79,4 +94,4 @@
-
\ No newline at end of file +
diff --git a/src/app/components/sidenav/sidenav.component.spec.ts b/src/app/components/sidenav/sidenav.component.spec.ts index 07e53b2fc7..4d48dbca59 100644 --- a/src/app/components/sidenav/sidenav.component.spec.ts +++ b/src/app/components/sidenav/sidenav.component.spec.ts @@ -38,6 +38,7 @@ import { BrowsingFilesService } from '../../common/services/browsing-files.servi import { NodePermissionService } from '../../common/services/node-permission.service'; import { SidenavComponent } from './sidenav.component'; +import { ElectronModule } from '@ngstack/electron'; describe('SidenavComponent', () => { let fixture; @@ -61,7 +62,8 @@ describe('SidenavComponent', () => { MatMenuModule, MatSnackBarModule, TranslateModule.forRoot(), - RouterTestingModule + RouterTestingModule, + ElectronModule ], declarations: [ SidenavComponent diff --git a/src/app/components/sidenav/sidenav.component.ts b/src/app/components/sidenav/sidenav.component.ts index 84fe64749c..385c96df64 100644 --- a/src/app/components/sidenav/sidenav.component.ts +++ b/src/app/components/sidenav/sidenav.component.ts @@ -31,6 +31,7 @@ import { AppConfigService, NotificationService } from '@alfresco/adf-core'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; +import { ElectronService } from '@ngstack/electron'; @Component({ selector: 'app-sidenav', @@ -40,6 +41,7 @@ import { NodePermissionService } from '../../common/services/node-permission.ser export class SidenavComponent implements OnInit, OnDestroy { @Input() showLabel: boolean; + isDesktopApp = false; node: MinimalNodeEntryEntity = null; navigation = []; @@ -49,7 +51,8 @@ export class SidenavComponent implements OnInit, OnDestroy { private notificationService: NotificationService, private browsingFilesService: BrowsingFilesService, private appConfig: AppConfigService, - public permission: NodePermissionService + public permission: NodePermissionService, + private electronService: ElectronService ) {} ngOnInit() { @@ -59,6 +62,8 @@ export class SidenavComponent implements OnInit, OnDestroy { this.browsingFilesService.onChangeParent .subscribe((node: MinimalNodeEntryEntity) => this.node = node) ]); + + this.isDesktopApp = this.electronService.isDesktopApp; } openSnackMessage(event: any) { @@ -78,4 +83,8 @@ export class SidenavComponent implements OnInit, OnDestroy { return Object.keys(data).map((key) => data[key]); } + + uploadFolderDesktop() { + this.electronService.send('core:uploadFolder', this.node.id); + } } From 60da9d8b94a60bd5b8b9ebe61c59e8841f0b6365 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 14 May 2018 10:54:13 +0100 Subject: [PATCH 029/179] Cypress integration (#357) * initial cypress setup and sample specs * integrate with e2e run * update ci settings * config update * update config * remove cypress from e2e setup * update protractor settings * upgrade libs * restore tsconfig * re-enable cypress --- cypress.json | 5 + cypress/fixtures/example.json | 5 + cypress/integration/login.spec.js | 17 + cypress/plugins/index.js | 17 + cypress/support/commands.js | 25 + cypress/support/index.js | 26 + package-lock.json | 1122 +++++++++++++++++++++++------ package.json | 10 +- 8 files changed, 1009 insertions(+), 218 deletions(-) create mode 100644 cypress.json create mode 100644 cypress/fixtures/example.json create mode 100644 cypress/integration/login.spec.js create mode 100644 cypress/plugins/index.js create mode 100644 cypress/support/commands.js create mode 100644 cypress/support/index.js diff --git a/cypress.json b/cypress.json new file mode 100644 index 0000000000..6c92d4cfbf --- /dev/null +++ b/cypress.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://on.cypress.io/cypress.schema.json", + "baseUrl": "http://localhost:4200", + "videoRecording": false +} diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 0000000000..da18d9352a --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} \ No newline at end of file diff --git a/cypress/integration/login.spec.js b/cypress/integration/login.spec.js new file mode 100644 index 0000000000..19ec8d4876 --- /dev/null +++ b/cypress/integration/login.spec.js @@ -0,0 +1,17 @@ +describe('Login', function() { + + it('logs in as an admin', () => { + cy.visit('/login'); + cy + .get('#username') + .type('admin') + .should('have.value', 'admin'); + cy + .get('#password') + .type('admin') + .should('have.value', 'admin'); + + cy.get('#login-button').click(); + cy.url().should('include', '#/personal-files'); + }); +}); diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js new file mode 100644 index 0000000000..fd170fba69 --- /dev/null +++ b/cypress/plugins/index.js @@ -0,0 +1,17 @@ +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 0000000000..c1f5a772e2 --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This is will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/cypress/support/index.js b/cypress/support/index.js new file mode 100644 index 0000000000..69c55b9d70 --- /dev/null +++ b/cypress/support/index.js @@ -0,0 +1,26 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') + +Cypress.on('uncaught:exception', (err, runnable) => { + // returning false here prevents Cypress from + // failing the test + return false +}); diff --git a/package-lock.json b/package-lock.json index 8dcd5cc651..8ac296b962 100644 --- a/package-lock.json +++ b/package-lock.json @@ -417,6 +417,54 @@ "tslib": "^1.7.1" } }, + "@cypress/listr-verbose-renderer": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", + "integrity": "sha1-p3SS9LEdzHxEajSz4ochr9M8ZCo=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-cursor": "^1.0.2", + "date-fns": "^1.27.2", + "figures": "^1.7.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "@cypress/xvfb": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.1.3.tgz", + "integrity": "sha512-EfRzw+wgI0Zdb4ZlhSvjh3q7I+oenqEYPXvr7oH/2RnzQqGDrPr7IU1Pi2yzGwoXmkNUQbo6qvntnItvQj0F4Q==", + "dev": true, + "requires": { + "lodash.once": "^4.1.1" + } + }, "@mat-datetimepicker/core": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@mat-datetimepicker/core/-/core-1.0.1.tgz", @@ -507,6 +555,34 @@ } } }, + "@types/blob-util": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/blob-util/-/blob-util-1.3.3.tgz", + "integrity": "sha512-4ahcL/QDnpjWA2Qs16ZMQif7HjGP2cw3AGjHabybjw7Vm1EKu+cfQN1D78BaZbS1WJNa1opSMF5HNMztx7lR0w==", + "dev": true + }, + "@types/bluebird": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.18.tgz", + "integrity": "sha512-OTPWHmsyW18BhrnG5x8F7PzeZ2nFxmHGb42bZn79P9hl+GI5cMzyPgQTwNjbem0lJhoru/8vtjAFCUOu3+gE2w==", + "dev": true + }, + "@types/chai": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.0.8.tgz", + "integrity": "sha512-m812CONwdZn/dMzkIJEY0yAs4apyTkTORgfB2UsMOxgkUbC205AHnm4T8I0I5gPg9MHrFc1dJ35iS75c0CJkjg==", + "dev": true + }, + "@types/chai-jquery": { + "version": "1.1.35", + "resolved": "https://registry.npmjs.org/@types/chai-jquery/-/chai-jquery-1.1.35.tgz", + "integrity": "sha512-7aIt9QMRdxuagLLI48dPz96YJdhu64p6FCa6n4qkGN5DQLHnrIjZpD9bXCvV2G0NwgZ1FAmfP214dxc5zNCfgQ==", + "dev": true, + "requires": { + "@types/chai": "*", + "@types/jquery": "*" + } + }, "@types/jasmine": { "version": "2.8.7", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.7.tgz", @@ -522,6 +598,30 @@ "@types/jasmine": "*" } }, + "@types/jquery": { + "version": "3.2.16", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.2.16.tgz", + "integrity": "sha512-q2WC02YxQoX2nY1HRKlYGHpGP1saPmD7GN0pwCDlTz35a4eOtJG+aHRlXyjCuXokUukSrR2aXyBhSW3j+jPc0A==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.87", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.87.tgz", + "integrity": "sha512-AqRC+aEF4N0LuNHtcjKtvF9OTfqZI0iaBoe3dA6m/W+/YZJBZjBmW/QIZ8fBeXC6cnytSY9tBoFBqZ9uSCeVsw==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.1.tgz", + "integrity": "sha512-rUO/jz10KRSyA9SHoCWQ8WX9BICyj5jZYu1/ucKEJKb4KzLZCKMURdYbadP157Q6Zl1x0vHsrU+Z/O0XlhYQDw==", + "dev": true + }, + "@types/mocha": { + "version": "2.2.44", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.44.tgz", + "integrity": "sha512-k2tWTQU8G4+iSMvqKi0Q9IIsWAp/n8xzdZS4Q4YVIltApoMA00wFBFdlJnmoaK1/z7B0Cy0yPe6GgXteSmdUNw==", + "dev": true + }, "@types/node": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-9.3.0.tgz", @@ -540,6 +640,22 @@ "integrity": "sha512-yrqQvb1EZhH+ONMzUmsEnBjzitortVv0lynRe5US2+FofdoMWUE4wf7v4peCd62fqXq8COCVTbpS1/jIg5EbuQ==", "dev": true }, + "@types/sinon": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.0.0.tgz", + "integrity": "sha512-cuK4xM8Lg2wd8cxshcQa8RG4IK/xfyB6TNE6tNVvkrShR4xdrYgsV04q6Dp6v1Lp6biEFdzD8k8zg/ujQeiw+A==", + "dev": true + }, + "@types/sinon-chai": { + "version": "2.7.29", + "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-2.7.29.tgz", + "integrity": "sha512-EkI/ZvJT4hglWo7Ipf9SX+J+R9htNOMjW8xiOhce7+0csqvgoF5IXqY5Ae1GqRgNtWCuaywR5HjVa1snkTqpOw==", + "dev": true, + "requires": { + "@types/chai": "*", + "@types/sinon": "*" + } + }, "@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", @@ -611,21 +727,12 @@ "dev": true }, "agent-base": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", - "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz", + "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==", "dev": true, "requires": { - "extend": "~3.0.0", - "semver": "~5.0.1" - }, - "dependencies": { - "semver": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", - "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", - "dev": true - } + "es6-promisify": "^5.0.0" } }, "ajv": { @@ -713,6 +820,12 @@ } } }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, "ansi-html": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", @@ -1561,6 +1674,12 @@ "isarray": "^1.0.0" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, "buffer-from": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", @@ -1777,6 +1896,12 @@ "color-name": "^1.0.0" } }, + "check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", + "dev": true + }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -1800,6 +1925,12 @@ "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true }, + "ci-info": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz", + "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==", + "dev": true + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -1817,9 +1948,9 @@ "dev": true }, "circular-json": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.3.tgz", - "integrity": "sha512-YlxLOimeIoQGHnMe3kbf8qIV2Bj7uXLbljMPRguNT49GmSAzooNfS9EJ91rSJKbLBOOzM5agvtx0WyechZN/Hw==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.4.tgz", + "integrity": "sha512-vnJA8KS0BfOihugYEUkLRcnmq21FbuivbxgzDLXNs3zIk4KllV4Mx4UuTzBXht9F00C7QfD1YqMXg1zP6EXpig==", "dev": true }, "class-utils": { @@ -1860,6 +1991,31 @@ "source-map": "0.5.x" } }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "^1.0.1" + } + }, + "cli-spinners": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", + "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=", + "dev": true + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" + } + }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -2592,6 +2748,145 @@ "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", "dev": true }, + "cypress": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-2.1.0.tgz", + "integrity": "sha512-EKXGjKFKUkhXXfAkYixBN2Lo2Gji4ZGC+ezWflRf/co49+OyHarZaXp7Y/n826WjmMdpHTmkOw4wUWBgyFHEHQ==", + "dev": true, + "requires": { + "@cypress/listr-verbose-renderer": "0.4.1", + "@cypress/xvfb": "1.1.3", + "@types/blob-util": "1.3.3", + "@types/bluebird": "3.5.18", + "@types/chai": "4.0.8", + "@types/chai-jquery": "1.1.35", + "@types/jquery": "3.2.16", + "@types/lodash": "4.14.87", + "@types/minimatch": "3.0.1", + "@types/mocha": "2.2.44", + "@types/sinon": "4.0.0", + "@types/sinon-chai": "2.7.29", + "bluebird": "3.5.0", + "chalk": "2.1.0", + "check-more-types": "2.24.0", + "commander": "2.11.0", + "common-tags": "1.4.0", + "debug": "3.1.0", + "extract-zip": "1.6.6", + "fs-extra": "4.0.1", + "getos": "2.8.4", + "glob": "7.1.2", + "is-ci": "1.0.10", + "is-installed-globally": "0.1.0", + "lazy-ass": "1.6.0", + "listr": "0.12.0", + "lodash": "4.17.4", + "minimist": "1.2.0", + "progress": "1.1.8", + "ramda": "0.24.1", + "request": "2.81.0", + "request-progress": "0.3.1", + "supports-color": "5.1.0", + "tmp": "0.0.31", + "url": "0.11.0", + "yauzl": "2.8.0" + }, + "dependencies": { + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", + "dev": true + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" + }, + "dependencies": { + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + } + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "common-tags": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.4.0.tgz", + "integrity": "sha1-EYe+Tz1M8MBCfUP3Tu8fc1AWFMA=", + "dev": true, + "requires": { + "babel-runtime": "^6.18.0" + } + }, + "fs-extra": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.1.tgz", + "integrity": "sha1-f8DGyJV/mD9X8waiTlud3Y0N2IA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "supports-color": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", + "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + }, + "tmp": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", + "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, "d": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", @@ -2624,6 +2919,12 @@ "dev": true, "optional": true }, + "date-fns": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", + "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==", + "dev": true + }, "date-format": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", @@ -3036,6 +3337,12 @@ "integrity": "sha1-RYrBscXHYM6IEaFtK/vZfsMLr7g=", "dev": true }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, "elliptic": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", @@ -3261,6 +3568,23 @@ "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", "dev": true }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "dev": true + } + } + }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -3503,6 +3827,12 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, "expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", @@ -3696,6 +4026,58 @@ } } }, + "extract-zip": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz", + "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "debug": "2.6.9", + "mkdirp": "0.5.0", + "yauzl": "2.4.1" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "requires": { + "fd-slicer": "~1.0.1" + } + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -3734,6 +4116,25 @@ "websocket-driver": ">=0.5.1" } }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, "file-loader": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", @@ -4637,6 +5038,26 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, + "getos": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/getos/-/getos-2.8.4.tgz", + "integrity": "sha1-e4YD02GcKOOMsP56T2PDrLgNUWM=", + "dev": true, + "requires": { + "async": "2.1.4" + }, + "dependencies": { + "async": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz", + "integrity": "sha1-LSFgx3iAMuTdbL4lAvH5osj2zeQ=", + "dev": true, + "requires": { + "lodash": "^4.14.0" + } + } + } + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -4687,6 +5108,15 @@ "is-glob": "^2.0.0" } }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", @@ -5184,25 +5614,13 @@ } }, "http-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz", - "integrity": "sha1-zBzjjkU7+YSg93AtLdWcc9CBKEo=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", "dev": true, "requires": { - "agent-base": "2", - "debug": "2", - "extend": "3" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } + "agent-base": "4", + "debug": "3.1.0" } }, "http-proxy-middleware": { @@ -5268,25 +5686,13 @@ "dev": true }, "https-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", - "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", "dev": true, "requires": { - "agent-base": "2", - "debug": "2", - "extend": "3" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } + "agent-base": "^4.1.0", + "debug": "^3.1.0" } }, "iconv-lite": { @@ -5365,9 +5771,9 @@ "dev": true }, "inflection": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.10.0.tgz", - "integrity": "sha1-W//LEZetPoEFD44X4hZoCH7p6y8=", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", "dev": true, "optional": true }, @@ -5479,6 +5885,15 @@ "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", "dev": true }, + "is-ci": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz", + "integrity": "sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4=", + "dev": true, + "requires": { + "ci-info": "^1.0.0" + } + }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", @@ -5573,6 +5988,16 @@ "is-extglob": "^1.0.0" } }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, "is-my-ip-valid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", @@ -5673,6 +6098,12 @@ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "dev": true }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, "is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", @@ -6292,6 +6723,12 @@ "graceful-fs": "^4.1.9" } }, + "lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", + "dev": true + }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", @@ -6400,6 +6837,151 @@ "immediate": "~3.0.5" } }, + "listr": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.12.0.tgz", + "integrity": "sha1-a84sD1YD+klYDqF81qAMwOX6RRo=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "figures": "^1.7.0", + "indent-string": "^2.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.2.0", + "listr-verbose-renderer": "^0.4.0", + "log-symbols": "^1.0.2", + "log-update": "^1.0.2", + "ora": "^0.2.3", + "p-map": "^1.1.1", + "rxjs": "^5.0.0-beta.11", + "stream-to-observable": "^0.1.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz", + "integrity": "sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^1.0.2", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "listr-verbose-renderer": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", + "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-cursor": "^1.0.2", + "date-fns": "^1.27.2", + "figures": "^1.7.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -6473,6 +7055,12 @@ "dev": true, "optional": true }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "dev": true + }, "lodash.tail": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", @@ -6485,25 +7073,71 @@ "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", "dev": true }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "log-update": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", + "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", + "dev": true, + "requires": { + "ansi-escapes": "^1.0.0", + "cli-cursor": "^1.0.2" + } + }, "log4js": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.5.3.tgz", - "integrity": "sha512-YL/qpTxYtK0iWWbuKCrevDZz5lh+OjyHHD+mICqpjnYGKdNRBvPeh/1uYjkKUemT1CSO4wwLOwphWMpKAnD9kw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.6.0.tgz", + "integrity": "sha512-9rG2W9o0D4GJDzQjno1rRpe+hzK0IEG/uGdjzNROStW/DWhV3sNX2r8OdPKppThlK7gr+08C5FSReWqmaRb/Ww==", "dev": true, "requires": { "amqplib": "^0.5.2", "axios": "^0.15.3", - "circular-json": "^0.5.1", + "circular-json": "^0.5.4", "date-format": "^1.2.0", "debug": "^3.1.0", "hipchat-notifier": "^1.1.0", "loggly": "^1.1.0", - "mailgun-js": "^0.7.0", + "mailgun-js": "^0.18.0", "nodemailer": "^2.5.0", "redis": "^2.7.1", - "semver": "^5.3.0", + "semver": "^5.5.0", "slack-node": "~0.2.0", - "streamroller": "^0.7.0" + "streamroller": "0.7.0" } }, "loggly": { @@ -6699,69 +7333,21 @@ } }, "mailgun-js": { - "version": "0.7.15", - "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.7.15.tgz", - "integrity": "sha1-7jZqINrGTDwVwD1sGz4O15UlKrs=", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.18.0.tgz", + "integrity": "sha512-o0P6jjZlx5CQj12tvVgDTbgjTqVN0+5h6/6P1+3c6xmozVKBwniQ6Qt3MkCSF0+ueVTbobAfWyGpWRZMJu8t1g==", "dev": true, "optional": true, "requires": { - "async": "~2.1.2", - "debug": "~2.2.0", - "form-data": "~2.1.1", - "inflection": "~1.10.0", + "async": "~2.6.0", + "debug": "~3.1.0", + "form-data": "~2.3.0", + "inflection": "~1.12.0", "is-stream": "^1.1.0", "path-proxy": "~1.0.0", - "proxy-agent": "~2.0.0", - "q": "~1.4.0", + "promisify-call": "^2.0.2", + "proxy-agent": "~3.0.0", "tsscmp": "~1.0.0" - }, - "dependencies": { - "async": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/async/-/async-2.1.5.tgz", - "integrity": "sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw=", - "dev": true, - "optional": true, - "requires": { - "lodash": "^4.14.0" - } - }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "optional": true, - "requires": { - "ms": "0.7.1" - } - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "optional": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true, - "optional": true - }, - "q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", - "dev": true, - "optional": true - } } }, "make-dir": { @@ -7711,6 +8297,12 @@ "wrappy": "1" } }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, "opn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", @@ -7760,6 +8352,45 @@ "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", "dev": true }, + "ora": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", + "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "cli-cursor": "^1.0.2", + "cli-spinners": "^0.1.2", + "object-assign": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, "original": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", @@ -7855,63 +8486,34 @@ "dev": true }, "pac-proxy-agent": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz", - "integrity": "sha512-QBELCWyLYPgE2Gj+4wUEiMscHrQ8nRPBzYItQNOHWavwBt25ohZHQC4qnd5IszdVVrFbLsQ+dPkm6eqdjJAmwQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-2.0.2.tgz", + "integrity": "sha512-cDNAN1Ehjbf5EHkNY5qnRhGPUCp6SnpyVof5fRzN800QV1Y2OkzbH9rmjZkbBRa8igof903yOnjIl6z0SlAhxA==", "dev": true, "optional": true, "requires": { - "agent-base": "2", - "debug": "2", - "extend": "3", - "get-uri": "2", - "http-proxy-agent": "1", - "https-proxy-agent": "1", - "pac-resolver": "~2.0.0", - "raw-body": "2", - "socks-proxy-agent": "2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - } + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "get-uri": "^2.0.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "pac-resolver": "^3.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "^3.0.0" } }, "pac-resolver": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-2.0.0.tgz", - "integrity": "sha1-mbiNLxk/ve78HJpSnB8yYKtSd80=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", + "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", "dev": true, "optional": true, "requires": { - "co": "~3.0.6", - "degenerator": "~1.0.2", - "ip": "1.0.1", - "netmask": "~1.0.4", - "thunkify": "~2.1.1" - }, - "dependencies": { - "co": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/co/-/co-3.0.6.tgz", - "integrity": "sha1-FEXyJsXrlWE45oyawwFn6n0ua9o=", - "dev": true, - "optional": true - }, - "ip": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.0.1.tgz", - "integrity": "sha1-x+NWzeoiWucbNtcPLnGpK6TkJZA=", - "dev": true, - "optional": true - } + "co": "^4.6.0", + "degenerator": "^1.0.4", + "ip": "^1.1.5", + "netmask": "^1.0.6", + "thunkify": "^2.1.2" } }, "pako": { @@ -8108,6 +8710,12 @@ "worker-loader": "^1.1.0" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "performance-now": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", @@ -8331,6 +8939,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", @@ -8347,10 +8961,20 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "promisify-call": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/promisify-call/-/promisify-call-2.0.4.tgz", + "integrity": "sha1-1IwtRWUszM1SgB3ey9UzptS9X7o=", + "dev": true, + "optional": true, + "requires": { + "with-callback": "^1.0.2" + } + }, "protractor": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.3.1.tgz", - "integrity": "sha512-AW9qJ0prx2QEMy1gnhJ1Sl1WBQL2R3fx/VnG09FEmWprPIQPK14t0B83OB/pAGddpxiDCAAV0KiNNLf2c2Y/lQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.3.2.tgz", + "integrity": "sha512-pw4uwwiy5lHZjIguxNpkEwJJa7hVz+bJsvaTI+IbXlfn2qXwzbF8eghW/RmrZwE2sGx82I8etb8lVjQ+JrjejA==", "dev": true, "requires": { "@types/node": "^6.0.46", @@ -8363,7 +8987,7 @@ "jasminewd2": "^2.1.0", "optimist": "~0.6.0", "q": "1.4.1", - "saucelabs": "~1.3.0", + "saucelabs": "^1.5.0", "selenium-webdriver": "3.6.0", "source-map-support": "~0.4.0", "webdriver-js-extender": "^1.0.0", @@ -8371,9 +8995,9 @@ }, "dependencies": { "@types/node": { - "version": "6.0.107", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.107.tgz", - "integrity": "sha512-iuJWRFHqU0tFLCYH6cfBZzMxThAAsNK31FZxoq+fKIDOSZk1p+3IhNWfEdvPJfsQXcTq8z+57s8xjQlrDAB0Gw==", + "version": "6.0.110", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.110.tgz", + "integrity": "sha512-LiaH3mF+OAqR+9Wo1OTJDbZDtCewAVjTbMhF1ZgUJ3fc8xqOJq6VqbpBh9dJVCVzByGmYIg2fREbuXNX0TKiJA==", "dev": true }, "@types/selenium-webdriver": { @@ -8383,9 +9007,9 @@ "dev": true }, "adm-zip": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.9.tgz", - "integrity": "sha512-eknaJ3Io/JasGGinVeqY5TsPlQgHbiNlHnK5zdFPRNs9XRggDykKz8zPesneOMEZJxWji7G3CfsUW0Ds9Dw0Bw==", + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.11.tgz", + "integrity": "sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA==", "dev": true }, "ansi-styles": { @@ -8513,41 +9137,29 @@ } }, "proxy-agent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-2.0.0.tgz", - "integrity": "sha1-V+tTR6qAXXTsaByyVknbo5yTNJk=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.0.tgz", + "integrity": "sha512-g6n6vnk8fRf705ShN+FEXFG/SDJaW++lSs0d9KaJh4uBWW/wi7en4Cpo5VYQW3SZzAE121lhB/KLQrbURoubZw==", "dev": true, "optional": true, "requires": { - "agent-base": "2", - "debug": "2", - "extend": "3", - "http-proxy-agent": "1", - "https-proxy-agent": "1", - "lru-cache": "~2.6.5", - "pac-proxy-agent": "1", - "socks-proxy-agent": "2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "lru-cache": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz", - "integrity": "sha1-5W1jVBSO3o13B7WNFDIg/QjfD9U=", - "dev": true, - "optional": true - } + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "pac-proxy-agent": "^2.0.1", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^3.0.0" } }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "dev": true, + "optional": true + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -8634,6 +9246,12 @@ "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", "dev": true }, + "ramda": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz", + "integrity": "sha1-w7d1UZfzW43DUCIoJixMkd22uFc=", + "dev": true + }, "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", @@ -9065,6 +9683,15 @@ } } }, + "request-progress": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz", + "integrity": "sha1-ByHBBdipasayzossia4tXs/Pazo=", + "dev": true, + "requires": { + "throttleit": "~0.0.2" + } + }, "request-promise": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", @@ -9153,6 +9780,16 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -9251,12 +9888,33 @@ } }, "saucelabs": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", - "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", "dev": true, "requires": { - "https-proxy-agent": "^1.0.0" + "https-proxy-agent": "^2.2.1" + }, + "dependencies": { + "agent-base": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz", + "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + } + } } }, "sax": { @@ -9574,6 +10232,12 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, "smart-buffer": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", @@ -9853,14 +10517,13 @@ } }, "socks-proxy-agent": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz", - "integrity": "sha512-sFtmYqdUK5dAMh85H0LEVFUCO7OhJJe1/z2x/Z6mxp3s7/QPf1RkZmpZy+BpuU0bEjcV9npqKjq9Y3kwFUjnxw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz", + "integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==", "dev": true, "requires": { - "agent-base": "2", - "extend": "3", - "socks": "~1.1.5" + "agent-base": "^4.1.0", + "socks": "^1.1.10" } }, "source-list-map": { @@ -10116,6 +10779,12 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", "dev": true }, + "stream-to-observable": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.1.0.tgz", + "integrity": "sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4=", + "dev": true + }, "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", @@ -10340,6 +11009,12 @@ "inherits": "2" } }, + "throttleit": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", + "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", + "dev": true + }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -12531,6 +13206,13 @@ "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true }, + "with-callback": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/with-callback/-/with-callback-1.0.2.tgz", + "integrity": "sha1-oJYpuakgAo1yFAT7Q1vc/1yRvCE=", + "dev": true, + "optional": true + }, "wordwrap": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", @@ -12709,6 +13391,16 @@ } } }, + "yauzl": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.8.0.tgz", + "integrity": "sha1-eUUK/yKyqcWkHvVOAtuQfM+/nuI=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.0.1" + } + }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", diff --git a/package.json b/package.json index a94d76c2da..e437da3990 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,10 @@ "e2e": "npm run wd:update && protractor protractor.conf.js", "start:docker": "docker-compose up -d --build && wait-on http://localhost:8080 && wait-on http://localhost:3000", "stop:docker": "docker-compose stop", - "e2e:docker": "npm run start:docker && npm run e2e && npm run stop:docker" + "e2e:docker": "npm run start:docker && npm run cypress:ci && npm run e2e && npm run stop:docker", + "cypress:open": "cypress open", + "cypress:run": "cypress run", + "cypress:ci": "cypress run --browser chrome --config baseUrl=http://localhost:3000" }, "private": true, "dependencies": { @@ -62,19 +65,20 @@ "@types/selenium-webdriver": "^3.0.8", "codacy-coverage": "^2.0.3", "codelyzer": "^4.0.1", + "cypress": "^2.1.0", "jasmine-core": "~2.8.0", "jasmine-reporters": "^2.2.1", "jasmine-spec-reporter": "~4.2.1", "jasmine2-protractor-utils": "^1.3.0", "jasminewd2": "^2.2.0", - "karma": "~2.0.0", + "karma": "2.0.2", "karma-chrome-launcher": "~2.2.0", "karma-cli": "~1.0.1", "karma-coverage-istanbul-reporter": "^1.2.1", "karma-jasmine": "~1.1.0", "karma-jasmine-html-reporter": "^0.2.2", "node-rest-client": "^3.1.0", - "protractor": "5.3.1", + "protractor": "5.3.2", "rimraf": "2.6.2", "selenium-webdriver": "4.0.0-alpha.1", "ts-node": "~4.1.0", From 90caabafc081519d734b23904f514c970afb0951 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 14 May 2018 13:55:15 +0300 Subject: [PATCH 030/179] preserve state (#358) --- src/app.config.json | 4 + .../components/layout/layout.component.html | 9 +- .../layout/layout.component.spec.ts | 108 +++++++++++++++++- src/app/components/layout/layout.component.ts | 29 ++++- 4 files changed, 137 insertions(+), 13 deletions(-) diff --git a/src/app.config.json b/src/app.config.json index 7fe0ce8710..0fb00c0e68 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -19,6 +19,10 @@ "allowDownload": true, "allowDelete": true }, + "sideNav" : { + "preserveState" : true, + "expandedSidenav": true + }, "navigation": { "main": [ { diff --git a/src/app/components/layout/layout.component.html b/src/app/components/layout/layout.component.html index 958362bc2a..090d002c05 100644 --- a/src/app/components/layout/layout.component.html +++ b/src/app/components/layout/layout.component.html @@ -7,14 +7,13 @@ [sidenavMin]="70" [sidenavMax]="320" [stepOver]="600" - [hideSidenav]="isPreview" - [expandedSidenav]="true"> + [hideSidenav]="hideSidenav" + [expandedSidenav]="expandedSidenav" + (expanded)="setState($event)"> - - - + diff --git a/src/app/components/layout/layout.component.spec.ts b/src/app/components/layout/layout.component.spec.ts index 166179c456..0424abf35f 100644 --- a/src/app/components/layout/layout.component.spec.ts +++ b/src/app/components/layout/layout.component.spec.ts @@ -45,6 +45,8 @@ describe('LayoutComponent', () => { let fixture: ComponentFixture; let component: LayoutComponent; let browsingFilesService: BrowsingFilesService; + let appConfig: AppConfigService; + let userPreference: UserPreferencesService; const navItem = { label: 'some-label', route: { @@ -86,18 +88,114 @@ describe('LayoutComponent', () => { fixture = TestBed.createComponent(LayoutComponent); component = fixture.componentInstance; browsingFilesService = TestBed.get(BrowsingFilesService); - - const appConfig = TestBed.get(AppConfigService); - spyOn(appConfig, 'get').and.returnValue([navItem]); - - fixture.detectChanges(); + appConfig = TestBed.get(AppConfigService); + userPreference = TestBed.get(UserPreferencesService); }); it('sets current node', () => { + appConfig.config = { + navigation: [navItem] + }; + const currentNode = { id: 'someId' }; + fixture.detectChanges(); + browsingFilesService.onChangeParent.next(currentNode); expect(component.node).toEqual(currentNode); }); + + 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 = {}; + + 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'; + } + }); + + 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'; + } + }); + + fixture.detectChanges(); + + expect(component.expandedSidenav).toBe(false); + }); + + it('should set expandedSidenav to true if configuration is true', () => { + spyOn(userPreference, 'set'); + + appConfig.config = { + sideNav: { + expandedSidenav: false, + preserveState: true + } + }; + + fixture.detectChanges(); + component.setState(true); + + expect(userPreference.set).toHaveBeenCalledWith( 'expandedSidenav', true); + }); + + it('should set expandedSidenav to false if configuration is true', () => { + spyOn(userPreference, 'set'); + + appConfig.config = { + sideNav: { + expandedSidenav: false, + preserveState: true + } + }; + + fixture.detectChanges(); + component.setState(false); + + expect(userPreference.set).toHaveBeenCalledWith( 'expandedSidenav', false); + }); + }); }); diff --git a/src/app/components/layout/layout.component.ts b/src/app/components/layout/layout.component.ts index 07f3fa06ec..1800a8ddc6 100644 --- a/src/app/components/layout/layout.component.ts +++ b/src/app/components/layout/layout.component.ts @@ -27,6 +27,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router, NavigationEnd } from '@angular/router'; import { Subscription } from 'rxjs/Rx'; import { MinimalNodeEntryEntity } from 'alfresco-js-api'; +import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; @@ -37,22 +38,27 @@ import { NodePermissionService } from '../../common/services/node-permission.ser }) export class LayoutComponent implements OnInit, OnDestroy { node: MinimalNodeEntryEntity; - isPreview = false; - + hideSidenav: boolean; + expandedSidenav: boolean; + private hideConditions: string[] = ['preview']; private subscriptions: Subscription[] = []; constructor( private router: Router, private browsingFilesService: BrowsingFilesService, + private userPreferenceService: UserPreferencesService, + private appConfigService: AppConfigService, public permission: NodePermissionService) { this.router.events .filter(event => event instanceof NavigationEnd) .subscribe( (event: any ) => { - this.isPreview = event.urlAfterRedirects.includes('preview'); + this.hideSidenav = this.hideConditions.some(el => event.urlAfterRedirects.includes(el)); }); } ngOnInit() { + this.expandedSidenav = this.sidenavState; + this.subscriptions.concat([ this.browsingFilesService.onChangeParent.subscribe((node: MinimalNodeEntryEntity) => this.node = node) ]); @@ -61,4 +67,21 @@ export class LayoutComponent implements OnInit, OnDestroy { ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } + + get sidenavState(): boolean { + const expand = this.appConfigService.get('sideNav.expandedSidenav', true); + const preserveState = this.appConfigService.get('sideNav.preserveState', true); + + if (preserveState) { + return (this.userPreferenceService.get('expandedSidenav', expand.toString()) === 'true'); + } + + return expand; + } + + setState(state) { + if (this.appConfigService.get('sideNav.preserveState')) { + this.userPreferenceService.set('expandedSidenav', state); + } + } } From 3ff9a9b536e1d745bea62afa939438b60f1a46e8 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 14 May 2018 11:57:41 +0100 Subject: [PATCH 031/179] run cypress only with travis for now --- .travis.yml | 2 +- package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f97f4facde..7da6fc0ced 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,4 +21,4 @@ install: script: # - docker-compose stop - - npm run build && npm run e2e:docker + - npm run build && npm run e2e:all diff --git a/package.json b/package.json index e437da3990..be7e9ff6eb 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "e2e": "npm run wd:update && protractor protractor.conf.js", "start:docker": "docker-compose up -d --build && wait-on http://localhost:8080 && wait-on http://localhost:3000", "stop:docker": "docker-compose stop", - "e2e:docker": "npm run start:docker && npm run cypress:ci && npm run e2e && npm run stop:docker", + "e2e:docker": "npm run start:docker && npm run e2e && npm run stop:docker", + "e2e:all": "npm run start:docker && npm run cypress:ci && npm run e2e && npm run stop:docker", "cypress:open": "cypress open", "cypress:run": "cypress run", "cypress:ci": "cypress run --browser chrome --config baseUrl=http://localhost:3000" From 122f26e015ee16d3fa90a18cec7c96ab2bc21180 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 15 May 2018 20:38:22 +0100 Subject: [PATCH 032/179] simple loading indicator --- src/index.html | 57 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/index.html b/src/index.html index 688fda628a..faccdb5036 100644 --- a/src/index.html +++ b/src/index.html @@ -7,8 +7,63 @@ + + - + +
+
+
+
+
+
+
From bda89943a89b1be89c0c98d86ba29ad5defb430f Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 17 May 2018 10:38:13 +0100 Subject: [PATCH 033/179] [desktop] settings dialog (#360) * settings route * settings component * translate strings * use 'www' output folder for electron builds --- .gitignore | 1 + package.json | 2 +- src/app/app.module.ts | 8 +- src/app/app.routes.ts | 8 ++ .../services/hybrid-app-config.service.ts | 37 ++++++++ .../settings/settings.component.html | 43 +++++++++ .../settings/settings.component.scss | 69 +++++++++++++++ .../components/settings/settings.component.ts | 88 +++++++++++++++++++ src/assets/i18n/en.json | 7 ++ 9 files changed, 260 insertions(+), 3 deletions(-) create mode 100644 src/app/common/services/hybrid-app-config.service.ts create mode 100644 src/app/components/settings/settings.component.html create mode 100644 src/app/components/settings/settings.component.scss create mode 100644 src/app/components/settings/settings.component.ts diff --git a/.gitignore b/.gitignore index c5d885dad0..e2df279f2a 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ npm-debug.log testem.log /typings +/www # e2e /e2e/*.js diff --git a/package.json b/package.json index be7e9ff6eb..ef8c23ba58 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build:prod": "npm run server-versions && ng build --prod", "build:dev": "npm run server-versions && ng build", "build:tomcat": "npm run server-versions && ng build --base-href ./", - "build:electron": "npm run server-versions && ng build --base-href ./", + "build:electron": "npm run server-versions && ng build --output-path www --base-href ./", "test": "ng test --code-coverage", "test:ci": "ng test --code-coverage --single-run --no-progress && cat ./coverage/lcov.info | ./node_modules/.bin/codacy-coverage && rm -rf ./coverage", "lint": "ng lint", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 519b51d765..f12f94d524 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -28,7 +28,7 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { TRANSLATION_PROVIDER, CoreModule } from '@alfresco/adf-core'; +import { TRANSLATION_PROVIDER, CoreModule, AppConfigService } from '@alfresco/adf-core'; import { ContentModule } from '@alfresco/adf-content-services'; import { ElectronModule } from '@ngstack/electron'; @@ -66,6 +66,8 @@ import { NodeActionsService } from './common/services/node-actions.service'; import { NodePermissionService } from './common/services/node-permission.service'; import { MatMenuModule, MatIconModule, MatButtonModule, MatDialogModule, MatInputModule } from '@angular/material'; import { SearchComponent } from './components/search/search.component'; +import { SettingsComponent } from './components/settings/settings.component'; +import { HybridAppConfigService } from './common/services/hybrid-app-config.service'; @NgModule({ imports: [ @@ -113,9 +115,11 @@ import { SearchComponent } from './components/search/search.component'; NodeInfoDirective, NodeVersionsDirective, VersionManagerDialogAdapterComponent, - SearchComponent + SearchComponent, + SettingsComponent ], providers: [ + { provide: AppConfigService, useClass: HybridAppConfigService }, { provide: TRANSLATION_PROVIDER, multi: true, diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 3a098acb5b..eb6089c308 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -40,6 +40,7 @@ import { LoginComponent } from './components/login/login.component'; import { PreviewComponent } from './components/preview/preview.component'; import { GenericErrorComponent } from './components/generic-error/generic-error.component'; import { SearchComponent } from './components/search/search.component'; +import { SettingsComponent } from './components/settings/settings.component'; export const APP_ROUTES: Routes = [ { @@ -49,6 +50,13 @@ export const APP_ROUTES: Routes = [ i18nTitle: 'APP.SIGN_IN' } }, + { + path: 'settings', + component: SettingsComponent, + data: { + i18nTitle: 'Settings' + } + }, { path: '', component: LayoutComponent, diff --git a/src/app/common/services/hybrid-app-config.service.ts b/src/app/common/services/hybrid-app-config.service.ts new file mode 100644 index 0000000000..9aa53e017c --- /dev/null +++ b/src/app/common/services/hybrid-app-config.service.ts @@ -0,0 +1,37 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { AppConfigService, StorageService } from '@alfresco/adf-core'; + +@Injectable() +export class HybridAppConfigService extends AppConfigService { + + constructor(private storage: StorageService, http: HttpClient) { + super(http); + } + + /** @override */ + get(key: string, defaultValue?: T): T { + if (key === 'ecmHost' || key === 'bpmHost') { + return ( this.storage.getItem(key) || super.get(key)); + } + return super.get(key, defaultValue); + } + +} diff --git a/src/app/components/settings/settings.component.html b/src/app/components/settings/settings.component.html new file mode 100644 index 0000000000..89c2e8cb78 --- /dev/null +++ b/src/app/components/settings/settings.component.html @@ -0,0 +1,43 @@ + + + + {{ appName }} + + + + +
+ + + + {{ 'APP.SETTINGS.REPOSITORY-SETTINGS' | translate }} + + +
+ + + + {{ 'APP.SETTINGS.INVALID-VALUE-FORMAT' | translate }} + + + {{ 'APP.SETTINGS.REQUIRED-FIELD' | translate }} + + +
+ +
+ + +
+ +
+
+
diff --git a/src/app/components/settings/settings.component.scss b/src/app/components/settings/settings.component.scss new file mode 100644 index 0000000000..ad87b64920 --- /dev/null +++ b/src/app/components/settings/settings.component.scss @@ -0,0 +1,69 @@ +@import 'variables'; + +.app-settings { + .settings-input { + width: 50%; + } + + .settings-buttons { + text-align: right; + + .mat-button { + text-transform: uppercase; + } + } + + $app-menu-height: 64px; + + .app-menu { + height: $app-menu-height; + + &.adf-toolbar { + .mat-toolbar { + background-color: inherit; + font-family: inherit; + min-height: $app-menu-height; + height: $app-menu-height; + + .mat-toolbar-layout { + height: $app-menu-height; + + .mat-toolbar-row { + height: $app-menu-height; + } + } + } + + .adf-toolbar-divider { + margin-left: 5px; + margin-right: 5px; + + & > div { + background-color: $alfresco-white !important; + } + } + + .adf-toolbar-title { + color: $alfresco-white; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + } + } + + .app-menu__title { + width: 100px; + height: 50px; + margin-left: 40px; + display: flex; + justify-content: center; + align-items: stretch; + + &> img { + width: 100%; + object-fit: contain; + } + } + } +} diff --git a/src/app/components/settings/settings.component.ts b/src/app/components/settings/settings.component.ts new file mode 100644 index 0000000000..f0087bb065 --- /dev/null +++ b/src/app/components/settings/settings.component.ts @@ -0,0 +1,88 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Component, ViewEncapsulation, SecurityContext, OnInit } from '@angular/core'; +import { AppConfigService, StorageService, SettingsService } from '@alfresco/adf-core'; +import { DomSanitizer } from '@angular/platform-browser'; +import { Validators, FormGroup, FormBuilder } from '@angular/forms'; + +@Component({ + selector: 'app-settings', + templateUrl: './settings.component.html', + styleUrls: ['./settings.component.scss'], + encapsulation: ViewEncapsulation.None, + // tslint:disable-next-line:use-host-property-decorator + host: { class: 'app-settings' } +}) +export class SettingsComponent implements OnInit { + + private defaultPath = '/assets/images/alfresco-logo-white.svg'; + private defaultBackgroundColor = '#2196F3'; + + form: FormGroup; + + constructor( + private appConfig: AppConfigService, + private sanitizer: DomSanitizer, + private settingsService: SettingsService, + private storage: StorageService, + private fb: FormBuilder) { + + } + + get appName(): string { + return this.appConfig.get('application.name'); + } + + get logo() { + return this.appConfig.get('application.logo', this.defaultPath); + } + + get backgroundColor() { + const color = this.appConfig.get('headerColor', this.defaultBackgroundColor); + return this.sanitizer.sanitize(SecurityContext.STYLE, color); + } + + ngOnInit() { + this.form = this.fb.group({ + ecmHost: ['', [Validators.required, Validators.pattern('^(http|https):\/\/.*[^/]$')]] + }); + + this.reset(); + } + + apply(model: any, isValid: boolean) { + if (isValid) { + this.storage.setItem('ecmHost', model.ecmHost); + // window.location.reload(true); + } + } + + reset() { + this.form.reset({ + ecmHost: this.storage.getItem('ecmHost') || this.settingsService.ecmHost + }); + } +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 8d0e088ed6..0316a4f369 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -3,6 +3,13 @@ "LANGUAGE": "Language", "SIGN_IN": "Sign in", "SIGN_OUT": "Sign out", + "SETTINGS": { + "REPOSITORY-SETTINGS": "Repository Settings", + "INVALID-VALUE-FORMAT": "Invalid value format", + "REQUIRED-FIELD": "This field is required", + "RESET": "Reset", + "APPLY": "Apply" + }, "PREVIEW": { "TITLE": "Preview" }, From 829b4211081e99c02de0eb365792498a022ca58d Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 21 May 2018 06:40:41 +0100 Subject: [PATCH 034/179] [ACA-1390] add spellcheck for the typescript code (#363) * add spellcheck for the typescript code * update CI config * update spellcheck rules * update spellcheck config and code * run spellcheck for e2e tests * disable e2e test * disable cypress for now --- .circleci/config.yml | 13 + .travis.yml | 2 +- cspell.json | 40 ++ e2e/suites/actions/mark-favorite.test.ts | 4 +- .../actions/toolbar-single-selection.test.ts | 2 +- e2e/suites/authentication/login.test.ts | 2 + e2e/suites/navigation/breadcrumb.test.ts | 48 +-- .../reporters/console/console-logger.ts | 2 +- e2e/utilities/reporters/console/console.ts | 2 +- package-lock.json | 345 ++++++++++++++++-- package.json | 4 +- .../directives/node-delete.directive.ts | 4 +- .../directives/node-restore.directive.ts | 4 +- .../services/node-actions.service.spec.ts | 16 +- 14 files changed, 415 insertions(+), 73 deletions(-) create mode 100644 cspell.json diff --git a/.circleci/config.yml b/.circleci/config.yml index 077b30a374..8c32532fa9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,6 +24,16 @@ jobs: key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }} - run: npm install - run: npm run lint + spellcheck: + working_directory: ~/alfresco-content-app + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }} + - run: npm install + - run: npm run spellcheck test: working_directory: ~/alfresco-content-app docker: @@ -53,6 +63,9 @@ workflows: - lint: requires: - install + - spellcheck: + requires: + - install - test: requires: - install diff --git a/.travis.yml b/.travis.yml index 7da6fc0ced..f97f4facde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,4 +21,4 @@ install: script: # - docker-compose stop - - npm run build && npm run e2e:all + - npm run build && npm run e2e:docker diff --git a/cspell.json b/cspell.json new file mode 100644 index 0000000000..9e9b86be0c --- /dev/null +++ b/cspell.json @@ -0,0 +1,40 @@ +{ + "version": "0.1", + "language": "en", + "words": [ + "succes", + + "ngstack", + "sidenav", + "injectable", + "truthy", + "cryptodoc", + "mysites", + "afts", + "classlist", + "folderlink", + "filelink", + "datatable", + "repo", + "snackbar", + "promisify", + "xdescribe", + "unfavorite", + + "unshare", + "validators", + "guid", + "polyfill", + "polyfills", + "jsonp", + "hammerjs", + "pdfjs", + "xpath", + "tooltip", + "tooltips", + "unindent" + ], + "dictionaries": [ + "html" + ] +} diff --git a/e2e/suites/actions/mark-favorite.test.ts b/e2e/suites/actions/mark-favorite.test.ts index f6f79cf090..cc861d0224 100644 --- a/e2e/suites/actions/mark-favorite.test.ts +++ b/e2e/suites/actions/mark-favorite.test.ts @@ -87,7 +87,7 @@ describe('Mark items as favorites', () => { browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform().then(done); }); - it('Favorite action has empty star icon for unfavorited item', () => { + it('Favorite action has empty star icon for an item not marked as favorite', () => { dataTable.clickOnItemName(file1NotFav) .then(() => toolbar.actions.openMoreMenu()) .then(() => expect(toolbar.actions.menu.getItemIconText('Favorite')).toEqual('star_border')); @@ -99,7 +99,7 @@ describe('Mark items as favorites', () => { .then(() => expect(toolbar.actions.menu.getItemIconText('Favorite')).toEqual('star_border')); }); - it('Favorite action has full star icon for favorited items', () => { + it('Favorite action has full star icon for items marked as favorite', () => { dataTable.clickOnItemName(file3Fav) .then(() => toolbar.actions.openMoreMenu()) .then(() => expect(toolbar.actions.menu.getItemIconText('Favorite')).toEqual('star')); diff --git a/e2e/suites/actions/toolbar-single-selection.test.ts b/e2e/suites/actions/toolbar-single-selection.test.ts index 5c9dc25aee..5404e40622 100755 --- a/e2e/suites/actions/toolbar-single-selection.test.ts +++ b/e2e/suites/actions/toolbar-single-selection.test.ts @@ -274,7 +274,7 @@ describe('Toolbar actions - single selection : ', () => { .then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform()); }); - it('on Shared Files', () => { + xit('on Shared Files', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.SHARED_FILES) .then(() => dataTable.waitForHeader()) .then(() => dataTable.selectMultipleItems([ file1, file2 ])) diff --git a/e2e/suites/authentication/login.test.ts b/e2e/suites/authentication/login.test.ts index 3ab8cdfab6..e17028248e 100755 --- a/e2e/suites/authentication/login.test.ts +++ b/e2e/suites/authentication/login.test.ts @@ -35,9 +35,11 @@ describe('Login', () => { const loginPage = new LoginPage(); const logoutPage = new LogoutPage(); + /* cspell:disable-next-line */ const testUser = `user-${Utils.random()}@alfness`; const russianUser = { + /* cspell:disable-next-line */ username: `пользвате${Utils.random()}`, password: '密碼中國' }; diff --git a/e2e/suites/navigation/breadcrumb.test.ts b/e2e/suites/navigation/breadcrumb.test.ts index 419950ed38..974c62df7f 100755 --- a/e2e/suites/navigation/breadcrumb.test.ts +++ b/e2e/suites/navigation/breadcrumb.test.ts @@ -34,8 +34,8 @@ describe('Breadcrumb', () => { const username = `user-${Utils.random()}`; const parent = `parent-${Utils.random()}`; let parentId; - const subfolder1 = `subfolder1-${Utils.random()}`; let subfolder1Id; - const subfolder2 = `subfolder2-${Utils.random()}`; let subfolder2Id; + const subFolder1 = `subFolder1-${Utils.random()}`; let subFolder1Id; + const subFolder2 = `subFolder2-${Utils.random()}`; let subFolder2Id; const fileName1 = `file1-${Utils.random()}.txt`; const siteName = `site-${Utils.random()}`; @@ -57,9 +57,9 @@ describe('Breadcrumb', () => { beforeAll(done => { apis.admin.people.createUser(username) .then(() => apis.user.nodes.createFolder(parent)).then(resp => parentId = resp.data.entry.id) - .then(() => apis.user.nodes.createFolder(subfolder1, parentId)).then(resp => subfolder1Id = resp.data.entry.id) - .then(() => apis.user.nodes.createFolder(subfolder2, subfolder1Id)).then(resp => subfolder2Id = resp.data.entry.id) - .then(() => apis.user.nodes.createFile(fileName1, subfolder2Id)) + .then(() => apis.user.nodes.createFolder(subFolder1, parentId)).then(resp => subFolder1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFolder(subFolder2, subFolder1Id)).then(resp => subFolder2Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(fileName1, subFolder2Id)) .then(() => apis.user.nodes.createFolder(parent2)).then(resp => parent2Id = resp.data.entry.id) .then(() => apis.user.nodes.createFolder(folder1, parent2Id)).then(resp => folder1Id = resp.data.entry.id) @@ -67,9 +67,9 @@ describe('Breadcrumb', () => { .then(() => apis.user.sites.createSite(siteName, SITE_VISIBILITY.PUBLIC)) .then(() => apis.user.sites.getDocLibId(siteName)) .then(resp => apis.user.nodes.createFolder(parent, resp)).then(resp => parentId = resp.data.entry.id) - .then(() => apis.user.nodes.createFolder(subfolder1, parentId)).then(resp => subfolder1Id = resp.data.entry.id) - .then(() => apis.user.nodes.createFolder(subfolder2, subfolder1Id)).then(resp => subfolder2Id = resp.data.entry.id) - .then(() => apis.user.nodes.createFile(fileName1, subfolder2Id)) + .then(() => apis.user.nodes.createFolder(subFolder1, parentId)).then(resp => subFolder1Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFolder(subFolder2, subFolder1Id)).then(resp => subFolder2Id = resp.data.entry.id) + .then(() => apis.user.nodes.createFile(fileName1, subFolder2Id)) .then(() => loginPage.loginWith(username)) .then(done); @@ -137,10 +137,10 @@ describe('Breadcrumb', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) .then(() => page.dataTable.waitForHeader()) .then(() => page.dataTable.doubleClickOnItemName(parent)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder2)) .then(() => { - const expectedBreadcrumb = [ 'Personal Files', parent, subfolder1, subfolder2 ]; + const expectedBreadcrumb = [ 'Personal Files', parent, subFolder1, subFolder2 ]; expect(breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); }); }); @@ -150,10 +150,10 @@ describe('Breadcrumb', () => { .then(() => page.dataTable.waitForHeader()) .then(() => page.dataTable.doubleClickOnItemName(siteName)) .then(() => page.dataTable.doubleClickOnItemName(parent)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder2)) .then(() => { - const expectedItems = [ 'File Libraries', siteName, parent, subfolder1, subfolder2 ]; + const expectedItems = [ 'File Libraries', siteName, parent, subFolder1, subFolder2 ]; expect(breadcrumb.getAllItems()).toEqual(expectedItems); }); }); @@ -162,11 +162,11 @@ describe('Breadcrumb', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) .then(() => page.dataTable.waitForHeader()) .then(() => page.dataTable.doubleClickOnItemName(parent)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) - .then(() => breadcrumb.clickItem(subfolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder2)) + .then(() => breadcrumb.clickItem(subFolder1)) .then(() => { - const expectedBreadcrumb = [ 'Personal Files', parent, subfolder1 ]; + const expectedBreadcrumb = [ 'Personal Files', parent, subFolder1 ]; expect(breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); }); }); @@ -175,10 +175,10 @@ describe('Breadcrumb', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) .then(() => page.dataTable.waitForHeader()) .then(() => page.dataTable.doubleClickOnItemName(parent)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder2)) .then(() => { - expect(breadcrumb.getNthItemTooltip(3)).toEqual(subfolder1); + expect(breadcrumb.getNthItemTooltip(3)).toEqual(subFolder1); }); }); @@ -200,13 +200,13 @@ describe('Breadcrumb', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) .then(() => page.dataTable.waitForHeader()) .then(() => page.dataTable.doubleClickOnItemName(parent)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder1)) - .then(() => page.dataTable.doubleClickOnItemName(subfolder2)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder1)) + .then(() => page.dataTable.doubleClickOnItemName(subFolder2)) .then(() => page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.TRASH)) .then(() => page.dataTable.waitForEmptyState()) .then(() => browser.navigate().back()) .then(() => { - const expectedBreadcrumb = [ 'Personal Files', parent, subfolder1, subfolder2 ]; + const expectedBreadcrumb = [ 'Personal Files', parent, subFolder1, subFolder2 ]; expect(breadcrumb.getAllItems()).toEqual(expectedBreadcrumb); }); }); diff --git a/e2e/utilities/reporters/console/console-logger.ts b/e2e/utilities/reporters/console/console-logger.ts index 756bfb4a86..76d6683e59 100755 --- a/e2e/utilities/reporters/console/console-logger.ts +++ b/e2e/utilities/reporters/console/console-logger.ts @@ -39,7 +39,7 @@ export const log = { return this; }, - dedent() { + unindent() { this.i--; return this; }, diff --git a/e2e/utilities/reporters/console/console.ts b/e2e/utilities/reporters/console/console.ts index 2f92e394ab..ad08110be3 100755 --- a/e2e/utilities/reporters/console/console.ts +++ b/e2e/utilities/reporters/console/console.ts @@ -62,7 +62,7 @@ export const consoleReporter = { }, suiteDone: (result) => { - log.dedent(); + log.unindent(); }, jasmineDone: (result) => { diff --git a/package-lock.json b/package-lock.json index 8ac296b962..f6cd038579 100644 --- a/package-lock.json +++ b/package-lock.json @@ -842,7 +842,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" }, @@ -851,7 +850,6 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, "requires": { "color-name": "^1.1.1" } @@ -2295,8 +2293,15 @@ "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" + }, + "comment-json": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-1.1.3.tgz", + "integrity": "sha1-aYbDMw/uDEyeAMI5jNYa+l2PI54=", + "requires": { + "json-parser": "^1.0.0" + } }, "common-tags": { "version": "1.7.2", @@ -2394,6 +2399,32 @@ "typedarray": "^0.0.6" } }, + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "configstore-fork": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/configstore-fork/-/configstore-fork-3.1.6.tgz", + "integrity": "sha512-sQ31B6Ayj9Tqs2nPBrq+2cg8j9sb1Hd6iyqDx2rH+W1EoBDevYAkLk5ncNqktkj7hCeyrUzcNhQ5kUozKXd75A==", + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, "connect": { "version": "3.6.6", "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", @@ -2671,6 +2702,205 @@ "randomfill": "^1.0.3" } }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" + }, + "cspell": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-2.1.12.tgz", + "integrity": "sha512-6ydTFFhPDirjOAl7ChrtlaVXiyqt1LmTRMpvYU1Jw9FarHxupnNq34itPL5BSDDjqeue5wI0A+VCjBnfAKuWMQ==", + "requires": { + "chalk": "^2.3.2", + "commander": "^2.15.1", + "comment-json": "^1.1.3", + "configstore-fork": "^3.1.6", + "cspell-dict-cpp": "^1.1.6", + "cspell-dict-django": "^1.0.2", + "cspell-dict-en-gb": "^1.1.0", + "cspell-dict-en_us": "^1.2.3", + "cspell-dict-golang": "^1.1.3", + "cspell-dict-latex": "^1.0.1", + "cspell-dict-php": "^1.0.2", + "cspell-dict-python": "^1.0.3", + "cspell-dict-rust": "^1.0.0", + "cspell-lib": "^2.0.2", + "cspell-trie": "^2.0.3", + "fs-extra": "^5.0.0", + "gensequence": "^2.1.1", + "glob": "^7.1.2", + "minimatch": "^3.0.4", + "rxjs": "^5.5.10", + "rxjs-from-iterable": "^1.0.5", + "vscode-uri": "^1.0.3", + "xregexp": "^4.1.1" + }, + "dependencies": { + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "fs-extra": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", + "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "rxjs": { + "version": "5.5.10", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz", + "integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==", + "requires": { + "symbol-observable": "1.0.1" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" + }, + "xregexp": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.1.1.tgz", + "integrity": "sha512-QJ1gfSUV7kEOLfpKFCjBJRnfPErUzkNKFMso4kDSmGpp3x6ZgkyKf74inxI7PnnQCFYq5TqYJCd7DrgDN8Q05A==" + } + } + }, + "cspell-dict-cpp": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/cspell-dict-cpp/-/cspell-dict-cpp-1.1.6.tgz", + "integrity": "sha512-eVNenrvoViBsrfZYzChoJ1YJ5b0VxwgYCFhxxKjL3Bjk3Te98FM8Bk/ExSnv5KlwT56EhT5y+CBi0ejEv5XW/g==", + "requires": { + "configstore": "^3.1.0" + } + }, + "cspell-dict-django": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cspell-dict-django/-/cspell-dict-django-1.0.2.tgz", + "integrity": "sha512-t52Ga2S7GgsCYaLsN+iqWLgHUHfqGfkMUv0gSjp2QOVOxGNQ4kjj1oJ6GkcZB5k6UnI2sgQ7uku/bjmNlnctDw==", + "requires": { + "configstore": "^3.1.0" + } + }, + "cspell-dict-en-gb": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cspell-dict-en-gb/-/cspell-dict-en-gb-1.1.2.tgz", + "integrity": "sha512-ry4yNIzjVMZDwSrK7U/0M9vXdbzo7ZFpUHUAYa4r6B4CwUFHBC/d8C0fcav2Hf1jjfQ866AApg00HiRJLP3Aug==", + "requires": { + "configstore": "^3.1.1" + } + }, + "cspell-dict-en_us": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/cspell-dict-en_us/-/cspell-dict-en_us-1.2.5.tgz", + "integrity": "sha512-OaoOaVzIGxJeeyAjZE6Re2+S5OuLHsMFzQcZ3qaD87uO0Q7U9TF6EFPJEmwNuR0Ye9o1rXYYMiFKan6EzH40qg==", + "requires": { + "configstore": "^3.1.0" + } + }, + "cspell-dict-golang": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cspell-dict-golang/-/cspell-dict-golang-1.1.3.tgz", + "integrity": "sha512-maImSmm4ctZ5cQ3tFyZr5nglBQ/GwY5OYT1eq6O6USjJRQxzWtzmI1EV8WKng1UEA1i07NqgUDQLejTx3W1hIg==", + "requires": { + "configstore": "^3.1.0" + } + }, + "cspell-dict-latex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cspell-dict-latex/-/cspell-dict-latex-1.0.1.tgz", + "integrity": "sha512-RyK6TgEpt6AfGbXStPi5G7Fy2CFJGmIAYs1ie6Qsyss7h3sAsHk19F2yZvwJU0dlHXyw4LujFbzo9ZR3HR7BIA==", + "requires": { + "configstore": "^3.1.0" + } + }, + "cspell-dict-php": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cspell-dict-php/-/cspell-dict-php-1.0.2.tgz", + "integrity": "sha512-F2NyT9rZ6CmcLhbeGH8OKwLlD9Q5zQConpNDVdu/E/ucEQ+HXIf65Ou5KJzlQcyUGC8P9PUmmUBEF60oW5HcCA==", + "requires": { + "configstore": "^3.1.0" + } + }, + "cspell-dict-python": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cspell-dict-python/-/cspell-dict-python-1.0.3.tgz", + "integrity": "sha512-zQYJu/kWvsZusuMelRk7e9B5xINglh49uLswLv598T+ZptzRzKO83im/yCG0RHBWvgYS+ze0eCpr0Ja5uqHu3Q==", + "requires": { + "configstore": "^3.1.0" + } + }, + "cspell-dict-rust": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cspell-dict-rust/-/cspell-dict-rust-1.0.0.tgz", + "integrity": "sha512-9Rew1ad6yPXQW9fxFQ/J41+fbKg6t9p4oSm7JS0aHuCtWc3w0knFYK7Ty/mVMw6oDFlemBNaBCPZON0M3+oIKg==", + "requires": { + "configstore": "^3.1.0" + } + }, + "cspell-lib": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-2.0.2.tgz", + "integrity": "sha512-AcNlLBuOFR0xZGO9SwP0g42oFvu8TMooehLJ7FqDzAvCWqtO1u0ddvJ7bm8l8UZgABVchUSy2oqcLVAr4XdCvA==", + "requires": { + "iconv-lite": "^0.4.19", + "rxjs": "^5.5.6", + "rxjs-stream": "^1.1.0" + }, + "dependencies": { + "rxjs": { + "version": "5.5.10", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.10.tgz", + "integrity": "sha512-SRjimIDUHJkon+2hFo7xnvNC4ZEHGzCRwh9P7nzX3zPkCGFEg/tuElrNR7L/rZMagnK2JeH2jQwPRpmyXyLB6A==", + "requires": { + "symbol-observable": "1.0.1" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" + } + } + }, + "cspell-trie": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/cspell-trie/-/cspell-trie-2.0.3.tgz", + "integrity": "sha512-5jJiOPbKWzHNoJAwOQ/fkBXJ2xs+P5zfQmj2OEqq1k4Ck5/88KLEkXJmNOPDG8nDP1va5kaLz3vUtAxABo1bwg==", + "requires": { + "commander": "^2.11.0", + "cspell-lib": "^2.0.1", + "fs-extra": "^4.0.2", + "gensequence": "^2.1.1", + "rxjs": "^5.5.2", + "rxjs-from-iterable": "^1.0.5", + "rxjs-stream": "^1.0.4" + } + }, "css-parse": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", @@ -3290,6 +3520,14 @@ "domelementtype": "1" } }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "requires": { + "is-obj": "^1.0.0" + } + }, "double-ended-queue": { "version": "2.1.0-0", "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", @@ -3670,8 +3908,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "1.9.1", @@ -4332,7 +4569,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "dev": true, "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -4354,8 +4590,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "1.2.3", @@ -4987,6 +5222,11 @@ "is-property": "^1.0.0" } }, + "gensequence": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-2.1.1.tgz", + "integrity": "sha512-AyZrG5Qq8Tn0qnaDCnH2n9TsWnJLKBXEa2FcUlHWfEgl1rRS3MbcvB4OsarxyEekx/PwYlyKXvjQwNvYsByXAw==" + }, "get-caller-file": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", @@ -5079,7 +5319,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5152,8 +5391,7 @@ "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "hammerjs": { "version": "2.0.8", @@ -5698,8 +5936,7 @@ "iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", - "dev": true + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" }, "ieee754": { "version": "1.1.11", @@ -5745,8 +5982,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "in-publish": { "version": "2.0.0", @@ -5781,7 +6017,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -6028,6 +6263,11 @@ "kind-of": "^3.0.2" } }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + }, "is-odd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", @@ -6477,6 +6717,21 @@ "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", "dev": true }, + "json-parser": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/json-parser/-/json-parser-1.1.5.tgz", + "integrity": "sha1-5i7FJh0aal/CDoEqMgdAxtkAVnc=", + "requires": { + "esprima": "^2.7.0" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" + } + } + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -6518,7 +6773,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, "requires": { "graceful-fs": "^4.1.6" } @@ -7354,7 +7608,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", - "dev": true, "requires": { "pify": "^3.0.0" } @@ -8292,7 +8545,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -8633,8 +8885,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -8725,8 +8976,7 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "pinkie": { "version": "2.0.4", @@ -9847,6 +10097,16 @@ "symbol-observable": "^1.0.1" } }, + "rxjs-from-iterable": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/rxjs-from-iterable/-/rxjs-from-iterable-1.0.5.tgz", + "integrity": "sha1-zqsVcAVLO7Bf0m15iBSCx9sbc9c=" + }, + "rxjs-stream": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rxjs-stream/-/rxjs-stream-1.3.0.tgz", + "integrity": "sha512-Vj86/1qAYvCApBOIi7gghVteCrMCXTnQxICPnW/D+4vtFIpgSE/xDegUDYJy9bwKyxR7VteVDhZyCvQt4RV/xQ==" + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -10193,8 +10453,7 @@ "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "silent-error": { "version": "1.1.0", @@ -11579,11 +11838,18 @@ "imurmurhash": "^0.1.4" } }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "requires": { + "crypto-random-string": "^1.0.0" + } + }, "universalify": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", - "dev": true + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" }, "unpipe": { "version": "1.0.0", @@ -11880,6 +12146,11 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, + "vscode-uri": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.3.tgz", + "integrity": "sha1-Yxvb9xbcyrDmUpGo3CXCMjIIWlI=" + }, "wait-on": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-2.1.0.tgz", @@ -13250,8 +13521,17 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", + "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } }, "ws": { "version": "3.3.3", @@ -13264,6 +13544,11 @@ "ultron": "~1.1.0" } }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" + }, "xml2js": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", diff --git a/package.json b/package.json index ef8c23ba58..a2d3de4e26 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "e2e:all": "npm run start:docker && npm run cypress:ci && npm run e2e && npm run stop:docker", "cypress:open": "cypress open", "cypress:run": "cypress run", - "cypress:ci": "cypress run --browser chrome --config baseUrl=http://localhost:3000" + "cypress:ci": "cypress run --browser chrome --config baseUrl=http://localhost:3000", + "spellcheck": "cspell 'src/**/*.ts' 'e2e/**/*.ts'" }, "private": true, "dependencies": { @@ -49,6 +50,7 @@ "@ngx-translate/core": "9.1.1", "alfresco-js-api": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", "core-js": "2.5.3", + "cspell": "^2.1.12", "hammerjs": "2.0.8", "moment-es6": "1.0.0", "pdfjs-dist": "2.0.303", diff --git a/src/app/common/directives/node-delete.directive.ts b/src/app/common/directives/node-delete.directive.ts index 758eb24e9a..291cced24e 100644 --- a/src/app/common/directives/node-delete.directive.ts +++ b/src/app/common/directives/node-delete.directive.ts @@ -66,7 +66,7 @@ export class NodeDeleteDirective { (data) => { const processedData = this.processStatus(data); - this.getDeleteMesssage(processedData) + this.getDeleteMessage(processedData) .subscribe((message) => { const withUndo = processedData.someSucceeded ? this.translation.translate.instant('APP.ACTIONS.UNDO') : ''; @@ -194,7 +194,7 @@ export class NodeDeleteDirective { } } - private getDeleteMesssage(status): Observable { + private getDeleteMessage(status): Observable { if (status.allFailed && !status.oneFailed) { return this.translation.get( 'APP.MESSAGES.ERRORS.NODE_DELETION_PLURAL', diff --git a/src/app/common/directives/node-restore.directive.ts b/src/app/common/directives/node-restore.directive.ts index 2b83ad19c0..dfd4801268 100644 --- a/src/app/common/directives/node-restore.directive.ts +++ b/src/app/common/directives/node-restore.directive.ts @@ -79,10 +79,10 @@ export class NodeRestoreDirective { .flatMap(() => this.getDeletedNodes()) .subscribe( (deletedNodesList: DeletedNodesPaging) => { - const { entries: nodelist } = deletedNodesList.list; + const { entries: nodeList } = deletedNodesList.list; const { fail: restoreErrorNodes } = this.restoreProcessStatus; const selectedNodes = this.diff(restoreErrorNodes, selection, false); - const remainingNodes = this.diff(selectedNodes, nodelist); + const remainingNodes = this.diff(selectedNodes, nodeList); if (!remainingNodes.length) { this.restoreNotification(); diff --git a/src/app/common/services/node-actions.service.spec.ts b/src/app/common/services/node-actions.service.spec.ts index 2942e578ed..c3037f4a39 100644 --- a/src/app/common/services/node-actions.service.spec.ts +++ b/src/app/common/services/node-actions.service.spec.ts @@ -1069,21 +1069,21 @@ describe('NodeActionsService', () => { baseName: 'withExtension.txt', expected: 'withExtension-1.txt' }, { - name: 'with-lineStringSufix.txt', - baseName: 'with-lineStringSufix.txt', - expected: 'with-lineStringSufix-1.txt' + name: 'with-lineStringSuffix.txt', + baseName: 'with-lineStringSuffix.txt', + expected: 'with-lineStringSuffix-1.txt' }, { name: 'noExtension-1', baseName: 'noExtension-1', expected: 'noExtension-1-1' }, { - name: 'with-lineNumberSufix-1.txt', - baseName: 'with-lineNumberSufix-1.txt', - expected: 'with-lineNumberSufix-1-1.txt' + name: 'with-lineNumberSuffix-1.txt', + baseName: 'with-lineNumberSuffix-1.txt', + expected: 'with-lineNumberSuffix-1-1.txt' }, { - name: 'with-lineNumberSufix.txt', + name: 'with-lineNumberSuffix.txt', baseName: undefined, - expected: 'with-lineNumberSufix-1.txt' + expected: 'with-lineNumberSuffix-1.txt' }, { name: 'noExtension-1', baseName: 'noExtension', From b78f97c79dc473bbf91345caec136db7ee4ed8fb Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 21 May 2018 12:27:12 +0100 Subject: [PATCH 035/179] Upgrade to latest ADF (alpha) (#361) * upgrade libs * update libs * upgrade page title management * restore app config * use 'title' property * update libs * disble cypress * update libs * disable irrelevant tests --- e2e/suites/navigation/breadcrumb.test.ts | 8 ++--- package-lock.json | 24 +++++++-------- package.json | 6 ++-- src/app/app.component.ts | 11 ++----- src/app/app.routes.ts | 34 ++++++++++----------- src/app/components/files/files.component.ts | 2 +- 6 files changed, 39 insertions(+), 46 deletions(-) diff --git a/e2e/suites/navigation/breadcrumb.test.ts b/e2e/suites/navigation/breadcrumb.test.ts index 974c62df7f..2f11df8d2e 100755 --- a/e2e/suites/navigation/breadcrumb.test.ts +++ b/e2e/suites/navigation/breadcrumb.test.ts @@ -133,7 +133,7 @@ describe('Breadcrumb', () => { }); }); - it('Personal Files breadcrumb for a folder hierarchy [C260965]', () => { + xit('Personal Files breadcrumb for a folder hierarchy [C260965]', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) .then(() => page.dataTable.waitForHeader()) .then(() => page.dataTable.doubleClickOnItemName(parent)) @@ -145,7 +145,7 @@ describe('Breadcrumb', () => { }); }); - it('File Libraries breadcrumb for a folder hierarchy [C260967]', () => { + xit('File Libraries breadcrumb for a folder hierarchy [C260967]', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) .then(() => page.dataTable.waitForHeader()) .then(() => page.dataTable.doubleClickOnItemName(siteName)) @@ -171,7 +171,7 @@ describe('Breadcrumb', () => { }); }); - it('Tooltip appears on hover on a step in breadcrumb [C213237]', () => { + xit('Tooltip appears on hover on a step in breadcrumb [C213237]', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) .then(() => page.dataTable.waitForHeader()) .then(() => page.dataTable.doubleClickOnItemName(parent)) @@ -196,7 +196,7 @@ describe('Breadcrumb', () => { }); }); - it('Browser back navigates to previous location regardless of breadcrumb steps [C213240]', () => { + xit('Browser back navigates to previous location regardless of breadcrumb steps [C213240]', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.PERSONAL_FILES) .then(() => page.dataTable.waitForHeader()) .then(() => page.dataTable.doubleClickOnItemName(parent)) diff --git a/package-lock.json b/package-lock.json index f6cd038579..719988861a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f.tgz", - "integrity": "sha512-NsfU+FOe52lgXD+qU+0ynkGJBNTZInQIRlKl1n5x/2JEExFBaHV1gGYO7JhFTxWdZg9hNpZGQN/fY5J4Ey/AhA==", + "version": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44.tgz", + "integrity": "sha512-HVPOq5XPQbH81dxKxQd5nlH4UpxD3J2lV+khrdjvdeH8rt3413KxuakaWCmItjHWcBDl18MmEsL6BelzYn7JCw==", "requires": { - "@alfresco/adf-core": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", + "@alfresco/adf-core": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", + "alfresco-js-api": "2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -61,9 +61,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f.tgz", - "integrity": "sha512-eLNvztTWrYMp93iaOJ+XM4EvBOCou0ofNSv2ffDfFZyqEPeO+sliRcPcaVtBc6jRfOH6l9GBAKzS5KOx10hOMA==", + "version": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44.tgz", + "integrity": "sha512-lol5Yc4/t1ywbM/VrSgNpPCQ6T3SDys0IJuAjJAtZB8qFWc5o/oi+p2JbSBWskiv9PUW0a3aZQhYKbL0tHdg4g==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -79,7 +79,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", + "alfresco-js-api": "2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -752,9 +752,9 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "alfresco-js-api": { - "version": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18.tgz", - "integrity": "sha512-Ty3QQdvP+6/Fqe4CUuV6fYqkYG9xYvshnrHEzsFju36FSgNkWxZcOmwAAGVIWeNnCA7DuQqE7D+Vp7pgnPNTxQ==", + "version": "2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000.tgz", + "integrity": "sha512-TOqZvoQnskePEINpLBiC4JQL+ak8gBDIE16lnkRLiSjSmrQ6rZL6Xq58lkTLa7ysSVv+Trgx9+ie+KQ+LCgxfw==", "requires": { "event-emitter": "0.3.4", "superagent": "3.8.2" diff --git a/package.json b/package.json index a2d3de4e26..336b364e7f 100644 --- a/package.json +++ b/package.json @@ -29,8 +29,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", - "@alfresco/adf-core": "2.4.0-9d0ccff189e89e79605d56b2b8f23d540db1222f", + "@alfresco/adf-content-services": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", + "@alfresco/adf-core": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -48,7 +48,7 @@ "@mat-datetimepicker/moment": "1.0.1", "@ngstack/electron": "0.1.0", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-31a7fc6e5d58dc8bf202ef9a80bc993c9f48fe18", + "alfresco-js-api": "2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000", "core-js": "2.5.3", "cspell": "^2.1.12", "hammerjs": "2.0.8", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 61548951ca..e1f84dca93 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -26,7 +26,7 @@ import { Component, OnInit, EventEmitter } from '@angular/core'; import { Router, ActivatedRoute, NavigationEnd } from '@angular/router'; import { - TranslationService, PageTitleService, UserPreferencesService, AppConfigService, + PageTitleService, UserPreferencesService, AppConfigService, FileModel, UploadService } from '@alfresco/adf-core'; import { ElectronService } from '@ngstack/electron'; @@ -41,7 +41,6 @@ export class AppComponent implements OnInit { private route: ActivatedRoute, private router: Router, private pageTitle: PageTitleService, - private translateService: TranslationService, preferences: UserPreferencesService, config: AppConfigService, private electronService: ElectronService, @@ -67,13 +66,7 @@ export class AppComponent implements OnInit { const snapshot: any = currentRoute.snapshot || {}; const data: any = snapshot.data || {}; - if (data.i18nTitle) { - pageTitle.setTitle( - this.translateService.instant(data.i18nTitle) - ); - } else { - pageTitle.setTitle(data.title || ''); - } + pageTitle.setTitle(data.title || ''); }); this.electronService.on('app:navigateRoute', (event: any, ...args: string[]) => { diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index eb6089c308..cc06445f29 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -47,14 +47,14 @@ export const APP_ROUTES: Routes = [ path: 'login', component: LoginComponent, data: { - i18nTitle: 'APP.SIGN_IN' + title: 'APP.SIGN_IN' } }, { path: 'settings', component: SettingsComponent, data: { - i18nTitle: 'Settings' + title: 'Settings' } }, { @@ -76,14 +76,14 @@ export const APP_ROUTES: Routes = [ path: '', component: FavoritesComponent, data: { - i18nTitle: 'APP.BROWSE.FAVORITES.TITLE' + title: 'APP.BROWSE.FAVORITES.TITLE' } }, { path: 'preview/:nodeId', component: PreviewComponent, data: { - i18nTitle: 'APP.PREVIEW.TITLE', + title: 'APP.PREVIEW.TITLE', navigateMultiple: true, navigateSource: 'favorites' } @@ -99,13 +99,13 @@ export const APP_ROUTES: Routes = [ path: '', component: LibrariesComponent, data: { - i18nTitle: 'APP.BROWSE.LIBRARIES.TITLE' + title: 'APP.BROWSE.LIBRARIES.TITLE' } }, { path: ':folderId', component: FilesComponent, data: { - i18nTitle: 'APP.BROWSE.LIBRARIES.TITLE', + title: 'APP.BROWSE.LIBRARIES.TITLE', preferencePrefix: 'libraries-files' } }, @@ -113,7 +113,7 @@ export const APP_ROUTES: Routes = [ path: ':folderId/preview/:nodeId', component: PreviewComponent, data: { - i18nTitle: 'APP.PREVIEW.TITLE', + title: 'APP.PREVIEW.TITLE', navigateMultiple: true, navigateSource: 'libraries' } @@ -130,7 +130,7 @@ export const APP_ROUTES: Routes = [ path: '', component: FilesComponent, data: { - i18nTitle: 'APP.BROWSE.PERSONAL.TITLE', + title: 'APP.BROWSE.PERSONAL.TITLE', defaultNodeId: '-my-' } }, @@ -138,14 +138,14 @@ export const APP_ROUTES: Routes = [ path: ':folderId', component: FilesComponent, data: { - i18nTitle: 'APP.BROWSE.PERSONAL.TITLE' + title: 'APP.BROWSE.PERSONAL.TITLE' } }, { path: 'preview/:nodeId', component: PreviewComponent, data: { - i18nTitle: 'APP.PREVIEW.TITLE', + title: 'APP.PREVIEW.TITLE', navigateMultiple: true, navigateSource: 'personal-files' } @@ -154,7 +154,7 @@ export const APP_ROUTES: Routes = [ path: ':folderId/preview/:nodeId', component: PreviewComponent, data: { - i18nTitle: 'APP.PREVIEW.TITLE', + title: 'APP.PREVIEW.TITLE', navigateMultiple: true, navigateSource: 'personal-files' } @@ -171,14 +171,14 @@ export const APP_ROUTES: Routes = [ path: '', component: RecentFilesComponent, data: { - i18nTitle: 'APP.BROWSE.RECENT.TITLE' + title: 'APP.BROWSE.RECENT.TITLE' } }, { path: 'preview/:nodeId', component: PreviewComponent, data: { - i18nTitle: 'APP.PREVIEW.TITLE', + title: 'APP.PREVIEW.TITLE', navigateMultiple: true, navigateSource: 'recent-files' } @@ -195,14 +195,14 @@ export const APP_ROUTES: Routes = [ path: '', component: SharedFilesComponent, data: { - i18nTitle: 'APP.BROWSE.SHARED.TITLE' + title: 'APP.BROWSE.SHARED.TITLE' } }, { path: 'preview/:nodeId', component: PreviewComponent, data: { - i18nTitle: 'APP.PREVIEW.TITLE', + title: 'APP.PREVIEW.TITLE', navigateMultiple: true, navigateSource: 'shared' } @@ -213,7 +213,7 @@ export const APP_ROUTES: Routes = [ path: 'trashcan', component: TrashcanComponent, data: { - i18nTitle: 'APP.BROWSE.TRASHCAN.TITLE', + title: 'APP.BROWSE.TRASHCAN.TITLE', preferencePrefix: 'trashcan' } }, @@ -221,7 +221,7 @@ export const APP_ROUTES: Routes = [ path: 'about', component: AboutComponent, data: { - i18nTitle: 'APP.BROWSE.ABOUT.TITLE' + title: 'APP.BROWSE.ABOUT.TITLE' } }, { diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index 86018017b6..ba3774b40f 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -78,7 +78,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { const { route, contentManagementService, contentService, nodeActionsService, uploadService } = this; const { data } = route.snapshot; - this.title = data.i18nTitle; + this.title = data.title; route.params.subscribe(({ folderId }: Params) => { const nodeId = folderId || data.defaultNodeId; From 2176d1eab71c62e3487880050b25c5b2f1b8d8f8 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 24 May 2018 12:45:18 +0100 Subject: [PATCH 036/179] update libs (#365) * update libs * update libs * upgrade to latest search components --- cypress.json | 5 - package-lock.json | 784 +----------------- package.json | 11 +- src/app.config.json | 40 +- .../components/search/search.component.html | 6 + .../components/search/search.component.scss | 4 + src/app/components/search/search.component.ts | 27 +- 7 files changed, 87 insertions(+), 790 deletions(-) delete mode 100644 cypress.json diff --git a/cypress.json b/cypress.json deleted file mode 100644 index 6c92d4cfbf..0000000000 --- a/cypress.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://on.cypress.io/cypress.schema.json", - "baseUrl": "http://localhost:4200", - "videoRecording": false -} diff --git a/package-lock.json b/package-lock.json index 719988861a..3c11813384 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44.tgz", - "integrity": "sha512-HVPOq5XPQbH81dxKxQd5nlH4UpxD3J2lV+khrdjvdeH8rt3413KxuakaWCmItjHWcBDl18MmEsL6BelzYn7JCw==", + "version": "2.4.0-c5936e7db09d85eb50b06eacdc3a5f105aa9b7f9", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-c5936e7db09d85eb50b06eacdc3a5f105aa9b7f9.tgz", + "integrity": "sha512-8SViybcMNJ1PXFDlOZD3/yaP6VdIGtjgfjhSy9Ya3iIEntSqQchS5JBHQpfhQBiSt8HZvzT+LcYNEnJGh0BUDA==", "requires": { - "@alfresco/adf-core": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", + "@alfresco/adf-core": "2.4.0-c5936e7db09d85eb50b06eacdc3a5f105aa9b7f9", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000", + "alfresco-js-api": "2.4.0-2dbba5b40321688b340f51a376e9a1114864e658", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -61,9 +61,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44.tgz", - "integrity": "sha512-lol5Yc4/t1ywbM/VrSgNpPCQ6T3SDys0IJuAjJAtZB8qFWc5o/oi+p2JbSBWskiv9PUW0a3aZQhYKbL0tHdg4g==", + "version": "2.4.0-c5936e7db09d85eb50b06eacdc3a5f105aa9b7f9", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-c5936e7db09d85eb50b06eacdc3a5f105aa9b7f9.tgz", + "integrity": "sha512-Q4aazvuWOOJKGKRG3pZHqjC9uL+xBVPFNaMfLTfFkKkGh622WWQPPS2TsGtaPDFNFmfTaaURYzqkzrRZATVwAQ==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -79,7 +79,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000", + "alfresco-js-api": "2.4.0-2dbba5b40321688b340f51a376e9a1114864e658", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -417,54 +417,6 @@ "tslib": "^1.7.1" } }, - "@cypress/listr-verbose-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@cypress/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", - "integrity": "sha1-p3SS9LEdzHxEajSz4ochr9M8ZCo=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-cursor": "^1.0.2", - "date-fns": "^1.27.2", - "figures": "^1.7.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "@cypress/xvfb": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.1.3.tgz", - "integrity": "sha512-EfRzw+wgI0Zdb4ZlhSvjh3q7I+oenqEYPXvr7oH/2RnzQqGDrPr7IU1Pi2yzGwoXmkNUQbo6qvntnItvQj0F4Q==", - "dev": true, - "requires": { - "lodash.once": "^4.1.1" - } - }, "@mat-datetimepicker/core": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@mat-datetimepicker/core/-/core-1.0.1.tgz", @@ -555,34 +507,6 @@ } } }, - "@types/blob-util": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/blob-util/-/blob-util-1.3.3.tgz", - "integrity": "sha512-4ahcL/QDnpjWA2Qs16ZMQif7HjGP2cw3AGjHabybjw7Vm1EKu+cfQN1D78BaZbS1WJNa1opSMF5HNMztx7lR0w==", - "dev": true - }, - "@types/bluebird": { - "version": "3.5.18", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.18.tgz", - "integrity": "sha512-OTPWHmsyW18BhrnG5x8F7PzeZ2nFxmHGb42bZn79P9hl+GI5cMzyPgQTwNjbem0lJhoru/8vtjAFCUOu3+gE2w==", - "dev": true - }, - "@types/chai": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.0.8.tgz", - "integrity": "sha512-m812CONwdZn/dMzkIJEY0yAs4apyTkTORgfB2UsMOxgkUbC205AHnm4T8I0I5gPg9MHrFc1dJ35iS75c0CJkjg==", - "dev": true - }, - "@types/chai-jquery": { - "version": "1.1.35", - "resolved": "https://registry.npmjs.org/@types/chai-jquery/-/chai-jquery-1.1.35.tgz", - "integrity": "sha512-7aIt9QMRdxuagLLI48dPz96YJdhu64p6FCa6n4qkGN5DQLHnrIjZpD9bXCvV2G0NwgZ1FAmfP214dxc5zNCfgQ==", - "dev": true, - "requires": { - "@types/chai": "*", - "@types/jquery": "*" - } - }, "@types/jasmine": { "version": "2.8.7", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.7.tgz", @@ -598,30 +522,6 @@ "@types/jasmine": "*" } }, - "@types/jquery": { - "version": "3.2.16", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.2.16.tgz", - "integrity": "sha512-q2WC02YxQoX2nY1HRKlYGHpGP1saPmD7GN0pwCDlTz35a4eOtJG+aHRlXyjCuXokUukSrR2aXyBhSW3j+jPc0A==", - "dev": true - }, - "@types/lodash": { - "version": "4.14.87", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.87.tgz", - "integrity": "sha512-AqRC+aEF4N0LuNHtcjKtvF9OTfqZI0iaBoe3dA6m/W+/YZJBZjBmW/QIZ8fBeXC6cnytSY9tBoFBqZ9uSCeVsw==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.1.tgz", - "integrity": "sha512-rUO/jz10KRSyA9SHoCWQ8WX9BICyj5jZYu1/ucKEJKb4KzLZCKMURdYbadP157Q6Zl1x0vHsrU+Z/O0XlhYQDw==", - "dev": true - }, - "@types/mocha": { - "version": "2.2.44", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.44.tgz", - "integrity": "sha512-k2tWTQU8G4+iSMvqKi0Q9IIsWAp/n8xzdZS4Q4YVIltApoMA00wFBFdlJnmoaK1/z7B0Cy0yPe6GgXteSmdUNw==", - "dev": true - }, "@types/node": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-9.3.0.tgz", @@ -640,22 +540,6 @@ "integrity": "sha512-yrqQvb1EZhH+ONMzUmsEnBjzitortVv0lynRe5US2+FofdoMWUE4wf7v4peCd62fqXq8COCVTbpS1/jIg5EbuQ==", "dev": true }, - "@types/sinon": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.0.0.tgz", - "integrity": "sha512-cuK4xM8Lg2wd8cxshcQa8RG4IK/xfyB6TNE6tNVvkrShR4xdrYgsV04q6Dp6v1Lp6biEFdzD8k8zg/ujQeiw+A==", - "dev": true - }, - "@types/sinon-chai": { - "version": "2.7.29", - "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-2.7.29.tgz", - "integrity": "sha512-EkI/ZvJT4hglWo7Ipf9SX+J+R9htNOMjW8xiOhce7+0csqvgoF5IXqY5Ae1GqRgNtWCuaywR5HjVa1snkTqpOw==", - "dev": true, - "requires": { - "@types/chai": "*", - "@types/sinon": "*" - } - }, "@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", @@ -752,9 +636,9 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "alfresco-js-api": { - "version": "2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000.tgz", - "integrity": "sha512-TOqZvoQnskePEINpLBiC4JQL+ak8gBDIE16lnkRLiSjSmrQ6rZL6Xq58lkTLa7ysSVv+Trgx9+ie+KQ+LCgxfw==", + "version": "2.4.0-2dbba5b40321688b340f51a376e9a1114864e658", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-2dbba5b40321688b340f51a376e9a1114864e658.tgz", + "integrity": "sha512-O7mKfyjpjPA1BpsEHZe/aF4JU7kUpmhaBu0zBvHaumoAAecPWwkLvz/tfma80UNNg32bJ/IPKgGl6ixVbuz+Ow==", "requires": { "event-emitter": "0.3.4", "superagent": "3.8.2" @@ -820,12 +704,6 @@ } } }, - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "dev": true - }, "ansi-html": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", @@ -1672,12 +1550,6 @@ "isarray": "^1.0.0" } }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, "buffer-from": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", @@ -1894,12 +1766,6 @@ "color-name": "^1.0.0" } }, - "check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", - "dev": true - }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -1923,12 +1789,6 @@ "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true }, - "ci-info": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz", - "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==", - "dev": true - }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -1989,31 +1849,6 @@ "source-map": "0.5.x" } }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true, - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "cli-spinners": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", - "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=", - "dev": true - }, - "cli-truncate": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", - "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", - "dev": true, - "requires": { - "slice-ansi": "0.0.4", - "string-width": "^1.0.1" - } - }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -2978,145 +2813,6 @@ "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", "dev": true }, - "cypress": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-2.1.0.tgz", - "integrity": "sha512-EKXGjKFKUkhXXfAkYixBN2Lo2Gji4ZGC+ezWflRf/co49+OyHarZaXp7Y/n826WjmMdpHTmkOw4wUWBgyFHEHQ==", - "dev": true, - "requires": { - "@cypress/listr-verbose-renderer": "0.4.1", - "@cypress/xvfb": "1.1.3", - "@types/blob-util": "1.3.3", - "@types/bluebird": "3.5.18", - "@types/chai": "4.0.8", - "@types/chai-jquery": "1.1.35", - "@types/jquery": "3.2.16", - "@types/lodash": "4.14.87", - "@types/minimatch": "3.0.1", - "@types/mocha": "2.2.44", - "@types/sinon": "4.0.0", - "@types/sinon-chai": "2.7.29", - "bluebird": "3.5.0", - "chalk": "2.1.0", - "check-more-types": "2.24.0", - "commander": "2.11.0", - "common-tags": "1.4.0", - "debug": "3.1.0", - "extract-zip": "1.6.6", - "fs-extra": "4.0.1", - "getos": "2.8.4", - "glob": "7.1.2", - "is-ci": "1.0.10", - "is-installed-globally": "0.1.0", - "lazy-ass": "1.6.0", - "listr": "0.12.0", - "lodash": "4.17.4", - "minimist": "1.2.0", - "progress": "1.1.8", - "ramda": "0.24.1", - "request": "2.81.0", - "request-progress": "0.3.1", - "supports-color": "5.1.0", - "tmp": "0.0.31", - "url": "0.11.0", - "yauzl": "2.8.0" - }, - "dependencies": { - "bluebird": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", - "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", - "dev": true - }, - "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.1.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^4.0.0" - }, - "dependencies": { - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, - "requires": { - "has-flag": "^2.0.0" - } - } - } - }, - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", - "dev": true - }, - "common-tags": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.4.0.tgz", - "integrity": "sha1-EYe+Tz1M8MBCfUP3Tu8fc1AWFMA=", - "dev": true, - "requires": { - "babel-runtime": "^6.18.0" - } - }, - "fs-extra": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.1.tgz", - "integrity": "sha1-f8DGyJV/mD9X8waiTlud3Y0N2IA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^3.0.0", - "universalify": "^0.1.0" - } - }, - "jsonfile": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", - "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "supports-color": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz", - "integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==", - "dev": true, - "requires": { - "has-flag": "^2.0.0" - } - }, - "tmp": { - "version": "0.0.31", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", - "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.1" - } - } - } - }, "d": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", @@ -3149,12 +2845,6 @@ "dev": true, "optional": true }, - "date-fns": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", - "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==", - "dev": true - }, "date-format": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", @@ -3575,12 +3265,6 @@ "integrity": "sha1-RYrBscXHYM6IEaFtK/vZfsMLr7g=", "dev": true }, - "elegant-spinner": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", - "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", - "dev": true - }, "elliptic": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", @@ -4064,12 +3748,6 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true - }, "expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", @@ -4263,58 +3941,6 @@ } } }, - "extract-zip": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz", - "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", - "dev": true, - "requires": { - "concat-stream": "1.6.0", - "debug": "2.6.9", - "mkdirp": "0.5.0", - "yauzl": "2.4.1" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "mkdirp": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", - "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "yauzl": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", - "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", - "dev": true, - "requires": { - "fd-slicer": "~1.0.1" - } - } - } - }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -4353,25 +3979,6 @@ "websocket-driver": ">=0.5.1" } }, - "fd-slicer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, "file-loader": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", @@ -5278,26 +4885,6 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", "dev": true }, - "getos": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/getos/-/getos-2.8.4.tgz", - "integrity": "sha1-e4YD02GcKOOMsP56T2PDrLgNUWM=", - "dev": true, - "requires": { - "async": "2.1.4" - }, - "dependencies": { - "async": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz", - "integrity": "sha1-LSFgx3iAMuTdbL4lAvH5osj2zeQ=", - "dev": true, - "requires": { - "lodash": "^4.14.0" - } - } - } - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -5347,15 +4934,6 @@ "is-glob": "^2.0.0" } }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, - "requires": { - "ini": "^1.3.4" - } - }, "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", @@ -6120,15 +5698,6 @@ "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", "dev": true }, - "is-ci": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz", - "integrity": "sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4=", - "dev": true, - "requires": { - "ci-info": "^1.0.0" - } - }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", @@ -6223,16 +5792,6 @@ "is-extglob": "^1.0.0" } }, - "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", - "dev": true, - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" - } - }, "is-my-ip-valid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", @@ -6338,12 +5897,6 @@ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "dev": true }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, "is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", @@ -6977,12 +6530,6 @@ "graceful-fs": "^4.1.9" } }, - "lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", - "dev": true - }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", @@ -7091,151 +6638,6 @@ "immediate": "~3.0.5" } }, - "listr": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.12.0.tgz", - "integrity": "sha1-a84sD1YD+klYDqF81qAMwOX6RRo=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "figures": "^1.7.0", - "indent-string": "^2.1.0", - "is-promise": "^2.1.0", - "is-stream": "^1.1.0", - "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.2.0", - "listr-verbose-renderer": "^0.4.0", - "log-symbols": "^1.0.2", - "log-update": "^1.0.2", - "ora": "^0.2.3", - "p-map": "^1.1.1", - "rxjs": "^5.0.0-beta.11", - "stream-to-observable": "^0.1.0", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "listr-silent-renderer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", - "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", - "dev": true - }, - "listr-update-renderer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz", - "integrity": "sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "elegant-spinner": "^1.0.1", - "figures": "^1.7.0", - "indent-string": "^3.0.0", - "log-symbols": "^1.0.2", - "log-update": "^1.0.2", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "listr-verbose-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", - "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "cli-cursor": "^1.0.2", - "date-fns": "^1.27.2", - "figures": "^1.7.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -7309,12 +6711,6 @@ "dev": true, "optional": true }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", - "dev": true - }, "lodash.tail": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", @@ -7327,52 +6723,6 @@ "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", "dev": true }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "log-update": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", - "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", - "dev": true, - "requires": { - "ansi-escapes": "^1.0.0", - "cli-cursor": "^1.0.2" - } - }, "log4js": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.6.0.tgz", @@ -8549,12 +7899,6 @@ "wrappy": "1" } }, - "onetime": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, "opn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", @@ -8604,45 +7948,6 @@ "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", "dev": true }, - "ora": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", - "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", - "dev": true, - "requires": { - "chalk": "^1.1.1", - "cli-cursor": "^1.0.2", - "cli-spinners": "^0.1.2", - "object-assign": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "original": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", @@ -8961,12 +8266,6 @@ "worker-loader": "^1.1.0" } }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, "performance-now": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", @@ -9189,12 +8488,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, - "progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", - "dev": true - }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", @@ -9496,12 +8789,6 @@ "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", "dev": true }, - "ramda": { - "version": "0.24.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz", - "integrity": "sha1-w7d1UZfzW43DUCIoJixMkd22uFc=", - "dev": true - }, "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", @@ -9933,15 +9220,6 @@ } } }, - "request-progress": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz", - "integrity": "sha1-ByHBBdipasayzossia4tXs/Pazo=", - "dev": true, - "requires": { - "throttleit": "~0.0.2" - } - }, "request-promise": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", @@ -10030,16 +9308,6 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true, - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -10491,12 +9759,6 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - }, "smart-buffer": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", @@ -11038,12 +10300,6 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", "dev": true }, - "stream-to-observable": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.1.0.tgz", - "integrity": "sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4=", - "dev": true - }, "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", @@ -11268,12 +10524,6 @@ "inherits": "2" } }, - "throttleit": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", - "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", - "dev": true - }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -13676,16 +12926,6 @@ } } }, - "yauzl": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.8.0.tgz", - "integrity": "sha1-eUUK/yKyqcWkHvVOAtuQfM+/nuI=", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.0.1" - } - }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", diff --git a/package.json b/package.json index 336b364e7f..59ba236881 100644 --- a/package.json +++ b/package.json @@ -21,16 +21,12 @@ "start:docker": "docker-compose up -d --build && wait-on http://localhost:8080 && wait-on http://localhost:3000", "stop:docker": "docker-compose stop", "e2e:docker": "npm run start:docker && npm run e2e && npm run stop:docker", - "e2e:all": "npm run start:docker && npm run cypress:ci && npm run e2e && npm run stop:docker", - "cypress:open": "cypress open", - "cypress:run": "cypress run", - "cypress:ci": "cypress run --browser chrome --config baseUrl=http://localhost:3000", "spellcheck": "cspell 'src/**/*.ts' 'e2e/**/*.ts'" }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", - "@alfresco/adf-core": "2.4.0-b599e3a41a62540e5337b97d4806efd2da41ef44", + "@alfresco/adf-content-services": "2.4.0-c5936e7db09d85eb50b06eacdc3a5f105aa9b7f9", + "@alfresco/adf-core": "2.4.0-c5936e7db09d85eb50b06eacdc3a5f105aa9b7f9", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -48,7 +44,7 @@ "@mat-datetimepicker/moment": "1.0.1", "@ngstack/electron": "0.1.0", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-cbe2d189fafa5fc2c6e9f1b6d370faad9f6dd000", + "alfresco-js-api": "2.4.0-2dbba5b40321688b340f51a376e9a1114864e658", "core-js": "2.5.3", "cspell": "^2.1.12", "hammerjs": "2.0.8", @@ -68,7 +64,6 @@ "@types/selenium-webdriver": "^3.0.8", "codacy-coverage": "^2.0.3", "codelyzer": "^4.0.1", - "cypress": "^2.1.0", "jasmine-core": "~2.8.0", "jasmine-reporters": "^2.2.1", "jasmine-spec-reporter": "~4.2.1", diff --git a/src/app.config.json b/src/app.config.json index 0fb00c0e68..35f4f87238 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -3,7 +3,8 @@ "application": { "name": "Alfresco Example Content Application", "logo": "assets/images/alfresco-logo-white.svg", - "copyright": "© 2017 - 2018 Alfresco Software, Inc. All rights reserved." + "copyright": + "© 2017 - 2018 Alfresco Software, Inc. All rights reserved." }, "headerColor": "#2196F3", "languagePicker": false, @@ -19,8 +20,8 @@ "allowDownload": true, "allowDelete": true }, - "sideNav" : { - "preserveState" : true, + "sideNav": { + "preserveState": true, "expandedSidenav": true }, "navigation": { @@ -159,6 +160,39 @@ }, "search": { "include": ["path", "allowableOperations"], + "sorting": { + "options": [ + { + "key": "name", + "label": "Name", + "type": "FIELD", + "field": "cm:name", + "ascending": true + }, + { + "key": "content.sizeInBytes", + "label": "Size", + "type": "FIELD", + "field": "content.size", + "ascending": true + }, + { + "key": "description", + "label": "Description", + "type": "FIELD", + "field": "cm:description", + "ascending": true + } + ], + "defaults": [ + { + "key": "name", + "type": "FIELD", + "field": "cm:name", + "ascending": true + } + ] + }, "filterQueries": [ { "query": "TYPE:'cm:folder' OR TYPE:'cm:content'" }, { "query": "NOT cm:creator:System" } diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index a132eba678..6dd4e7397b 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -14,8 +14,14 @@
+
+ +
diff --git a/src/app/components/search/search.component.scss b/src/app/components/search/search.component.scss index a650b0c025..3367d7d1dc 100644 --- a/src/app/components/search/search.component.scss +++ b/src/app/components/search/search.component.scss @@ -17,6 +17,10 @@ border-left: 1px solid #eee; } + &__sorting { + text-align: right; + } + .adf-search-filter { min-width: 260px; padding: 5px; diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index 87ce6f8980..7fca7073a8 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -27,6 +27,7 @@ import { Component, OnInit, Optional, ViewChild } from '@angular/core'; import { NodePaging, Pagination } from 'alfresco-js-api'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { SearchQueryBuilderService, SearchComponent as AdfSearchComponent } from '@alfresco/adf-content-services'; +import { SearchConfigurationService } from '@alfresco/adf-core'; @Component({ selector: 'app-search', @@ -43,10 +44,12 @@ export class SearchComponent implements OnInit { data: NodePaging; maxItems = 5; skipCount = 0; + sorting = ['name', 'asc']; constructor( public router: Router, private queryBuilder: SearchQueryBuilderService, + private searchConfiguration: SearchConfigurationService, @Optional() private route: ActivatedRoute) { queryBuilder.paging = { skipCount: 0, @@ -55,11 +58,21 @@ export class SearchComponent implements OnInit { } ngOnInit() { + this.sorting = this.getSorting(); + + this.queryBuilder.updated.subscribe(() => { + this.sorting = this.getSorting(); + }); + if (this.route) { this.route.params.forEach((params: Params) => { this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null; - this.queryBuilder.queryFragments['queryName'] = `cm:name:'${this.searchedWord}'`; - this.queryBuilder.update(); + if (this.searchedWord) { + const queryBody = this.searchConfiguration.generateQueryBody(this.searchedWord, 0, 100); + + this.queryBuilder.userQuery = queryBody.query.query; + this.queryBuilder.update(); + } }); } } @@ -78,4 +91,14 @@ export class SearchComponent implements OnInit { }; this.queryBuilder.update(); } + + private getSorting(): string[] { + const primary = this.queryBuilder.getPrimarySorting(); + + if (primary) { + return [primary.key, primary.ascending ? 'asc' : 'desc']; + } + + return ['name', 'asc']; + } } From aaea3bad0cebaa525e4526c2375364e5f8cee136 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 24 May 2018 22:51:17 +0300 Subject: [PATCH 037/179] sidenav view manager (#366) --- src/app/app.module.ts | 2 + .../components/layout/layout.component.html | 6 +- .../layout/layout.component.spec.ts | 37 ++-------- src/app/components/layout/layout.component.ts | 48 ++++--------- .../layout/sidenav-views-manager.directive.ts | 72 +++++++++++++++++++ 5 files changed, 96 insertions(+), 69 deletions(-) create mode 100644 src/app/components/layout/sidenav-views-manager.directive.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f12f94d524..4ff689b404 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -45,6 +45,7 @@ import { RecentFilesComponent } from './components/recent-files/recent-files.com import { SharedFilesComponent } from './components/shared-files/shared-files.component'; import { TrashcanComponent } from './components/trashcan/trashcan.component'; import { LayoutComponent } from './components/layout/layout.component'; +import { SidenavViewsManagerDirective } from './components/layout/sidenav-views-manager.directive'; import { HeaderComponent } from './components/header/header.component'; import { CurrentUserComponent } from './components/current-user/current-user.component'; import { SearchInputComponent } from './components/search-input/search-input.component'; @@ -93,6 +94,7 @@ import { HybridAppConfigService } from './common/services/hybrid-app-config.serv GenericErrorComponent, LoginComponent, LayoutComponent, + SidenavViewsManagerDirective, HeaderComponent, CurrentUserComponent, SearchInputComponent, diff --git a/src/app/components/layout/layout.component.html b/src/app/components/layout/layout.component.html index 090d002c05..754195e4c7 100644 --- a/src/app/components/layout/layout.component.html +++ b/src/app/components/layout/layout.component.html @@ -4,12 +4,14 @@ [disabled]="!permission.check(node, ['create'])"> + (expanded)="sidenavManager.setState($event)"> diff --git a/src/app/components/layout/layout.component.spec.ts b/src/app/components/layout/layout.component.spec.ts index 0424abf35f..f892749062 100644 --- a/src/app/components/layout/layout.component.spec.ts +++ b/src/app/components/layout/layout.component.spec.ts @@ -40,6 +40,7 @@ import { Observable } from 'rxjs/Observable'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { LayoutComponent } from './layout.component'; +import { SidenavViewsManagerDirective } from './sidenav-views-manager.directive'; describe('LayoutComponent', () => { let fixture: ComponentFixture; @@ -47,6 +48,7 @@ describe('LayoutComponent', () => { let browsingFilesService: BrowsingFilesService; let appConfig: AppConfigService; let userPreference: UserPreferencesService; + const navItem = { label: 'some-label', route: { @@ -62,7 +64,8 @@ describe('LayoutComponent', () => { RouterTestingModule ], declarations: [ - LayoutComponent + LayoutComponent, + SidenavViewsManagerDirective ], providers: [ { provide: TranslationService, useClass: TranslationMock }, @@ -165,37 +168,5 @@ describe('LayoutComponent', () => { expect(component.expandedSidenav).toBe(false); }); - - it('should set expandedSidenav to true if configuration is true', () => { - spyOn(userPreference, 'set'); - - appConfig.config = { - sideNav: { - expandedSidenav: false, - preserveState: true - } - }; - - fixture.detectChanges(); - component.setState(true); - - expect(userPreference.set).toHaveBeenCalledWith( 'expandedSidenav', true); - }); - - it('should set expandedSidenav to false if configuration is true', () => { - spyOn(userPreference, 'set'); - - appConfig.config = { - sideNav: { - expandedSidenav: false, - preserveState: true - } - }; - - fixture.detectChanges(); - component.setState(false); - - expect(userPreference.set).toHaveBeenCalledWith( 'expandedSidenav', false); - }); }); }); diff --git a/src/app/components/layout/layout.component.ts b/src/app/components/layout/layout.component.ts index 1800a8ddc6..4f1cf43bcb 100644 --- a/src/app/components/layout/layout.component.ts +++ b/src/app/components/layout/layout.component.ts @@ -23,13 +23,12 @@ * along with Alfresco. If not, see . */ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { Router, NavigationEnd } from '@angular/router'; +import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { Subscription } from 'rxjs/Rx'; import { MinimalNodeEntryEntity } from 'alfresco-js-api'; -import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; +import { SidenavViewsManagerDirective } from './sidenav-views-manager.directive'; @Component({ selector: 'app-layout', @@ -37,27 +36,25 @@ import { NodePermissionService } from '../../common/services/node-permission.ser styleUrls: ['./layout.component.scss'] }) export class LayoutComponent implements OnInit, OnDestroy { - node: MinimalNodeEntryEntity; - hideSidenav: boolean; + @ViewChild(SidenavViewsManagerDirective) manager: SidenavViewsManagerDirective; + expandedSidenav: boolean; - private hideConditions: string[] = ['preview']; + node: MinimalNodeEntryEntity; + private subscriptions: Subscription[] = []; constructor( - private router: Router, private browsingFilesService: BrowsingFilesService, - private userPreferenceService: UserPreferencesService, - private appConfigService: AppConfigService, - public permission: NodePermissionService) { - this.router.events - .filter(event => event instanceof NavigationEnd) - .subscribe( (event: any ) => { - this.hideSidenav = this.hideConditions.some(el => event.urlAfterRedirects.includes(el)); - }); - } + public permission: NodePermissionService) {} ngOnInit() { - this.expandedSidenav = this.sidenavState; + if (!this.manager.minimizeSidenav) { + this.expandedSidenav = this.manager.sidenavState; + } else { + this.expandedSidenav = false; + } + + this.manager.run(true); this.subscriptions.concat([ this.browsingFilesService.onChangeParent.subscribe((node: MinimalNodeEntryEntity) => this.node = node) @@ -67,21 +64,4 @@ export class LayoutComponent implements OnInit, OnDestroy { ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } - - get sidenavState(): boolean { - const expand = this.appConfigService.get('sideNav.expandedSidenav', true); - const preserveState = this.appConfigService.get('sideNav.preserveState', true); - - if (preserveState) { - return (this.userPreferenceService.get('expandedSidenav', expand.toString()) === 'true'); - } - - return expand; - } - - setState(state) { - if (this.appConfigService.get('sideNav.preserveState')) { - this.userPreferenceService.set('expandedSidenav', state); - } - } } diff --git a/src/app/components/layout/sidenav-views-manager.directive.ts b/src/app/components/layout/sidenav-views-manager.directive.ts new file mode 100644 index 0000000000..513073faa2 --- /dev/null +++ b/src/app/components/layout/sidenav-views-manager.directive.ts @@ -0,0 +1,72 @@ +import { Directive, ContentChild } from '@angular/core'; +import { Router, NavigationEnd } from '@angular/router'; +import { UserPreferencesService, AppConfigService, SidenavLayoutComponent } from '@alfresco/adf-core'; + +@Directive({ + selector: '[acaSidenavManager]', + exportAs: 'acaSidenavManager' +}) +export class SidenavViewsManagerDirective { + + @ContentChild(SidenavLayoutComponent) sidenavLayout: SidenavLayoutComponent; + + minimizeSidenav = false; + hideSidenav = false; + + private _run = false; + private minimizeConditions: string[] = ['search']; + private hideConditions: string[] = ['preview']; + + constructor( + private router: Router, + private userPreferenceService: UserPreferencesService, + private appConfigService: AppConfigService + ) { + this.router.events + .filter(event => event instanceof NavigationEnd) + .subscribe( (event: any ) => { + this.minimizeSidenav = this.minimizeConditions.some(el => event.urlAfterRedirects.includes(el)); + this.hideSidenav = this.hideConditions.some(el => event.urlAfterRedirects.includes(el)); + + if (this._run) { + this.manageSidenavState(); + } + }); + + } + + run (shouldRun) { + this._run = shouldRun; + } + + manageSidenavState() { + if (this.minimizeSidenav && !this.sidenavLayout.isMenuMinimized) { + this.sidenavLayout.isMenuMinimized = true; + this.sidenavLayout.container.toggleMenu(); + } + + if (!this.minimizeSidenav) { + if (this.sidenavState && this.sidenavLayout.isMenuMinimized) { + this.sidenavLayout.isMenuMinimized = false; + this.sidenavLayout.container.toggleMenu(); + } + } + } + + setState(state) { + if (!this.minimizeSidenav && this.appConfigService.get('sideNav.preserveState')) { + this.userPreferenceService.set('expandedSidenav', state); + } + } + + get sidenavState(): boolean { + const expand = this.appConfigService.get('sideNav.expandedSidenav', true); + const preserveState = this.appConfigService.get('sideNav.preserveState', true); + + if (preserveState) { + return (this.userPreferenceService.get('expandedSidenav', expand.toString()) === 'true'); + } + + return expand; + } +} From 1d9bf48f15f9bdb61b7a0935ea97bd0547c7e2f9 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 25 May 2018 11:27:35 +0300 Subject: [PATCH 038/179] consisten width value (#368) --- src/app/ui/_layout.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/ui/_layout.scss b/src/app/ui/_layout.scss index e64871faf9..ad9e7e81d1 100644 --- a/src/app/ui/_layout.scss +++ b/src/app/ui/_layout.scss @@ -41,7 +41,8 @@ $alfresco-gray-background: #fafafa; display: block; height: 100%; overflow-y: scroll; - max-width: 320px; + max-width: 350px; + width: 350px; } } From 8c3fed10664ea09d77aae8fc967ff2cd967bc2e5 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 25 May 2018 09:37:27 +0100 Subject: [PATCH 039/179] remove style wokarounds for viewer toolbar (#367) --- .../components/preview/preview.component.html | 16 ++++++---------- src/app/ui/application.scss | 1 - src/app/ui/custom-theme.scss | 2 -- .../ui/overrides/_adf-viewer-more-actions.scss | 18 ------------------ 4 files changed, 6 insertions(+), 31 deletions(-) delete mode 100644 src/app/ui/overrides/_adf-viewer-more-actions.scss diff --git a/src/app/components/preview/preview.component.html b/src/app/components/preview/preview.component.html index 236345b5ff..ef8420396f 100644 --- a/src/app/components/preview/preview.component.html +++ b/src/app/components/preview/preview.component.html @@ -37,19 +37,15 @@ mat-menu-item #selection="adfFavorite" [adf-node-favorite]="selectedEntities"> - - {{ selection.hasFavorites() ? 'star' :'star_border' }} - + star + star_border {{ 'APP.ACTIONS.FAVORITE' | translate }} @@ -57,7 +53,7 @@ mat-menu-item *ngIf="permission.check(node, ['delete'])" [acaMoveNode]="selectedEntities"> - library_books + library_books {{ 'APP.ACTIONS.MOVE' | translate }} @@ -65,7 +61,7 @@ mat-menu-item *ngIf="permission.check(node, ['delete'])" (click)="deleteFile()"> - delete + delete {{ 'APP.ACTIONS.DELETE' | translate }} @@ -73,7 +69,7 @@ mat-menu-item *ngIf="permission.check(node, ['update'])" [acaNodeVersions]="selectedEntities"> - history + history {{ 'APP.ACTIONS.VERSIONS' | translate }} diff --git a/src/app/ui/application.scss b/src/app/ui/application.scss index e4ac8ee9af..0d28f2cd23 100644 --- a/src/app/ui/application.scss +++ b/src/app/ui/application.scss @@ -27,7 +27,6 @@ ng-component { @import './overrides/alfresco-upload-button'; @import './overrides/alfresco-upload-dialog'; @import './overrides/toolbar'; -@import './overrides/adf-viewer-more-actions'; @import './overrides/adf-info-drawer'; @import './overrides/_adf-sidebar-action-menu'; diff --git a/src/app/ui/custom-theme.scss b/src/app/ui/custom-theme.scss index 9cd3784d1c..d84615b8fa 100644 --- a/src/app/ui/custom-theme.scss +++ b/src/app/ui/custom-theme.scss @@ -3,7 +3,6 @@ @import '../components/sidenav/sidenav.component.theme'; @import './overrides/toolbar'; -@import './overrides/adf-viewer-more-actions'; $grey-scale: ( 50 : #e0e0e0, @@ -48,5 +47,4 @@ $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent); @mixin custom-theme($theme) { @include sidenav-component-theme($custom-theme); @include toolbar-component-theme($custom-theme); - @include viewer-more-actions-component-theme($custom-theme); } diff --git a/src/app/ui/overrides/_adf-viewer-more-actions.scss b/src/app/ui/overrides/_adf-viewer-more-actions.scss deleted file mode 100644 index fc9a7cc62f..0000000000 --- a/src/app/ui/overrides/_adf-viewer-more-actions.scss +++ /dev/null @@ -1,18 +0,0 @@ -@mixin viewer-more-actions-component-theme($theme) { - $primary: map-get($theme, primary); - $accent: map-get($theme, accent); - $background: map-get($theme, background); - - .adf-viewer-more-actions { - @include angular-material-theme($theme); - - .toolbar__option--active { - color: mat-color($accent) !important; - } - - .toolbar__option--default { - color: mat-color($primary, .87) !important; - } - } - -} From 58a71ad12a1940cb79d6731131133ecb79cd30cc Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 25 May 2018 22:00:50 +0100 Subject: [PATCH 040/179] cleanup toolbar styles (#369) * cleanup toolbar styles * a11y fixes, add missing tooltip * fix tests --- .../favorites/favorites.component.html | 19 +++----- src/app/components/files/files.component.html | 19 +++----- .../components/header/header.component.html | 7 ++- .../header/header.component.spec.ts | 9 ++-- .../recent-files/recent-files.component.html | 19 +++----- .../shared-files/shared-files.component.html | 21 ++++----- .../components/sidenav/sidenav.component.html | 3 +- src/app/ui/application.scss | 4 ++ src/app/ui/overrides/_toolbar.scss | 44 ++++--------------- src/assets/i18n/en.json | 3 +- src/index.html | 18 ++++---- 11 files changed, 66 insertions(+), 100 deletions(-) diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 37679d2319..d8369726ab 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -50,40 +50,35 @@ more_vert + [overlapTrigger]="false"> @@ -91,7 +86,7 @@ mat-menu-item *ngIf="isFileSelected(documentList.selection)" [acaNodeVersions]="documentList.selection"> - history + history {{ 'APP.ACTIONS.VERSIONS' | translate }} diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index 8107da7fd4..439f6ca0fa 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -54,25 +54,20 @@ + [overlapTrigger]="false"> @@ -80,7 +75,7 @@ mat-menu-item *ngIf="permission.check(documentList.selection, ['delete'])" [acaMoveNode]="documentList.selection"> - library_books + library_books {{ 'APP.ACTIONS.MOVE' | translate }} @@ -88,7 +83,7 @@ mat-menu-item *ngIf="permission.check(documentList.selection, ['delete'])" [acaDeleteNode]="documentList.selection"> - delete + delete {{ 'APP.ACTIONS.DELETE' | translate }} @@ -96,7 +91,7 @@ mat-menu-item *ngIf="isFileSelected(documentList.selection)" [acaNodeVersions]="documentList.selection"> - history + history {{ 'APP.ACTIONS.VERSIONS' | translate }} diff --git a/src/app/components/header/header.component.html b/src/app/components/header/header.component.html index 1e033fe0a8..8671743694 100644 --- a/src/app/components/header/header.component.html +++ b/src/app/components/header/header.component.html @@ -1,6 +1,9 @@ - + - diff --git a/src/app/components/header/header.component.spec.ts b/src/app/components/header/header.component.spec.ts index c32d91cfc8..468d3f63dd 100644 --- a/src/app/components/header/header.component.spec.ts +++ b/src/app/components/header/header.component.spec.ts @@ -26,11 +26,12 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { AppConfigService, PeopleContentService } from '@alfresco/adf-core'; +import { AppConfigService, PeopleContentService, TranslationService, TranslationMock } from '@alfresco/adf-core'; import { HttpClientModule } from '@angular/common/http'; import { Observable } from 'rxjs/Rx'; import { HeaderComponent } from './header.component'; +import { TranslateModule } from '@ngx-translate/core'; describe('HeaderComponent', () => { let fixture; @@ -41,14 +42,16 @@ describe('HeaderComponent', () => { TestBed.configureTestingModule({ imports: [ HttpClientModule, - RouterTestingModule + RouterTestingModule, + TranslateModule.forRoot(), ], declarations: [ HeaderComponent ], providers: [ AppConfigService, - PeopleContentService + PeopleContentService, + { provide: TranslationService, useClass: TranslationMock }, ], schemas: [ NO_ERRORS_SCHEMA ] }) diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index e20c81d00b..83102ad7fc 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -41,25 +41,20 @@ + [overlapTrigger]="false"> @@ -67,7 +62,7 @@ mat-menu-item *ngIf="permission.check(documentList.selection, ['delete'])" [acaMoveNode]="documentList.selection"> - library_books + library_books {{ 'APP.ACTIONS.MOVE' | translate }} @@ -75,7 +70,7 @@ mat-menu-item *ngIf="permission.check(documentList.selection, ['delete'])" [acaDeleteNode]="documentList.selection"> - delete + delete {{ 'APP.ACTIONS.DELETE' | translate }} @@ -83,7 +78,7 @@ mat-menu-item *ngIf="isFileSelected(documentList.selection)" [acaNodeVersions]="documentList.selection"> - history + history {{ 'APP.ACTIONS.VERSIONS' | translate }} diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 9bbf5a8def..15c563421e 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -40,25 +40,20 @@ + [overlapTrigger]="false"> @@ -66,7 +61,7 @@ mat-menu-item *ngIf="permission.check(documentList.selection, ['delete'], { target: 'allowableOperationsOnTarget' })" [acaMoveNode]="documentList.selection"> - library_books + library_books {{ 'APP.ACTIONS.MOVE' | translate }} @@ -75,7 +70,7 @@ *ngIf="permission.check(documentList.selection, ['delete'])" [acaUnshareNode]="documentList.selection" (links-unshared)="refresh()"> - stop_screen_share + stop_screen_share {{ 'APP.ACTIONS.UNSHARE' | translate }} @@ -83,7 +78,7 @@ mat-menu-item *ngIf="permission.check(documentList.selection, ['delete'], { target: 'allowableOperationsOnTarget' })" [acaDeleteNode]="documentList.selection"> - delete + delete {{ 'APP.ACTIONS.DELETE' | translate }} @@ -91,7 +86,7 @@ mat-menu-item *ngIf="permission.check(documentList.selection[0], ['update'], { target: 'allowableOperationsOnTarget' })" [acaNodeVersions]="documentList.selection"> - history + history {{ 'APP.ACTIONS.VERSIONS' | translate }} diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index 174af8aa7f..87708b9db3 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -3,7 +3,7 @@ arrow_drop_down
- queue + queue
From 20ad62d035ee963283554d2d4e6c517ab17dbddd Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sun, 3 Jun 2018 11:11:39 +0100 Subject: [PATCH 058/179] improved build workflow (#383) * improve workflow * update CI config * update config --- .circleci/config.yml | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8c32532fa9..309640f2de 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2 jobs: - install: + test: working_directory: ~/alfresco-content-app docker: - image: circleci/node:8-browsers @@ -14,6 +14,7 @@ jobs: key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }} paths: - "node_modules" + - run: xvfb-run -a npm run test:ci lint: working_directory: ~/alfresco-content-app docker: @@ -34,16 +35,6 @@ jobs: key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }} - run: npm install - run: npm run spellcheck - test: - working_directory: ~/alfresco-content-app - docker: - - image: circleci/node:8-browsers - steps: - - checkout - - restore_cache: - key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }} - - run: npm install - - run: xvfb-run -a npm run test:ci build: working_directory: ~/alfresco-content-app docker: @@ -59,16 +50,13 @@ workflows: version: 2 build_and_test: jobs: - - install + - test - lint: requires: - - install + - test - spellcheck: requires: - - install - - test: - requires: - - install + - test - build: requires: - - install + - test From aca73e2ff2a6498d95df3167d657ba5ef6fc02da Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sun, 3 Jun 2018 11:49:29 +0100 Subject: [PATCH 059/179] use instant translation (#382) * use instant translation * update code and tests * fix tests --- .../common/directives/node-copy.directive.ts | 14 +++-- .../directives/node-delete.directive.ts | 51 +++++++++---------- .../common/directives/node-move.directive.ts | 33 ++++++------ .../node-permanent-delete.directive.spec.ts | 14 ++--- .../node-permanent-delete.directive.ts | 20 ++++---- .../directives/node-restore.directive.spec.ts | 14 ++--- .../directives/node-restore.directive.ts | 24 ++++----- .../directives/node-versions.directive.ts | 4 +- 8 files changed, 81 insertions(+), 93 deletions(-) diff --git a/src/app/common/directives/node-copy.directive.ts b/src/app/common/directives/node-copy.directive.ts index 4256ebc5fb..29911cba4c 100644 --- a/src/app/common/directives/node-copy.directive.ts +++ b/src/app/common/directives/node-copy.directive.ts @@ -108,11 +108,10 @@ export class NodeCopyDirective { const undo = (numberOfCopiedItems > 0) ? this.translation.instant('APP.ACTIONS.UNDO') : ''; const withUndo = (numberOfCopiedItems > 0) ? '_WITH_UNDO' : ''; - this.translation.get(i18nMessageString, { success: numberOfCopiedItems, failed: failedItems }).subscribe(message => { - this.notification.openSnackMessageAction(message, undo, NodeActionsService[`SNACK_MESSAGE_DURATION${withUndo}`]) - .onAction() - .subscribe(() => this.deleteCopy(newItems)); - }); + const message = this.translation.instant(i18nMessageString, { success: numberOfCopiedItems, failed: failedItems }); + this.notification.openSnackMessageAction(message, undo, NodeActionsService[`SNACK_MESSAGE_DURATION${withUndo}`]) + .onAction() + .subscribe(() => this.deleteCopy(newItems)); } private deleteCopy(nodes: MinimalNodeEntity[]) { @@ -138,9 +137,8 @@ export class NodeCopyDirective { i18nMessageString = 'APP.MESSAGES.ERRORS.PERMISSION'; } - this.translation.get(i18nMessageString).subscribe(message => { - this.notification.openSnackMessageAction(message, '', NodeActionsService.SNACK_MESSAGE_DURATION); - }); + const message = this.translation.instant(i18nMessageString); + this.notification.openSnackMessageAction(message, '', NodeActionsService.SNACK_MESSAGE_DURATION); } ); } diff --git a/src/app/common/directives/node-delete.directive.ts b/src/app/common/directives/node-delete.directive.ts index 291cced24e..bce80a8c97 100644 --- a/src/app/common/directives/node-delete.directive.ts +++ b/src/app/common/directives/node-delete.directive.ts @@ -65,24 +65,21 @@ export class NodeDeleteDirective { .subscribe( (data) => { const processedData = this.processStatus(data); + const message = this.getDeleteMessage(processedData); + const withUndo = processedData.someSucceeded ? this.translation.instant('APP.ACTIONS.UNDO') : ''; - this.getDeleteMessage(processedData) - .subscribe((message) => { - const withUndo = processedData.someSucceeded ? this.translation.translate.instant('APP.ACTIONS.UNDO') : ''; + this.notification.openSnackMessageAction(message, withUndo, NodeDeleteDirective.DELETE_MESSAGE_DURATION) + .onAction() + .subscribe(() => this.restore(processedData.success)); - this.notification.openSnackMessageAction(message, withUndo, NodeDeleteDirective.DELETE_MESSAGE_DURATION) - .onAction() - .subscribe(() => this.restore(processedData.success)); - - if (processedData.someSucceeded) { - this.content.nodeDeleted.next(null); - } - }); + if (processedData.someSucceeded) { + this.content.nodeDeleted.next(null); + } } ); } - private restore(items): void { + private restore(items: any[]): void { const batch = []; items.forEach((item) => { @@ -95,12 +92,10 @@ export class NodeDeleteDirective { const processedData = this.processStatus(data); if (processedData.failed.length) { - this.getRestoreMessage(processedData) - .subscribe((message) => { - this.notification.openSnackMessageAction( - message, '' , NodeDeleteDirective.RESTORE_MESSAGE_DURATION - ); - }); + const message = this.getRestoreMessage(processedData); + this.notification.openSnackMessageAction( + message, '' , NodeDeleteDirective.RESTORE_MESSAGE_DURATION + ); } if (processedData.someSucceeded) { @@ -178,39 +173,39 @@ export class NodeDeleteDirective { ); } - private getRestoreMessage(status): Observable { + private getRestoreMessage(status): string { if (status.someFailed && !status.oneFailed) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.NODE_RESTORE_PLURAL', { number: status.failed.length } ); } if (status.oneFailed) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.NODE_RESTORE', { name: status.failed[0].name } ); } } - private getDeleteMessage(status): Observable { + private getDeleteMessage(status): string { if (status.allFailed && !status.oneFailed) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.NODE_DELETION_PLURAL', { number: status.failed.length } ); } if (status.allSucceeded && !status.oneSucceeded) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.INFO.NODE_DELETION.PLURAL', { number: status.success.length } ); } if (status.someFailed && status.someSucceeded && !status.oneSucceeded) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.INFO.NODE_DELETION.PARTIAL_PLURAL', { success: status.success.length, @@ -220,7 +215,7 @@ export class NodeDeleteDirective { } if (status.someFailed && status.oneSucceeded) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.INFO.NODE_DELETION.PARTIAL_SINGULAR', { success: status.success.length, @@ -230,14 +225,14 @@ export class NodeDeleteDirective { } if (status.oneFailed && !status.someSucceeded) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.NODE_DELETION', { name: status.failed[0].name } ); } if (status.oneSucceeded && !status.someFailed) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.INFO.NODE_DELETION.SINGULAR', { name: status.success[0].name } ); diff --git a/src/app/common/directives/node-move.directive.ts b/src/app/common/directives/node-move.directive.ts index d3fab7451e..d2d6a91a0c 100644 --- a/src/app/common/directives/node-move.directive.ts +++ b/src/app/common/directives/node-move.directive.ts @@ -128,20 +128,21 @@ export class NodeMoveDirective { const initialParentId = this.nodeActionsService.getEntryParentId(this.selection[0].entry); - this.translation.get( + const messages = this.translation.instant( [successMessage, partialSuccessMessage, failedMessage], - { success: succeeded, failed: failures, partially: partiallySucceeded}).subscribe(messages => { - - this.notification.openSnackMessageAction( - messages[successMessage] - + beforePartialSuccessMessage + messages[partialSuccessMessage] - + beforeFailedMessage + messages[failedMessage], - undo, - NodeActionsService[`SNACK_MESSAGE_DURATION${withUndo}`] - ) - .onAction() - .subscribe(() => this.revertMoving(moveResponse, initialParentId)); - }); + { success: succeeded, failed: failures, partially: partiallySucceeded} + ); + + // TODO: review in terms of i18n + this.notification.openSnackMessageAction( + messages[successMessage] + + beforePartialSuccessMessage + messages[partialSuccessMessage] + + beforeFailedMessage + messages[failedMessage], + undo, + NodeActionsService[`SNACK_MESSAGE_DURATION${withUndo}`] + ) + .onAction() + .subscribe(() => this.revertMoving(moveResponse, initialParentId)); } getErrorMessage(errorObject): string { @@ -207,10 +208,8 @@ export class NodeMoveDirective { i18nMessageString = 'APP.MESSAGES.ERRORS.PERMISSION'; } - this.translation.get(i18nMessageString).subscribe(message => { - this.notification.openSnackMessage( - message, NodeActionsService.SNACK_MESSAGE_DURATION); - }); + const message = this.translation.instant(i18nMessageString); + this.notification.openSnackMessage(message, NodeActionsService.SNACK_MESSAGE_DURATION); } ); } diff --git a/src/app/common/directives/node-permanent-delete.directive.spec.ts b/src/app/common/directives/node-permanent-delete.directive.spec.ts index e5246daaa6..755f632b40 100644 --- a/src/app/common/directives/node-permanent-delete.directive.spec.ts +++ b/src/app/common/directives/node-permanent-delete.directive.spec.ts @@ -78,7 +78,7 @@ describe('NodePermanentDeleteDirective', () => { beforeEach(() => { nodesService = alfrescoService.getInstance().nodes; - spyOn(translation, 'get').and.returnValue(Observable.of('message')); + spyOn(translation, 'instant').and.returnValue(Observable.of('message')); spyOn(notificationService, 'openSnackMessage').and.returnValue({}); spyOn(dialog, 'open').and.returnValue({ @@ -138,7 +138,7 @@ describe('NodePermanentDeleteDirective', () => { tick(); expect(notificationService.openSnackMessage).toHaveBeenCalled(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.INFO.TRASH.NODES_PURGE.PARTIAL_SINGULAR', { name: 'name1', failed: 2 } ); @@ -175,7 +175,7 @@ describe('NodePermanentDeleteDirective', () => { tick(); expect(notificationService.openSnackMessage).toHaveBeenCalled(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.INFO.TRASH.NODES_PURGE.PARTIAL_PLURAL', { number: 2, failed: 2 } ); @@ -193,7 +193,7 @@ describe('NodePermanentDeleteDirective', () => { tick(); expect(notificationService.openSnackMessage).toHaveBeenCalled(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.INFO.TRASH.NODES_PURGE.SINGULAR', { name: 'name1' } ); @@ -211,7 +211,7 @@ describe('NodePermanentDeleteDirective', () => { tick(); expect(notificationService.openSnackMessage).toHaveBeenCalled(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.ERRORS.TRASH.NODES_PURGE.SINGULAR', { name: 'name1' } ); @@ -238,7 +238,7 @@ describe('NodePermanentDeleteDirective', () => { tick(); expect(notificationService.openSnackMessage).toHaveBeenCalled(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.INFO.TRASH.NODES_PURGE.PLURAL', { number: 2 } ); @@ -265,7 +265,7 @@ describe('NodePermanentDeleteDirective', () => { tick(); expect(notificationService.openSnackMessage).toHaveBeenCalled(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.ERRORS.TRASH.NODES_PURGE.PLURAL', { number: 2 } ); diff --git a/src/app/common/directives/node-permanent-delete.directive.ts b/src/app/common/directives/node-permanent-delete.directive.ts index a9aa7f90ad..501976ae1c 100644 --- a/src/app/common/directives/node-permanent-delete.directive.ts +++ b/src/app/common/directives/node-permanent-delete.directive.ts @@ -116,15 +116,13 @@ export class NodePermanentDeleteDirective { } private purgeNotification(status): void { - this.getPurgeMessage(status) - .subscribe((message) => { - this.notification.openSnackMessage(message, 3000); - }); + const message = this.getPurgeMessage(status); + this.notification.openSnackMessage(message, 3000); } - private getPurgeMessage(status): Observable { + private getPurgeMessage(status): string { if (status.oneSucceeded && status.someFailed && !status.oneFailed) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.INFO.TRASH.NODES_PURGE.PARTIAL_SINGULAR', { name: status.success[0].name, @@ -134,7 +132,7 @@ export class NodePermanentDeleteDirective { } if (status.someSucceeded && !status.oneSucceeded && status.someFailed) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.INFO.TRASH.NODES_PURGE.PARTIAL_PLURAL', { number: status.success.length, @@ -144,28 +142,28 @@ export class NodePermanentDeleteDirective { } if (status.oneSucceeded) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.INFO.TRASH.NODES_PURGE.SINGULAR', { name: status.success[0].name } ); } if (status.oneFailed) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.TRASH.NODES_PURGE.SINGULAR', { name: status.fail[0].name } ); } if (status.allSucceeded) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.INFO.TRASH.NODES_PURGE.PLURAL', { number: status.success.length } ); } if (status.allFailed) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.TRASH.NODES_PURGE.PLURAL', { number: status.fail.length } ); diff --git a/src/app/common/directives/node-restore.directive.spec.ts b/src/app/common/directives/node-restore.directive.spec.ts index 8a3958b7a0..9a7c557086 100644 --- a/src/app/common/directives/node-restore.directive.spec.ts +++ b/src/app/common/directives/node-restore.directive.spec.ts @@ -84,7 +84,7 @@ describe('NodeRestoreDirective', () => { nodesService = alfrescoService.getInstance().nodes; coreApi = alfrescoService.getInstance().core; - spyOn(translation, 'get').and.returnValue(Observable.of('message')); + spyOn(translation, 'instant').and.returnValue(Observable.of('message')); }); it('does not restore nodes if no selection', () => { @@ -209,7 +209,7 @@ describe('NodeRestoreDirective', () => { element.triggerEventHandler('click', null); tick(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.ERRORS.TRASH.NODES_RESTORE.PARTIAL_PLURAL', { number: 2 } ); @@ -229,7 +229,7 @@ describe('NodeRestoreDirective', () => { element.triggerEventHandler('click', null); tick(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.ERRORS.TRASH.NODES_RESTORE.NODE_EXISTS', { name: 'name1' } ); @@ -249,7 +249,7 @@ describe('NodeRestoreDirective', () => { element.triggerEventHandler('click', null); tick(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.ERRORS.TRASH.NODES_RESTORE.GENERIC', { name: 'name1' } ); @@ -269,7 +269,7 @@ describe('NodeRestoreDirective', () => { element.triggerEventHandler('click', null); tick(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.ERRORS.TRASH.NODES_RESTORE.LOCATION_MISSING', { name: 'name1' } ); @@ -296,7 +296,7 @@ describe('NodeRestoreDirective', () => { element.triggerEventHandler('click', null); tick(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.INFO.TRASH.NODES_RESTORE.PLURAL' ); })); @@ -313,7 +313,7 @@ describe('NodeRestoreDirective', () => { element.triggerEventHandler('click', null); tick(); - expect(translation.get).toHaveBeenCalledWith( + expect(translation.instant).toHaveBeenCalledWith( 'APP.MESSAGES.INFO.TRASH.NODES_RESTORE.SINGULAR', { name: 'name1' } ); diff --git a/src/app/common/directives/node-restore.directive.ts b/src/app/common/directives/node-restore.directive.ts index dfd4801268..cb0ff38b3d 100644 --- a/src/app/common/directives/node-restore.directive.ts +++ b/src/app/common/directives/node-restore.directive.ts @@ -190,11 +190,11 @@ export class NodeRestoreDirective { ); } - private getRestoreMessage(): Observable { + private getRestoreMessage(): string { const { restoreProcessStatus: status } = this; if (status.someFailed && !status.oneFailed) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.TRASH.NODES_RESTORE.PARTIAL_PLURAL', { number: status.fail.length @@ -204,14 +204,14 @@ export class NodeRestoreDirective { if (status.oneFailed && status.fail[0].statusCode) { if (status.fail[0].statusCode === 409) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.TRASH.NODES_RESTORE.NODE_EXISTS', { name: status.fail[0].entry.name } ); } else { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.TRASH.NODES_RESTORE.GENERIC', { name: status.fail[0].entry.name @@ -221,7 +221,7 @@ export class NodeRestoreDirective { } if (status.oneFailed && !status.fail[0].statusCode) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.ERRORS.TRASH.NODES_RESTORE.LOCATION_MISSING', { name: status.fail[0].entry.name @@ -230,11 +230,11 @@ export class NodeRestoreDirective { } if (status.allSucceeded && !status.oneSucceeded) { - return this.translation.get('APP.MESSAGES.INFO.TRASH.NODES_RESTORE.PLURAL'); + return this.translation.instant('APP.MESSAGES.INFO.TRASH.NODES_RESTORE.PLURAL'); } if (status.allSucceeded && status.oneSucceeded) { - return this.translation.get( + return this.translation.instant( 'APP.MESSAGES.INFO.TRASH.NODES_RESTORE.SINGULAR', { name: status.success[0].entry.name @@ -246,13 +246,11 @@ export class NodeRestoreDirective { private restoreNotification(): void { const status = Object.assign({}, this.restoreProcessStatus); const action = (status.oneSucceeded && !status.someFailed) ? this.translation.translate.instant('APP.ACTIONS.VIEW') : ''; + const message = this.getRestoreMessage(); - this.getRestoreMessage() - .subscribe((message) => { - this.notification.openSnackMessageAction(message, action, 3000) - .onAction() - .subscribe(() => this.navigateLocation(status.success[0].entry.path)); - }); + this.notification.openSnackMessageAction(message, action, 3000) + .onAction() + .subscribe(() => this.navigateLocation(status.success[0].entry.path)); } private refresh(): void { diff --git a/src/app/common/directives/node-versions.directive.ts b/src/app/common/directives/node-versions.directive.ts index 169e114c17..93c209f358 100644 --- a/src/app/common/directives/node-versions.directive.ts +++ b/src/app/common/directives/node-versions.directive.ts @@ -71,8 +71,8 @@ export class NodeVersionsDirective { VersionManagerDialogAdapterComponent, { data: { contentEntry }, panelClass: 'adf-version-manager-dialog', width: '630px' }); } else { - const translatedErrorMessage: any = this.translation.get('APP.MESSAGES.ERRORS.PERMISSION'); - this.notification.openSnackMessage(translatedErrorMessage.value, 4000); + const translatedErrorMessage = this.translation.instant('APP.MESSAGES.ERRORS.PERMISSION'); + this.notification.openSnackMessage(translatedErrorMessage, 4000); this.nodeVersionError.emit(); } From c9cd7ae5c4c567ea7eb684f5319a8d1404a904f2 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sun, 3 Jun 2018 12:18:31 +0100 Subject: [PATCH 060/179] remove cypress code --- cypress/fixtures/example.json | 5 ----- cypress/integration/login.spec.js | 17 ----------------- cypress/plugins/index.js | 17 ----------------- cypress/support/commands.js | 25 ------------------------- cypress/support/index.js | 26 -------------------------- 5 files changed, 90 deletions(-) delete mode 100644 cypress/fixtures/example.json delete mode 100644 cypress/integration/login.spec.js delete mode 100644 cypress/plugins/index.js delete mode 100644 cypress/support/commands.js delete mode 100644 cypress/support/index.js diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json deleted file mode 100644 index da18d9352a..0000000000 --- a/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} \ No newline at end of file diff --git a/cypress/integration/login.spec.js b/cypress/integration/login.spec.js deleted file mode 100644 index 19ec8d4876..0000000000 --- a/cypress/integration/login.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -describe('Login', function() { - - it('logs in as an admin', () => { - cy.visit('/login'); - cy - .get('#username') - .type('admin') - .should('have.value', 'admin'); - cy - .get('#password') - .type('admin') - .should('have.value', 'admin'); - - cy.get('#login-button').click(); - cy.url().should('include', '#/personal-files'); - }); -}); diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js deleted file mode 100644 index fd170fba69..0000000000 --- a/cypress/plugins/index.js +++ /dev/null @@ -1,17 +0,0 @@ -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) - -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config -} diff --git a/cypress/support/commands.js b/cypress/support/commands.js deleted file mode 100644 index c1f5a772e2..0000000000 --- a/cypress/support/commands.js +++ /dev/null @@ -1,25 +0,0 @@ -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add("login", (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This is will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/cypress/support/index.js b/cypress/support/index.js deleted file mode 100644 index 69c55b9d70..0000000000 --- a/cypress/support/index.js +++ /dev/null @@ -1,26 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands' - -// Alternatively you can use CommonJS syntax: -// require('./commands') - -Cypress.on('uncaught:exception', (err, runnable) => { - // returning false here prevents Cypress from - // failing the test - return false -}); From a67dd43ad6c7b26f043b7cb15d07170a05489977 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 4 Jun 2018 08:57:50 +0100 Subject: [PATCH 061/179] [ACA-1430] Initial NgRx setup (#384) * initial ngrx integration, migrate header * update header tests * update spellcheck rules * fix locked image path for virtual paths --- cspell.json | 1 + package-lock.json | 20 +++++++++ package.json | 4 ++ src/app/app.component.ts | 26 ++++++++++- src/app/app.module.ts | 14 +++++- .../components/header/header.component.html | 6 +-- .../header/header.component.spec.ts | 31 ++++++++++--- src/app/components/header/header.component.ts | 35 ++++++--------- src/app/components/page.component.ts | 2 +- src/app/store/actions/app-name.action.ts | 8 ++++ src/app/store/actions/header-color.action.ts | 8 ++++ src/app/store/actions/logo-path.action.ts | 8 ++++ src/app/store/reducers/app.reducer.ts | 44 +++++++++++++++++++ src/app/store/selectors/app.selectors.ts | 7 +++ src/app/store/states/app.state.ts | 19 ++++++++ 15 files changed, 198 insertions(+), 35 deletions(-) create mode 100644 src/app/store/actions/app-name.action.ts create mode 100644 src/app/store/actions/header-color.action.ts create mode 100644 src/app/store/actions/logo-path.action.ts create mode 100644 src/app/store/reducers/app.reducer.ts create mode 100644 src/app/store/selectors/app.selectors.ts create mode 100644 src/app/store/states/app.state.ts diff --git a/cspell.json b/cspell.json index 9e9b86be0c..9789a3c847 100644 --- a/cspell.json +++ b/cspell.json @@ -4,6 +4,7 @@ "words": [ "succes", + "ngrx", "ngstack", "sidenav", "injectable", diff --git a/package-lock.json b/package-lock.json index 4d46e20e3c..944545eca9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -445,6 +445,26 @@ "resolved": "https://registry.npmjs.org/@mat-datetimepicker/moment/-/moment-1.0.1.tgz", "integrity": "sha1-YYUwbd/QeTBlq9XbBjKpQZgjdPQ=" }, + "@ngrx/effects": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-5.2.0.tgz", + "integrity": "sha1-qnYractv1GRNckoc7NJlyqQrrwk=" + }, + "@ngrx/router-store": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-5.2.0.tgz", + "integrity": "sha1-v0sXTOGaNuuoIR/B3erx41rnQ2g=" + }, + "@ngrx/store": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-5.2.0.tgz", + "integrity": "sha1-Yn7XTJzZVGKTBIXZEqVXEXsjkD4=" + }, + "@ngrx/store-devtools": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-5.2.0.tgz", + "integrity": "sha1-L/+RapqjSTdYJncrNZ27ZLnl1iI=" + }, "@ngstack/electron": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@ngstack/electron/-/electron-0.1.0.tgz", diff --git a/package.json b/package.json index bba3d10505..2799ebc8f4 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,10 @@ "@angular/router": "5.1.1", "@mat-datetimepicker/core": "1.0.1", "@mat-datetimepicker/moment": "1.0.1", + "@ngrx/effects": "^5.2.0", + "@ngrx/router-store": "^5.2.0", + "@ngrx/store": "^5.2.0", + "@ngrx/store-devtools": "^5.2.0", "@ngstack/electron": "0.1.0", "@ngx-translate/core": "9.1.1", "alfresco-js-api": "2.4.0-beta9", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index e1f84dca93..f2846ea89c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -30,6 +30,11 @@ import { FileModel, UploadService } from '@alfresco/adf-core'; import { ElectronService } from '@ngstack/electron'; +import { Store } from '@ngrx/store'; +import { AcaState } from './store/states/app.state'; +import { SetHeaderColorAction } from './store/actions/header-color.action'; +import { SetAppNameAction } from './store/actions/app-name.action'; +import { SetLogoPathAction } from './store/actions/logo-path.action'; @Component({ selector: 'app-root', @@ -42,7 +47,8 @@ export class AppComponent implements OnInit { private router: Router, private pageTitle: PageTitleService, preferences: UserPreferencesService, - config: AppConfigService, + private store: Store, + private config: AppConfigService, private electronService: ElectronService, private uploadService: UploadService) { // TODO: remove once ADF 2.3.0 is out (needs bug fixes) @@ -51,6 +57,9 @@ export class AppComponent implements OnInit { } ngOnInit() { + + this.loadAppSettings(); + const { router, pageTitle, route } = this; router @@ -89,4 +98,19 @@ export class AppComponent implements OnInit { } }); } + + private loadAppSettings() { + const headerColor = this.config.get('headerColor'); + if (headerColor) { + this.store.dispatch(new SetHeaderColorAction(headerColor)); + } + const appName = this.config.get('application.name'); + if (appName) { + this.store.dispatch(new SetAppNameAction(appName)); + } + const logoPath = this.config.get('application.logo'); + if (logoPath) { + this.store.dispatch(new SetLogoPathAction(logoPath)); + } + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index cef4d50fcf..8776393e88 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -32,6 +32,10 @@ import { TRANSLATION_PROVIDER, CoreModule, AppConfigService } from '@alfresco/ad import { ContentModule } from '@alfresco/adf-content-services'; import { ElectronModule } from '@ngstack/electron'; +import { StoreModule } from '@ngrx/store'; +import { EffectsModule } from '@ngrx/effects'; +import { StoreRouterConnectingModule } from '@ngrx/router-store'; + import { AppComponent } from './app.component'; import { APP_ROUTES } from './app.routes'; @@ -71,6 +75,10 @@ import { SettingsComponent } from './components/settings/settings.component'; import { HybridAppConfigService } from './common/services/hybrid-app-config.service'; import { SortingPreferenceKeyDirective } from './directives/sorting-preference-key.directive'; +import { INITIAL_STATE } from './store/states/app.state'; +import { appReducer } from './store/reducers/app.reducer'; + + @NgModule({ imports: [ BrowserModule, @@ -88,7 +96,11 @@ import { SortingPreferenceKeyDirective } from './directives/sorting-preference-k MatInputModule, CoreModule, ContentModule, - ElectronModule + ElectronModule, + + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + StoreRouterConnectingModule.forRoot({ stateKey: 'router' }), + EffectsModule.forRoot([]) ], declarations: [ AppComponent, diff --git a/src/app/components/header/header.component.html b/src/app/components/header/header.component.html index d17090b6cf..c389a6072c 100644 --- a/src/app/components/header/header.component.html +++ b/src/app/components/header/header.component.html @@ -1,4 +1,4 @@ - + @@ -100,7 +97,10 @@ [navigate]="false" [sorting]="[ 'modifiedAt', 'desc' ]" [acaSortingPreferenceKey]="sortingPreferenceKey" - (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"> + (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)"> @@ -168,39 +168,8 @@
-
- - - -
- -
- - - -
- - - - - - - -
- face - {{ 'VERSION.SELECTION.EMPTY' | translate }} -
-
-
-
+
+
diff --git a/src/app/components/favorites/favorites.component.spec.ts b/src/app/components/favorites/favorites.component.spec.ts index 22227f806c..7b5e7bf88b 100644 --- a/src/app/components/favorites/favorites.component.spec.ts +++ b/src/app/components/favorites/favorites.component.spec.ts @@ -44,10 +44,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { FavoritesComponent } from './favorites.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('Favorites Routed Component', () => { let fixture: ComponentFixture; @@ -95,14 +97,14 @@ describe('Favorites Routed Component', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, FavoritesComponent, AppConfigPipe @@ -232,56 +234,6 @@ describe('Favorites Routed Component', () => { }); }); - describe('edit option', () => { - it('should return false if a file node is selected', () => { - const selection = [ - { - entry: { - isFolder: false, - isFile: true - } - } - ]; - - const result = component.showEditOption(selection); - expect(result).toBe(false); - }); - - it('should return false if multiple nodes are selected', () => { - const selection = [ - { - entry: { - isFolder: true, - isFile: false - } - }, - { - entry: { - isFolder: true, - isFile: false - } - } - ]; - - const result = component.showEditOption(selection); - expect(result).toBe(false); - }); - - it('should return true if selected node is a folder', () => { - const selection = [ - { - entry: { - isFolder: true, - isFile: false - } - } - ]; - - const result = component.showEditOption(selection); - expect(result).toBe(true); - }); - }); - describe('refresh', () => { it('should call document list reload', () => { spyOn(component.documentList, 'reload'); diff --git a/src/app/components/favorites/favorites.component.ts b/src/app/components/favorites/favorites.component.ts index 67d8d1f92a..83e302e6b7 100644 --- a/src/app/components/favorites/favorites.component.ts +++ b/src/app/components/favorites/favorites.component.ts @@ -25,30 +25,35 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { MinimalNodeEntryEntity, MinimalNodeEntity, PathElementEntity, PathInfo } from 'alfresco-js-api'; +import { MinimalNodeEntryEntity, PathElementEntity, PathInfo } from 'alfresco-js-api'; import { ContentService, NodesApiService, UserPreferencesService, NotificationService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './favorites.component.html' }) export class FavoritesComponent extends PageComponent implements OnInit { - constructor(private router: Router, + constructor(router: Router, route: ActivatedRoute, + store: Store, private nodesApi: NodesApiService, private contentService: ContentService, private content: ContentManagementService, private notificationService: NotificationService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + this.subscriptions = this.subscriptions.concat([ this.content.nodeDeleted.subscribe(() => this.reload()), this.content.nodeRestored.subscribe(() => this.reload()), @@ -87,10 +92,6 @@ export class FavoritesComponent extends PageComponent implements OnInit { } } - showEditOption(selection: MinimalNodeEntity[]) { - return selection && selection.length === 1 && selection[0].entry.isFolder; - } - openSnackMessage(event: any) { this.notificationService.openSnackMessage( event, diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index d7de9b9023..5c50a342f4 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -6,39 +6,36 @@ (navigate)="onBreadcrumbNavigate($event)"> - + @@ -117,7 +113,9 @@ [navigate]="false" [imageResolver]="imageResolver" (node-dblclick)="onNodeDoubleClick($event)" - (node-select)="onNodeSelect($event, documentList)"> + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)">
-
- - - -
- -
- - - -
- - - - - - - -
- face - {{ 'VERSION.SELECTION.EMPTY' | translate }} -
-
-
-
+
+
diff --git a/src/app/components/files/files.component.spec.ts b/src/app/components/files/files.component.spec.ts index 220c7e91cc..bf96426283 100644 --- a/src/app/components/files/files.component.spec.ts +++ b/src/app/components/files/files.component.spec.ts @@ -46,9 +46,11 @@ import { ContentManagementService } from '../../common/services/content-manageme import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodeActionsService } from '../../common/services/node-actions.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { FilesComponent } from './files.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('FilesComponent', () => { let node; @@ -73,7 +75,8 @@ describe('FilesComponent', () => { TranslateModule.forRoot(), RouterTestingModule, MatSnackBarModule, MatIconModule, - MatDialogModule + MatDialogModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ FilesComponent, @@ -81,7 +84,6 @@ describe('FilesComponent', () => { TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, FileSizePipe, AppConfigPipe diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index 7c7e57ca46..9973f0ef26 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -38,6 +38,8 @@ import { NodeActionsService } from '../../common/services/node-actions.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './files.component.html' @@ -48,8 +50,9 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { private nodePath: PathElement[]; - constructor(private router: Router, + constructor(router: Router, route: ActivatedRoute, + store: Store, private nodesApi: NodesApiService, private nodeActionsService: NodeActionsService, private uploadService: UploadService, @@ -60,10 +63,12 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { private notificationService: NotificationService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + const { route, contentManagementService, contentService, nodeActionsService, uploadService } = this; const { data } = route.snapshot; @@ -156,14 +161,6 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { } } - showPreview(node: MinimalNodeEntryEntity) { - if (node) { - if (node.isFile) { - this.router.navigate(['./preview', node.id], { relativeTo: this.route }); - } - } - } - onBreadcrumbNavigate(route: PathElementEntity) { // todo: review this approach once 5.2.3 is out if (this.nodePath && this.nodePath.length > 2) { diff --git a/src/app/components/header/header.component.spec.ts b/src/app/components/header/header.component.spec.ts index 139ecda594..66347206ee 100644 --- a/src/app/components/header/header.component.spec.ts +++ b/src/app/components/header/header.component.spec.ts @@ -50,7 +50,7 @@ describe('HeaderComponent', () => { HttpClientModule, RouterTestingModule, TranslateModule.forRoot(), - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ HeaderComponent diff --git a/src/app/components/info-drawer/info-drawer.component.html b/src/app/components/info-drawer/info-drawer.component.html new file mode 100644 index 0000000000..99468992fe --- /dev/null +++ b/src/app/components/info-drawer/info-drawer.component.html @@ -0,0 +1,28 @@ +
+ +
+ + + + + + + + + + + + + +
+ face + {{ 'VERSION.SELECTION.EMPTY' | translate }} +
+
+
+
+
diff --git a/src/app/components/info-drawer/info-drawer.component.ts b/src/app/components/info-drawer/info-drawer.component.ts new file mode 100644 index 0000000000..df3b064f86 --- /dev/null +++ b/src/app/components/info-drawer/info-drawer.component.ts @@ -0,0 +1,94 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; +import { NodePermissionService } from '../../common/services/node-permission.service'; +import { AlfrescoApiService } from '@alfresco/adf-core'; + +@Component({ + selector: 'aca-info-drawer', + templateUrl: './info-drawer.component.html' +}) +export class InfoDrawerComponent implements OnChanges { + @Input() nodeId: string; + + @Input() node: MinimalNodeEntity; + + isLoading = false; + displayNode: MinimalNodeEntryEntity; + + canUpdateNode(): boolean { + if (this.node) { + if ((this.node.entry).nodeId) { + return this.permission.check(this.node.entry, ['update'], { + target: 'allowableOperationsOnTarget' + }); + } + return this.permission.check(this.node.entry, ['update']); + } + + return false; + } + + get isFileSelected(): boolean { + if (this.node && this.node.entry) { + return this.node.entry.isFile; + } + return false; + } + + constructor( + public permission: NodePermissionService, + private apiService: AlfrescoApiService + ) {} + + ngOnChanges(changes: SimpleChanges) { + if (this.node) { + const entry = this.node.entry; + if (entry.nodeId) { + this.loadNodeInfo(entry.nodeId); + } else { + this.displayNode = this.node.entry; + } + } + } + + private loadNodeInfo(nodeId: string) { + if (nodeId) { + this.isLoading = true; + + this.apiService.nodesApi + .getNodeInfo(nodeId, { include: ['allowableOperations'] }) + .then((entity: MinimalNodeEntryEntity) => { + this.displayNode = entity; + this.isLoading = false; + }) + .catch(() => { + this.isLoading = false; + }); + } + } +} diff --git a/src/app/components/libraries/libraries.component.html b/src/app/components/libraries/libraries.component.html index 9031c518db..0083aefba8 100644 --- a/src/app/components/libraries/libraries.component.html +++ b/src/app/components/libraries/libraries.component.html @@ -14,6 +14,9 @@ [navigate]="false" [sorting]="[ 'title', 'asc' ]" [acaSortingPreferenceKey]="sortingPreferenceKey" + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)" (node-dblclick)="onNodeDoubleClick($event)"> diff --git a/src/app/components/libraries/libraries.component.spec.ts b/src/app/components/libraries/libraries.component.spec.ts index 28ed0f3ce9..fc2e0db7f3 100644 --- a/src/app/components/libraries/libraries.component.spec.ts +++ b/src/app/components/libraries/libraries.component.spec.ts @@ -44,6 +44,9 @@ import { DocumentListService } from '@alfresco/adf-content-services'; import { ShareDataTableAdapter } from '@alfresco/adf-content-services'; import { LibrariesComponent } from './libraries.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('Libraries Routed Component', () => { let fixture: ComponentFixture; @@ -78,7 +81,8 @@ describe('Libraries Routed Component', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, diff --git a/src/app/components/libraries/libraries.component.ts b/src/app/components/libraries/libraries.component.ts index 0d66e02baa..a34c0215d1 100644 --- a/src/app/components/libraries/libraries.component.ts +++ b/src/app/components/libraries/libraries.component.ts @@ -29,6 +29,8 @@ import { NodesApiService, UserPreferencesService } from '@alfresco/adf-core'; import { ShareDataRow } from '@alfresco/adf-content-services'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './libraries.component.html' @@ -37,9 +39,10 @@ export class LibrariesComponent extends PageComponent { constructor(private nodesApi: NodesApiService, route: ActivatedRoute, - private router: Router, + store: Store, + router: Router, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } makeLibraryTooltip(library: any): string { diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index 2543ec889b..fc38e6fce6 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -24,17 +24,22 @@ */ import { PageComponent } from './page.component'; +import { MinimalNodeEntity } from 'alfresco-js-api'; class TestClass extends PageComponent { node: any; + setSelection(selection: MinimalNodeEntity[] = []) { + this.onSelectionChanged(selection); + } + constructor() { - super(null, null); + super(null, null, null, null); } } describe('PageComponent', () => { - let component; + let component: TestClass; beforeEach(() => { component = new TestClass(); @@ -56,47 +61,44 @@ describe('PageComponent', () => { describe('hasSelection()', () => { it('returns true when it has nodes selected', () => { - const hasSelection = component.hasSelection([ {}, {} ]); - expect(hasSelection).toBe(true); + component.setSelection([ + { entry: { isFile: true } }, + { entry: { isFile: true } } + ]); + expect(component.hasSelection).toBe(true); }); it('returns false when it has no selections', () => { - const hasSelection = component.hasSelection([]); - expect(hasSelection).toBe(false); + component.setSelection([]); + expect(component.hasSelection).toBe(false); }); }); - describe('isFileSelected()', () => { + describe('firstSelectedDocument', () => { it('returns true if selected node is file', () => { const selection = [ { entry: { isFile: true } } ]; - expect(component.isFileSelected(selection)).toBe(true); + component.setSelection(selection); + expect(component.firstSelectedDocument).toBe(selection[0]); }); it('returns false if selected node is folder', () => { - const selection = [ { entry: { isFolder: true } } ]; - expect(component.isFileSelected(selection)).toBe(false); - }); - - it('returns false if there are more than one selections', () => { - const selection = [ { entry: { isFile: true } }, { entry: { isFile: true } } ]; - expect(component.isFileSelected(selection)).toBe(false); + const selection = [ { entry: { isFile: false, isFolder: true } } ]; + component.setSelection(selection); + expect(component.firstSelectedDocument).toBeFalsy(); }); }); - describe('isFolderSelected()', () => { + describe('firstSelectedFolder', () => { it('returns true if selected node is folder', () => { - const selection = [ { entry: { isFolder: true } } ]; - expect(component.isFolderSelected(selection)).toBe(true); + const selection = [ { entry: { isFile: false, isFolder: true } } ]; + component.setSelection(selection); + expect(component.firstSelectedFolder).toBe(selection[0]); }); it('returns false if selected node is file', () => { - const selection = [ { entry: { isFile: true } } ]; - expect(component.isFolderSelected(selection)).toBe(false); - }); - - it('returns false if there are more than one selections', () => { - const selection = [ { entry: { isFolder: true } }, { entry: { isFolder: true } } ]; - expect(component.isFolderSelected(selection)).toBe(false); + const selection = [ { entry: { isFile: true, isFolder: false } } ]; + component.setSelection(selection); + expect(component.firstSelectedFolder).toBeFalsy(); }); }); }); diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index edcd1b1261..b2dfce3d24 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -26,11 +26,18 @@ import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco-js-api'; import { UserPreferencesService } from '@alfresco/adf-core'; import { ShareDataRow, DocumentListComponent } from '@alfresco/adf-content-services'; -import { ActivatedRoute } from '@angular/router'; -import { OnDestroy, ViewChild } from '@angular/core'; -import { Subscription } from 'rxjs/Rx'; +import { ActivatedRoute, Router } from '@angular/router'; +import { OnDestroy, ViewChild, OnInit } from '@angular/core'; +import { Subscription, Subject } from 'rxjs/Rx'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../store/states/app.state'; +import { SetSelectedNodesAction } from '../store/actions/select-nodes.action'; +import { selectedNodes } from '../store/selectors/app.selectors'; +import { takeUntil } from 'rxjs/operators'; -export abstract class PageComponent implements OnDestroy { +export abstract class PageComponent implements OnInit, OnDestroy { + + onDestroy$: Subject = new Subject(); @ViewChild(DocumentListComponent) documentList: DocumentListComponent; @@ -39,6 +46,13 @@ export abstract class PageComponent implements OnDestroy { infoDrawerOpened = false; node: MinimalNodeEntryEntity; + hasSelection = false; + firstSelectedDocument: MinimalNodeEntity; + firstSelectedFolder: MinimalNodeEntity; + firstSelectedNode: MinimalNodeEntity; + lastSelectedNode: MinimalNodeEntity; + selectedNodes: MinimalNodeEntity[]; + protected subscriptions: Subscription[] = []; get sortingPreferenceKey(): string { @@ -49,59 +63,82 @@ export abstract class PageComponent implements OnDestroy { return node.isLocked || (node.properties && node.properties['cm:lockType'] === 'READ_ONLY_LOCK'); } - constructor(protected preferences: UserPreferencesService, protected route: ActivatedRoute) { + constructor(protected preferences: UserPreferencesService, + protected router: Router, + protected route: ActivatedRoute, + protected store: Store) { + } + + ngOnInit() { + this.store + .select(selectedNodes) + .pipe(takeUntil(this.onDestroy$)) + .subscribe(selection => this.onSelectionChanged(selection)); } ngOnDestroy() { this.subscriptions.forEach(subscription => subscription.unsubscribe()); this.subscriptions = []; + this.onDestroy$.complete(); } - getParentNodeId(): string { - return this.node ? this.node.id : null; - } - - hasSelection(selection: Array): boolean { - return selection && selection.length > 0; + // Precalculates all the "static state" flags so that UI does not re-evaluate that on every tick + protected onSelectionChanged(selection: MinimalNodeEntity[] = []) { + this.selectedNodes = selection; + this.hasSelection = selection.length > 0; + + if (selection.length > 0) { + const firstNode = selection[0]; + this.firstSelectedNode = firstNode; + this.firstSelectedDocument = selection.find(entity => entity.entry.isFile); + this.firstSelectedFolder = selection.find(entity => entity.entry.isFolder); + } else { + this.firstSelectedNode = null; + this.firstSelectedDocument = null; + this.firstSelectedFolder = null; + this.lastSelectedNode = null; + this.infoDrawerOpened = false; + } } - isFileSelected(selection: Array): boolean { - if (selection && selection.length === 1) { - const entry = selection[0].entry; - - if (entry && entry.isFile) { - return true; + showPreview(node: MinimalNodeEntity) { + if (node && node.entry) { + if (node.entry.isFile) { + this.router.navigate(['./preview', node.entry.id], { relativeTo: this.route }); } } - return false; } - isFolderSelected(selection: Array): boolean { - if (selection && selection.length === 1) { - const entry = selection[0].entry; - - if (entry && entry.isFolder) { - return true; - } - } - return false; + getParentNodeId(): string { + return this.node ? this.node.id : null; } onChangePageSize(event: Pagination): void { this.preferences.paginationSize = event.maxItems; } - onNodeSelect(event, documentList) { + onNodeSelect(event: CustomEvent, documentList: DocumentListComponent) { if (!!event.detail && !!event.detail.node) { const node: MinimalNodeEntryEntity = event.detail.node.entry; if (node && PageComponent.isLockedNode(node)) { this.unSelectLockedNodes(documentList); } + + this.lastSelectedNode = event.detail.node; + this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); } } - unSelectLockedNodes(documentList) { + onDocumentListReady(event: CustomEvent, documentList: DocumentListComponent) { + this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); + } + + onNodeUnselect(event: CustomEvent, documentList: DocumentListComponent) { + this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); + } + + unSelectLockedNodes(documentList: DocumentListComponent) { documentList.selection = documentList.selection.filter(item => !PageComponent.isLockedNode(item.entry)); const dataTable = documentList.dataTable; @@ -143,6 +180,7 @@ export abstract class PageComponent implements OnDestroy { reload(): void { if (this.documentList) { this.documentList.resetSelection(); + this.store.dispatch(new SetSelectedNodesAction([])); this.documentList.reload(); } } diff --git a/src/app/components/preview/preview.component.html b/src/app/components/preview/preview.component.html index ef8420396f..666879f6e9 100644 --- a/src/app/components/preview/preview.component.html +++ b/src/app/components/preview/preview.component.html @@ -68,7 +68,7 @@ diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 635316fa95..3019f1b108 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -3,29 +3,27 @@ - + @@ -95,7 +92,9 @@ [acaSortingPreferenceKey]="sortingPreferenceKey" [imageResolver]="imageResolver" (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" - (node-select)="onNodeSelect($event, documentList)"> + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)"> @@ -156,41 +155,8 @@
-
- - - -
- -
- - - -
- - - - - - - -
- face - {{ 'VERSION.SELECTION.EMPTY' | translate }} -
-
-
-
+
+
diff --git a/src/app/components/recent-files/recent-files.component.spec.ts b/src/app/components/recent-files/recent-files.component.spec.ts index 323a5b2318..c89aa944b3 100644 --- a/src/app/components/recent-files/recent-files.component.spec.ts +++ b/src/app/components/recent-files/recent-files.component.spec.ts @@ -41,10 +41,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { RecentFilesComponent } from './recent-files.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('RecentFiles Routed Component', () => { let fixture: ComponentFixture; @@ -71,14 +73,14 @@ describe('RecentFiles Routed Component', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, RecentFilesComponent, AppConfigPipe diff --git a/src/app/components/recent-files/recent-files.component.ts b/src/app/components/recent-files/recent-files.component.ts index c771a410c0..f74895f805 100644 --- a/src/app/components/recent-files/recent-files.component.ts +++ b/src/app/components/recent-files/recent-files.component.ts @@ -31,6 +31,8 @@ import { UserPreferencesService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { PageComponent } from '../page.component'; import { NodePermissionService } from '../../common/services/node-permission.service'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './recent-files.component.html' @@ -38,15 +40,18 @@ import { NodePermissionService } from '../../common/services/node-permission.ser export class RecentFilesComponent extends PageComponent implements OnInit { constructor( - private router: Router, + router: Router, route: ActivatedRoute, + store: Store, private content: ContentManagementService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + this.subscriptions = this.subscriptions.concat([ this.content.nodeDeleted.subscribe(() => this.reload()), this.content.nodeMoved.subscribe(() => this.reload()), diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 15beb27c8f..41c8c843ef 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -3,28 +3,25 @@ - + @@ -100,7 +96,10 @@ selectionMode="multiple" [sorting]="[ 'modifiedAt', 'desc' ]" [acaSortingPreferenceKey]="sortingPreferenceKey" - (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"> + (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)"> @@ -173,41 +172,8 @@
-
- - - -
- -
- - - -
- - - - - - - -
- face - {{ 'VERSION.SELECTION.EMPTY' | translate }} -
-
-
-
+
+
diff --git a/src/app/components/shared-files/shared-files.component.spec.ts b/src/app/components/shared-files/shared-files.component.spec.ts index 730702330f..ab1c3a15ad 100644 --- a/src/app/components/shared-files/shared-files.component.spec.ts +++ b/src/app/components/shared-files/shared-files.component.spec.ts @@ -41,10 +41,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { SharedFilesComponent } from './shared-files.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('SharedFilesComponent', () => { let fixture: ComponentFixture; @@ -73,14 +75,14 @@ describe('SharedFilesComponent', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, SharedFilesComponent, AppConfigPipe diff --git a/src/app/components/shared-files/shared-files.component.ts b/src/app/components/shared-files/shared-files.component.ts index f6c7cc5a4e..e238068788 100644 --- a/src/app/components/shared-files/shared-files.component.ts +++ b/src/app/components/shared-files/shared-files.component.ts @@ -31,22 +31,27 @@ import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './shared-files.component.html' }) export class SharedFilesComponent extends PageComponent implements OnInit { - constructor(private router: Router, + constructor(router: Router, route: ActivatedRoute, + store: Store, private content: ContentManagementService, private apiService: AlfrescoApiService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + this.subscriptions = this.subscriptions.concat([ this.content.nodeDeleted.subscribe(() => this.reload()), this.content.nodeMoved.subscribe(() => this.reload()), @@ -65,9 +70,4 @@ export class SharedFilesComponent extends PageComponent implements OnInit { ); } } - - /** @override */ - isFileSelected(selection: Array): boolean { - return selection && selection.length === 1; - } } diff --git a/src/app/components/sidenav/sidenav.component.spec.ts b/src/app/components/sidenav/sidenav.component.spec.ts index 4d48dbca59..73df9f2fbb 100644 --- a/src/app/components/sidenav/sidenav.component.spec.ts +++ b/src/app/components/sidenav/sidenav.component.spec.ts @@ -32,13 +32,14 @@ import { HttpClientModule } from '@angular/common/http'; import { AppConfigService, AuthenticationService, UserPreferencesService, StorageService, AlfrescoApiService, - CookieService, LogService, NotificationService + CookieService, LogService, NotificationService, TranslationService, TranslationMock } from '@alfresco/adf-core'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { SidenavComponent } from './sidenav.component'; import { ElectronModule } from '@ngstack/electron'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; describe('SidenavComponent', () => { let fixture; @@ -58,6 +59,7 @@ describe('SidenavComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ + NoopAnimationsModule, HttpClientModule, MatMenuModule, MatSnackBarModule, @@ -69,6 +71,7 @@ describe('SidenavComponent', () => { SidenavComponent ], providers: [ + { provide: TranslationService, useClass: TranslationMock }, LogService, CookieService, AlfrescoApiService, diff --git a/src/app/components/trashcan/trashcan.component.html b/src/app/components/trashcan/trashcan.component.html index 12775a8517..e792b078f0 100644 --- a/src/app/components/trashcan/trashcan.component.html +++ b/src/app/components/trashcan/trashcan.component.html @@ -3,13 +3,12 @@ - + @@ -18,8 +17,7 @@ color="primary" mat-icon-button (selection-node-restored)="reload()" - [acaRestoreNode]="documentList.selection" - *ngIf="documentList.selection.length" + [acaRestoreNode]="selectedNodes" title="{{ 'APP.ACTIONS.RESTORE' | translate }}"> restore @@ -33,7 +31,10 @@ selectionMode="multiple" [navigate]="false" [sorting]="[ 'archivedAt', 'desc' ]" - [acaSortingPreferenceKey]="sortingPreferenceKey"> + [acaSortingPreferenceKey]="sortingPreferenceKey" + (ready)="onDocumentListReady($event, documentList)" + (node-select)="onNodeSelect($event, documentList)" + (node-unselect)="onNodeUnselect($event, documentList)"> diff --git a/src/app/components/trashcan/trashcan.component.spec.ts b/src/app/components/trashcan/trashcan.component.spec.ts index 7ba36264a6..d646e10e16 100644 --- a/src/app/components/trashcan/trashcan.component.spec.ts +++ b/src/app/components/trashcan/trashcan.component.spec.ts @@ -40,9 +40,11 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodeInfoDirective } from '../../common/directives/node-info.directive'; import { TrashcanComponent } from './trashcan.component'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; describe('TrashcanComponent', () => { let fixture: ComponentFixture; @@ -68,14 +70,14 @@ describe('TrashcanComponent', () => { HttpClientModule, TranslateModule.forRoot(), RouterTestingModule, - MatSnackBarModule, MatIconModule + MatSnackBarModule, MatIconModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, - NodeInfoDirective, DocumentListComponent, TrashcanComponent, AppConfigPipe diff --git a/src/app/components/trashcan/trashcan.component.ts b/src/app/components/trashcan/trashcan.component.ts index 542a1dec0b..37ccdbf5b4 100644 --- a/src/app/components/trashcan/trashcan.component.ts +++ b/src/app/components/trashcan/trashcan.component.ts @@ -24,11 +24,13 @@ */ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { Pagination } from 'alfresco-js-api'; import { UserPreferencesService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AcaState } from '../../store/states/app.state'; @Component({ templateUrl: './trashcan.component.html' @@ -37,11 +39,15 @@ export class TrashcanComponent extends PageComponent implements OnInit { constructor(private contentManagementService: ContentManagementService, preferences: UserPreferencesService, + store: Store, + router: Router, route: ActivatedRoute) { - super(preferences, route); + super(preferences, router, route, store); } ngOnInit() { + super.ngOnInit(); + this.subscriptions.push( this.contentManagementService.nodeRestored.subscribe(() => this.reload()) ); diff --git a/src/app/store/actions/select-nodes.action.ts b/src/app/store/actions/select-nodes.action.ts new file mode 100644 index 0000000000..1e0646fd5c --- /dev/null +++ b/src/app/store/actions/select-nodes.action.ts @@ -0,0 +1,8 @@ +import { Action } from '@ngrx/store'; + +export const SET_SELECTED_NODES = 'SET_SELECTED_NODES'; + +export class SetSelectedNodesAction implements Action { + readonly type = SET_SELECTED_NODES; + constructor(public payload: any[] = []) {} +} diff --git a/src/app/store/reducers/app.reducer.ts b/src/app/store/reducers/app.reducer.ts index 48fa50df3c..d12eae6ea3 100644 --- a/src/app/store/reducers/app.reducer.ts +++ b/src/app/store/reducers/app.reducer.ts @@ -3,6 +3,7 @@ import { AppState, INITIAL_APP_STATE } from '../states/app.state'; import { SET_HEADER_COLOR, SetHeaderColorAction } from '../actions/header-color.action'; import { SET_APP_NAME, SetAppNameAction } from '../actions/app-name.action'; import { SET_LOGO_PATH, SetLogoPathAction } from '../actions/logo-path.action'; +import { SET_SELECTED_NODES, SetSelectedNodesAction } from '../actions/select-nodes.action'; export function appReducer(state: AppState = INITIAL_APP_STATE, action: Action): AppState { @@ -18,6 +19,9 @@ export function appReducer(state: AppState = INITIAL_APP_STATE, action: Action): case SET_LOGO_PATH: newState = updateLogoPath(state, action); break; + case SET_SELECTED_NODES: + newState = updateSelectedNodes(state, action); + break; default: newState = Object.assign({}, state); } @@ -42,3 +46,9 @@ function updateLogoPath(state: AppState, action: SetLogoPathAction): AppState { newState.logoPath = action.payload; return newState; } + +function updateSelectedNodes(state: AppState, action: SetSelectedNodesAction): AppState { + const newState = Object.assign({}, state); + newState.selectedNodes = [...action.payload]; + return newState; +} diff --git a/src/app/store/selectors/app.selectors.ts b/src/app/store/selectors/app.selectors.ts index 52e6a81f3c..d495887668 100644 --- a/src/app/store/selectors/app.selectors.ts +++ b/src/app/store/selectors/app.selectors.ts @@ -5,3 +5,4 @@ export const selectApp = (state: AcaState) => state.app; export const selectHeaderColor = createSelector(selectApp, (state: AppState) => state.headerColor); export const selectAppName = createSelector(selectApp, (state: AppState) => state.appName); export const selectLogoPath = createSelector(selectApp, (state: AppState) => state.logoPath); +export const selectedNodes = createSelector(selectApp, (state: AppState) => state.selectedNodes); diff --git a/src/app/store/states/app.state.ts b/src/app/store/states/app.state.ts index 75fcd165dc..370e2c78e0 100644 --- a/src/app/store/states/app.state.ts +++ b/src/app/store/states/app.state.ts @@ -1,13 +1,17 @@ +import { MinimalNodeEntity } from 'alfresco-js-api'; + export interface AppState { appName: string; headerColor: string; logoPath: string; + selectedNodes: MinimalNodeEntity[]; } export const INITIAL_APP_STATE: AppState = { appName: 'Alfresco Example Content Application', headerColor: '#2196F3', - logoPath: 'assets/images/alfresco-logo-white.svg' + logoPath: 'assets/images/alfresco-logo-white.svg', + selectedNodes: [] }; export interface AcaState { diff --git a/tslint.json b/tslint.json index 34eed5a450..b43b9774e4 100644 --- a/tslint.json +++ b/tslint.json @@ -122,7 +122,7 @@ "component-selector": [ true, "element", - "app", + [ "app", "aca"], "kebab-case" ], "use-input-property-decorator": true, From f30bb86a6eb3bc461e8410eacb657a0b69173981 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 6 Jun 2018 14:53:56 +0300 Subject: [PATCH 063/179] search sort options (#386) --- src/app.config.json | 35 ++++++++++++++++++++++++++++------- src/assets/i18n/en.json | 8 ++++++++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/app.config.json b/src/app.config.json index 0fb20094c0..476d72c495 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -162,33 +162,54 @@ "include": ["path", "allowableOperations"], "sorting": { "options": [ + { + "key": "score", + "label": "SEARCH.SORT.RELEVANCE", + "type": "FIELD", + "field": "score", + "ascending": true + }, { "key": "name", - "label": "Name", + "label": "SEARCH.SORT.FILENAME", "type": "FIELD", "field": "cm:name", "ascending": true }, + { + "key": "title", + "label": "SEARCH.SORT.TITLE", + "type": "FIELD", + "field": "cm:title", + "ascending": true + }, + { + "key": "modified", + "label": "SEARCH.SORT.MODIFIED_DATE", + "type": "FIELD", + "field": "cm:modified", + "ascending": true + }, { "key": "content.sizeInBytes", - "label": "Size", + "label": "SEARCH.SORT.SIZE", "type": "FIELD", "field": "content.size", "ascending": true }, { - "key": "description", - "label": "Description", + "key": "content.mimetype", + "label": "SEARCH.SORT.TYPE", "type": "FIELD", - "field": "cm:description", + "field": "content.mimetype", "ascending": true } ], "defaults": [ { - "key": "name", + "key": "score", "type": "FIELD", - "field": "cm:name", + "field": "score", "ascending": true } ] diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 8697776863..988f46999b 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -236,6 +236,14 @@ } }, "SEARCH": { + "SORT": { + "RELEVANCE": "Relevance", + "FILENAME": "Filename", + "TITLE": "Title", + "MODIFIED_DATE": "Modified Date", + "SIZE": "Size", + "TYPE": "Type" + }, "FACET_FIELDS": { "FILE_TYPE": "File Type", "CREATOR": "Creator", From 1bf897639ca1acfdd476abf007e162bbba7f6cfe Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 6 Jun 2018 14:06:23 +0100 Subject: [PATCH 064/179] fix toolbar test --- e2e/suites/actions/toolbar-single-selection.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/suites/actions/toolbar-single-selection.test.ts b/e2e/suites/actions/toolbar-single-selection.test.ts index 5404e40622..3d163eb3bf 100755 --- a/e2e/suites/actions/toolbar-single-selection.test.ts +++ b/e2e/suites/actions/toolbar-single-selection.test.ts @@ -260,7 +260,7 @@ describe('Toolbar actions - single selection : ', () => { .then(() => dataTable.waitForHeader()) .then(() => dataTable.selectMultipleItems([ file1, file2 ])) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for selected files`); + expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for selected files`); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for selected files`); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for selected files`); }) From 15dff74eeacc2fc768b460e3b9b95e5618a2ede7 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 7 Jun 2018 13:32:51 +0100 Subject: [PATCH 065/179] use port 4000 for e2e runs (#387) * use port 4000 for e2e runs * upgrade to latest node images * Revert "upgrade to latest node images" This reverts commit 88177f508468f7f9b7d07c388785df1a5c30e27e. * disable the deletion test for now --- docker-compose.yml | 4 ++-- e2e/suites/actions/delete.test.ts | 3 ++- package.json | 2 +- protractor.conf.js | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 720c0b1def..a05cc08912 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -72,7 +72,7 @@ services: networks: - internal ports: - - 3001:80 + - 4001:80 # volumes: # - ./app.config.json:/usr/share/nginx/html/app.config.json # - ./nginx.conf:/etc/nginx/conf.d/default.conf @@ -86,7 +86,7 @@ services: networks: - internal ports: - - 3000:80 + - 4000:80 networks: internal: diff --git a/e2e/suites/actions/delete.test.ts b/e2e/suites/actions/delete.test.ts index bb0bf1564f..f3a7b4c2f8 100755 --- a/e2e/suites/actions/delete.test.ts +++ b/e2e/suites/actions/delete.test.ts @@ -189,7 +189,8 @@ describe('Delete content', () => { .then(() => apis.user.trashcan.restore(file1Id)); }); - it('Notification on multiple items deletion - all items fail to delete', () => { + // TODO: needs to operate on two folders containing locked items + xit('Notification on multiple items deletion - all items fail to delete', () => { dataTable.selectMultipleItems([fileLocked1, folder2]) .then(() => toolbar.actions.openMoreMenu()) .then(() => toolbar.actions.menu.clickMenuItem('Delete')) diff --git a/package.json b/package.json index ff5d8ffcdd..1d5c6a9f28 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "_e2e": "ng e2e", "wd:update": "webdriver-manager update --gecko=false --versions.chrome=2.38", "e2e": "npm run wd:update && protractor protractor.conf.js", - "start:docker": "docker-compose up -d --build && wait-on http://localhost:8080 && wait-on http://localhost:3000", + "start:docker": "docker-compose up -d --build && wait-on http://localhost:8080 && wait-on http://localhost:4000", "stop:docker": "docker-compose stop", "e2e:docker": "npm run start:docker && npm run e2e && npm run stop:docker", "spellcheck": "cspell 'src/**/*.ts' 'e2e/**/*.ts'" diff --git a/protractor.conf.js b/protractor.conf.js index 3971e2d2cd..6b6fbb0d47 100755 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -34,7 +34,7 @@ exports.config = { directConnect: true, - baseUrl: 'http://localhost:3000', + baseUrl: 'http://localhost:4000', framework: 'jasmine2', jasmineNodeOpts: { From 952c541a9a9570a244b8b1b36812063490acec43 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 7 Jun 2018 15:46:05 +0300 Subject: [PATCH 066/179] input as MinimalNodeEntryEntity (#388) --- src/app/common/directives/node-versions.directive.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/common/directives/node-versions.directive.ts b/src/app/common/directives/node-versions.directive.ts index 6b8551dab8..367eb31c47 100644 --- a/src/app/common/directives/node-versions.directive.ts +++ b/src/app/common/directives/node-versions.directive.ts @@ -68,6 +68,8 @@ export class NodeVersionsDirective { } else { this.openVersionManagerDialog(entry); } + } else if (this.node) { + this.openVersionManagerDialog(this.node); } } From f73f99ccf2592728d970fa73a8befcd688b9d1ee Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 7 Jun 2018 15:13:47 +0100 Subject: [PATCH 067/179] upgrade libs and code (#389) --- package-lock.json | 14 +++++++------- package.json | 4 ++-- .../components/favorites/favorites.component.html | 1 + src/app/components/files/files.component.html | 1 + .../components/libraries/libraries.component.html | 1 + .../recent-files/recent-files.component.html | 1 + .../shared-files/shared-files.component.html | 1 + .../components/trashcan/trashcan.component.html | 1 + 8 files changed, 15 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 76829abc04..ceb989c3eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-24b573b08f3a072327efefc0196bd949cbca3766.tgz", - "integrity": "sha512-5B/JHEsCdvksEP16TyS5yHtOT/zCOLj7uHS8lqGhu7Z20Cj5K7RTBwco4flTh3T8OSyoUBzdmp3HQgfqJk/QrQ==", + "version": "2.4.0-cb70c034d2deb86eff5b0c6a4ab347a89f6f6abc", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-cb70c034d2deb86eff5b0c6a4ab347a89f6f6abc.tgz", + "integrity": "sha512-1XRjWbVFBsCJ1WHC5iSaHq1rZmJYsqK6Kk4VTDYdu5rMam0XOurth4maE4izGWgLPJYDHb+HiwVdLUHP7MQ1kw==", "requires": { - "@alfresco/adf-core": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", + "@alfresco/adf-core": "2.4.0-cb70c034d2deb86eff5b0c6a4ab347a89f6f6abc", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -61,9 +61,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-24b573b08f3a072327efefc0196bd949cbca3766.tgz", - "integrity": "sha512-vDC4Wz+j6uSEMzdZUhy5xB0Sm63brb360o+uiPXs0uMyL9agMEh5wUPAl4Zfic0alnlww8OGADA8r6sFwb7HhQ==", + "version": "2.4.0-cb70c034d2deb86eff5b0c6a4ab347a89f6f6abc", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-cb70c034d2deb86eff5b0c6a4ab347a89f6f6abc.tgz", + "integrity": "sha512-QrZuiDVWfZ6V7SshJNl2sOvdEv3qW08hW3lp0crhLNe95zELesOouiIMj0GgEwHMA0evZtRM7NE8JOaHBd8wDg==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", diff --git a/package.json b/package.json index 1d5c6a9f28..5175f46854 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", - "@alfresco/adf-core": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766", + "@alfresco/adf-content-services": "2.4.0-cb70c034d2deb86eff5b0c6a4ab347a89f6f6abc", + "@alfresco/adf-core": "2.4.0-cb70c034d2deb86eff5b0c6a4ab347a89f6f6abc", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 5d7e66beaf..990035274a 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -93,6 +93,7 @@
Date: Fri, 8 Jun 2018 21:07:43 +0100 Subject: [PATCH 068/179] [ACA-1439] Resolve multi-select issues (#392) * toolbar enhancements * code cleanup --- .../favorites/favorites.component.html | 12 ++++++------ src/app/components/files/files.component.html | 12 ++++++------ src/app/components/page.component.spec.ts | 12 ++++++------ src/app/components/page.component.ts | 19 +++++++++---------- .../recent-files/recent-files.component.html | 8 ++++---- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 990035274a..6a50e94481 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -8,9 +8,9 @@ @@ -25,10 +25,10 @@ @@ -81,8 +81,8 @@ diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index ba77cd66d5..e4a41e09bf 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -10,9 +10,9 @@ @@ -27,10 +27,10 @@ @@ -85,8 +85,8 @@ diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index fc38e6fce6..f46fe39663 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -74,31 +74,31 @@ describe('PageComponent', () => { }); }); - describe('firstSelectedDocument', () => { + describe('selectedFile', () => { it('returns true if selected node is file', () => { const selection = [ { entry: { isFile: true } } ]; component.setSelection(selection); - expect(component.firstSelectedDocument).toBe(selection[0]); + expect(component.selectedFile).toBe(selection[0]); }); it('returns false if selected node is folder', () => { const selection = [ { entry: { isFile: false, isFolder: true } } ]; component.setSelection(selection); - expect(component.firstSelectedDocument).toBeFalsy(); + expect(component.selectedFile).toBeFalsy(); }); }); - describe('firstSelectedFolder', () => { + describe('selectedFolder', () => { it('returns true if selected node is folder', () => { const selection = [ { entry: { isFile: false, isFolder: true } } ]; component.setSelection(selection); - expect(component.firstSelectedFolder).toBe(selection[0]); + expect(component.selectedFolder).toBe(selection[0]); }); it('returns false if selected node is file', () => { const selection = [ { entry: { isFile: true, isFolder: false } } ]; component.setSelection(selection); - expect(component.firstSelectedFolder).toBeFalsy(); + expect(component.selectedFolder).toBeFalsy(); }); }); }); diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index b2dfce3d24..296c4a478a 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -46,10 +46,10 @@ export abstract class PageComponent implements OnInit, OnDestroy { infoDrawerOpened = false; node: MinimalNodeEntryEntity; + selectedFolder: MinimalNodeEntity; + selectedFile: MinimalNodeEntity; + hasSelection = false; - firstSelectedDocument: MinimalNodeEntity; - firstSelectedFolder: MinimalNodeEntity; - firstSelectedNode: MinimalNodeEntity; lastSelectedNode: MinimalNodeEntity; selectedNodes: MinimalNodeEntity[]; @@ -86,16 +86,15 @@ export abstract class PageComponent implements OnInit, OnDestroy { protected onSelectionChanged(selection: MinimalNodeEntity[] = []) { this.selectedNodes = selection; this.hasSelection = selection.length > 0; + this.selectedFolder = null; + this.selectedFile = null; if (selection.length > 0) { - const firstNode = selection[0]; - this.firstSelectedNode = firstNode; - this.firstSelectedDocument = selection.find(entity => entity.entry.isFile); - this.firstSelectedFolder = selection.find(entity => entity.entry.isFolder); + if (selection.length === 1) { + this.selectedFile = selection.find(entity => entity.entry.isFile); + this.selectedFolder = selection.find(entity => entity.entry.isFolder); + } } else { - this.firstSelectedNode = null; - this.firstSelectedDocument = null; - this.firstSelectedFolder = null; this.lastSelectedNode = null; this.infoDrawerOpened = false; } diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index c964cc1750..a868fd498e 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -8,9 +8,9 @@ @@ -73,8 +73,8 @@ From 1bd50287a1543b58d655ea77f602d165fdaa033f Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 8 Jun 2018 21:31:00 +0100 Subject: [PATCH 069/179] update e2e tests according to the toolbar changes View button tests will be reviewed in the future once new "cycling through the selection" is introduced --- .../toolbar-multiple-selection.test.ts | 39 ++++++++++++------- .../actions/toolbar-single-selection.test.ts | 2 +- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/e2e/suites/actions/toolbar-multiple-selection.test.ts b/e2e/suites/actions/toolbar-multiple-selection.test.ts index a717626dbb..4bd05d0378 100755 --- a/e2e/suites/actions/toolbar-multiple-selection.test.ts +++ b/e2e/suites/actions/toolbar-multiple-selection.test.ts @@ -161,8 +161,14 @@ describe('Toolbar actions - multiple selection : ', () => { .then(() => dataTable.clearSelection()); }); - it('should display View action when at least one file selected', async () => { + it('should not display View action when multiple entries selected', async () => { await dataTable.selectMultipleItems([folder1, file1, folder2]); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'Action is displayed'); + }); + + + it('should display View action when one file is selected', async () => { + await dataTable.selectMultipleItems([file1]); expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'Action is not displayed'); }); @@ -182,11 +188,16 @@ describe('Toolbar actions - multiple selection : ', () => { expect(toolbar.actions.isButtonPresent('Download')).toBe(false, 'Action is displayed'); }); - it('should display Edit action when at least one folder selected', async () => { - await dataTable.selectMultipleItems([folder1, file1, folder2]); + it('should display Edit action when single folder selected', async () => { + await dataTable.selectMultipleItems([folder1]); expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Action is not displayed'); }); + it('should not display Edit action when multiple folders selected', async () => { + await dataTable.selectMultipleItems([folder1, file1, folder2]); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Action is displayed'); + }); + it('should not display Edit action if no folders selected', async () => { await dataTable.selectMultipleItems([file1, file2]); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Action is displayed'); @@ -244,7 +255,7 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1Admin, file2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); }) @@ -265,7 +276,7 @@ describe('Toolbar actions - multiple selection : ', () => { .then(() => { expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { @@ -282,9 +293,9 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when both files and folders are selected', () => { dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { @@ -311,7 +322,7 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1Admin, file2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed for selected files'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); }) @@ -349,7 +360,7 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when both files and folders are selected', () => { dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) @@ -385,7 +396,7 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1, file2]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files'); }) @@ -455,7 +466,7 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1, file2]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) @@ -476,7 +487,7 @@ describe('Toolbar actions - multiple selection : ', () => { .then(() => { expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { @@ -493,9 +504,9 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when both files and folders are selected', () => { dataTable.selectMultipleItems([file1, file2, folder1, folder2]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files'); - expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed'); + expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) .then(() => toolbar.actions.openMoreMenu()) .then(menu => { diff --git a/e2e/suites/actions/toolbar-single-selection.test.ts b/e2e/suites/actions/toolbar-single-selection.test.ts index 3d163eb3bf..5404e40622 100755 --- a/e2e/suites/actions/toolbar-single-selection.test.ts +++ b/e2e/suites/actions/toolbar-single-selection.test.ts @@ -260,7 +260,7 @@ describe('Toolbar actions - single selection : ', () => { .then(() => dataTable.waitForHeader()) .then(() => dataTable.selectMultipleItems([ file1, file2 ])) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(true, `View is not displayed for selected files`); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, `View is displayed for selected files`); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, `Download is not displayed for selected files`); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, `Edit is displayed for selected files`); }) From eefba093521185af357b1c53be438450fbde207e Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sat, 9 Jun 2018 07:05:18 +0100 Subject: [PATCH 070/179] update tests --- e2e/suites/actions/toolbar-multiple-selection.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/suites/actions/toolbar-multiple-selection.test.ts b/e2e/suites/actions/toolbar-multiple-selection.test.ts index 4bd05d0378..56c39453b5 100755 --- a/e2e/suites/actions/toolbar-multiple-selection.test.ts +++ b/e2e/suites/actions/toolbar-multiple-selection.test.ts @@ -431,7 +431,7 @@ describe('Toolbar actions - multiple selection : ', () => { it('correct actions appear when multiple files are selected', () => { dataTable.selectMultipleItems([file1, file2]) .then(() => { - expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed'); + expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed'); expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed'); expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed'); }) From 1ac85c0149d817cfd0ca92786bbaf064249eb08a Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sat, 9 Jun 2018 07:36:23 +0100 Subject: [PATCH 071/179] update test --- src/app/components/shared-files/shared-files.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index cad70b4eb8..2ed6862e9b 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -5,6 +5,7 @@ @@ -98,7 +97,7 @@ [navigate]="false" [sorting]="[ 'modifiedAt', 'desc' ]" [acaSortingPreferenceKey]="sortingPreferenceKey" - (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" + (node-dblclick)="onNodeDoubleClick($event.detail?.node)" (ready)="onDocumentListReady($event, documentList)" (node-select)="onNodeSelect($event, documentList)" (node-unselect)="onNodeUnselect($event, documentList)"> diff --git a/src/app/components/favorites/favorites.component.spec.ts b/src/app/components/favorites/favorites.component.spec.ts index 7b5e7bf88b..806666799f 100644 --- a/src/app/components/favorites/favorites.component.spec.ts +++ b/src/app/components/favorites/favorites.component.spec.ts @@ -51,14 +51,12 @@ import { StoreModule } from '@ngrx/store'; import { appReducer } from '../../store/reducers/app.reducer'; import { INITIAL_STATE } from '../../store/states/app.state'; -describe('Favorites Routed Component', () => { +describe('FavoritesComponent', () => { let fixture: ComponentFixture; let component: FavoritesComponent; let nodesApi: NodesApiService; let alfrescoApi: AlfrescoApiService; - let alfrescoContentService: ContentService; let contentService: ContentManagementService; - let notificationService: NotificationService; let router: Router; let page; let node; @@ -132,10 +130,8 @@ describe('Favorites Routed Component', () => { component = fixture.componentInstance; nodesApi = TestBed.get(NodesApiService); - notificationService = TestBed.get(NotificationService); alfrescoApi = TestBed.get(AlfrescoApiService); alfrescoApi.reset(); - alfrescoContentService = TestBed.get(ContentService); contentService = TestBed.get(ContentManagementService); router = TestBed.get(Router); }); @@ -152,25 +148,25 @@ describe('Favorites Routed Component', () => { }); it('should refresh on editing folder event', () => { - alfrescoContentService.folderEdit.next(null); + contentService.folderEdited.next(null); expect(component.reload).toHaveBeenCalled(); }); it('should refresh on move node event', () => { - contentService.nodeMoved.next(null); + contentService.nodesMoved.next(null); expect(component.reload).toHaveBeenCalled(); }); it('should refresh on node deleted event', () => { - contentService.nodeDeleted.next(null); + contentService.nodesDeleted.next(null); expect(component.reload).toHaveBeenCalled(); }); it('should refresh on node restore event', () => { - contentService.nodeRestored.next(null); + contentService.nodesRestored.next(null); expect(component.reload).toHaveBeenCalled(); }); @@ -218,7 +214,7 @@ describe('Favorites Routed Component', () => { node.isFolder = true; spyOn(router, 'navigate'); - component.onNodeDoubleClick(node); + component.onNodeDoubleClick({ entry: node }); expect(router.navigate).toHaveBeenCalled(); }); @@ -228,7 +224,7 @@ describe('Favorites Routed Component', () => { node.isFile = true; spyOn(router, 'navigate').and.stub(); - component.onNodeDoubleClick(node); + component.onNodeDoubleClick({ entry: node }); expect(router.navigate['calls'].argsFor(0)[0]).toEqual(['./preview', 'folder-node']); }); @@ -244,16 +240,4 @@ describe('Favorites Routed Component', () => { expect(component.documentList.reload).toHaveBeenCalled(); }); }); - - describe('openSnackMessage', () => { - it('should call notification service', () => { - const message = 'notification message'; - - spyOn(notificationService, 'openSnackMessage'); - - component.openSnackMessage(message); - - expect(notificationService.openSnackMessage).toHaveBeenCalledWith(message, 4000); - }); - }); }); diff --git a/src/app/components/favorites/favorites.component.ts b/src/app/components/favorites/favorites.component.ts index e2083f7745..5754f7f650 100644 --- a/src/app/components/favorites/favorites.component.ts +++ b/src/app/components/favorites/favorites.component.ts @@ -25,8 +25,8 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { MinimalNodeEntryEntity, PathElementEntity, PathInfo } from 'alfresco-js-api'; -import { ContentService, NodesApiService, UserPreferencesService, NotificationService } from '@alfresco/adf-core'; +import { MinimalNodeEntryEntity, PathElementEntity, PathInfo, MinimalNodeEntity } from 'alfresco-js-api'; +import { NodesApiService, UserPreferencesService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; @@ -43,9 +43,7 @@ export class FavoritesComponent extends PageComponent implements OnInit { route: ActivatedRoute, store: Store, private nodesApi: NodesApiService, - private contentService: ContentService, private content: ContentManagementService, - private notificationService: NotificationService, public permission: NodePermissionService, preferences: UserPreferencesService) { super(preferences, router, route, store); @@ -55,10 +53,10 @@ export class FavoritesComponent extends PageComponent implements OnInit { super.ngOnInit(); this.subscriptions = this.subscriptions.concat([ - this.content.nodeDeleted.subscribe(() => this.reload()), - this.content.nodeRestored.subscribe(() => this.reload()), - this.contentService.folderEdit.subscribe(() => this.reload()), - this.content.nodeMoved.subscribe(() => this.reload()) + this.content.nodesDeleted.subscribe(() => this.reload()), + this.content.nodesRestored.subscribe(() => this.reload()), + this.content.folderEdited.subscribe(() => this.reload()), + this.content.nodesMoved.subscribe(() => this.reload()) ]); } @@ -80,22 +78,13 @@ export class FavoritesComponent extends PageComponent implements OnInit { } } - onNodeDoubleClick(node: MinimalNodeEntryEntity) { - if (node) { - if (node.isFolder) { - this.navigate(node); + onNodeDoubleClick(node: MinimalNodeEntity) { + if (node && node.entry) { + if (node.entry.isFolder) { + this.navigate(node.entry); } - if (node.isFile) { - this.router.navigate(['./preview', node.id], { relativeTo: this.route }); - } + this.showPreview(node); } } - - openSnackMessage(event: any) { - this.notificationService.openSnackMessage( - event, - 4000 - ); - } } diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index e4a41e09bf..126c867ffd 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -28,9 +28,8 @@ color="primary" mat-icon-button *ngIf="selectedFolder && permission.check(selectedFolder, ['update'])" - [attr.title]="'APP.ACTIONS.EDIT' | translate" - (error)="openSnackMessage($event)" - [adf-edit-folder]="selectedFolder?.entry"> + title="{{ 'APP.ACTIONS.EDIT' | translate }}" + [acaEditFolder]="selectedFolder"> create diff --git a/src/app/components/files/files.component.spec.ts b/src/app/components/files/files.component.spec.ts index bf96426283..9b05e2b0bf 100644 --- a/src/app/components/files/files.component.spec.ts +++ b/src/app/components/files/files.component.spec.ts @@ -58,13 +58,11 @@ describe('FilesComponent', () => { let fixture; let component: FilesComponent; let contentManagementService: ContentManagementService; - let alfrescoContentService: ContentService; let uploadService: UploadService; let nodesApi: NodesApiService; let router: Router; let browsingFilesService: BrowsingFilesService; let nodeActionsService: NodeActionsService; - let notificationService: NotificationService; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -122,9 +120,7 @@ describe('FilesComponent', () => { uploadService = TestBed.get(UploadService); nodesApi = TestBed.get(NodesApiService); router = TestBed.get(Router); - alfrescoContentService = TestBed.get(ContentService); browsingFilesService = TestBed.get(BrowsingFilesService); - notificationService = TestBed.get(NotificationService); nodeActionsService = TestBed.get(NodeActionsService); }); })); @@ -243,31 +239,31 @@ describe('FilesComponent', () => { }); it('should call refresh onCreateFolder event', () => { - alfrescoContentService.folderCreate.next(); + contentManagementService.folderCreated.next(); expect(component.documentList.reload).toHaveBeenCalled(); }); it('should call refresh editFolder event', () => { - alfrescoContentService.folderEdit.next(); + contentManagementService.folderEdited.next(); expect(component.documentList.reload).toHaveBeenCalled(); }); it('should call refresh deleteNode event', () => { - contentManagementService.nodeDeleted.next(); + contentManagementService.nodesDeleted.next(); expect(component.documentList.reload).toHaveBeenCalled(); }); it('should call refresh moveNode event', () => { - contentManagementService.nodeMoved.next(); + contentManagementService.nodesMoved.next(); expect(component.documentList.reload).toHaveBeenCalled(); }); it('should call refresh restoreNode event', () => { - contentManagementService.nodeRestored.next(); + contentManagementService.nodesRestored.next(); expect(component.documentList.reload).toHaveBeenCalled(); }); @@ -453,16 +449,4 @@ describe('FilesComponent', () => { expect(component.isSiteContainer(mock)).toBe(true); }); }); - - describe('openSnackMessage', () => { - it('should call notification service', () => { - const message = 'notification message'; - - spyOn(notificationService, 'openSnackMessage'); - - component.openSnackMessage(message); - - expect(notificationService.openSnackMessage).toHaveBeenCalledWith(message, 4000); - }); - }); }); diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index b1cd8e1ec3..0e1b4e5837 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -29,7 +29,7 @@ import { Router, ActivatedRoute, Params } from '@angular/router'; import { MinimalNodeEntity, MinimalNodeEntryEntity, PathElementEntity, NodePaging, PathElement } from 'alfresco-js-api'; import { UploadService, FileUploadEvent, NodesApiService, - ContentService, AlfrescoApiService, UserPreferencesService, NotificationService + AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; @@ -58,9 +58,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { private uploadService: UploadService, private contentManagementService: ContentManagementService, private browsingFilesService: BrowsingFilesService, - private contentService: ContentService, private apiService: AlfrescoApiService, - private notificationService: NotificationService, public permission: NodePermissionService, preferences: UserPreferencesService) { super(preferences, router, route, store); @@ -69,7 +67,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { ngOnInit() { super.ngOnInit(); - const { route, contentManagementService, contentService, nodeActionsService, uploadService } = this; + const { route, contentManagementService, nodeActionsService, uploadService } = this; const { data } = route.snapshot; this.title = data.title; @@ -99,11 +97,11 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { this.subscriptions = this.subscriptions.concat([ nodeActionsService.contentCopied.subscribe((nodes) => this.onContentCopied(nodes)), - contentService.folderCreate.subscribe(() => this.documentList.reload()), - contentService.folderEdit.subscribe(() => this.documentList.reload()), - contentManagementService.nodeDeleted.subscribe(() => this.documentList.reload()), - contentManagementService.nodeMoved.subscribe(() => this.documentList.reload()), - contentManagementService.nodeRestored.subscribe(() => this.documentList.reload()), + contentManagementService.folderCreated.subscribe(() => this.documentList.reload()), + contentManagementService.folderEdited.subscribe(() => this.documentList.reload()), + contentManagementService.nodesDeleted.subscribe(() => this.documentList.reload()), + contentManagementService.nodesMoved.subscribe(() => this.documentList.reload()), + contentManagementService.nodesRestored.subscribe(() => this.documentList.reload()), uploadService.fileUploadComplete.subscribe(file => this.onFileUploadedEvent(file)), uploadService.fileUploadDeleted.subscribe((file) => this.onFileUploadedEvent(file)) ]); @@ -253,11 +251,4 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { } return false; } - - openSnackMessage(event: any) { - this.notificationService.openSnackMessage( - event, - 4000 - ); - } } diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 78a9afbbf2..61efe7c6b5 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -31,7 +31,7 @@ import { OnDestroy, ViewChild, OnInit } from '@angular/core'; import { Subscription, Subject } from 'rxjs/Rx'; import { Store } from '@ngrx/store'; import { AppStore } from '../store/states/app.state'; -import { SetSelectedNodesAction } from '../store/actions/select-nodes.action'; +import { SetSelectedNodesAction } from '../store/actions/node.action'; import { selectedNodes } from '../store/selectors/app.selectors'; import { takeUntil } from 'rxjs/operators'; @@ -101,10 +101,8 @@ export abstract class PageComponent implements OnInit, OnDestroy { } showPreview(node: MinimalNodeEntity) { - if (node && node.entry) { - if (node.entry.isFile) { - this.router.navigate(['./preview', node.entry.id], { relativeTo: this.route }); - } + if (node && node.entry && node.entry.isFile) { + this.router.navigate(['./preview', node.entry.id], { relativeTo: this.route }); } } diff --git a/src/app/components/preview/preview.component.spec.ts b/src/app/components/preview/preview.component.spec.ts index f8c7e150e5..1bc2bd754e 100644 --- a/src/app/components/preview/preview.component.spec.ts +++ b/src/app/components/preview/preview.component.spec.ts @@ -28,17 +28,20 @@ import { Router, ActivatedRoute } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { - AlfrescoApiService, UserPreferencesService, TranslationService, TranslationMock, - AppConfigService, StorageService, CookieService, NotificationService, NodeFavoriteDirective + AlfrescoApiService, UserPreferencesService, + TranslationService, TranslationMock, + CoreModule } from '@alfresco/adf-core'; -import { TranslateModule } from '@ngx-translate/core'; -import { HttpClientModule } from '@angular/common/http'; import { PreviewComponent } from './preview.component'; import { Observable } from 'rxjs/Rx'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { MatSnackBarModule } from '@angular/material'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../../store/states/app.state'; +import { EffectsModule } from '@ngrx/effects'; +import { NodeEffects } from '../../store/effects/node.effects'; describe('PreviewComponent', () => { @@ -52,25 +55,19 @@ describe('PreviewComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - HttpClientModule, RouterTestingModule, - TranslateModule.forRoot(), - MatSnackBarModule + CoreModule.forRoot(), + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + EffectsModule.forRoot([NodeEffects]) ], providers: [ { provide: TranslationService, useClass: TranslationMock }, - AlfrescoApiService, - AppConfigService, - StorageService, - CookieService, - NotificationService, - UserPreferencesService, NodePermissionService, ContentManagementService ], declarations: [ PreviewComponent, - NodeFavoriteDirective + // NodeFavoriteDirective ], schemas: [ NO_ERRORS_SCHEMA ] }) diff --git a/src/app/components/preview/preview.component.ts b/src/app/components/preview/preview.component.ts index 1a84f6b509..554a22f2cc 100644 --- a/src/app/components/preview/preview.component.ts +++ b/src/app/components/preview/preview.component.ts @@ -28,7 +28,9 @@ import { ActivatedRoute, Router, UrlTree, UrlSegmentGroup, UrlSegment, PRIMARY_O import { AlfrescoApiService, UserPreferencesService, ObjectUtils } from '@alfresco/adf-core'; import { Node, MinimalNodeEntity } from 'alfresco-js-api'; import { NodePermissionService } from '../../common/services/node-permission.service'; -import { ContentManagementService } from '../../common/services/content-management.service'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../../store/states/app.state'; +import { DeleteNodesAction } from '../../store/actions'; @Component({ selector: 'app-preview', @@ -54,11 +56,12 @@ export class PreviewComponent implements OnInit { selectedEntities: MinimalNodeEntity[] = []; - constructor(private router: Router, + constructor( + private store: Store, + private router: Router, private route: ActivatedRoute, private apiService: AlfrescoApiService, private preferences: UserPreferencesService, - private content: ContentManagementService, public permission: NodePermissionService) { } @@ -326,12 +329,14 @@ export class PreviewComponent implements OnInit { return path; } - async deleteFile() { - try { - await this.content.deleteNode(this.node); - this.onVisibilityChanged(false); - } catch { - } + deleteFile() { + this.store.dispatch(new DeleteNodesAction([ + { + id: this.node.nodeId || this.node.id, + name: this.node.name + } + ])); + this.onVisibilityChanged(false); } private getNavigationCommands(url: string): any[] { diff --git a/src/app/components/recent-files/recent-files.component.spec.ts b/src/app/components/recent-files/recent-files.component.spec.ts index c89aa944b3..c74b89c878 100644 --- a/src/app/components/recent-files/recent-files.component.spec.ts +++ b/src/app/components/recent-files/recent-files.component.spec.ts @@ -130,7 +130,7 @@ describe('RecentFiles Routed Component', () => { it('should reload nodes on onDeleteNode event', () => { fixture.detectChanges(); - contentService.nodeDeleted.next(); + contentService.nodesDeleted.next(); expect(component.reload).toHaveBeenCalled(); }); @@ -138,7 +138,7 @@ describe('RecentFiles Routed Component', () => { it('should reload on onRestoreNode event', () => { fixture.detectChanges(); - contentService.nodeRestored.next(); + contentService.nodesRestored.next(); expect(component.reload).toHaveBeenCalled(); }); @@ -146,7 +146,7 @@ describe('RecentFiles Routed Component', () => { it('should reload on move node event', () => { fixture.detectChanges(); - contentService.nodeMoved.next(); + contentService.nodesMoved.next(); expect(component.reload).toHaveBeenCalled(); }); diff --git a/src/app/components/recent-files/recent-files.component.ts b/src/app/components/recent-files/recent-files.component.ts index 32a5a10387..0e2670e898 100644 --- a/src/app/components/recent-files/recent-files.component.ts +++ b/src/app/components/recent-files/recent-files.component.ts @@ -53,9 +53,9 @@ export class RecentFilesComponent extends PageComponent implements OnInit { super.ngOnInit(); this.subscriptions = this.subscriptions.concat([ - this.content.nodeDeleted.subscribe(() => this.reload()), - this.content.nodeMoved.subscribe(() => this.reload()), - this.content.nodeRestored.subscribe(() => this.reload()) + this.content.nodesDeleted.subscribe(() => this.reload()), + this.content.nodesMoved.subscribe(() => this.reload()), + this.content.nodesRestored.subscribe(() => this.reload()) ]); } diff --git a/src/app/components/shared-files/shared-files.component.spec.ts b/src/app/components/shared-files/shared-files.component.spec.ts index ab1c3a15ad..1ebf9755de 100644 --- a/src/app/components/shared-files/shared-files.component.spec.ts +++ b/src/app/components/shared-files/shared-files.component.spec.ts @@ -131,7 +131,7 @@ describe('SharedFilesComponent', () => { it('should refresh on deleteNode event', () => { fixture.detectChanges(); - contentService.nodeDeleted.next(); + contentService.nodesDeleted.next(); expect(component.reload).toHaveBeenCalled(); }); @@ -139,7 +139,7 @@ describe('SharedFilesComponent', () => { it('should refresh on restoreNode event', () => { fixture.detectChanges(); - contentService.nodeRestored.next(); + contentService.nodesRestored.next(); expect(component.reload).toHaveBeenCalled(); }); @@ -147,7 +147,7 @@ describe('SharedFilesComponent', () => { it('should reload on move node event', () => { fixture.detectChanges(); - contentService.nodeMoved.next(); + contentService.nodesMoved.next(); expect(component.reload).toHaveBeenCalled(); }); @@ -170,17 +170,6 @@ describe('SharedFilesComponent', () => { expect(router.navigate['calls'].argsFor(0)[0]).toEqual(['./preview', node.entry.id]); })); - it('does nothing if node is folder', fakeAsync(() => { - spyOn(router, 'navigate').and.stub(); - spyOn(nodeService, 'getNode').and.returnValue(Promise.resolve({ entry: { isFile: false } })); - const link = { nodeId: 'nodeId' }; - - component.onNodeDoubleClick(link); - tick(); - - expect(router.navigate).not.toHaveBeenCalled(); - })); - it('does nothing if link data is not passed', () => { spyOn(router, 'navigate').and.stub(); spyOn(nodeService, 'getNode').and.returnValue(Promise.resolve({ entry: { isFile: true } })); diff --git a/src/app/components/shared-files/shared-files.component.ts b/src/app/components/shared-files/shared-files.component.ts index eb3ea20745..47f9af629b 100644 --- a/src/app/components/shared-files/shared-files.component.ts +++ b/src/app/components/shared-files/shared-files.component.ts @@ -25,8 +25,7 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { MinimalNodeEntity } from 'alfresco-js-api'; -import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core'; +import { UserPreferencesService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; @@ -43,7 +42,6 @@ export class SharedFilesComponent extends PageComponent implements OnInit { route: ActivatedRoute, store: Store, private content: ContentManagementService, - private apiService: AlfrescoApiService, public permission: NodePermissionService, preferences: UserPreferencesService) { super(preferences, router, route, store); @@ -53,21 +51,15 @@ export class SharedFilesComponent extends PageComponent implements OnInit { super.ngOnInit(); this.subscriptions = this.subscriptions.concat([ - this.content.nodeDeleted.subscribe(() => this.reload()), - this.content.nodeMoved.subscribe(() => this.reload()), - this.content.nodeRestored.subscribe(() => this.reload()) + this.content.nodesDeleted.subscribe(() => this.reload()), + this.content.nodesMoved.subscribe(() => this.reload()), + this.content.nodesRestored.subscribe(() => this.reload()) ]); } onNodeDoubleClick(link: { nodeId?: string }) { if (link && link.nodeId) { - this.apiService.nodesApi.getNode(link.nodeId).then( - (node: MinimalNodeEntity) => { - if (node && node.entry && node.entry.isFile) { - this.router.navigate(['./preview', node.entry.id], { relativeTo: this.route }); - } - } - ); + this.router.navigate(['./preview', link.nodeId], { relativeTo: this.route }); } } } diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index 87708b9db3..e42cb40be7 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -9,8 +9,7 @@ @@ -16,7 +15,6 @@ From 9076c7ee9f17a3f7debc35a31d5c7a7b15835a38 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Tue, 12 Jun 2018 09:51:57 +0300 Subject: [PATCH 077/179] [ACA-1407] Version Manager - file name conflict message (#398) * upoad file conflict message * SnackbarErrorAction --- src/app/components/files/files.component.ts | 3 ++- src/app/components/page.component.ts | 14 ++++++++++++- .../preview/preview.component.spec.ts | 5 +++-- .../components/preview/preview.component.ts | 21 ++++++++++++------- .../recent-files.component.spec.ts | 5 +++-- .../recent-files/recent-files.component.ts | 6 ++++-- .../shared-files.component.spec.ts | 5 +++-- .../shared-files/shared-files.component.ts | 6 ++++-- src/assets/i18n/en.json | 5 +++++ 9 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index 0e1b4e5837..bb25fe00c7 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -103,7 +103,8 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { contentManagementService.nodesMoved.subscribe(() => this.documentList.reload()), contentManagementService.nodesRestored.subscribe(() => this.documentList.reload()), uploadService.fileUploadComplete.subscribe(file => this.onFileUploadedEvent(file)), - uploadService.fileUploadDeleted.subscribe((file) => this.onFileUploadedEvent(file)) + uploadService.fileUploadDeleted.subscribe((file) => this.onFileUploadedEvent(file)), + uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error)) ]); } diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 61efe7c6b5..4bcb4fd309 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -24,7 +24,7 @@ */ import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco-js-api'; -import { UserPreferencesService } from '@alfresco/adf-core'; +import { UserPreferencesService, FileUploadErrorEvent } from '@alfresco/adf-core'; import { ShareDataRow, DocumentListComponent } from '@alfresco/adf-content-services'; import { ActivatedRoute, Router } from '@angular/router'; import { OnDestroy, ViewChild, OnInit } from '@angular/core'; @@ -34,6 +34,8 @@ import { AppStore } from '../store/states/app.state'; import { SetSelectedNodesAction } from '../store/actions/node.action'; import { selectedNodes } from '../store/selectors/app.selectors'; import { takeUntil } from 'rxjs/operators'; +import { SnackbarErrorAction } from '../store/actions'; + export abstract class PageComponent implements OnInit, OnDestroy { @@ -181,4 +183,14 @@ export abstract class PageComponent implements OnInit, OnDestroy { this.documentList.reload(); } } + + onFileUploadedError(error: FileUploadErrorEvent) { + let message = null; + + if (error.error.status === 409) { + message = new SnackbarErrorAction('VERSION.MESSAGE.ERROR.CONFLICT'); + } + + this.store.dispatch(message); + } } diff --git a/src/app/components/preview/preview.component.spec.ts b/src/app/components/preview/preview.component.spec.ts index 1bc2bd754e..73f0fdc391 100644 --- a/src/app/components/preview/preview.component.spec.ts +++ b/src/app/components/preview/preview.component.spec.ts @@ -30,7 +30,7 @@ import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { AlfrescoApiService, UserPreferencesService, TranslationService, TranslationMock, - CoreModule + CoreModule, UploadService } from '@alfresco/adf-core'; import { PreviewComponent } from './preview.component'; @@ -63,7 +63,8 @@ describe('PreviewComponent', () => { providers: [ { provide: TranslationService, useClass: TranslationMock }, NodePermissionService, - ContentManagementService + ContentManagementService, + UploadService ], declarations: [ PreviewComponent, diff --git a/src/app/components/preview/preview.component.ts b/src/app/components/preview/preview.component.ts index 554a22f2cc..e989fa993d 100644 --- a/src/app/components/preview/preview.component.ts +++ b/src/app/components/preview/preview.component.ts @@ -25,13 +25,13 @@ import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { ActivatedRoute, Router, UrlTree, UrlSegmentGroup, UrlSegment, PRIMARY_OUTLET } from '@angular/router'; -import { AlfrescoApiService, UserPreferencesService, ObjectUtils } from '@alfresco/adf-core'; +import { AlfrescoApiService, UserPreferencesService, ObjectUtils, UploadService } from '@alfresco/adf-core'; import { Node, MinimalNodeEntity } from 'alfresco-js-api'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; import { DeleteNodesAction } from '../../store/actions'; - +import { PageComponent } from '../page.component'; @Component({ selector: 'app-preview', templateUrl: 'preview.component.html', @@ -40,7 +40,7 @@ import { DeleteNodesAction } from '../../store/actions'; // tslint:disable-next-line:use-host-property-decorator host: { 'class': 'app-preview' } }) -export class PreviewComponent implements OnInit { +export class PreviewComponent extends PageComponent implements OnInit { node: Node; previewLocation: string = null; @@ -57,12 +57,15 @@ export class PreviewComponent implements OnInit { selectedEntities: MinimalNodeEntity[] = []; constructor( - private store: Store, - private router: Router, - private route: ActivatedRoute, + private uploadService: UploadService, private apiService: AlfrescoApiService, - private preferences: UserPreferencesService, + preferences: UserPreferencesService, + route: ActivatedRoute, + router: Router, + store: Store, public permission: NodePermissionService) { + + super(preferences, router, route, store); } ngOnInit() { @@ -90,6 +93,10 @@ export class PreviewComponent implements OnInit { this.displayNode(id); } }); + + this.subscriptions = this.subscriptions.concat([ + this.uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error)) + ]); } /** diff --git a/src/app/components/recent-files/recent-files.component.spec.ts b/src/app/components/recent-files/recent-files.component.spec.ts index c74b89c878..43e11c588d 100644 --- a/src/app/components/recent-files/recent-files.component.spec.ts +++ b/src/app/components/recent-files/recent-files.component.spec.ts @@ -30,7 +30,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { HttpClientModule } from '@angular/common/http'; import { NotificationService, TranslationService, TranslationMock, - NodesApiService, AlfrescoApiService, ContentService, + NodesApiService, AlfrescoApiService, ContentService, UploadService, UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, AuthenticationService, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe @@ -99,7 +99,8 @@ describe('RecentFiles Routed Component', () => { NodesApiService, DocumentListService, ThumbnailService, - CustomResourcesService + CustomResourcesService, + UploadService ], schemas: [ NO_ERRORS_SCHEMA ] }) diff --git a/src/app/components/recent-files/recent-files.component.ts b/src/app/components/recent-files/recent-files.component.ts index 0e2670e898..9d8999f6e3 100644 --- a/src/app/components/recent-files/recent-files.component.ts +++ b/src/app/components/recent-files/recent-files.component.ts @@ -26,7 +26,7 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { MinimalNodeEntryEntity } from 'alfresco-js-api'; -import { UserPreferencesService } from '@alfresco/adf-core'; +import { UserPreferencesService, UploadService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { PageComponent } from '../page.component'; @@ -43,6 +43,7 @@ export class RecentFilesComponent extends PageComponent implements OnInit { router: Router, route: ActivatedRoute, store: Store, + private uploadService: UploadService, private content: ContentManagementService, public permission: NodePermissionService, preferences: UserPreferencesService) { @@ -55,7 +56,8 @@ export class RecentFilesComponent extends PageComponent implements OnInit { this.subscriptions = this.subscriptions.concat([ this.content.nodesDeleted.subscribe(() => this.reload()), this.content.nodesMoved.subscribe(() => this.reload()), - this.content.nodesRestored.subscribe(() => this.reload()) + this.content.nodesRestored.subscribe(() => this.reload()), + this.uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error)) ]); } diff --git a/src/app/components/shared-files/shared-files.component.spec.ts b/src/app/components/shared-files/shared-files.component.spec.ts index 1ebf9755de..e5de301989 100644 --- a/src/app/components/shared-files/shared-files.component.spec.ts +++ b/src/app/components/shared-files/shared-files.component.spec.ts @@ -31,7 +31,7 @@ import { HttpClientModule } from '@angular/common/http'; import { NotificationService, TranslationService, TranslationMock, NodesApiService, AlfrescoApiService, ContentService, - UserPreferencesService, LogService, AppConfigService, + UserPreferencesService, LogService, AppConfigService, UploadService, StorageService, CookieService, ThumbnailService, AuthenticationService, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; @@ -101,7 +101,8 @@ describe('SharedFilesComponent', () => { NodesApiService, DocumentListService, ThumbnailService, - CustomResourcesService + CustomResourcesService, + UploadService ], schemas: [ NO_ERRORS_SCHEMA ] }) diff --git a/src/app/components/shared-files/shared-files.component.ts b/src/app/components/shared-files/shared-files.component.ts index 47f9af629b..efc8898536 100644 --- a/src/app/components/shared-files/shared-files.component.ts +++ b/src/app/components/shared-files/shared-files.component.ts @@ -25,7 +25,7 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { UserPreferencesService } from '@alfresco/adf-core'; +import { UserPreferencesService, UploadService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; @@ -41,6 +41,7 @@ export class SharedFilesComponent extends PageComponent implements OnInit { constructor(router: Router, route: ActivatedRoute, store: Store, + private uploadService: UploadService, private content: ContentManagementService, public permission: NodePermissionService, preferences: UserPreferencesService) { @@ -53,7 +54,8 @@ export class SharedFilesComponent extends PageComponent implements OnInit { this.subscriptions = this.subscriptions.concat([ this.content.nodesDeleted.subscribe(() => this.reload()), this.content.nodesMoved.subscribe(() => this.reload()), - this.content.nodesRestored.subscribe(() => this.reload()) + this.content.nodesRestored.subscribe(() => this.reload()), + this.uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error)) ]); } diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 988f46999b..2dcbe46ec7 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -226,6 +226,11 @@ "SEARCH": "Search" }, "VERSION": { + "MESSAGE": { + "ERROR": { + "CONFLICT": "New version not uploaded, another file with the same name already exists" + } + }, "DIALOG": { "TITLE": "Manage Versions", "CLOSE": "Close" From 4c1556e47588bb01c9c6f2ea2b30ec0226b22185 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Tue, 12 Jun 2018 09:52:34 +0300 Subject: [PATCH 078/179] [ACA-1445] Shared files - verison manager panel (#397) * shared files verion manager panel * show content when loaded * node info loaded * cast as boolean --- src/app/components/info-drawer/info-drawer.component.html | 2 +- src/app/components/info-drawer/info-drawer.component.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app/components/info-drawer/info-drawer.component.html b/src/app/components/info-drawer/info-drawer.component.html index 99468992fe..f6f75fe038 100644 --- a/src/app/components/info-drawer/info-drawer.component.html +++ b/src/app/components/info-drawer/info-drawer.component.html @@ -1,7 +1,7 @@
- + Date: Tue, 12 Jun 2018 11:18:42 +0300 Subject: [PATCH 079/179] [ACA-117][ACA-1434] navigate to new search results on input change (#390) * [ACA-117][ACA-1434] change total results info * [ACA-117][ACA-1434] update search results on input change * [ACA-117][ACA-1434] update search results on input change - only when on the results page already * [ACA-117][ACA-1434] check url if on the search results page * [ACA-117][ACA-1434] no live search enabled and no expandable search control on the results page --- .../search-input/search-input.component.html | 5 ++- .../search-input/search-input.component.ts | 31 +++++++++++++++++++ .../components/search/search.component.html | 2 +- src/assets/i18n/en.json | 2 +- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/app/components/search-input/search-input.component.html b/src/app/components/search-input/search-input.component.html index d1ca1b18cc..2d892668db 100644 --- a/src/app/components/search-input/search-input.component.html +++ b/src/app/components/search-input/search-input.component.html @@ -1,5 +1,8 @@ + [expandable]="!onSearchResults" + [liveSearchEnabled]="!onSearchResults" + (submit)="onSearchSubmit($event)" + (searchChange)="onSearchChange($event)"> diff --git a/src/app/components/search-input/search-input.component.ts b/src/app/components/search-input/search-input.component.ts index b0a14c365f..e6893912ec 100644 --- a/src/app/components/search-input/search-input.component.ts +++ b/src/app/components/search-input/search-input.component.ts @@ -34,6 +34,10 @@ import { MinimalNodeEntity } from 'alfresco-js-api'; }) export class SearchInputComponent { + hasOneChange = false; + hasNewChange = false; + navigationTimer: any; + constructor( private router: Router) { } @@ -59,4 +63,31 @@ export class SearchInputComponent { q: value }]); } + + onSearchChange(event: string) { + if (this.onSearchResults) { + + if (this.hasOneChange) { + this.hasNewChange = true; + } else { + this.hasOneChange = true; + } + + if (this.hasNewChange) { + clearTimeout(this.navigationTimer); + this.hasNewChange = false; + } + + this.navigationTimer = setTimeout(() => { + if (event) { + this.router.navigate(['/search', {q: event}]); + } + this.hasOneChange = false; + }, 1000); + } + } + + get onSearchResults() { + return this.router.url.indexOf('/search') === 0; + } } diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 45d8be7e5e..938e1d8d09 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -22,7 +22,7 @@
-
{{ 'APP.BROWSE.SEARCH.SHOW_RESULTS_NUMBER' | translate: { number: totalResults } }}
+
{{ 'APP.BROWSE.SEARCH.FOUND_RESULTS' | translate: { number: totalResults } }}
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 2dcbe46ec7..0a29509dba 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -98,7 +98,7 @@ }, "SEARCH": { "TITLE": "Search Results", - "SHOW_RESULTS_NUMBER": "Showing {{ number }} results" + "FOUND_RESULTS": "{{ number }} results found" } }, "ACTIONS": { From 0c696b5991ace1e8c858b145a56b07de0729f754 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Tue, 12 Jun 2018 12:12:42 +0300 Subject: [PATCH 080/179] get info for favorite entry (#400) --- src/app/components/info-drawer/info-drawer.component.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/components/info-drawer/info-drawer.component.ts b/src/app/components/info-drawer/info-drawer.component.ts index 334a010804..bc9b56cc3f 100644 --- a/src/app/components/info-drawer/info-drawer.component.ts +++ b/src/app/components/info-drawer/info-drawer.component.ts @@ -75,6 +75,9 @@ export class InfoDrawerComponent implements OnChanges { const entry = this.node.entry; if (entry.nodeId) { this.loadNodeInfo(entry.nodeId); + } else if ((entry).guid) { + // workaround for Favorite files + this.loadNodeInfo(entry.id); } else { this.displayNode = this.node.entry; } From 56e4826053616d1c3ec620c141fca471246732cb Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 12 Jun 2018 10:38:20 +0100 Subject: [PATCH 081/179] unit testing enhancements (#401) * app testing module * reduce favorites test dependencies * remove fdescribe * setup store integration for app testing module --- .../current-user/current-user.component.html | 2 +- .../current-user.component.spec.ts | 24 ++++---- .../current-user/current-user.component.ts | 9 +-- .../favorites/favorites.component.spec.ts | 17 +----- src/app/testing/app-testing.module.ts | 57 +++++++++++++++++++ src/app/testing/translate-pipe.directive.ts | 33 +++++++++++ src/app/testing/translation.service.ts | 34 +++++++++++ 7 files changed, 140 insertions(+), 36 deletions(-) create mode 100644 src/app/testing/app-testing.module.ts create mode 100644 src/app/testing/translate-pipe.directive.ts create mode 100644 src/app/testing/translation.service.ts diff --git a/src/app/components/current-user/current-user.component.html b/src/app/components/current-user/current-user.component.html index 638f9230be..9ce4be5ac9 100644 --- a/src/app/components/current-user/current-user.component.html +++ b/src/app/components/current-user/current-user.component.html @@ -9,7 +9,7 @@
- diff --git a/src/app/components/current-user/current-user.component.spec.ts b/src/app/components/current-user/current-user.component.spec.ts index 77d6a8ddf1..88f025232c 100644 --- a/src/app/components/current-user/current-user.component.spec.ts +++ b/src/app/components/current-user/current-user.component.spec.ts @@ -25,18 +25,19 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { TestBed, async } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; import { Observable } from 'rxjs/Rx'; -import { HttpClientModule } from '@angular/common/http'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule } from '@angular/material'; import { - TranslationService, TranslationMock, AlfrescoApiService, - AppConfigService, StorageService, PeopleContentService, UserPreferencesService + AlfrescoApiService, + AppConfigService, + StorageService, + PeopleContentService, + UserPreferencesService, + AppConfigPipe } from '@alfresco/adf-core'; import { CurrentUserComponent } from './current-user.component'; +import { AppTestingModule } from '../../testing/app-testing.module'; describe('CurrentUserComponent', () => { let fixture; @@ -51,17 +52,14 @@ describe('CurrentUserComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - HttpClientModule, - TranslateModule.forRoot(), - NoopAnimationsModule, - MatMenuModule, - RouterTestingModule + AppTestingModule, + MatMenuModule ], declarations: [ - CurrentUserComponent + CurrentUserComponent, + AppConfigPipe ], providers: [ - { provide: TranslationService, useClass: TranslationMock }, AlfrescoApiService, AppConfigService, StorageService, diff --git a/src/app/components/current-user/current-user.component.ts b/src/app/components/current-user/current-user.component.ts index 6ef40663ae..b91bd6ce1e 100644 --- a/src/app/components/current-user/current-user.component.ts +++ b/src/app/components/current-user/current-user.component.ts @@ -24,7 +24,7 @@ */ import { Component, OnInit, OnDestroy } from '@angular/core'; -import { PeopleContentService, AppConfigService } from '@alfresco/adf-core'; +import { PeopleContentService } from '@alfresco/adf-core'; import { Subscription } from 'rxjs/Rx'; @Component({ @@ -38,8 +38,7 @@ export class CurrentUserComponent implements OnInit, OnDestroy { user: any = null; constructor( - private peopleApi: PeopleContentService, - private appConfig: AppConfigService + private peopleApi: PeopleContentService ) {} ngOnInit() { @@ -71,8 +70,4 @@ export class CurrentUserComponent implements OnInit, OnDestroy { const { userFirstName: first, userLastName: last } = this; return [ first[0], last[0] ].join(''); } - - get showLanguagePicker() { - return this.appConfig.get('languagePicker') || false; - } } diff --git a/src/app/components/favorites/favorites.component.spec.ts b/src/app/components/favorites/favorites.component.spec.ts index 806666799f..c6529cf939 100644 --- a/src/app/components/favorites/favorites.component.spec.ts +++ b/src/app/components/favorites/favorites.component.spec.ts @@ -26,11 +26,8 @@ import { Observable } from 'rxjs/Rx'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientModule } from '@angular/common/http'; import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { - NotificationService, TranslationService, TranslationMock, NodesApiService, AlfrescoApiService, ContentService, UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, @@ -39,17 +36,13 @@ import { } from '@alfresco/adf-core'; import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { FavoritesComponent } from './favorites.component'; -import { StoreModule } from '@ngrx/store'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; +import { AppTestingModule } from '../../testing/app-testing.module'; describe('FavoritesComponent', () => { let fixture: ComponentFixture; @@ -90,13 +83,9 @@ describe('FavoritesComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ + AppTestingModule, MatMenuModule, - NoopAnimationsModule, - HttpClientModule, - TranslateModule.forRoot(), - RouterTestingModule, MatSnackBarModule, MatIconModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) ], declarations: [ DataTableComponent, @@ -108,14 +97,12 @@ describe('FavoritesComponent', () => { AppConfigPipe ], providers: [ - { provide: TranslationService, useClass: TranslationMock }, AuthenticationService, UserPreferencesService, AppConfigService, StorageService, CookieService, AlfrescoApiService, CustomResourcesService, LogService, - NotificationService, ContentManagementService, ContentService, NodesApiService, diff --git a/src/app/testing/app-testing.module.ts b/src/app/testing/app-testing.module.ts new file mode 100644 index 0000000000..e061a03dec --- /dev/null +++ b/src/app/testing/app-testing.module.ts @@ -0,0 +1,57 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { NgModule } from '@angular/core'; +import { TranslatePipe, TranslateService } from '@ngx-translate/core'; +import { TranslatePipeMock } from './translate-pipe.directive'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { TranslationService, TranslationMock } from '@alfresco/adf-core'; +import { HttpClientModule } from '@angular/common/http'; +import { TranslateServiceMock } from './translation.service'; +import { StoreModule } from '@ngrx/store'; +import { appReducer } from '../store/reducers/app.reducer'; +import { INITIAL_STATE } from '../store/states/app.state'; +import { RouterTestingModule } from '@angular/router/testing'; + +@NgModule({ + imports: [ + NoopAnimationsModule, + HttpClientModule, + RouterTestingModule, + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) + ], + declarations: [ + TranslatePipeMock + ], + exports: [ + TranslatePipeMock + ], + providers: [ + { provide: TranslationService, useClass: TranslationMock }, + { provide: TranslateService, useClass: TranslateServiceMock }, + { provide: TranslatePipe, useClass: TranslatePipeMock } + ] +}) +export class AppTestingModule {} diff --git a/src/app/testing/translate-pipe.directive.ts b/src/app/testing/translate-pipe.directive.ts new file mode 100644 index 0000000000..727f85e8b9 --- /dev/null +++ b/src/app/testing/translate-pipe.directive.ts @@ -0,0 +1,33 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ name: 'translate' }) +export class TranslatePipeMock implements PipeTransform { + transform(value: any, ...args: any[]) { + return value; + } +} diff --git a/src/app/testing/translation.service.ts b/src/app/testing/translation.service.ts new file mode 100644 index 0000000000..09dbd495be --- /dev/null +++ b/src/app/testing/translation.service.ts @@ -0,0 +1,34 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Injectable } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + +@Injectable() +export class TranslateServiceMock extends TranslateService { + constructor() { + super(null, null, null, null, null); + } +} From e83cc18964359971cb9c62f1087ef3457f97cd12 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 12 Jun 2018 12:50:19 +0100 Subject: [PATCH 082/179] fix page title service (#402) --- src/app/app.module.ts | 4 +- src/app/common/services/page-title.service.ts | 67 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/app/common/services/page-title.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index b0774cbd4d..a4943d35f3 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -28,7 +28,7 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { TRANSLATION_PROVIDER, CoreModule, AppConfigService } from '@alfresco/adf-core'; +import { TRANSLATION_PROVIDER, CoreModule, AppConfigService, PageTitleService } from '@alfresco/adf-core'; import { ContentModule } from '@alfresco/adf-content-services'; import { ElectronModule } from '@ngstack/electron'; @@ -74,6 +74,7 @@ import { SearchComponent } from './components/search/search.component'; import { SettingsComponent } from './components/settings/settings.component'; import { HybridAppConfigService } from './common/services/hybrid-app-config.service'; import { SortingPreferenceKeyDirective } from './directives/sorting-preference-key.directive'; +import { PageTitleService as AcaPageTitleService } from './common/services/page-title.service'; import { INITIAL_STATE } from './store/states/app.state'; import { appReducer } from './store/reducers/app.reducer'; @@ -145,6 +146,7 @@ import { CreateFolderDirective } from './directives/create-folder.directive'; CreateFolderDirective ], providers: [ + { provide: PageTitleService, useClass: AcaPageTitleService }, { provide: AppConfigService, useClass: HybridAppConfigService }, { provide: TRANSLATION_PROVIDER, diff --git a/src/app/common/services/page-title.service.ts b/src/app/common/services/page-title.service.ts new file mode 100644 index 0000000000..c1a723c3a4 --- /dev/null +++ b/src/app/common/services/page-title.service.ts @@ -0,0 +1,67 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Injectable } from '@angular/core'; +import { Title } from '@angular/platform-browser'; +import { AppConfigService, TranslationService } from '@alfresco/adf-core'; + +@Injectable() +export class PageTitleService { + + private originalTitle = ''; + private translatedTitle = ''; + + constructor( + private titleService: Title, + private appConfig: AppConfigService, + private translationService: TranslationService) { + translationService.translate.onLangChange.subscribe(() => this.onLanguageChanged()); + // TODO: contribute this fix to ADF 2.5.0 + translationService.translate.onTranslationChange.subscribe(() => this.onLanguageChanged()); + } + + /** + * Sets the page title. + * @param value The new title + */ + setTitle(value: string = '') { + this.originalTitle = value; + this.translatedTitle = this.translationService.instant(value); + + this.updateTitle(); + } + + private onLanguageChanged() { + this.translatedTitle = this.translationService.instant(this.originalTitle); + this.updateTitle(); + } + + private updateTitle() { + const name = this.appConfig.get('application.name') || 'Alfresco ADF Application'; + + const title = this.translatedTitle ? `${this.translatedTitle} - ${name}` : `${name}`; + this.titleService.setTitle(title); + } +} From 0a934930e5961e8028d59421d16110885f908d7f Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 12 Jun 2018 15:47:26 +0100 Subject: [PATCH 083/179] explicit column layout for search results --- .../components/search/search.component.html | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 938e1d8d09..4c6ab1665f 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -34,6 +34,41 @@ [node]="data" (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"> + + + + + + + + + + + + +
From 17ceb5e1cffd0eb76bc18cfe782844dddd31be19 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 12 Jun 2018 18:55:23 +0100 Subject: [PATCH 084/179] [ACA-1447] style fixes (#403) * style fixes * style fixes * fix 'New' label styles --- src/app/ui/application.scss | 4 -- src/app/ui/custom-theme.scss | 8 ++- .../overrides/_adf-sidebar-action-menu.scss | 39 ----------- .../ui/overrides/_alfresco-upload-button.scss | 49 ------------- .../adf-sidebar-action-menu.theme.scss | 70 +++++++++++++++++++ .../{_toolbar.scss => adf-toolbar.theme.scss} | 2 +- .../ui/overrides/adf-upload-button.theme.scss | 53 ++++++++++++++ 7 files changed, 130 insertions(+), 95 deletions(-) delete mode 100644 src/app/ui/overrides/_adf-sidebar-action-menu.scss delete mode 100644 src/app/ui/overrides/_alfresco-upload-button.scss create mode 100644 src/app/ui/overrides/adf-sidebar-action-menu.theme.scss rename src/app/ui/overrides/{_toolbar.scss => adf-toolbar.theme.scss} (89%) create mode 100644 src/app/ui/overrides/adf-upload-button.theme.scss diff --git a/src/app/ui/application.scss b/src/app/ui/application.scss index 4fe5b50a73..461c404ff9 100644 --- a/src/app/ui/application.scss +++ b/src/app/ui/application.scss @@ -28,8 +28,4 @@ ng-component { @import './overrides/adf-sidenav-layout'; @import './overrides/alfresco-document-list'; @import './overrides/alfresco-upload-drag-area'; -@import './overrides/alfresco-upload-button'; @import './overrides/alfresco-upload-dialog'; -@import './overrides/toolbar'; -@import './overrides/_adf-sidebar-action-menu'; - diff --git a/src/app/ui/custom-theme.scss b/src/app/ui/custom-theme.scss index c1ce61c98b..0a6b0020ce 100644 --- a/src/app/ui/custom-theme.scss +++ b/src/app/ui/custom-theme.scss @@ -2,9 +2,11 @@ @import '~@alfresco/adf-content-services/theming'; @import '../components/sidenav/sidenav.component.theme'; -@import './overrides/toolbar'; +@import './overrides/adf-toolbar.theme'; @import './overrides/adf-search-filter.theme'; @import './overrides/adf-info-drawer.theme'; +@import './overrides/adf-upload-button.theme'; +@import './overrides/adf-sidebar-action-menu.theme'; @import 'snackbar'; $grey-scale: ( @@ -49,8 +51,10 @@ $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent); @mixin custom-theme($theme) { @include sidenav-component-theme($custom-theme); - @include toolbar-component-theme($custom-theme); + @include adf-toolbar-theme($custom-theme); @include snackbar-theme($custom-theme); @include adf-search-filter-theme($custom-theme); @include adf-info-drawer-theme($custom-theme); + @include adf-upload-button-theme($custom-theme); + @include adf-sidebar-action-menu-theme($custom-theme); } diff --git a/src/app/ui/overrides/_adf-sidebar-action-menu.scss b/src/app/ui/overrides/_adf-sidebar-action-menu.scss deleted file mode 100644 index 35dc19ae34..0000000000 --- a/src/app/ui/overrides/_adf-sidebar-action-menu.scss +++ /dev/null @@ -1,39 +0,0 @@ -.adf-sidebar-action-menu-options div .mat-menu-item { - display: flex; - flex-direction: row; - align-items: center; -} - -.mat-menu-item[disabled], -.mat-menu-item[disabled]:hover { - color: rgba(0, 0, 0, 0.38); -} - -.mat-menu-panel.adf-sidebar-action-menu-panel { - max-width: 290px !important; -} - -.adf-sidebar-action-menu-panel { - width: 290px; - display: flex; - align-items: center; - justify-content: center; -} - -.adf-sidebar-action-menu-panel .mat-menu-content { - width: 100%; -} - -.adf-sidebar-action-menu-icon { - margin: 0; -} - -.adf-sidebar-action-menu-icon div[sidebar-menu-expand-icon] { - display: flex; - align-items: center; - justify-content: center; -} - -.adf-sidebar-action-menu { - width: 100%; -} diff --git a/src/app/ui/overrides/_alfresco-upload-button.scss b/src/app/ui/overrides/_alfresco-upload-button.scss deleted file mode 100644 index 896211be37..0000000000 --- a/src/app/ui/overrides/_alfresco-upload-button.scss +++ /dev/null @@ -1,49 +0,0 @@ -@import '../_variables.scss'; - -adf-upload-button { - .mat-raised-button.mat-primary { - width: 100%; - border-radius: 0; - text-align: left; - line-height: 48px; - box-shadow: none; - transform: none; - transition: unset; - background-color: $alfresco-white; - } - - .mat-raised-button.mat-primary:hover:not([disabled]) { - background-color: rgba(0, 0, 0, 0.04); - } - - .mat-raised-button.mat-primary[disabled] { - background: none; - } - - .mat-raised-button.mat-primary[disabled] label { - color: rgba(0, 0, 0, 0.38); - } - - .mat-raised-button:not([disabled]):active { - box-shadow: none; - } - - mat-icon { - color: rgba(0, 0, 0, 0.54); - } - - label { - text-transform: capitalize; - font-family: Muli; - font-size: 16px; - font-weight: normal; - text-align: left; - margin-left: 12px; - color: $alfresco-primary-text-color; - } - - &:hover label { - color: #ff9800; - opacity: inherit; - } -} diff --git a/src/app/ui/overrides/adf-sidebar-action-menu.theme.scss b/src/app/ui/overrides/adf-sidebar-action-menu.theme.scss new file mode 100644 index 0000000000..b245c1b025 --- /dev/null +++ b/src/app/ui/overrides/adf-sidebar-action-menu.theme.scss @@ -0,0 +1,70 @@ +@mixin adf-sidebar-action-menu-theme($theme) { + $foreground: map-get($theme, foreground); + $accent: map-get($theme, accent); + $primary: map-get($theme, primary); + + .adf-sidebar-action-menu { + .adf-sidebar-action-menu-button { + font-size: 12.7px; + font-weight: normal; + text-transform: uppercase; + } + } + + .mat-menu-panel.adf-sidebar-action-menu-panel { + max-width: 290px !important; + } + + .adf-sidebar-action-menu-panel { + width: 290px; + display: flex; + align-items: center; + justify-content: center; + } + + .adf-sidebar-action-menu-panel .mat-menu-content { + width: 100%; + } + + .adf-sidebar-action-menu-icon { + margin: 0; + } + + .adf-sidebar-action-menu-icon div[sidebar-menu-expand-icon] { + display: flex; + align-items: center; + justify-content: center; + } + + .adf-sidebar-action-menu { + width: 100%; + } + + .adf-sidebar-action-menu-options { + width: 100% !important; + + .mat-menu-item { + display: flex; + flex-direction: row; + align-items: center; + font-size: 14px; + color: mat-color($foreground, text, 0.54); + line-height: 48px; + box-shadow: none; + transform: none; + transition: unset; + font-weight: normal; + text-transform: capitalize; + color: mat-color($primary); + + &:hover { + color: mat-color($accent); + } + } + + .mat-menu-item[disabled], + .mat-menu-item[disabled]:hover { + color: mat-color($foreground, text, 0.38); + } + } +} diff --git a/src/app/ui/overrides/_toolbar.scss b/src/app/ui/overrides/adf-toolbar.theme.scss similarity index 89% rename from src/app/ui/overrides/_toolbar.scss rename to src/app/ui/overrides/adf-toolbar.theme.scss index 9a8c46193a..b2fa28225d 100644 --- a/src/app/ui/overrides/_toolbar.scss +++ b/src/app/ui/overrides/adf-toolbar.theme.scss @@ -1,4 +1,4 @@ -@mixin toolbar-component-theme($theme) { +@mixin adf-toolbar-theme($theme) { .adf-toolbar { @include angular-material-theme($theme); diff --git a/src/app/ui/overrides/adf-upload-button.theme.scss b/src/app/ui/overrides/adf-upload-button.theme.scss new file mode 100644 index 0000000000..8ee04c650b --- /dev/null +++ b/src/app/ui/overrides/adf-upload-button.theme.scss @@ -0,0 +1,53 @@ +@mixin adf-upload-button-theme($theme) { + $foreground: map-get($theme, foreground); + $accent: map-get($theme, accent); + $primary: map-get($theme, primary); + + adf-upload-button { + .mat-raised-button.mat-primary { + width: 100%; + border-radius: 0; + text-align: left; + line-height: 48px; + box-shadow: none; + transform: none; + transition: unset; + background-color: transparent; + } + + .mat-raised-button.mat-primary:hover:not([disabled]) { + background-color: mat-color($foreground, text, 0.04); + } + + .mat-raised-button.mat-primary[disabled] { + background: none; + } + + .mat-raised-button.mat-primary[disabled] label { + color: mat-color($foreground, text, 0.38); + } + + .mat-raised-button:not([disabled]):active { + box-shadow: none; + } + + mat-icon { + color: mat-color($foreground, text, 0.54); + } + + label { + text-transform: capitalize; + font-family: Muli; + font-size: 14px; + font-weight: normal; + text-align: left; + margin-left: 12px; + color: mat-color($primary); + } + + &:hover label { + color: mat-color($accent); + opacity: inherit; + } + } +} From 2320265416cf71b878735c97d02acd0163e25143 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 12 Jun 2018 19:00:34 +0100 Subject: [PATCH 085/179] search fixes --- src/app/components/search/search.component.html | 1 - src/app/components/search/search.component.ts | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 4c6ab1665f..4d2e0347a7 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -11,7 +11,6 @@
diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index 38936fdac5..9a127c4294 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -41,7 +41,6 @@ export class SearchComponent implements OnInit { search: AdfSearchComponent; queryParamName = 'q'; - searchedWord = ''; data: NodePaging; totalResults = 0; maxItems = 5; @@ -68,9 +67,9 @@ export class SearchComponent implements OnInit { if (this.route) { this.route.params.forEach((params: Params) => { - this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null; - if (this.searchedWord) { - const queryBody = this.searchConfiguration.generateQueryBody(this.searchedWord, 0, 100); + const searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null; + if (searchedWord) { + const queryBody = this.searchConfiguration.generateQueryBody(searchedWord, 0, 100); this.queryBuilder.userQuery = queryBody.query.query; this.queryBuilder.update(); From b6938060aecec7859fa42a518808afc1f93d69b9 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 12 Jun 2018 19:16:01 +0100 Subject: [PATCH 086/179] fix snackbar selector --- e2e/pages/page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/pages/page.ts b/e2e/pages/page.ts index 570b40c007..f4d3343426 100755 --- a/e2e/pages/page.ts +++ b/e2e/pages/page.ts @@ -35,7 +35,7 @@ export abstract class Page { overlay: by.css('.cdk-overlay-container'), dialogContainer: by.css('.mat-dialog-container'), snackBarContainer: '.cdk-overlay-pane snack-bar-container.mat-snack-bar-container', - snackBar: 'simple-snack-bar', + snackBar: 'mat-simple-snackbar', snackBarAction: 'button.mat-simple-snackbar-action' }; From 66206005502bba0483c15d3e562481d28cb845fe Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 12 Jun 2018 20:00:32 +0100 Subject: [PATCH 087/179] Revert "fix snackbar selector" This reverts commit b6938060aecec7859fa42a518808afc1f93d69b9. --- e2e/pages/page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/pages/page.ts b/e2e/pages/page.ts index f4d3343426..570b40c007 100755 --- a/e2e/pages/page.ts +++ b/e2e/pages/page.ts @@ -35,7 +35,7 @@ export abstract class Page { overlay: by.css('.cdk-overlay-container'), dialogContainer: by.css('.mat-dialog-container'), snackBarContainer: '.cdk-overlay-pane snack-bar-container.mat-snack-bar-container', - snackBar: 'mat-simple-snackbar', + snackBar: 'simple-snack-bar', snackBarAction: 'button.mat-simple-snackbar-action' }; From a849a215bbdf8128a40ee22f88d2353db347a8d5 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 13 Jun 2018 14:21:09 +0100 Subject: [PATCH 088/179] [ACA-1379] Search Results Actions and Bulk Actions (#406) * download actions and effects * download multiple search results * remove inline toolbar * base page and toolbar for the Search results * toolbar actions * update search settings * toggle favorites from search results * manage versions dialog * folder navigation * sidebar integration * remove obsolete style --- src/app/app.module.ts | 7 +- src/app/components/files/files.component.ts | 2 +- .../components/search/search.component.html | 189 ++++++++++++------ src/app/components/search/search.component.ts | 36 +++- .../directives/download-nodes.directive.ts | 58 ++++++ src/app/store/actions/node.action.ts | 8 + src/app/store/actions/router.action.ts | 6 + src/app/store/effects/download.effects.ts | 86 ++++++++ src/app/store/effects/router.effects.ts | 44 +++- 9 files changed, 362 insertions(+), 74 deletions(-) create mode 100644 src/app/directives/download-nodes.directive.ts create mode 100644 src/app/store/effects/download.effects.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a4943d35f3..711a02d838 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -85,6 +85,8 @@ import { NodeEffects } from './store/effects/node.effects'; import { environment } from '../environments/environment'; import { RouterEffects } from './store/effects/router.effects'; import { CreateFolderDirective } from './directives/create-folder.directive'; +import { DownloadEffects } from './store/effects/download.effects'; +import { DownloadNodesDirective } from './directives/download-nodes.directive'; @NgModule({ @@ -108,7 +110,7 @@ import { CreateFolderDirective } from './directives/create-folder.directive'; StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), StoreRouterConnectingModule.forRoot({ stateKey: 'router' }), - EffectsModule.forRoot([SnackbarEffects, NodeEffects, RouterEffects]), + EffectsModule.forRoot([SnackbarEffects, NodeEffects, RouterEffects, DownloadEffects]), !environment.production ? StoreDevtoolsModule.instrument({ maxAge: 25 }) : [] ], declarations: [ @@ -143,7 +145,8 @@ import { CreateFolderDirective } from './directives/create-folder.directive'; SortingPreferenceKeyDirective, InfoDrawerComponent, EditFolderDirective, - CreateFolderDirective + CreateFolderDirective, + DownloadNodesDirective ], providers: [ { provide: PageTitleService, useClass: AcaPageTitleService }, diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index bb25fe00c7..3bba704b3f 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -139,7 +139,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { }); } - onNodeDoubleClick(event) { + onNodeDoubleClick(event: CustomEvent) { if (!!event.detail && !!event.detail.node) { const node: MinimalNodeEntryEntity = event.detail.node.entry; diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 4d2e0347a7..de16027fba 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -2,6 +2,65 @@
+ + + + + + + + + + + + + + + + +
@@ -11,77 +70,87 @@
-
- +
+
+ -
-
-
{{ 'APP.BROWSE.SEARCH.FOUND_RESULTS' | translate: { number: totalResults } }}
- -
+
+
+
{{ 'APP.BROWSE.SEARCH.FOUND_RESULTS' | translate: { number: totalResults } }}
+ +
- + - - - - - - - - - - - - + + + + + + + + + + + + - - -
-

Your search returned 0 results

-
-
-
-
+ + +
+

Your search returned 0 results

+
+
+
+
- - + + +
+
+ +
diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index 9a127c4294..fdb6c4b82f 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -23,23 +23,28 @@ * along with Alfresco. If not, see . */ -import { Component, OnInit, Optional, ViewChild } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api'; import { Router, ActivatedRoute, Params } from '@angular/router'; -import { SearchQueryBuilderService, SearchComponent as AdfSearchComponent } from '@alfresco/adf-content-services'; -import { SearchConfigurationService } from '@alfresco/adf-core'; +import { SearchQueryBuilderService, SearchComponent as AdfSearchComponent, NodePermissionService } from '@alfresco/adf-content-services'; +import { SearchConfigurationService, UserPreferencesService, SearchService } from '@alfresco/adf-core'; import { PageComponent } from '../page.component'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../../store/states/app.state'; +import { NavigateToLocationAction } from '../../store/actions'; @Component({ selector: 'app-search', templateUrl: './search.component.html', - styleUrls: ['./search.component.scss'] + styleUrls: ['./search.component.scss'], + providers: [SearchService] }) -export class SearchComponent implements OnInit { +export class SearchComponent extends PageComponent implements OnInit { @ViewChild('search') search: AdfSearchComponent; + searchedWord: string; queryParamName = 'q'; data: NodePaging; totalResults = 0; @@ -48,10 +53,15 @@ export class SearchComponent implements OnInit { sorting = ['name', 'asc']; constructor( - public router: Router, + public permission: NodePermissionService, private queryBuilder: SearchQueryBuilderService, private searchConfiguration: SearchConfigurationService, - @Optional() private route: ActivatedRoute) { + store: Store, + router: Router, + preferences: UserPreferencesService, + route: ActivatedRoute) { + super(preferences, router, route, store); + queryBuilder.paging = { skipCount: 0, maxItems: 25 @@ -59,6 +69,8 @@ export class SearchComponent implements OnInit { } ngOnInit() { + super.ngOnInit(); + this.sorting = this.getSorting(); this.queryBuilder.updated.subscribe(() => { @@ -67,9 +79,9 @@ export class SearchComponent implements OnInit { if (this.route) { this.route.params.forEach((params: Params) => { - const searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null; - if (searchedWord) { - const queryBody = this.searchConfiguration.generateQueryBody(searchedWord, 0, 100); + this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null; + if (this.searchedWord) { + const queryBody = this.searchConfiguration.generateQueryBody(this.searchedWord, 0, 100); this.queryBuilder.userQuery = queryBody.query.query; this.queryBuilder.update(); @@ -112,6 +124,10 @@ export class SearchComponent implements OnInit { } onNodeDoubleClick(node: MinimalNodeEntryEntity) { + if (node && node.isFolder) { + this.store.dispatch(new NavigateToLocationAction(node)); + } + if (node && PageComponent.isLockedNode(node)) { event.preventDefault(); diff --git a/src/app/directives/download-nodes.directive.ts b/src/app/directives/download-nodes.directive.ts new file mode 100644 index 0000000000..53a7904045 --- /dev/null +++ b/src/app/directives/download-nodes.directive.ts @@ -0,0 +1,58 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Directive, HostListener, Input } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../store/states/app.state'; +import { MinimalNodeEntity } from '@alfresco/adf-core/node_modules/alfresco-js-api'; +import { DownloadNodesAction } from '../store/actions'; + +@Directive({ + selector: '[acaDownloadNodes]' +}) +export class DownloadNodesDirective { + // tslint:disable-next-line:no-input-rename + @Input('acaDownloadNodes') + nodes: Array | MinimalNodeEntity; + + constructor(private store: Store) {} + + @HostListener('click') + onClick() { + const targets = Array.isArray(this.nodes) ? this.nodes : [this.nodes]; + const toDownload = targets.map(node => { + const { id, nodeId, name, isFile, isFolder } = node.entry; + + return { + id: nodeId || id, + name, + isFile, + isFolder + }; + }); + + this.store.dispatch(new DownloadNodesAction(toDownload)); + } +} diff --git a/src/app/store/actions/node.action.ts b/src/app/store/actions/node.action.ts index e76bd7bc50..4d7cb313a7 100644 --- a/src/app/store/actions/node.action.ts +++ b/src/app/store/actions/node.action.ts @@ -5,10 +5,13 @@ export const DELETE_NODES = 'DELETE_NODES'; export const UNDO_DELETE_NODES = 'UNDO_DELETE_NODES'; export const RESTORE_DELETED_NODES = 'RESTORE_DELETED_NODES'; export const PURGE_DELETED_NODES = 'PURGE_DELETED_NODES'; +export const DOWNLOAD_NODES = 'DOWNLOAD_NODES'; export interface NodeInfo { id: string; name: string; + isFile?: boolean; + isFolder?: boolean; } export class SetSelectedNodesAction implements Action { @@ -35,3 +38,8 @@ export class PurgeDeletedNodesAction implements Action { readonly type = PURGE_DELETED_NODES; constructor(public payload: NodeInfo[] = []) {} } + +export class DownloadNodesAction implements Action { + readonly type = DOWNLOAD_NODES; + constructor(public payload: NodeInfo[] = []) {} +} diff --git a/src/app/store/actions/router.action.ts b/src/app/store/actions/router.action.ts index 859f4918c2..5bedc85afc 100644 --- a/src/app/store/actions/router.action.ts +++ b/src/app/store/actions/router.action.ts @@ -1,8 +1,14 @@ import { Action } from '@ngrx/store'; export const NAVIGATE_ROUTE = 'NAVIGATE_ROUTE'; +export const NAVIGATE_LOCATION = 'NAVIGATE_LOCATION'; export class NavigateRouteAction implements Action { readonly type = NAVIGATE_ROUTE; constructor(public payload: any[]) {} } + +export class NavigateToLocationAction implements Action { + readonly type = NAVIGATE_LOCATION; + constructor(public payload: any) {} +} diff --git a/src/app/store/effects/download.effects.ts b/src/app/store/effects/download.effects.ts new file mode 100644 index 0000000000..224c9afef5 --- /dev/null +++ b/src/app/store/effects/download.effects.ts @@ -0,0 +1,86 @@ +import { Effect, Actions, ofType } from '@ngrx/effects'; +import { Injectable } from '@angular/core'; +import { map } from 'rxjs/operators'; +import { DownloadNodesAction, DOWNLOAD_NODES } from '../actions'; +import { AlfrescoApiService } from '@alfresco/adf-core'; +import { MatDialog } from '@angular/material'; +import { NodeInfo } from '../actions/node.action'; +import { DownloadZipDialogComponent } from '@alfresco/adf-content-services'; + +@Injectable() +export class DownloadEffects { + constructor( + private actions$: Actions, + private apiService: AlfrescoApiService, + private dialog: MatDialog + ) {} + + @Effect({ dispatch: false }) + downloadNode$ = this.actions$.pipe( + ofType(DOWNLOAD_NODES), + map(action => { + if (action.payload && action.payload.length > 0) { + this.downloadNodes(action.payload); + } + }) + ); + + private downloadNodes(nodes: Array) { + if (!nodes || nodes.length === 0) { + return; + } + + if (nodes.length === 1) { + this.downloadNode(nodes[0]); + } else { + this.downloadZip(nodes); + } + } + + private downloadNode(node: NodeInfo) { + if (node) { + if (node.isFolder) { + this.downloadZip([node]); + } else { + this.downloadFile(node); + } + } + } + + private downloadFile(node: NodeInfo) { + if (node) { + this.download( + this.apiService.contentApi.getContentUrl(node.id, true), + node.name + ); + } + } + + private downloadZip(nodes: Array) { + if (nodes && nodes.length > 0) { + const nodeIds = nodes.map(node => node.id); + + this.dialog.open(DownloadZipDialogComponent, { + width: '600px', + disableClose: true, + data: { + nodeIds + } + }); + } + } + + private download(url: string, fileName: string) { + if (url && fileName) { + const link = document.createElement('a'); + + link.style.display = 'none'; + link.download = fileName; + link.href = url; + + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + } +} diff --git a/src/app/store/effects/router.effects.ts b/src/app/store/effects/router.effects.ts index b5d761cda6..08adb84cd7 100644 --- a/src/app/store/effects/router.effects.ts +++ b/src/app/store/effects/router.effects.ts @@ -1,6 +1,9 @@ import { Effect, Actions, ofType } from '@ngrx/effects'; import { Injectable } from '@angular/core'; -import { NavigateRouteAction, NAVIGATE_ROUTE } from '../actions/router.action'; +import { PathInfoEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; +import { + NavigateRouteAction, NAVIGATE_ROUTE, NavigateToLocationAction, NAVIGATE_LOCATION +} from '../actions/router.action'; import { map } from 'rxjs/operators'; import { Router } from '@angular/router'; @@ -15,4 +18,43 @@ export class RouterEffects { this.router.navigate(action.payload); }) ); + + @Effect({ dispatch: false }) + navigateLocation$ = this.actions$.pipe( + ofType(NAVIGATE_LOCATION), + map(action => { + if (action.payload) { + this.navigateToLocation(action.payload); + } + }) + ); + + private navigateToLocation(node: MinimalNodeEntryEntity) { + let link = null; + const { path } = node; + + if (path && path.name && path.elements) { + const isLibraryPath = this.isLibraryContent(path); + + const parent = path.elements[path.elements.length - 1]; + const area = isLibraryPath ? '/libraries' : '/personal-files'; + + if (!isLibraryPath) { + link = [ area, parent.id ]; + } else { + // parent.id could be 'Site' folder or child as 'documentLibrary' + link = [ area, (parent.name === 'Sites' ? {} : parent.id) ]; + } + } + + this.router.navigate(link); + } + + private isLibraryContent(path: PathInfoEntity): boolean { + if (path && path.elements.length >= 2 && path.elements[1].name === 'Sites') { + return true; + } + + return false; + } } From e8ad0ad9ab420a4191eaf7cfe0bed02ec35d9b10 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 13 Jun 2018 16:56:59 +0300 Subject: [PATCH 089/179] manage version for favorite nodes (#405) --- src/app/common/directives/node-versions.directive.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/common/directives/node-versions.directive.ts b/src/app/common/directives/node-versions.directive.ts index 49c7ee4848..e94d6c13a5 100644 --- a/src/app/common/directives/node-versions.directive.ts +++ b/src/app/common/directives/node-versions.directive.ts @@ -58,9 +58,9 @@ export class NodeVersionsDirective { if (this.node && this.node.entry) { let entry = this.node.entry; - if (entry.nodeId) { + if (entry.nodeId || (entry).guid) { entry = await this.apiService.nodesApi.getNodeInfo( - entry.nodeId, + entry.nodeId || (entry).id, { include: ['allowableOperations'] } ); this.openVersionManagerDialog(entry); From 1384a0e49df3dcac568a0146a6534d685e799796 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 13 Jun 2018 17:25:10 +0300 Subject: [PATCH 090/179] styling (#407) --- .../components/search/search.component.html | 17 ++++++++------ .../components/search/search.component.scss | 22 +++++++++++++++---- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index de16027fba..3116bca57a 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -63,10 +63,6 @@
-
- -
-
-
-
{{ 'APP.BROWSE.SEARCH.FOUND_RESULTS' | translate: { number: totalResults } }}
- +
+
+
{{ 'APP.BROWSE.SEARCH.FOUND_RESULTS' | translate: { number: totalResults } }}
+ +
+ +
+
+ +
Date: Wed, 13 Jun 2018 17:25:23 +0300 Subject: [PATCH 091/179] fix import (#408) --- src/app/directives/download-nodes.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/directives/download-nodes.directive.ts b/src/app/directives/download-nodes.directive.ts index 53a7904045..ea2d61dc71 100644 --- a/src/app/directives/download-nodes.directive.ts +++ b/src/app/directives/download-nodes.directive.ts @@ -26,7 +26,7 @@ import { Directive, HostListener, Input } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppStore } from '../store/states/app.state'; -import { MinimalNodeEntity } from '@alfresco/adf-core/node_modules/alfresco-js-api'; +import { MinimalNodeEntity } from 'alfresco-js-api'; import { DownloadNodesAction } from '../store/actions'; @Directive({ From 2d7e844d8f7e479c76af30292e7cc2698689f3bd Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 13 Jun 2018 18:10:46 +0100 Subject: [PATCH 092/179] turn ADF customisations into theme mixins (#409) * theming support for upload dialog customisations * pagination theme * about dialog theme * update shared workspace settings for VS code * remove hardcoded color variable * upgrade sidenav theme * document list theme * upload drag area theme --- .vscode/settings.json | 9 +- src/app/components/about/about.component.scss | 37 -------- .../about/about.component.theme.scss | 39 ++++++++ src/app/components/about/about.component.ts | 3 +- src/app/ui/_variables.scss | 7 -- src/app/ui/application.scss | 9 +- src/app/ui/custom-theme.scss | 17 +++- src/app/ui/overrides/_adf-sidenav-layout.scss | 18 ---- .../ui/overrides/_alfresco-document-list.scss | 86 ----------------- .../ui/overrides/_alfresco-upload-dialog.scss | 31 ------- .../overrides/_alfresco-upload-drag-area.scss | 76 --------------- .../ui/overrides/adf-document-list.theme.scss | 92 +++++++++++++++++++ .../ui/overrides/adf-pagination.theme.scss | 7 ++ .../overrides/adf-sidenav-layout.theme.scss | 20 ++++ .../ui/overrides/adf-upload-dialog.theme.scss | 31 +++++++ .../overrides/adf-upload-drag-area.theme.scss | 83 +++++++++++++++++ 16 files changed, 296 insertions(+), 269 deletions(-) delete mode 100644 src/app/components/about/about.component.scss create mode 100644 src/app/components/about/about.component.theme.scss delete mode 100644 src/app/ui/overrides/_adf-sidenav-layout.scss delete mode 100644 src/app/ui/overrides/_alfresco-document-list.scss delete mode 100644 src/app/ui/overrides/_alfresco-upload-dialog.scss delete mode 100644 src/app/ui/overrides/_alfresco-upload-drag-area.scss create mode 100644 src/app/ui/overrides/adf-document-list.theme.scss create mode 100644 src/app/ui/overrides/adf-pagination.theme.scss create mode 100644 src/app/ui/overrides/adf-sidenav-layout.theme.scss create mode 100644 src/app/ui/overrides/adf-upload-dialog.theme.scss create mode 100644 src/app/ui/overrides/adf-upload-drag-area.theme.scss diff --git a/.vscode/settings.json b/.vscode/settings.json index acadd47def..831fd7c983 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { - "cSpell.words": [ - "sidenav" - ] -} \ No newline at end of file + "javascript.preferences.quoteStyle": "single", + "typescript.preferences.quoteStyle": "single", + "javascript.preferences.importModuleSpecifier": "relative", + "typescript.preferences.importModuleSpecifier": "relative" +} diff --git a/src/app/components/about/about.component.scss b/src/app/components/about/about.component.scss deleted file mode 100644 index 6e5d684cdd..0000000000 --- a/src/app/components/about/about.component.scss +++ /dev/null @@ -1,37 +0,0 @@ -@import 'variables'; - -article { - color: $alfresco-secondary-text-color; -} - -article:first-of-type { - padding-bottom: 0; -} - -article:last-of-type { - margin-bottom: 50px; -} - -header { - line-height: 24px; - font-size: 14px; - font-weight: 800; - letter-spacing: -0.2px; -} - -a { - text-decoration: none; - color: $alfresco-primary-text-color; -} - -.padding { - padding: 25px; -} - -.padding-top-bottom { - padding: 25px 0 25px 0; -} - -.padding-left-right { - padding: 0 25px 0 25px; -} diff --git a/src/app/components/about/about.component.theme.scss b/src/app/components/about/about.component.theme.scss new file mode 100644 index 0000000000..71be08396d --- /dev/null +++ b/src/app/components/about/about.component.theme.scss @@ -0,0 +1,39 @@ +@mixin aca-about-component-theme($theme) { + $foreground: map-get($theme, foreground); + + article { + color: mat-color($foreground, text, 0.54); + } + + article:first-of-type { + padding-bottom: 0; + } + + article:last-of-type { + margin-bottom: 50px; + } + + header { + line-height: 24px; + font-size: 14px; + font-weight: 800; + letter-spacing: -0.2px; + } + + a { + text-decoration: none; + color: mat-color($foreground, text, 0.87); + } + + .padding { + padding: 25px; + } + + .padding-top-bottom { + padding: 25px 0 25px 0; + } + + .padding-left-right { + padding: 0 25px 0 25px; + } +} diff --git a/src/app/components/about/about.component.ts b/src/app/components/about/about.component.ts index 8bcad5897c..0c55d3f131 100644 --- a/src/app/components/about/about.component.ts +++ b/src/app/components/about/about.component.ts @@ -30,8 +30,7 @@ import { EcmProductVersionModel, ObjectDataTableAdapter } from '@alfresco/adf-c @Component({ selector: 'app-about', - templateUrl: './about.component.html', - styleUrls: [ './about.component.scss' ] + templateUrl: './about.component.html' }) export class AboutComponent implements OnInit { ecmVersion: EcmProductVersionModel = null; diff --git a/src/app/ui/_variables.scss b/src/app/ui/_variables.scss index 25054d3183..02fdf15ec4 100644 --- a/src/app/ui/_variables.scss +++ b/src/app/ui/_variables.scss @@ -1,13 +1,6 @@ -// Primary color palette -// - please note that Hue 2 and Enhanced Hue 1 and 2 -// are missing from specs -$alfresco-app-color--default: #00bcd4; -$alfresco-app-color--hue-1: #e0f7fa; - // Grayscale $alfresco-white: #fff; $alfresco-black: #000; // Dark -$alfresco-primary-text-color: rgba($alfresco-black, .87); $alfresco-secondary-text-color: rgba($alfresco-black, .54); diff --git a/src/app/ui/application.scss b/src/app/ui/application.scss index 461c404ff9..e04d525abf 100644 --- a/src/app/ui/application.scss +++ b/src/app/ui/application.scss @@ -2,11 +2,13 @@ @import 'variables'; @import 'theme'; +$foreground: map-get($theme, foreground); + html, body { @include flex-column; font-size: 14px; font-family: "Muli", sans-serif; - color: $alfresco-primary-text-color; + color: mat-color($foreground, text, 0.87); margin: 0; & > main { @@ -24,8 +26,3 @@ ng-component { } @import 'layout'; - -@import './overrides/adf-sidenav-layout'; -@import './overrides/alfresco-document-list'; -@import './overrides/alfresco-upload-drag-area'; -@import './overrides/alfresco-upload-dialog'; diff --git a/src/app/ui/custom-theme.scss b/src/app/ui/custom-theme.scss index 0a6b0020ce..8e8ed64799 100644 --- a/src/app/ui/custom-theme.scss +++ b/src/app/ui/custom-theme.scss @@ -2,11 +2,18 @@ @import '~@alfresco/adf-content-services/theming'; @import '../components/sidenav/sidenav.component.theme'; +@import '../components/about/about.component.theme'; @import './overrides/adf-toolbar.theme'; @import './overrides/adf-search-filter.theme'; @import './overrides/adf-info-drawer.theme'; @import './overrides/adf-upload-button.theme'; @import './overrides/adf-sidebar-action-menu.theme'; +@import './overrides/adf-upload-dialog.theme'; +@import './overrides/adf-pagination.theme'; +@import './overrides/adf-sidenav-layout.theme'; +@import './overrides/adf-document-list.theme'; +@import './overrides/adf-upload-drag-area.theme'; + @import 'snackbar'; $grey-scale: ( @@ -50,11 +57,17 @@ $custom-theme-warn: mat-palette($alfresco-warn); $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent); @mixin custom-theme($theme) { - @include sidenav-component-theme($custom-theme); @include adf-toolbar-theme($custom-theme); - @include snackbar-theme($custom-theme); @include adf-search-filter-theme($custom-theme); @include adf-info-drawer-theme($custom-theme); @include adf-upload-button-theme($custom-theme); @include adf-sidebar-action-menu-theme($custom-theme); + @include adf-pagination-theme($custom-theme); + @include adf-sidenav-layout-theme($custom-theme); + @include adf-document-list-theme($custom-theme); + @include adf-upload-drag-area-theme($custom-theme); + + @include snackbar-theme($custom-theme); + @include sidenav-component-theme($custom-theme); + @include aca-about-component-theme($custom-theme); } diff --git a/src/app/ui/overrides/_adf-sidenav-layout.scss b/src/app/ui/overrides/_adf-sidenav-layout.scss deleted file mode 100644 index cdec99c348..0000000000 --- a/src/app/ui/overrides/_adf-sidenav-layout.scss +++ /dev/null @@ -1,18 +0,0 @@ -@import 'mixins'; - -adf-sidenav-layout { - @include flex-column; - - .mat-drawer-content { - @include flex-column; - overflow: auto; - } -} - -.sidenav-layout { - @include flex-column; -} - -.mat-drawer-content>div, .mat-drawer-content>div>div { - @include flex-column; -} diff --git a/src/app/ui/overrides/_alfresco-document-list.scss b/src/app/ui/overrides/_alfresco-document-list.scss deleted file mode 100644 index 737b54ecd8..0000000000 --- a/src/app/ui/overrides/_alfresco-document-list.scss +++ /dev/null @@ -1,86 +0,0 @@ -@import 'variables'; -@import 'mixins'; - -adf-document-list { - @include flex-column; - background-color: white; // TODO: remove when ADF 2.4.0 is out. -} - -adf-datatable { - @include flex-column; - overflow-y: scroll; -} - -.adf-data-table { - border: none !important; - - .adf-datatable-header, .adf-datatable-row, .adf-data-table-cell { - color: $alfresco-secondary-text-color; - &:focus { - outline: none !important; - } - } - - .adf-datatable-table-cell-header:focus { - outline: none !important; - } - - .adf-datatable-body .adf-datatable-row { - &:hover, &:focus { - background-color: $alfresco-app-color--hue-1; - } - - &.is-selected, &.is-selected:hover { - background-color: $alfresco-app-color--hue-1; - } - } - - .adf-data-table-cell, .adf-datatable-header { - width: 100%; - text-align: left; - } - - .adf-datatable-body .adf-data-table-cell--image { - padding-left: 24px; - padding-right: 0; - width: 10px; - } - - .adf-data-table-cell--ellipsis .cell-value, - .adf-data-table-cell--ellipsis__name .cell-value { - display: flex; - align-items: center; - } - - .adf-data-table-cell--ellipsis .adf-datatable-cell, - .adf-data-table-cell--ellipsis__name .adf-datatable-cell { - white-space: nowrap; - display: block; - overflow: hidden; - text-overflow: ellipsis; - } - - .adf-data-table-cell--ellipsis .adf-datatable-cell { - max-width: 7vw; - } - - .adf-data-table-cell--ellipsis__name .adf-datatable-cell { - position: absolute; - max-width: calc(100% - 2em); - } - - .adf-datatable-row:last-child .adf-datatable-table-cell { - border-bottom: 1px solid rgba(0, 0, 0, 0.07); - } - - &.adf-data-table--empty { - .adf-datatable-row:hover, - .adf-datatable-row:focus { - background-color: unset; - } - } -} - -.adf-pagination__empty { - display: none; -} diff --git a/src/app/ui/overrides/_alfresco-upload-dialog.scss b/src/app/ui/overrides/_alfresco-upload-dialog.scss deleted file mode 100644 index 76d9a1382f..0000000000 --- a/src/app/ui/overrides/_alfresco-upload-dialog.scss +++ /dev/null @@ -1,31 +0,0 @@ -@import 'variables'; - -$alfresco-primary-accent--hue-3: #ff6d00; -$alfresco-warn-color--hue-3: #d50000; -$alfresco-dark-color--hue-3: #546e7a; - -.upload-dialog { - z-index: 999; -} - -.adf-file-uploading-row { - &__status { - &--done { - color: $alfresco-app-color--default !important; - } - - &--error { - color: $alfresco-primary-accent--hue-3 !important; - } - } - - &__action { - &--cancel { - color: $alfresco-warn-color--hue-3 !important; - } - - &--remove { - color: $alfresco-dark-color--hue-3 !important; - } - } -} diff --git a/src/app/ui/overrides/_alfresco-upload-drag-area.scss b/src/app/ui/overrides/_alfresco-upload-drag-area.scss deleted file mode 100644 index afafe9d43e..0000000000 --- a/src/app/ui/overrides/_alfresco-upload-drag-area.scss +++ /dev/null @@ -1,76 +0,0 @@ -@import 'mixins'; -@import 'variables.scss'; - -@mixin file-draggable__input-focus { - color: $alfresco-secondary-text-color !important; - border: 1px solid $alfresco-app-color--default !important; - margin-left: 0 !important; -} - -adf-upload-drag-area { - @include flex-column; - - .upload-border { - @include flex-column; - - vertical-align: unset; - text-align: unset; - } -} - -adf-upload-drag-area:first-child { - & > div { - adf-upload-drag-area { - .file-draggable__input-focus { - @include file-draggable__input-focus; - } - } - } - - .upload-border { - vertical-align: inherit !important; - text-align: inherit !important; - } - - .file-draggable__input-focus { - color: none !important; - border: none !important; - margin-left: 0 !important; - - adf-upload-drag-area { - & > div { - @include file-draggable__input-focus; - } - } - } -} - -adf-upload-drag-area { - .file-draggable__input-focus { - adf-document-list { - background: $alfresco-app-color--hue-1; - - adf-datatable > table { - background: inherit; - } - } - } - - .adf-upload__dragging { - background: $alfresco-app-color--hue-1; - color: $alfresco-secondary-text-color !important; - } - - .adf-upload__dragging td { - border-top: 1px solid $alfresco-app-color--default !important; - border-bottom: 1px solid $alfresco-app-color--default !important; - - &:first-child { - border-left: 1px solid $alfresco-app-color--default !important; - } - - &:last-child { - border-right: 1px solid $alfresco-app-color--default !important; - } - } -} diff --git a/src/app/ui/overrides/adf-document-list.theme.scss b/src/app/ui/overrides/adf-document-list.theme.scss new file mode 100644 index 0000000000..95691ef0b3 --- /dev/null +++ b/src/app/ui/overrides/adf-document-list.theme.scss @@ -0,0 +1,92 @@ +@import 'variables'; +@import 'mixins'; + +@mixin adf-document-list-theme($theme) { + $foreground: map-get($theme, foreground); + $primary: map-get($theme, primary); + + adf-document-list { + @include flex-column; + background-color: white; // TODO: remove when ADF 2.4.0 is out. + } + + adf-datatable { + @include flex-column; + overflow-y: scroll; + } + + .adf-data-table { + border: none !important; + + .adf-datatable-selected > svg { + // fill: mat-color($primary); + fill: #2196f3; + } + + .adf-datatable-header, .adf-datatable-row, .adf-data-table-cell { + color: mat-color($foreground, text, 0.54); + &:focus { + outline: none !important; + } + } + + .adf-datatable-table-cell-header:focus { + outline: none !important; + } + + .adf-datatable-body .adf-datatable-row { + &:hover, &:focus { + background-color: #e0f7fa; + } + + &.is-selected, &.is-selected:hover { + background-color: #e0f7fa; + } + } + + .adf-data-table-cell, .adf-datatable-header { + width: 100%; + text-align: left; + } + + .adf-datatable-body .adf-data-table-cell--image { + padding-left: 24px; + padding-right: 0; + width: 10px; + } + + .adf-data-table-cell--ellipsis .cell-value, + .adf-data-table-cell--ellipsis__name .cell-value { + display: flex; + align-items: center; + } + + .adf-data-table-cell--ellipsis .adf-datatable-cell, + .adf-data-table-cell--ellipsis__name .adf-datatable-cell { + white-space: nowrap; + display: block; + overflow: hidden; + text-overflow: ellipsis; + } + + .adf-data-table-cell--ellipsis .adf-datatable-cell { + max-width: 7vw; + } + + .adf-data-table-cell--ellipsis__name .adf-datatable-cell { + position: absolute; + max-width: calc(100% - 2em); + } + + .adf-datatable-row:last-child .adf-datatable-table-cell { + border-bottom: 1px solid rgba(0, 0, 0, 0.07); + } + + &.adf-data-table--empty { + .adf-datatable-row:hover, + .adf-datatable-row:focus { + background-color: unset; + } + } + } +} diff --git a/src/app/ui/overrides/adf-pagination.theme.scss b/src/app/ui/overrides/adf-pagination.theme.scss new file mode 100644 index 0000000000..47060f65bf --- /dev/null +++ b/src/app/ui/overrides/adf-pagination.theme.scss @@ -0,0 +1,7 @@ +@mixin adf-pagination-theme($theme) { + .adf-pagination { + &.adf-pagination__empty { + display: none; + } + } +} diff --git a/src/app/ui/overrides/adf-sidenav-layout.theme.scss b/src/app/ui/overrides/adf-sidenav-layout.theme.scss new file mode 100644 index 0000000000..06b2490e67 --- /dev/null +++ b/src/app/ui/overrides/adf-sidenav-layout.theme.scss @@ -0,0 +1,20 @@ +@import 'mixins'; + +@mixin adf-sidenav-layout-theme($theme) { + adf-sidenav-layout { + @include flex-column; + + .mat-drawer-content { + @include flex-column; + overflow: auto; + } + } + + .sidenav-layout { + @include flex-column; + } + + .mat-drawer-content>div, .mat-drawer-content>div>div { + @include flex-column; + } +} diff --git a/src/app/ui/overrides/adf-upload-dialog.theme.scss b/src/app/ui/overrides/adf-upload-dialog.theme.scss new file mode 100644 index 0000000000..1b232ee3e1 --- /dev/null +++ b/src/app/ui/overrides/adf-upload-dialog.theme.scss @@ -0,0 +1,31 @@ +@mixin adf-upload-dialog-theme($theme) { + $primary: map-get($theme, primary); + $accent: map-get($theme, accent); + $warn: map-get($theme, warn); + + .upload-dialog { + z-index: 999; + } + + .adf-file-uploading-row { + &__status { + &--done { + color: mat-color($accent); + } + + &--error { + color: mat-color($warn); + } + } + + &__action { + &--cancel { + color: mat-color($warn); + } + + &--remove { + color: mat-color($warn); + } + } + } +} diff --git a/src/app/ui/overrides/adf-upload-drag-area.theme.scss b/src/app/ui/overrides/adf-upload-drag-area.theme.scss new file mode 100644 index 0000000000..ad5d4d35d5 --- /dev/null +++ b/src/app/ui/overrides/adf-upload-drag-area.theme.scss @@ -0,0 +1,83 @@ +@import 'mixins'; + +$alfresco-app-color--default: #00bcd4; + +@mixin file-draggable__input-focus($theme) { + $foreground: map-get($theme, foreground); + + color: mat-color($foreground, text, 0.54); + border: 1px solid $alfresco-app-color--default !important; + margin-left: 0 !important; +} + +@mixin adf-upload-drag-area-theme($theme) { + $foreground: map-get($theme, foreground); + + adf-upload-drag-area { + @include flex-column; + + .upload-border { + @include flex-column; + + vertical-align: unset; + text-align: unset; + } + } + + adf-upload-drag-area:first-child { + & > div { + adf-upload-drag-area { + .file-draggable__input-focus { + @include file-draggable__input-focus($theme); + } + } + } + + .upload-border { + vertical-align: inherit !important; + text-align: inherit !important; + } + + .file-draggable__input-focus { + color: none !important; + border: none !important; + margin-left: 0 !important; + + adf-upload-drag-area { + & > div { + @include file-draggable__input-focus($theme); + } + } + } + } + + adf-upload-drag-area { + .file-draggable__input-focus { + adf-document-list { + background: #e0f7fa; + + adf-datatable > table { + background: inherit; + } + } + } + + .adf-upload__dragging { + background: #e0f7fa; + color: mat-color($foreground, text, 0.54); + } + + .adf-upload__dragging td { + border-top: 1px solid $alfresco-app-color--default !important; + border-bottom: 1px solid $alfresco-app-color--default !important; + + &:first-child { + border-left: 1px solid $alfresco-app-color--default !important; + } + + &:last-child { + border-right: 1px solid $alfresco-app-color--default !important; + } + } + } +} From d1e5353d7ad1e2304cbecfab4f85b8a6573fcd71 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 14 Jun 2018 13:32:02 +0300 Subject: [PATCH 093/179] use navigation @effect (#410) --- .../location-link/location-link.component.ts | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/app/components/location-link/location-link.component.ts b/src/app/components/location-link/location-link.component.ts index dc198a35de..a64d7c9eff 100644 --- a/src/app/components/location-link/location-link.component.ts +++ b/src/app/components/location-link/location-link.component.ts @@ -28,10 +28,14 @@ import { AlfrescoApiService, DataColumn, DataRow, DataTableAdapter } from '@alfr import { PathInfoEntity } from 'alfresco-js-api'; import { Observable } from 'rxjs/Rx'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../../store/states/app.state'; +import { NavigateToLocationAction } from '../../store/actions'; + @Component({ selector: 'app-location-link', template: ` - + {{ displayText | async }} `, @@ -56,7 +60,17 @@ export class LocationLinkComponent implements OnInit { @Input() tooltip: Observable; - constructor(private apiService: AlfrescoApiService) { + constructor( + private store: Store, + private apiService: AlfrescoApiService) { + } + + goToLocation() { + if (this.context) { + const { node } = this.context.row; + + this.store.dispatch(new NavigateToLocationAction(node.entry)); + } } ngOnInit() { @@ -67,31 +81,12 @@ export class LocationLinkComponent implements OnInit { const value: PathInfoEntity = data.getValue(row, col); if (value && value.name && value.elements) { - const isLibraryPath = this.isLibraryContent(value); - this.displayText = this.getDisplayText(value); this.tooltip = this.getTooltip(value); - - const parent = value.elements[value.elements.length - 1]; - const area = isLibraryPath ? '/libraries' : '/personal-files'; - - if (!isLibraryPath) { - this.link = [ area, parent.id ]; - } else { - // parent.id could be 'Site' folder or child as 'documentLibrary' - this.link = [ area, (parent.name === 'Sites' ? {} : parent.id) ]; - } } } } - private isLibraryContent(path: PathInfoEntity): boolean { - if (path && path.elements.length >= 2 && path.elements[1].name === 'Sites') { - return true; - } - return false; - } - // todo: review once 5.2.3 is out private getDisplayText(path: PathInfoEntity): Observable { const elements = path.elements.map(e => e.name); From f8fe664f1fbb17b0c1447d3c5c34cff982748f2d Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 14 Jun 2018 14:10:31 +0100 Subject: [PATCH 094/179] [ACA-1455] universal Viewer @effect (#412) * viewer @effect * universal preview effect * remove router where not needed * update tests * update tests --- src/app/app.module.ts | 9 +++- .../favorites/favorites.component.spec.ts | 26 ----------- .../favorites/favorites.component.ts | 4 +- src/app/components/files/files.component.html | 2 +- .../components/files/files.component.spec.ts | 43 ------------------- src/app/components/files/files.component.ts | 29 ++++++------- .../libraries/libraries.component.ts | 4 +- src/app/components/page.component.spec.ts | 2 +- src/app/components/page.component.ts | 17 ++++++-- .../components/preview/preview.component.ts | 4 +- .../recent-files/recent-files.component.html | 2 +- .../recent-files.component.spec.ts | 25 ----------- .../recent-files/recent-files.component.ts | 19 ++++---- .../components/search/search.component.html | 2 +- src/app/components/search/search.component.ts | 26 +++++------ .../shared-files/shared-files.component.html | 2 +- .../shared-files.component.spec.ts | 34 +-------------- .../shared-files/shared-files.component.ts | 13 ++---- .../components/trashcan/trashcan.component.ts | 5 +-- src/app/store/actions/node.action.ts | 1 + src/app/store/actions/viewer.action.ts | 9 ++++ src/app/store/effects/viewer.effects.ts | 37 ++++++++++++++++ 22 files changed, 122 insertions(+), 193 deletions(-) create mode 100644 src/app/store/actions/viewer.action.ts create mode 100644 src/app/store/effects/viewer.effects.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 711a02d838..7cea82e7ac 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -87,6 +87,7 @@ import { RouterEffects } from './store/effects/router.effects'; import { CreateFolderDirective } from './directives/create-folder.directive'; import { DownloadEffects } from './store/effects/download.effects'; import { DownloadNodesDirective } from './directives/download-nodes.directive'; +import { ViewerEffects } from './store/effects/viewer.effects'; @NgModule({ @@ -110,7 +111,13 @@ import { DownloadNodesDirective } from './directives/download-nodes.directive'; StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), StoreRouterConnectingModule.forRoot({ stateKey: 'router' }), - EffectsModule.forRoot([SnackbarEffects, NodeEffects, RouterEffects, DownloadEffects]), + EffectsModule.forRoot([ + SnackbarEffects, + NodeEffects, + RouterEffects, + DownloadEffects, + ViewerEffects + ]), !environment.production ? StoreDevtoolsModule.instrument({ maxAge: 25 }) : [] ], declarations: [ diff --git a/src/app/components/favorites/favorites.component.spec.ts b/src/app/components/favorites/favorites.component.spec.ts index c6529cf939..9edb6f2953 100644 --- a/src/app/components/favorites/favorites.component.spec.ts +++ b/src/app/components/favorites/favorites.component.spec.ts @@ -191,32 +191,6 @@ describe('FavoritesComponent', () => { }); }); - describe('onNodeDoubleClick', () => { - beforeEach(() => { - spyOn(nodesApi, 'getNode').and.returnValue(Observable.of(node)); - fixture.detectChanges(); - }); - - it('navigates if node is a folder', () => { - node.isFolder = true; - spyOn(router, 'navigate'); - - component.onNodeDoubleClick({ entry: node }); - - expect(router.navigate).toHaveBeenCalled(); - }); - - it('opens preview if node is a file', () => { - node.isFolder = false; - node.isFile = true; - spyOn(router, 'navigate').and.stub(); - - component.onNodeDoubleClick({ entry: node }); - - expect(router.navigate['calls'].argsFor(0)[0]).toEqual(['./preview', 'folder-node']); - }); - }); - describe('refresh', () => { it('should call document list reload', () => { spyOn(component.documentList, 'reload'); diff --git a/src/app/components/favorites/favorites.component.ts b/src/app/components/favorites/favorites.component.ts index 5754f7f650..7870c69841 100644 --- a/src/app/components/favorites/favorites.component.ts +++ b/src/app/components/favorites/favorites.component.ts @@ -39,14 +39,14 @@ import { AppStore } from '../../store/states/app.state'; }) export class FavoritesComponent extends PageComponent implements OnInit { - constructor(router: Router, + constructor(private router: Router, route: ActivatedRoute, store: Store, private nodesApi: NodesApiService, private content: ContentManagementService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, router, route, store); + super(preferences, route, store); } ngOnInit() { diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index 126c867ffd..41ebb77cd2 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -112,7 +112,7 @@ [allowDropFiles]="true" [navigate]="false" [imageResolver]="imageResolver" - (node-dblclick)="onNodeDoubleClick($event)" + (node-dblclick)="onNodeDoubleClick($event.detail?.node)" (ready)="onDocumentListReady($event, documentList)" (node-select)="onNodeSelect($event, documentList)" (node-unselect)="onNodeUnselect($event, documentList)"> diff --git a/src/app/components/files/files.component.spec.ts b/src/app/components/files/files.component.spec.ts index 9b05e2b0bf..a39ad52bda 100644 --- a/src/app/components/files/files.component.spec.ts +++ b/src/app/components/files/files.component.spec.ts @@ -335,49 +335,6 @@ describe('FilesComponent', () => { }); }); - describe('onNodeDoubleClick()', () => { - beforeEach(() => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); - spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); - - fixture.detectChanges(); - }); - - it('should open preview if node is file', () => { - spyOn(router, 'navigate').and.stub(); - node.isFile = true; - node.isFolder = false; - - const event: any = { - detail: { - node: { - entry: node - } - } - }; - component.onNodeDoubleClick(event); - - expect(router.navigate['calls'].argsFor(0)[0]).toEqual(['./preview', node.id]); - }); - - it('should navigate if node is folder', () => { - spyOn(component, 'navigate').and.stub(); - node.isFolder = true; - - - const event: any = { - detail: { - node: { - entry: node - } - } - }; - component.onNodeDoubleClick(event); - - expect(component.navigate).toHaveBeenCalledWith(node.id); - }); - }); - describe('onBreadcrumbNavigate()', () => { beforeEach(() => { spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index 3bba704b3f..beabc58fa9 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -50,7 +50,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { private nodePath: PathElement[]; - constructor(router: Router, + constructor(private router: Router, route: ActivatedRoute, store: Store, private nodesApi: NodesApiService, @@ -61,7 +61,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { private apiService: AlfrescoApiService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, router, route, store); + super(preferences, route, store); } ngOnInit() { @@ -139,24 +139,21 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { }); } - onNodeDoubleClick(event: CustomEvent) { - if (!!event.detail && !!event.detail.node) { + onNodeDoubleClick(node: MinimalNodeEntity) { + if (node && node.entry) { + const { id, isFolder } = node.entry; - const node: MinimalNodeEntryEntity = event.detail.node.entry; - if (node) { - - if (node.isFolder) { - this.navigate(node.id); - } - - if (PageComponent.isLockedNode(node)) { - event.preventDefault(); + if (isFolder) { + this.navigate(id); + return; + } - } else if (node.isFile) { - this.router.navigate(['./preview', node.id], { relativeTo: this.route }); - } + if (PageComponent.isLockedNode(node.entry)) { + event.preventDefault(); + return; } + this.showPreview(node); } } diff --git a/src/app/components/libraries/libraries.component.ts b/src/app/components/libraries/libraries.component.ts index 098ac4ceb8..74cfc73df3 100644 --- a/src/app/components/libraries/libraries.component.ts +++ b/src/app/components/libraries/libraries.component.ts @@ -40,9 +40,9 @@ export class LibrariesComponent extends PageComponent { constructor(private nodesApi: NodesApiService, route: ActivatedRoute, store: Store, - router: Router, + private router: Router, preferences: UserPreferencesService) { - super(preferences, router, route, store); + super(preferences, route, store); } makeLibraryTooltip(library: any): string { diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index f46fe39663..680eee69bd 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -34,7 +34,7 @@ class TestClass extends PageComponent { } constructor() { - super(null, null, null, null); + super(null, null, null); } } diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 4bcb4fd309..9a4af15c65 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -26,7 +26,7 @@ import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco-js-api'; import { UserPreferencesService, FileUploadErrorEvent } from '@alfresco/adf-core'; import { ShareDataRow, DocumentListComponent } from '@alfresco/adf-content-services'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { OnDestroy, ViewChild, OnInit } from '@angular/core'; import { Subscription, Subject } from 'rxjs/Rx'; import { Store } from '@ngrx/store'; @@ -35,6 +35,7 @@ import { SetSelectedNodesAction } from '../store/actions/node.action'; import { selectedNodes } from '../store/selectors/app.selectors'; import { takeUntil } from 'rxjs/operators'; import { SnackbarErrorAction } from '../store/actions'; +import { ViewNodeAction } from '../store/actions/viewer.action'; export abstract class PageComponent implements OnInit, OnDestroy { @@ -66,7 +67,6 @@ export abstract class PageComponent implements OnInit, OnDestroy { } constructor(protected preferences: UserPreferencesService, - protected router: Router, protected route: ActivatedRoute, protected store: Store) { } @@ -103,8 +103,17 @@ export abstract class PageComponent implements OnInit, OnDestroy { } showPreview(node: MinimalNodeEntity) { - if (node && node.entry && node.entry.isFile) { - this.router.navigate(['./preview', node.entry.id], { relativeTo: this.route }); + if (node && node.entry) { + const { id, nodeId, name, isFile, isFolder } = node.entry; + const parentId = this.node ? this.node.id : null; + + this.store.dispatch(new ViewNodeAction({ + parentId, + id: nodeId || id, + name, + isFile, + isFolder + })); } } diff --git a/src/app/components/preview/preview.component.ts b/src/app/components/preview/preview.component.ts index e989fa993d..1d140d3a03 100644 --- a/src/app/components/preview/preview.component.ts +++ b/src/app/components/preview/preview.component.ts @@ -61,11 +61,11 @@ export class PreviewComponent extends PageComponent implements OnInit { private apiService: AlfrescoApiService, preferences: UserPreferencesService, route: ActivatedRoute, - router: Router, + private router: Router, store: Store, public permission: NodePermissionService) { - super(preferences, router, route, store); + super(preferences, route, store); } ngOnInit() { diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index a868fd498e..70eb1765e8 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -92,7 +92,7 @@ [sorting]="[ 'modifiedAt', 'desc' ]" [acaSortingPreferenceKey]="sortingPreferenceKey" [imageResolver]="imageResolver" - (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" + (node-dblclick)="onNodeDoubleClick($event.detail?.node)" (ready)="onDocumentListReady($event, documentList)" (node-select)="onNodeSelect($event, documentList)" (node-unselect)="onNodeUnselect($event, documentList)"> diff --git a/src/app/components/recent-files/recent-files.component.spec.ts b/src/app/components/recent-files/recent-files.component.spec.ts index 43e11c588d..235ab5b297 100644 --- a/src/app/components/recent-files/recent-files.component.spec.ts +++ b/src/app/components/recent-files/recent-files.component.spec.ts @@ -25,7 +25,6 @@ import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { HttpClientModule } from '@angular/common/http'; import { @@ -51,7 +50,6 @@ import { INITIAL_STATE } from '../../store/states/app.state'; describe('RecentFiles Routed Component', () => { let fixture: ComponentFixture; let component: RecentFilesComponent; - let router: Router; let alfrescoApi: AlfrescoApiService; let contentService: ContentManagementService; let page; @@ -108,7 +106,6 @@ describe('RecentFiles Routed Component', () => { fixture = TestBed.createComponent(RecentFilesComponent); component = fixture.componentInstance; - router = TestBed.get(Router); contentService = TestBed.get(ContentManagementService); alfrescoApi = TestBed.get(AlfrescoApiService); alfrescoApi.reset(); @@ -153,28 +150,6 @@ describe('RecentFiles Routed Component', () => { }); }); - describe('onNodeDoubleClick()', () => { - it('open preview if node is file', () => { - spyOn(router, 'navigate').and.stub(); - const node: any = { id: 'node-id', isFile: true }; - - component.onNodeDoubleClick(node); - fixture.detectChanges(); - - expect(router.navigate['calls'].argsFor(0)[0]).toEqual(['./preview', node.id]); - }); - - it('does not open preview if node is folder', () => { - spyOn(router, 'navigate').and.stub(); - const node: any = { isFolder: true }; - - component.onNodeDoubleClick(node); - fixture.detectChanges(); - - expect(router.navigate).not.toHaveBeenCalled(); - }); - }); - describe('refresh', () => { it('should call document list reload', () => { spyOn(component.documentList, 'reload'); diff --git a/src/app/components/recent-files/recent-files.component.ts b/src/app/components/recent-files/recent-files.component.ts index 9d8999f6e3..cb5244acb3 100644 --- a/src/app/components/recent-files/recent-files.component.ts +++ b/src/app/components/recent-files/recent-files.component.ts @@ -24,8 +24,8 @@ */ import { Component, OnInit } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; -import { MinimalNodeEntryEntity } from 'alfresco-js-api'; +import { ActivatedRoute } from '@angular/router'; +import { MinimalNodeEntity } from 'alfresco-js-api'; import { UserPreferencesService, UploadService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; @@ -40,14 +40,13 @@ import { AppStore } from '../../store/states/app.state'; export class RecentFilesComponent extends PageComponent implements OnInit { constructor( - router: Router, route: ActivatedRoute, store: Store, private uploadService: UploadService, private content: ContentManagementService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, router, route, store); + super(preferences, route, store); } ngOnInit() { @@ -61,12 +60,14 @@ export class RecentFilesComponent extends PageComponent implements OnInit { ]); } - onNodeDoubleClick(node: MinimalNodeEntryEntity) { - if (node && PageComponent.isLockedNode(node)) { - event.preventDefault(); + onNodeDoubleClick(node: MinimalNodeEntity) { + if (node && node.entry) { + if (PageComponent.isLockedNode(node.entry)) { + event.preventDefault(); + return; + } - } else if (node && node.isFile) { - this.router.navigate(['./preview', node.id], { relativeTo: this.route }); + this.showPreview(node); } } } diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 3116bca57a..f4029e9a44 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -96,7 +96,7 @@ [sortingMode]="'server'" [sorting]="sorting" [node]="data" - (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" + (node-dblclick)="onNodeDoubleClick($event.detail?.node)" (ready)="onDocumentListReady($event, documentList)" (node-select)="onNodeSelect($event, documentList)" (node-unselect)="onNodeUnselect($event, documentList)"> diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index fdb6c4b82f..c982e6cb79 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -24,8 +24,8 @@ */ import { Component, OnInit, ViewChild } from '@angular/core'; -import { MinimalNodeEntryEntity, NodePaging, Pagination } from 'alfresco-js-api'; -import { Router, ActivatedRoute, Params } from '@angular/router'; +import { NodePaging, Pagination, MinimalNodeEntity } from 'alfresco-js-api'; +import { ActivatedRoute, Params } from '@angular/router'; import { SearchQueryBuilderService, SearchComponent as AdfSearchComponent, NodePermissionService } from '@alfresco/adf-content-services'; import { SearchConfigurationService, UserPreferencesService, SearchService } from '@alfresco/adf-core'; import { PageComponent } from '../page.component'; @@ -57,10 +57,9 @@ export class SearchComponent extends PageComponent implements OnInit { private queryBuilder: SearchQueryBuilderService, private searchConfiguration: SearchConfigurationService, store: Store, - router: Router, preferences: UserPreferencesService, route: ActivatedRoute) { - super(preferences, router, route, store); + super(preferences, route, store); queryBuilder.paging = { skipCount: 0, @@ -123,16 +122,19 @@ export class SearchComponent extends PageComponent implements OnInit { return ['name', 'asc']; } - onNodeDoubleClick(node: MinimalNodeEntryEntity) { - if (node && node.isFolder) { - this.store.dispatch(new NavigateToLocationAction(node)); - } + onNodeDoubleClick(node: MinimalNodeEntity) { + if (node && node.entry) { + if (node.entry.isFolder) { + this.store.dispatch(new NavigateToLocationAction(node)); + return; + } - if (node && PageComponent.isLockedNode(node)) { - event.preventDefault(); + if (PageComponent.isLockedNode(node.entry)) { + event.preventDefault(); + return; + } - } else if (node && node.isFile) { - this.router.navigate(['./preview', node.id], { relativeTo: this.route }); + this.showPreview(node); } } } diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 974bbd3a0d..7cce92bfd8 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -98,7 +98,7 @@ selectionMode="multiple" [sorting]="[ 'modifiedAt', 'desc' ]" [acaSortingPreferenceKey]="sortingPreferenceKey" - (node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)" + (node-dblclick)="showPreview($event.detail?.node)" (ready)="onDocumentListReady($event, documentList)" (node-select)="onNodeSelect($event, documentList)" (node-unselect)="onNodeUnselect($event, documentList)"> diff --git a/src/app/components/shared-files/shared-files.component.spec.ts b/src/app/components/shared-files/shared-files.component.spec.ts index e5de301989..db7fa5f2f4 100644 --- a/src/app/components/shared-files/shared-files.component.spec.ts +++ b/src/app/components/shared-files/shared-files.component.spec.ts @@ -23,9 +23,8 @@ * along with Alfresco. If not, see . */ -import { TestBed, async, fakeAsync, tick, ComponentFixture } from '@angular/core/testing'; +import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { HttpClientModule } from '@angular/common/http'; import { @@ -52,9 +51,7 @@ describe('SharedFilesComponent', () => { let fixture: ComponentFixture; let component: SharedFilesComponent; let contentService: ContentManagementService; - let nodeService; let alfrescoApi: AlfrescoApiService; - let router: Router; let page; beforeEach(() => { @@ -114,8 +111,6 @@ describe('SharedFilesComponent', () => { contentService = TestBed.get(ContentManagementService); alfrescoApi = TestBed.get(AlfrescoApiService); alfrescoApi.reset(); - nodeService = alfrescoApi.getInstance().nodes; - router = TestBed.get(Router); }); })); @@ -154,33 +149,6 @@ describe('SharedFilesComponent', () => { }); }); - describe('onNodeDoubleClick()', () => { - beforeEach(() => { - fixture.detectChanges(); - }); - - it('opens viewer if node is file', fakeAsync(() => { - spyOn(router, 'navigate').and.stub(); - const link = { nodeId: 'nodeId' }; - const node = { entry: { isFile: true, id: 'nodeId' } }; - - spyOn(nodeService, 'getNode').and.returnValue(Promise.resolve(node)); - component.onNodeDoubleClick(link); - tick(); - - expect(router.navigate['calls'].argsFor(0)[0]).toEqual(['./preview', node.entry.id]); - })); - - it('does nothing if link data is not passed', () => { - spyOn(router, 'navigate').and.stub(); - spyOn(nodeService, 'getNode').and.returnValue(Promise.resolve({ entry: { isFile: true } })); - - component.onNodeDoubleClick(null); - - expect(router.navigate).not.toHaveBeenCalled(); - }); - }); - describe('refresh', () => { it('should call document list reload', () => { spyOn(component.documentList, 'reload'); diff --git a/src/app/components/shared-files/shared-files.component.ts b/src/app/components/shared-files/shared-files.component.ts index efc8898536..b2cf92a82f 100644 --- a/src/app/components/shared-files/shared-files.component.ts +++ b/src/app/components/shared-files/shared-files.component.ts @@ -24,7 +24,7 @@ */ import { Component, OnInit } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { UserPreferencesService, UploadService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; @@ -38,14 +38,13 @@ import { AppStore } from '../../store/states/app.state'; }) export class SharedFilesComponent extends PageComponent implements OnInit { - constructor(router: Router, - route: ActivatedRoute, + constructor(route: ActivatedRoute, store: Store, private uploadService: UploadService, private content: ContentManagementService, public permission: NodePermissionService, preferences: UserPreferencesService) { - super(preferences, router, route, store); + super(preferences, route, store); } ngOnInit() { @@ -58,10 +57,4 @@ export class SharedFilesComponent extends PageComponent implements OnInit { this.uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error)) ]); } - - onNodeDoubleClick(link: { nodeId?: string }) { - if (link && link.nodeId) { - this.router.navigate(['./preview', link.nodeId], { relativeTo: this.route }); - } - } } diff --git a/src/app/components/trashcan/trashcan.component.ts b/src/app/components/trashcan/trashcan.component.ts index 5fa4648f63..a97d316c16 100644 --- a/src/app/components/trashcan/trashcan.component.ts +++ b/src/app/components/trashcan/trashcan.component.ts @@ -24,7 +24,7 @@ */ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { ActivatedRoute } from '@angular/router'; import { Pagination } from 'alfresco-js-api'; import { UserPreferencesService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; @@ -40,9 +40,8 @@ export class TrashcanComponent extends PageComponent implements OnInit { constructor(private contentManagementService: ContentManagementService, preferences: UserPreferencesService, store: Store, - router: Router, route: ActivatedRoute) { - super(preferences, router, route, store); + super(preferences, route, store); } ngOnInit() { diff --git a/src/app/store/actions/node.action.ts b/src/app/store/actions/node.action.ts index 4d7cb313a7..6503d085ce 100644 --- a/src/app/store/actions/node.action.ts +++ b/src/app/store/actions/node.action.ts @@ -8,6 +8,7 @@ export const PURGE_DELETED_NODES = 'PURGE_DELETED_NODES'; export const DOWNLOAD_NODES = 'DOWNLOAD_NODES'; export interface NodeInfo { + parentId?: string; id: string; name: string; isFile?: boolean; diff --git a/src/app/store/actions/viewer.action.ts b/src/app/store/actions/viewer.action.ts new file mode 100644 index 0000000000..e5c70d6e60 --- /dev/null +++ b/src/app/store/actions/viewer.action.ts @@ -0,0 +1,9 @@ +import { Action } from '@ngrx/store'; +import { NodeInfo } from './node.action'; + +export const VIEW_NODE = 'VIEW_NODE'; + +export class ViewNodeAction implements Action { + readonly type = VIEW_NODE; + constructor(public payload: NodeInfo) {} +} diff --git a/src/app/store/effects/viewer.effects.ts b/src/app/store/effects/viewer.effects.ts new file mode 100644 index 0000000000..a74bc6f8c1 --- /dev/null +++ b/src/app/store/effects/viewer.effects.ts @@ -0,0 +1,37 @@ +import { Effect, Actions, ofType } from '@ngrx/effects'; +import { Injectable } from '@angular/core'; +import { map } from 'rxjs/operators'; +import { ViewNodeAction, VIEW_NODE } from '../actions/viewer.action'; +import { Router } from '@angular/router'; + +@Injectable() +export class ViewerEffects { + constructor(private actions$: Actions, private router: Router) {} + + @Effect({ dispatch: false }) + viewNode$ = this.actions$.pipe( + ofType(VIEW_NODE), + map(action => { + const node = action.payload; + if (!node) { + return; + } + + let previewLocation = this.router.url; + if (previewLocation.lastIndexOf('/') > 0) { + previewLocation = previewLocation.substr( + 0, + this.router.url.indexOf('/', 1) + ); + } + previewLocation = previewLocation.replace(/\//g, ''); + + const path = [previewLocation]; + if (node.parentId) { + path.push(node.parentId); + } + path.push('preview', node.id); + this.router.navigateByUrl(path.join('/')); + }) + ); +} From 981b59095c97f5c1106e8371ef8e6e5dcad85a20 Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Thu, 14 Jun 2018 16:26:25 +0300 Subject: [PATCH 095/179] [ACA-1449][ACA-1448] Show searched term on the extended search input (#411) * [ACA-1449][ACA-1448] Show searched term on the extended search input * [ACA-1449][ACA-1448] fix test --- .../search-input/search-input.component.html | 25 +++++++--- .../search-input/search-input.component.scss | 18 +++++++ .../search-input.component.spec.ts | 4 +- .../search-input/search-input.component.ts | 49 +++++++++++++++++-- 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/app/components/search-input/search-input.component.html b/src/app/components/search-input/search-input.component.html index 2d892668db..f37d847a36 100644 --- a/src/app/components/search-input/search-input.component.html +++ b/src/app/components/search-input/search-input.component.html @@ -1,8 +1,17 @@ - - +
+ + + +
diff --git a/src/app/components/search-input/search-input.component.scss b/src/app/components/search-input/search-input.component.scss index 01065f7759..de837ebb53 100644 --- a/src/app/components/search-input/search-input.component.scss +++ b/src/app/components/search-input/search-input.component.scss @@ -8,3 +8,21 @@ adf-search-control { color: $alfresco-white; } + +.adf-search-control-wrapper { + display: flex; + box-sizing: border-box; + padding: 0; + width: 100%; + flex-direction: row; + align-items: center; + white-space: nowrap; + + .adf-search-button { + left: -15px; + margin-left: 13px; + align-items: flex-start; + font: 400 11px system-ui; + color: #fff; + } +} diff --git a/src/app/components/search-input/search-input.component.spec.ts b/src/app/components/search-input/search-input.component.spec.ts index 640ed4ac61..62d7101c9d 100644 --- a/src/app/components/search-input/search-input.component.spec.ts +++ b/src/app/components/search-input/search-input.component.spec.ts @@ -29,6 +29,7 @@ import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { SearchInputComponent } from './search-input.component'; +import { TranslateModule } from '@ngx-translate/core'; describe('SearchInputComponent', () => { let fixture; @@ -38,7 +39,8 @@ describe('SearchInputComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - RouterTestingModule + RouterTestingModule, + TranslateModule.forRoot() ], declarations: [ SearchInputComponent diff --git a/src/app/components/search-input/search-input.component.ts b/src/app/components/search-input/search-input.component.ts index e6893912ec..31ed8d2228 100644 --- a/src/app/components/search-input/search-input.component.ts +++ b/src/app/components/search-input/search-input.component.ts @@ -23,23 +23,62 @@ * along with Alfresco. If not, see . */ -import { Component } from '@angular/core'; -import { Router } from '@angular/router'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { + NavigationEnd, PRIMARY_OUTLET, Router, RouterEvent, UrlSegment, UrlSegmentGroup, + UrlTree +} from '@angular/router'; import { MinimalNodeEntity } from 'alfresco-js-api'; +import { SearchControlComponent } from '@alfresco/adf-content-services'; @Component({ selector: 'app-search-input', templateUrl: 'search-input.component.html', styleUrls: ['search-input.component.scss'] }) -export class SearchInputComponent { +export class SearchInputComponent implements OnInit { hasOneChange = false; hasNewChange = false; navigationTimer: any; - constructor( - private router: Router) { + @ViewChild('searchControl') + searchControl: SearchControlComponent; + + constructor(private router: Router) { + this.router.events.filter(e => e instanceof RouterEvent).subscribe(event => { + if (event instanceof NavigationEnd) { + this.showInputValue(); + } + }); + } + + ngOnInit() { + this.showInputValue(); + } + + showInputValue() { + if (this.onSearchResults) { + + let searchedWord = null; + const urlTree: UrlTree = this.router.parseUrl(this.router.url); + const urlSegmentGroup: UrlSegmentGroup = urlTree.root.children[PRIMARY_OUTLET]; + + if (urlSegmentGroup) { + const urlSegments: UrlSegment[] = urlSegmentGroup.segments; + searchedWord = urlSegments[0].parameters['q']; + } + + this.searchControl.searchTerm = searchedWord; + this.searchControl.subscriptAnimationState = 'no-animation'; + + } else { + if (this.searchControl.subscriptAnimationState === 'no-animation') { + this.searchControl.subscriptAnimationState = 'active'; + this.searchControl.searchTerm = ''; + this.searchControl.toggleSearchBar(); + } + } } onItemClicked(node: MinimalNodeEntity) { From 0144a53ed442a2bf71f3a3217e9b4dcf2902b7db Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 14 Jun 2018 16:30:40 +0100 Subject: [PATCH 096/179] search result fixes (#413) --- .../components/search/search.component.html | 8 ---- src/app/components/search/search.component.ts | 39 ++++++++++++------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index f4029e9a44..44f8bc4d59 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -64,14 +64,6 @@
- - -
diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index c982e6cb79..0b5a415af8 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -27,7 +27,7 @@ import { Component, OnInit, ViewChild } from '@angular/core'; import { NodePaging, Pagination, MinimalNodeEntity } from 'alfresco-js-api'; import { ActivatedRoute, Params } from '@angular/router'; import { SearchQueryBuilderService, SearchComponent as AdfSearchComponent, NodePermissionService } from '@alfresco/adf-content-services'; -import { SearchConfigurationService, UserPreferencesService, SearchService } from '@alfresco/adf-core'; +import { UserPreferencesService } from '@alfresco/adf-core'; import { PageComponent } from '../page.component'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; @@ -37,7 +37,6 @@ import { NavigateToLocationAction } from '../../store/actions'; selector: 'app-search', templateUrl: './search.component.html', styleUrls: ['./search.component.scss'], - providers: [SearchService] }) export class SearchComponent extends PageComponent implements OnInit { @@ -48,14 +47,11 @@ export class SearchComponent extends PageComponent implements OnInit { queryParamName = 'q'; data: NodePaging; totalResults = 0; - maxItems = 5; - skipCount = 0; sorting = ['name', 'asc']; constructor( public permission: NodePermissionService, private queryBuilder: SearchQueryBuilderService, - private searchConfiguration: SearchConfigurationService, store: Store, preferences: UserPreferencesService, route: ActivatedRoute) { @@ -72,23 +68,41 @@ export class SearchComponent extends PageComponent implements OnInit { this.sorting = this.getSorting(); - this.queryBuilder.updated.subscribe(() => { - this.sorting = this.getSorting(); - }); + this.subscriptions.push( + this.queryBuilder.updated.subscribe(() => { + this.sorting = this.getSorting(); + }), + + this.queryBuilder.executed.subscribe(data => { + console.log(data); + this.onSearchResultLoaded(data); + }) + ); if (this.route) { this.route.params.forEach((params: Params) => { this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null; - if (this.searchedWord) { - const queryBody = this.searchConfiguration.generateQueryBody(this.searchedWord, 0, 100); + const query = this.formatSearchQuery(this.searchedWord); - this.queryBuilder.userQuery = queryBody.query.query; + if (query) { + this.queryBuilder.userQuery = query; this.queryBuilder.update(); } }); } } + private formatSearchQuery(userInput: string) { + if (!userInput) { + return null; + } + + const suffix = userInput.lastIndexOf('*') >= 0 ? '' : '*'; + const query = `${userInput}${suffix} OR name:${userInput}${suffix}`; + + return query; + } + onSearchResultLoaded(nodePaging: NodePaging) { this.data = nodePaging; this.totalResults = this.getNumberOfResults(); @@ -102,9 +116,6 @@ export class SearchComponent extends PageComponent implements OnInit { } onPaginationChanged(pagination: Pagination) { - this.maxItems = pagination.maxItems; - this.skipCount = pagination.skipCount; - this.queryBuilder.paging = { maxItems: pagination.maxItems, skipCount: pagination.skipCount From edc9d6ba32ae783f464af19fa7b6f9816defa6c3 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 14 Jun 2018 18:18:31 +0100 Subject: [PATCH 097/179] remove console.log --- src/app/components/search/search.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index 0b5a415af8..7d798e2908 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -74,7 +74,6 @@ export class SearchComponent extends PageComponent implements OnInit { }), this.queryBuilder.executed.subscribe(data => { - console.log(data); this.onSearchResultLoaded(data); }) ); From b06dcd4391c91afd2c35af6c7e71147f68449436 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 15 Jun 2018 09:06:12 +0300 Subject: [PATCH 098/179] [ACA-1437] Custom row for search results DL (#414) * custom row * clean up --- src/app.config.json | 3 +- src/app/app.module.ts | 2 + .../custom-dl-row.component.html | 21 ++++ .../custom-dl-row.component.scss | 24 ++++ .../custom-dl-row/custom-dl-row.component.ts | 108 ++++++++++++++++++ .../location-link/location-link.component.ts | 3 +- .../components/search/search.component.html | 31 ++--- src/assets/i18n/en.json | 6 +- 8 files changed, 171 insertions(+), 27 deletions(-) create mode 100644 src/app/components/custom-dl-row/custom-dl-row.component.html create mode 100644 src/app/components/custom-dl-row/custom-dl-row.component.scss create mode 100644 src/app/components/custom-dl-row/custom-dl-row.component.ts diff --git a/src/app.config.json b/src/app.config.json index 476d72c495..3497e0e6f5 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -159,7 +159,7 @@ } }, "search": { - "include": ["path", "allowableOperations"], + "include": ["path", "allowableOperations", "properties"], "sorting": { "options": [ { @@ -217,6 +217,7 @@ "filterQueries": [ { "query": "TYPE:'cm:folder' OR TYPE:'cm:content'" }, { "query": "NOT cm:creator:System" }, + { "query": "NOT TYPE:'dl:dataList' AND NOT TYPE:'dl:todoList' AND NOT TYPE:'dl:issue' AND NOT TYPE:'fm:topic' AND NOT TYPE:'lnk:link' AND NOT TYPE:'fm:post'" }, { "query": "-(SITE: _REPOSITORY_)" } ], "facetFields": [ diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 7cea82e7ac..b4d5658e08 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -57,6 +57,7 @@ import { SearchInputComponent } from './components/search-input/search-input.com import { SidenavComponent } from './components/sidenav/sidenav.component'; import { AboutComponent } from './components/about/about.component'; import { LocationLinkComponent } from './components/location-link/location-link.component'; +import { CustomDlRowComponent } from './components/custom-dl-row/custom-dl-row.component'; import { NodeCopyDirective } from './common/directives/node-copy.directive'; import { NodeDeleteDirective } from './common/directives/node-delete.directive'; import { NodeMoveDirective } from './common/directives/node-move.directive'; @@ -139,6 +140,7 @@ import { ViewerEffects } from './store/effects/viewer.effects'; PreviewComponent, AboutComponent, LocationLinkComponent, + CustomDlRowComponent, NodeCopyDirective, NodeDeleteDirective, NodeMoveDirective, diff --git a/src/app/components/custom-dl-row/custom-dl-row.component.html b/src/app/components/custom-dl-row/custom-dl-row.component.html new file mode 100644 index 0000000000..7384e3a68a --- /dev/null +++ b/src/app/components/custom-dl-row/custom-dl-row.component.html @@ -0,0 +1,21 @@ +
+
+ {{ name }} + + {{ name }} + + ( {{ title }} ) +
+ +
{{ description }}
+ +
+ {{ 'APP.BROWSE.SEARCH.CUSTOM_ROW.MODIFIED' | translate }}: {{ modifiedAt | date:'medium' }} + + by {{ user }} + + | {{ size }} +
+ +
{{ 'APP.BROWSE.SEARCH.CUSTOM_ROW.LOCATION' | translate }}:
+
\ No newline at end of file diff --git a/src/app/components/custom-dl-row/custom-dl-row.component.scss b/src/app/components/custom-dl-row/custom-dl-row.component.scss new file mode 100644 index 0000000000..39b45278b4 --- /dev/null +++ b/src/app/components/custom-dl-row/custom-dl-row.component.scss @@ -0,0 +1,24 @@ +@import 'mixins'; + +.app-custom-search-row { + @include flex-column; +} + +.line { + margin: 5px 0; +} + +.bold { + font-weight: 400; + color: rgba(0, 0, 0, 0.87); +} + +.link { + text-decoration: none; + color: rgba(0, 0, 0, 0.87); +} + +.link:hover { + color: #2196F3; + text-decoration: underline; +} diff --git a/src/app/components/custom-dl-row/custom-dl-row.component.ts b/src/app/components/custom-dl-row/custom-dl-row.component.ts new file mode 100644 index 0000000000..6753b4a65c --- /dev/null +++ b/src/app/components/custom-dl-row/custom-dl-row.component.ts @@ -0,0 +1,108 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Component, Input, OnInit } from '@angular/core'; +import { MinimalNodeEntryEntity } from 'alfresco-js-api'; +import { ViewNodeAction } from '../../store/actions/viewer.action'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../../store/states/app.state'; + +@Component({ + selector: 'app-custom-dl-row', + templateUrl: './custom-dl-row.component.html', + styleUrls: ['./custom-dl-row.component.scss'] +}) +export class CustomDlRowComponent implements OnInit { + private node: MinimalNodeEntryEntity; + + @Input() + context: any; + + constructor(private store: Store) {} + + ngOnInit() { + this.node = this.context.row.node.entry; + } + + + get name() { + return this.getValue('name'); + } + + get title() { + return this.getValue('properties["cm:title"]'); + } + + get description() { + return this.getValue('properties["cm:description"]'); + } + + get modifiedAt() { + return this.getValue('modifiedAt'); + } + + get size() { + return this.getValue('content.modifiedAt'); + } + + get user() { + return this.getValue('modifiedByUser.displayName'); + } + + get hasDescription() { + return this.description; + } + + get hasTitle() { + return this.title; + } + + get hasSize() { + return this.size; + } + + get isFile() { + return this.getValue('isFile'); + } + + showPreview() { + const { id, name} = this.node; + + this.store.dispatch(new ViewNodeAction({ + id, + name + })); + } + + private getValue(path) { + return path + .replace('["', '.') + .replace('"]', '') + .replace('[', '.') + .replace(']', '') + .split('.') + .reduce((acc, part) => acc ? acc[part] : null, this.node); + } +} diff --git a/src/app/components/location-link/location-link.component.ts b/src/app/components/location-link/location-link.component.ts index a64d7c9eff..1cf93f11f6 100644 --- a/src/app/components/location-link/location-link.component.ts +++ b/src/app/components/location-link/location-link.component.ts @@ -78,7 +78,8 @@ export class LocationLinkComponent implements OnInit { const data: DataTableAdapter = this.context.data; const col: DataColumn = this.context.col; const row: DataRow = this.context.row; - const value: PathInfoEntity = data.getValue(row, col); + const path: PathInfoEntity = data.getValue(row, col); + const value = path || this.context.row.node.entry.path; if (value && value.name && value.elements) { this.displayText = this.getDisplayText(value); diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 44f8bc4d59..614de260ee 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -100,32 +100,15 @@ [sr-title]="'ADF-DOCUMENT-LIST.LAYOUT.THUMBNAIL'" [sortable]="false"> + - - - - - - + key + type="text"> + + + + diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 0a29509dba..7e39669eb3 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -98,7 +98,11 @@ }, "SEARCH": { "TITLE": "Search Results", - "FOUND_RESULTS": "{{ number }} results found" + "FOUND_RESULTS": "{{ number }} results found", + "CUSTOM_ROW": { + "MODIFIED": "Modified", + "LOCATION": "Location" + } } }, "ACTIONS": { From 51cd3744c52870fc9be631d18568369b093ebd36 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 15 Jun 2018 09:45:42 +0300 Subject: [PATCH 099/179] size data (#416) --- src/app/components/custom-dl-row/custom-dl-row.component.html | 2 +- src/app/components/custom-dl-row/custom-dl-row.component.ts | 2 +- src/assets/i18n/en.json | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/components/custom-dl-row/custom-dl-row.component.html b/src/app/components/custom-dl-row/custom-dl-row.component.html index 7384e3a68a..aeaeb0c4b0 100644 --- a/src/app/components/custom-dl-row/custom-dl-row.component.html +++ b/src/app/components/custom-dl-row/custom-dl-row.component.html @@ -14,7 +14,7 @@ by {{ user }} - | {{ size }} + | {{ 'APP.BROWSE.SEARCH.CUSTOM_ROW.SIZE' | translate }}: {{ size | adfFileSize }}
{{ 'APP.BROWSE.SEARCH.CUSTOM_ROW.LOCATION' | translate }}:
diff --git a/src/app/components/custom-dl-row/custom-dl-row.component.ts b/src/app/components/custom-dl-row/custom-dl-row.component.ts index 6753b4a65c..0d18534d59 100644 --- a/src/app/components/custom-dl-row/custom-dl-row.component.ts +++ b/src/app/components/custom-dl-row/custom-dl-row.component.ts @@ -64,7 +64,7 @@ export class CustomDlRowComponent implements OnInit { } get size() { - return this.getValue('content.modifiedAt'); + return this.getValue('content.sizeInBytes'); } get user() { diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 7e39669eb3..32b2564902 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -101,7 +101,8 @@ "FOUND_RESULTS": "{{ number }} results found", "CUSTOM_ROW": { "MODIFIED": "Modified", - "LOCATION": "Location" + "LOCATION": "Location", + "SIZE": "Size" } } }, From 13a28bebcdfb2e5228bca431c219e4df4a333092 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 15 Jun 2018 08:24:47 +0100 Subject: [PATCH 100/179] [ACA-1450] "manage versions" dialog enhancements (#415) * move dialog to the "dialogs" folder * rename to node-versions * style and layout refactoring * style fixes * layout fixes * fix scrollbars * code polishing --- src/app/app.module.ts | 6 +- .../directives/node-versions.directive.ts | 24 +++---- src/app/components/page.component.ts | 19 +++--- ...sion-manager-dialog-adapter.component.html | 9 --- ...sion-manager-dialog-adapter.component.scss | 52 --------------- ...ersion-manager-dialog-adapter.component.ts | 45 ------------- .../node-versions/node-versions.dialog.html | 7 ++ .../node-versions.dialog.theme.scss | 66 +++++++++++++++++++ .../node-versions/node-versions.dialog.ts | 52 +++++++++++++++ src/app/store/actions.ts | 1 + src/app/ui/custom-theme.scss | 2 + .../ui/overrides/adf-info-drawer.theme.scss | 3 +- 12 files changed, 153 insertions(+), 133 deletions(-) delete mode 100644 src/app/components/versions-dialog/version-manager-dialog-adapter.component.html delete mode 100644 src/app/components/versions-dialog/version-manager-dialog-adapter.component.scss delete mode 100644 src/app/components/versions-dialog/version-manager-dialog-adapter.component.ts create mode 100644 src/app/dialogs/node-versions/node-versions.dialog.html create mode 100644 src/app/dialogs/node-versions/node-versions.dialog.theme.scss create mode 100644 src/app/dialogs/node-versions/node-versions.dialog.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index b4d5658e08..953f374b69 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -65,7 +65,7 @@ import { NodeRestoreDirective } from './common/directives/node-restore.directive import { NodePermanentDeleteDirective } from './common/directives/node-permanent-delete.directive'; import { NodeUnshareDirective } from './common/directives/node-unshare.directive'; import { NodeVersionsDirective } from './common/directives/node-versions.directive'; -import { VersionManagerDialogAdapterComponent } from './components/versions-dialog/version-manager-dialog-adapter.component'; +import { NodeVersionsDialogComponent } from './dialogs/node-versions/node-versions.dialog'; import { BrowsingFilesService } from './common/services/browsing-files.service'; import { ContentManagementService } from './common/services/content-management.service'; import { NodeActionsService } from './common/services/node-actions.service'; @@ -148,7 +148,7 @@ import { ViewerEffects } from './store/effects/viewer.effects'; NodePermanentDeleteDirective, NodeUnshareDirective, NodeVersionsDirective, - VersionManagerDialogAdapterComponent, + NodeVersionsDialogComponent, SearchComponent, SettingsComponent, SortingPreferenceKeyDirective, @@ -174,7 +174,7 @@ import { ViewerEffects } from './store/effects/viewer.effects'; NodePermissionService ], entryComponents: [ - VersionManagerDialogAdapterComponent + NodeVersionsDialogComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/common/directives/node-versions.directive.ts b/src/app/common/directives/node-versions.directive.ts index e94d6c13a5..d3b4103b8c 100644 --- a/src/app/common/directives/node-versions.directive.ts +++ b/src/app/common/directives/node-versions.directive.ts @@ -28,7 +28,7 @@ import { Directive, HostListener, Input } from '@angular/core'; import { AlfrescoApiService } from '@alfresco/adf-core'; import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; -import { VersionManagerDialogAdapterComponent } from '../../components/versions-dialog/version-manager-dialog-adapter.component'; +import { NodeVersionsDialogComponent } from '../../dialogs/node-versions/node-versions.dialog'; import { MatDialog } from '@angular/material'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; @@ -38,10 +38,8 @@ import { SnackbarErrorAction } from '../../store/actions'; selector: '[acaNodeVersions]' }) export class NodeVersionsDirective { - // tslint:disable-next-line:no-input-rename - @Input('acaNodeVersions') - node: MinimalNodeEntity; + @Input('acaNodeVersions') node: MinimalNodeEntity; @HostListener('click') onClick() { @@ -56,7 +54,7 @@ export class NodeVersionsDirective { async onManageVersions() { if (this.node && this.node.entry) { - let entry = this.node.entry; + let entry = this.node.entry; if (entry.nodeId || (entry).guid) { entry = await this.apiService.nodesApi.getNodeInfo( @@ -72,13 +70,17 @@ export class NodeVersionsDirective { } } - openVersionManagerDialog(contentEntry: MinimalNodeEntryEntity) { - if (contentEntry.isFile) { - this.dialog.open( - VersionManagerDialogAdapterComponent, - { data: { contentEntry }, panelClass: 'adf-version-manager-dialog', width: '630px' }); + openVersionManagerDialog(node: MinimalNodeEntryEntity) { + if (node.isFile) { + this.dialog.open(NodeVersionsDialogComponent, { + data: { node }, + panelClass: 'adf-version-manager-dialog-panel', + width: '630px' + }); } else { - this.store.dispatch(new SnackbarErrorAction('APP.MESSAGES.ERRORS.PERMISSION')); + this.store.dispatch( + new SnackbarErrorAction('APP.MESSAGES.ERRORS.PERMISSION') + ); } } } diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 9a4af15c65..38cbc8f937 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -23,20 +23,17 @@ * along with Alfresco. If not, see . */ -import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco-js-api'; -import { UserPreferencesService, FileUploadErrorEvent } from '@alfresco/adf-core'; -import { ShareDataRow, DocumentListComponent } from '@alfresco/adf-content-services'; +import { DocumentListComponent, ShareDataRow } from '@alfresco/adf-content-services'; +import { FileUploadErrorEvent, UserPreferencesService } from '@alfresco/adf-core'; +import { OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { OnDestroy, ViewChild, OnInit } from '@angular/core'; -import { Subscription, Subject } from 'rxjs/Rx'; import { Store } from '@ngrx/store'; -import { AppStore } from '../store/states/app.state'; -import { SetSelectedNodesAction } from '../store/actions/node.action'; -import { selectedNodes } from '../store/selectors/app.selectors'; +import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco-js-api'; import { takeUntil } from 'rxjs/operators'; -import { SnackbarErrorAction } from '../store/actions'; -import { ViewNodeAction } from '../store/actions/viewer.action'; - +import { Subject, Subscription } from 'rxjs/Rx'; +import { SnackbarErrorAction, ViewNodeAction, SetSelectedNodesAction } from '../store/actions'; +import { selectedNodes } from '../store/selectors/app.selectors'; +import { AppStore } from '../store/states/app.state'; export abstract class PageComponent implements OnInit, OnDestroy { diff --git a/src/app/components/versions-dialog/version-manager-dialog-adapter.component.html b/src/app/components/versions-dialog/version-manager-dialog-adapter.component.html deleted file mode 100644 index c1874f01d6..0000000000 --- a/src/app/components/versions-dialog/version-manager-dialog-adapter.component.html +++ /dev/null @@ -1,9 +0,0 @@ -
-
{{'VERSION.DIALOG.TITLE' | translate}}
-
- -
-
- -
-
diff --git a/src/app/components/versions-dialog/version-manager-dialog-adapter.component.scss b/src/app/components/versions-dialog/version-manager-dialog-adapter.component.scss deleted file mode 100644 index 9be0594199..0000000000 --- a/src/app/components/versions-dialog/version-manager-dialog-adapter.component.scss +++ /dev/null @@ -1,52 +0,0 @@ -.adf-version-manager-dialog { - .mat-dialog-container { - padding-left: 0; - padding-right: 0; - padding-bottom: 8px; - } - - .mat-dialog-title { - margin-left: 24px; - margin-right: 24px; - font-size: 20px; - font-weight: 600; - font-style: normal; - font-stretch: normal; - line-height: 1.6; - letter-spacing: -0.5px; - color: rgba(0, 0, 0, 0.87); - } - - .mat-dialog-content { - margin: 0; - } - - .mat-dialog-actions { - padding: 8px 8px 24px 8px; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: end; - -ms-flex-pack: end; - justify-content: flex-end; - color: rgba(0, 0, 0, 0.54); - - button { - text-transform: uppercase; - font-weight: normal; - - &:enabled { - color: #ff9800; - } - } - } - - .adf-version-list { - height: 200px; - overflow: auto; - } -} - -.version-manager-dialog-adapter { - width: 100%; -} diff --git a/src/app/components/versions-dialog/version-manager-dialog-adapter.component.ts b/src/app/components/versions-dialog/version-manager-dialog-adapter.component.ts deleted file mode 100644 index 3a6e0e667e..0000000000 --- a/src/app/components/versions-dialog/version-manager-dialog-adapter.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -/*! - * @license - * Copyright 2016 Alfresco Software, Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Component, Inject, ViewEncapsulation } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef, MatSnackBarConfig } from '@angular/material'; -import { MinimalNodeEntryEntity } from 'alfresco-js-api'; -import { MatSnackBar } from '@angular/material'; - -@Component({ - templateUrl: './version-manager-dialog-adapter.component.html', - styleUrls: ['./version-manager-dialog-adapter.component.scss'], - encapsulation: ViewEncapsulation.None -}) -export class VersionManagerDialogAdapterComponent { - - public contentEntry: MinimalNodeEntryEntity; - - constructor(@Inject(MAT_DIALOG_DATA) data: any, - private snackBar: MatSnackBar, - private containingDialog?: MatDialogRef) { - this.contentEntry = data.contentEntry; - } - - uploadError(errorMessage: string) { - this.snackBar.open(errorMessage, '', { duration: 4000 }); - } - - close() { - this.containingDialog.close(); - } -} diff --git a/src/app/dialogs/node-versions/node-versions.dialog.html b/src/app/dialogs/node-versions/node-versions.dialog.html new file mode 100644 index 0000000000..4a0dc8e72f --- /dev/null +++ b/src/app/dialogs/node-versions/node-versions.dialog.html @@ -0,0 +1,7 @@ +
{{'VERSION.DIALOG.TITLE' | translate}}
+
+ +
+
+ +
diff --git a/src/app/dialogs/node-versions/node-versions.dialog.theme.scss b/src/app/dialogs/node-versions/node-versions.dialog.theme.scss new file mode 100644 index 0000000000..ab3ec908bf --- /dev/null +++ b/src/app/dialogs/node-versions/node-versions.dialog.theme.scss @@ -0,0 +1,66 @@ +@mixin aca-node-versions-dialog-theme($theme) { + $foreground: map-get($theme, foreground); + $accent: map-get($theme, accent); + + .adf-version-manager-dialog-panel { + height: 400px; + } + + .aca-node-versions-dialog { + + .mat-dialog-title { + font-size: 20px; + font-weight: 600; + font-style: normal; + font-stretch: normal; + line-height: 1.6; + letter-spacing: -0.5px; + color: mat-color($foreground, text, 0.87); + } + + .mat-dialog-actions { + padding: 8px 8px 24px 8px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + color: mat-color($foreground, text, 0.54); + + button { + text-transform: uppercase; + font-weight: normal; + + &:enabled { + color: mat-color($accent); + } + } + } + + .adf-new-version-container { + height: 100%; + + .adf-new-version-uploader-container { + & > .adf-version-upload { + width: 100%; + } + } + + + } + + .adf-version-list-container { + + .adf-version-list { + height: 180px; + overflow: hidden; + padding: 0; + } + + .mat-list.adf-version-list { + overflow: auto; + } + } + } +} diff --git a/src/app/dialogs/node-versions/node-versions.dialog.ts b/src/app/dialogs/node-versions/node-versions.dialog.ts new file mode 100644 index 0000000000..4a96bccf66 --- /dev/null +++ b/src/app/dialogs/node-versions/node-versions.dialog.ts @@ -0,0 +1,52 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Component, Inject, ViewEncapsulation } from '@angular/core'; +import { MAT_DIALOG_DATA } from '@angular/material'; +import { MinimalNodeEntryEntity } from 'alfresco-js-api'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../../store/states/app.state'; +import { SnackbarErrorAction } from '../../store/actions'; + +@Component({ + templateUrl: './node-versions.dialog.html', + encapsulation: ViewEncapsulation.None, + // tslint:disable-next-line:use-host-property-decorator + host: { class: 'aca-node-versions-dialog' } +}) +export class NodeVersionsDialogComponent { + node: MinimalNodeEntryEntity; + + constructor( + @Inject(MAT_DIALOG_DATA) data: any, + private store: Store + ) { + this.node = data.node; + } + + uploadError(errorMessage: string) { + this.store.dispatch(new SnackbarErrorAction(errorMessage)); + } +} diff --git a/src/app/store/actions.ts b/src/app/store/actions.ts index cbc694c2af..2ae5947193 100644 --- a/src/app/store/actions.ts +++ b/src/app/store/actions.ts @@ -4,3 +4,4 @@ export * from './actions/logo-path.action'; export * from './actions/node.action'; export * from './actions/snackbar.action'; export * from './actions/router.action'; +export * from './actions/viewer.action'; diff --git a/src/app/ui/custom-theme.scss b/src/app/ui/custom-theme.scss index 8e8ed64799..1f95358423 100644 --- a/src/app/ui/custom-theme.scss +++ b/src/app/ui/custom-theme.scss @@ -3,6 +3,7 @@ @import '../components/sidenav/sidenav.component.theme'; @import '../components/about/about.component.theme'; +@import '../dialogs/node-versions/node-versions.dialog.theme'; @import './overrides/adf-toolbar.theme'; @import './overrides/adf-search-filter.theme'; @import './overrides/adf-info-drawer.theme'; @@ -67,6 +68,7 @@ $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent); @include adf-document-list-theme($custom-theme); @include adf-upload-drag-area-theme($custom-theme); + @include aca-node-versions-dialog-theme($custom-theme); @include snackbar-theme($custom-theme); @include sidenav-component-theme($custom-theme); @include aca-about-component-theme($custom-theme); diff --git a/src/app/ui/overrides/adf-info-drawer.theme.scss b/src/app/ui/overrides/adf-info-drawer.theme.scss index 7cdfbeb92c..7cf3146e6c 100644 --- a/src/app/ui/overrides/adf-info-drawer.theme.scss +++ b/src/app/ui/overrides/adf-info-drawer.theme.scss @@ -30,8 +30,7 @@ } } - .adf-version-list-container, - .adf-version-manager-dialog .adf-version-list-container { + .adf-version-list-container { .adf-version-list { height: auto; } From 4fd455100e97e1f8e02eb3103a1c058120a9bbb8 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 15 Jun 2018 11:20:46 +0300 Subject: [PATCH 101/179] pass entry (#417) --- src/app/components/search/search.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index 7d798e2908..ae3308bb3b 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -135,7 +135,7 @@ export class SearchComponent extends PageComponent implements OnInit { onNodeDoubleClick(node: MinimalNodeEntity) { if (node && node.entry) { if (node.entry.isFolder) { - this.store.dispatch(new NavigateToLocationAction(node)); + this.store.dispatch(new NavigateToLocationAction(node.entry)); return; } From 13bfd118d684a6055bfe4387bbd5f8fe1dc933c5 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 15 Jun 2018 11:54:23 +0300 Subject: [PATCH 102/179] enable to search in personal files (#418) --- src/app.config.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app.config.json b/src/app.config.json index 3497e0e6f5..b0828ea993 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -217,8 +217,7 @@ "filterQueries": [ { "query": "TYPE:'cm:folder' OR TYPE:'cm:content'" }, { "query": "NOT cm:creator:System" }, - { "query": "NOT TYPE:'dl:dataList' AND NOT TYPE:'dl:todoList' AND NOT TYPE:'dl:issue' AND NOT TYPE:'fm:topic' AND NOT TYPE:'lnk:link' AND NOT TYPE:'fm:post'" }, - { "query": "-(SITE: _REPOSITORY_)" } + { "query": "NOT TYPE:'dl:dataList' AND NOT TYPE:'dl:todoList' AND NOT TYPE:'dl:issue' AND NOT TYPE:'fm:topic' AND NOT TYPE:'lnk:link' AND NOT TYPE:'fm:post'" } ], "facetFields": [ { "field": "content.mimetype", "mincount": 1, "label": "SEARCH.FACET_FIELDS.FILE_TYPE" }, From be8edcc9d646ef85767e7785eaa09943e410dab5 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 15 Jun 2018 14:18:30 +0300 Subject: [PATCH 103/179] [ACA] Upload - 500 error message (#419) * 500 error message * generic error message --- src/app/components/page.component.ts | 12 +++++++++--- src/assets/i18n/en.json | 12 +++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 38cbc8f937..a81857959c 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -191,12 +191,18 @@ export abstract class PageComponent implements OnInit, OnDestroy { } onFileUploadedError(error: FileUploadErrorEvent) { - let message = null; + let message = 'APP.MESSAGES.UPLOAD.ERROR.GENERIC'; if (error.error.status === 409) { - message = new SnackbarErrorAction('VERSION.MESSAGE.ERROR.CONFLICT'); + message = 'APP.MESSAGES.UPLOAD.ERROR.CONFLICT'; } - this.store.dispatch(message); + if (error.error.status === 500) { + message = 'APP.MESSAGES.UPLOAD.ERROR.500'; + } + + const action = new SnackbarErrorAction(message); + + this.store.dispatch(action); } } diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 32b2564902..cec609fb13 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -174,6 +174,13 @@ } } }, + "UPLOAD": { + "ERROR": { + "GENERIC": "Opps! There was a problem", + "CONFLICT": "New version not uploaded, another file with the same name already exists", + "500": "Opps! There was a problem while uploading" + } + }, "INFO": { "TRASH": { "NODES_PURGE": { @@ -231,11 +238,6 @@ "SEARCH": "Search" }, "VERSION": { - "MESSAGE": { - "ERROR": { - "CONFLICT": "New version not uploaded, another file with the same name already exists" - } - }, "DIALOG": { "TITLE": "Manage Versions", "CLOSE": "Close" From 7e1da5030eba116e7145726fe374e78d46979b0b Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 15 Jun 2018 15:22:30 +0300 Subject: [PATCH 104/179] title popup (#420) --- src/app/components/sidenav/sidenav.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index e42cb40be7..e688033965 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -3,7 +3,7 @@ arrow_drop_down
- queue + queue
+ + - - + + - - - -
+ + + diff --git a/src/app/components/current-user/current-user.component.scss b/src/app/components/current-user/current-user.component.scss deleted file mode 100644 index b301ce7bc1..0000000000 --- a/src/app/components/current-user/current-user.component.scss +++ /dev/null @@ -1,49 +0,0 @@ -@import 'variables'; - -$am-avatar-size: 40px; - -$am-avatar-light-bg: rgba(white, .15); -$am-avatar-dark-bg: rgba(black, .15); - -:host { - font-weight: lighter; - position: relative; - - color: $alfresco-white; - line-height: 20px; - - .am-avatar { - margin-left: 5px; - cursor: pointer; - - display: inline-block; - width: $am-avatar-size; - height: $am-avatar-size; - line-height: $am-avatar-size; - font-size: 1.2em; - text-align: center; - color: inherit; - border-radius: 100%; - - &--light { - background: $am-avatar-light-bg; - } - - &--dark { - background: $am-avatar-dark-bg; - } - } - - .current-user__full-name { - width: 100px; - text-align: right; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - display:inline-block; - height: 20px; - font-size: 14px; - line-height: 1.43; - letter-spacing: -0.2px; - } -} diff --git a/src/app/components/current-user/current-user.component.theme.scss b/src/app/components/current-user/current-user.component.theme.scss new file mode 100644 index 0000000000..6a22fa6658 --- /dev/null +++ b/src/app/components/current-user/current-user.component.theme.scss @@ -0,0 +1,38 @@ +@mixin aca-current-user-theme($theme) { + $background: map-get($theme, background); + $am-avatar-size: 40px; + + .aca-current-user { + font-weight: lighter; + position: relative; + color: mat-color($background, card); + line-height: 20px; + + .am-avatar { + margin-left: 5px; + cursor: pointer; + display: inline-block; + width: $am-avatar-size; + height: $am-avatar-size; + line-height: $am-avatar-size; + font-size: 1.2em; + text-align: center; + color: inherit; + border-radius: 100%; + background-color: mat-color($background, card, .15); + } + + .current-user__full-name { + width: 100px; + text-align: right; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display:inline-block; + height: 20px; + font-size: 14px; + line-height: 1.43; + letter-spacing: -0.2px; + } + } +} diff --git a/src/app/components/current-user/current-user.component.ts b/src/app/components/current-user/current-user.component.ts index b91bd6ce1e..996646cf54 100644 --- a/src/app/components/current-user/current-user.component.ts +++ b/src/app/components/current-user/current-user.component.ts @@ -23,14 +23,15 @@ * along with Alfresco. If not, see . */ -import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core'; import { PeopleContentService } from '@alfresco/adf-core'; import { Subscription } from 'rxjs/Rx'; @Component({ - selector: 'app-current-user', + selector: 'aca-current-user', templateUrl: './current-user.component.html', - styleUrls: [ './current-user.component.scss' ] + encapsulation: ViewEncapsulation.None, + host: { class: 'aca-current-user' } }) export class CurrentUserComponent implements OnInit, OnDestroy { private subscriptions: Subscription[] = []; diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index 41ebb77cd2..e24f683c7d 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -94,7 +94,7 @@
- +
diff --git a/src/app/components/generic-error/generic-error.component.html b/src/app/components/generic-error/generic-error.component.html index 1525e9ba33..ac7157b634 100644 --- a/src/app/components/generic-error/generic-error.component.html +++ b/src/app/components/generic-error/generic-error.component.html @@ -1,4 +1,4 @@ -
- ic_error -

This file / folder no longer exists or you don't have permission to view it.

-
\ No newline at end of file +ic_error +

+ {{ 'APP.MESSAGES.ERRORS.MISSING_CONTENT' | translate }} +

diff --git a/src/app/components/generic-error/generic-error.component.scss b/src/app/components/generic-error/generic-error.component.scss deleted file mode 100644 index a3b5b67f1c..0000000000 --- a/src/app/components/generic-error/generic-error.component.scss +++ /dev/null @@ -1,25 +0,0 @@ -@import 'variables'; - -$alfresco-warn-color--hue-2: #ff5252; - -.generic-error { - color: $alfresco-secondary-text-color; - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - width: 100%; - height: 100%; - - &__title { - font-size: 16px; - } - - mat-icon { - color: $alfresco-warn-color--hue-2; - direction: rtl; - font-size: 52px; - height: 52px; - width: 52px; - } - } diff --git a/src/app/components/generic-error/generic-error.component.theme.scss b/src/app/components/generic-error/generic-error.component.theme.scss new file mode 100644 index 0000000000..bbf0735e99 --- /dev/null +++ b/src/app/components/generic-error/generic-error.component.theme.scss @@ -0,0 +1,27 @@ +@mixin aca-generic-error-theme($theme) { + $warn: map-get($theme, warn); + $foreground: map-get($theme, foreground); + + .aca-generic-error { + color: mat-color($foreground, text, 0.54); + + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + width: 100%; + height: 100%; + + &__title { + font-size: 16px; + } + + mat-icon { + color: mat-color($warn); + direction: rtl; + font-size: 52px; + height: 52px; + width: 52px; + } + } +} diff --git a/src/app/components/generic-error/generic-error.component.ts b/src/app/components/generic-error/generic-error.component.ts index abfbf9a6df..dfae6b91e4 100644 --- a/src/app/components/generic-error/generic-error.component.ts +++ b/src/app/components/generic-error/generic-error.component.ts @@ -23,12 +23,14 @@ * along with Alfresco. If not, see . */ -import { Component } from '@angular/core'; +import { Component, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core'; @Component({ - selector: 'app-generic-error', - styleUrls: ['./generic-error.component.scss'], - templateUrl: './generic-error.component.html' + selector: 'aca-generic-error', + templateUrl: './generic-error.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + host: { class: 'aca-generic-error' } }) export class GenericErrorComponent {} diff --git a/src/app/components/header/header.component.html b/src/app/components/header/header.component.html index c389a6072c..2a4668d66f 100644 --- a/src/app/components/header/header.component.html +++ b/src/app/components/header/header.component.html @@ -16,9 +16,9 @@
- + - + diff --git a/src/app/components/header/header.component.scss b/src/app/components/header/header.component.scss deleted file mode 100644 index 1ef2058915..0000000000 --- a/src/app/components/header/header.component.scss +++ /dev/null @@ -1,55 +0,0 @@ -@import 'variables'; - -$app-menu-height: 64px; - -.app-menu { - height: $app-menu-height; - - &.adf-toolbar { - .mat-toolbar { - background-color: inherit; - font-family: inherit; - min-height: $app-menu-height; - height: $app-menu-height; - - .mat-toolbar-layout { - height: $app-menu-height; - - .mat-toolbar-row { - height: $app-menu-height; - } - } - } - - .adf-toolbar-divider { - margin-left: 5px; - margin-right: 5px; - - & > div { - background-color: $alfresco-white !important; - } - } - - .adf-toolbar-title { - color: $alfresco-white; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - } - } - - .app-menu__title { - width: 100px; - height: 50px; - margin-left: 40px; - display: flex; - justify-content: center; - align-items: stretch; - - &> img { - width: 100%; - object-fit: contain; - } - } -} diff --git a/src/app/components/header/header.component.theme.scss b/src/app/components/header/header.component.theme.scss new file mode 100644 index 0000000000..8b56a42247 --- /dev/null +++ b/src/app/components/header/header.component.theme.scss @@ -0,0 +1,59 @@ +@mixin aca-header-theme($theme) { + $background: map-get($theme, background); + $app-menu-height: 64px; + + .aca-header { + + .app-menu { + height: $app-menu-height; + + &.adf-toolbar { + .mat-toolbar { + background-color: inherit; + font-family: inherit; + min-height: $app-menu-height; + height: $app-menu-height; + + .mat-toolbar-layout { + height: $app-menu-height; + + .mat-toolbar-row { + height: $app-menu-height; + } + } + } + + .adf-toolbar-divider { + margin-left: 5px; + margin-right: 5px; + + & > div { + background-color: mat-color($background, card); + } + } + + .adf-toolbar-title { + color: mat-color($background, card); + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + } + } + + .app-menu__title { + width: 100px; + height: 50px; + margin-left: 40px; + display: flex; + justify-content: center; + align-items: stretch; + + &> img { + width: 100%; + object-fit: contain; + } + } + } + } +} diff --git a/src/app/components/header/header.component.ts b/src/app/components/header/header.component.ts index 2c121e61a7..6ad498bb3c 100644 --- a/src/app/components/header/header.component.ts +++ b/src/app/components/header/header.component.ts @@ -30,10 +30,10 @@ import { AppStore } from '../../store/states/app.state'; import { selectHeaderColor, selectAppName, selectLogoPath } from '../../store/selectors/app.selectors'; @Component({ - selector: 'app-header', + selector: 'aca-header', templateUrl: './header.component.html', - styleUrls: [ './header.component.scss' ], - encapsulation: ViewEncapsulation.None + encapsulation: ViewEncapsulation.None, + host: { class: 'aca-header' } }) export class HeaderComponent { @Output() menu: EventEmitter = new EventEmitter(); diff --git a/src/app/components/layout/layout.component.html b/src/app/components/layout/layout.component.html index 754195e4c7..52c37d768a 100644 --- a/src/app/components/layout/layout.component.html +++ b/src/app/components/layout/layout.component.html @@ -15,7 +15,7 @@ - + @@ -35,4 +35,4 @@ -
\ No newline at end of file +
diff --git a/src/app/components/location-link/location-link.component.ts b/src/app/components/location-link/location-link.component.ts index 1cf93f11f6..0277f76ce1 100644 --- a/src/app/components/location-link/location-link.component.ts +++ b/src/app/components/location-link/location-link.component.ts @@ -30,7 +30,7 @@ import { Observable } from 'rxjs/Rx'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; -import { NavigateToLocationAction } from '../../store/actions'; +import { NavigateToLocationAction } from '../../store/actions'; @Component({ selector: 'app-location-link', @@ -41,10 +41,7 @@ import { NavigateToLocationAction } from '../../store/actions'; `, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, - // tslint:disable-next-line:use-host-property-decorator - host: { - 'class': 'app-location-link adf-location-cell' - } + host: { 'class': 'app-location-link adf-location-cell' } }) export class LocationLinkComponent implements OnInit { diff --git a/src/app/components/preview/preview.component.ts b/src/app/components/preview/preview.component.ts index 1d140d3a03..cd603cd73e 100644 --- a/src/app/components/preview/preview.component.ts +++ b/src/app/components/preview/preview.component.ts @@ -37,7 +37,6 @@ import { PageComponent } from '../page.component'; templateUrl: 'preview.component.html', styleUrls: ['preview.component.scss'], encapsulation: ViewEncapsulation.None, - // tslint:disable-next-line:use-host-property-decorator host: { 'class': 'app-preview' } }) export class PreviewComponent extends PageComponent implements OnInit { diff --git a/src/app/components/search-input/search-input.component.html b/src/app/components/search-input/search-input.component.html index f37d847a36..95fd9b69d5 100644 --- a/src/app/components/search-input/search-input.component.html +++ b/src/app/components/search-input/search-input.component.html @@ -1,17 +1,15 @@ -
- - - -
+ + + diff --git a/src/app/components/search-input/search-input.component.scss b/src/app/components/search-input/search-input.component.scss deleted file mode 100644 index 513e16531b..0000000000 --- a/src/app/components/search-input/search-input.component.scss +++ /dev/null @@ -1,23 +0,0 @@ -@import 'variables'; - -adf-search-control { - color: $alfresco-white; -} - -.adf-search-control-wrapper { - display: flex; - box-sizing: border-box; - padding: 0; - width: 100%; - flex-direction: row; - align-items: center; - white-space: nowrap; - - .adf-search-button { - left: -15px; - margin-left: 13px; - align-items: flex-start; - font: 400 11px system-ui; - color: #fff; - } -} diff --git a/src/app/components/search-input/search-input.component.theme.scss b/src/app/components/search-input/search-input.component.theme.scss new file mode 100644 index 0000000000..ead9a266d1 --- /dev/null +++ b/src/app/components/search-input/search-input.component.theme.scss @@ -0,0 +1,28 @@ +@mixin aca-search-input-theme($theme) { + $background: map-get($theme, background); + + .aca-search-input{ + display: flex; + box-sizing: border-box; + padding: 0; + flex-direction: row; + align-items: center; + white-space: nowrap; + + .adf-search-control { + color: mat-color($background, card); + + .mat-form-field-underline { + background-color: mat-color($background, card); + } + } + + .adf-search-button { + left: -15px; + margin-left: 13px; + align-items: flex-start; + font: 400 11px system-ui; + color: mat-color($background, card); + } + } +} diff --git a/src/app/components/search-input/search-input.component.ts b/src/app/components/search-input/search-input.component.ts index 31ed8d2228..71b90270de 100644 --- a/src/app/components/search-input/search-input.component.ts +++ b/src/app/components/search-input/search-input.component.ts @@ -23,7 +23,7 @@ * along with Alfresco. If not, see . */ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { NavigationEnd, PRIMARY_OUTLET, Router, RouterEvent, UrlSegment, UrlSegmentGroup, UrlTree @@ -32,9 +32,10 @@ import { MinimalNodeEntity } from 'alfresco-js-api'; import { SearchControlComponent } from '@alfresco/adf-content-services'; @Component({ - selector: 'app-search-input', + selector: 'aca-search-input', templateUrl: 'search-input.component.html', - styleUrls: ['search-input.component.scss'] + encapsulation: ViewEncapsulation.None, + host: { class: 'aca-search-input' } }) export class SearchInputComponent implements OnInit { diff --git a/src/app/components/settings/settings.component.scss b/src/app/components/settings/settings.component.scss deleted file mode 100644 index ad87b64920..0000000000 --- a/src/app/components/settings/settings.component.scss +++ /dev/null @@ -1,69 +0,0 @@ -@import 'variables'; - -.app-settings { - .settings-input { - width: 50%; - } - - .settings-buttons { - text-align: right; - - .mat-button { - text-transform: uppercase; - } - } - - $app-menu-height: 64px; - - .app-menu { - height: $app-menu-height; - - &.adf-toolbar { - .mat-toolbar { - background-color: inherit; - font-family: inherit; - min-height: $app-menu-height; - height: $app-menu-height; - - .mat-toolbar-layout { - height: $app-menu-height; - - .mat-toolbar-row { - height: $app-menu-height; - } - } - } - - .adf-toolbar-divider { - margin-left: 5px; - margin-right: 5px; - - & > div { - background-color: $alfresco-white !important; - } - } - - .adf-toolbar-title { - color: $alfresco-white; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - } - } - - .app-menu__title { - width: 100px; - height: 50px; - margin-left: 40px; - display: flex; - justify-content: center; - align-items: stretch; - - &> img { - width: 100%; - object-fit: contain; - } - } - } -} diff --git a/src/app/components/settings/settings.component.theme.scss b/src/app/components/settings/settings.component.theme.scss new file mode 100644 index 0000000000..11de98a196 --- /dev/null +++ b/src/app/components/settings/settings.component.theme.scss @@ -0,0 +1,70 @@ +@mixin aca-settings-theme($theme) { + $background: map-get($theme, background); + $app-menu-height: 64px; + + .aca-settings { + .settings-input { + width: 50%; + } + + .settings-buttons { + text-align: right; + + .mat-button { + text-transform: uppercase; + } + } + + .app-menu { + height: $app-menu-height; + + &.adf-toolbar { + .mat-toolbar { + background-color: inherit; + font-family: inherit; + min-height: $app-menu-height; + height: $app-menu-height; + + .mat-toolbar-layout { + height: $app-menu-height; + + .mat-toolbar-row { + height: $app-menu-height; + } + } + } + + .adf-toolbar-divider { + margin-left: 5px; + margin-right: 5px; + + & > div { + background-color: mat-color($background, card); + } + } + + .adf-toolbar-title { + color: mat-color($background, card); + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + } + } + + .app-menu__title { + width: 100px; + height: 50px; + margin-left: 40px; + display: flex; + justify-content: center; + align-items: stretch; + + &> img { + width: 100%; + object-fit: contain; + } + } + } + } +} diff --git a/src/app/components/settings/settings.component.ts b/src/app/components/settings/settings.component.ts index f0087bb065..27507dd1af 100644 --- a/src/app/components/settings/settings.component.ts +++ b/src/app/components/settings/settings.component.ts @@ -29,12 +29,10 @@ import { DomSanitizer } from '@angular/platform-browser'; import { Validators, FormGroup, FormBuilder } from '@angular/forms'; @Component({ - selector: 'app-settings', + selector: 'aca-settings', templateUrl: './settings.component.html', - styleUrls: ['./settings.component.scss'], encapsulation: ViewEncapsulation.None, - // tslint:disable-next-line:use-host-property-decorator - host: { class: 'app-settings' } + host: { class: 'aca-settings' } }) export class SettingsComponent implements OnInit { diff --git a/src/app/dialogs/node-versions/node-versions.dialog.ts b/src/app/dialogs/node-versions/node-versions.dialog.ts index 4a96bccf66..e99e07d380 100644 --- a/src/app/dialogs/node-versions/node-versions.dialog.ts +++ b/src/app/dialogs/node-versions/node-versions.dialog.ts @@ -33,7 +33,6 @@ import { SnackbarErrorAction } from '../../store/actions'; @Component({ templateUrl: './node-versions.dialog.html', encapsulation: ViewEncapsulation.None, - // tslint:disable-next-line:use-host-property-decorator host: { class: 'aca-node-versions-dialog' } }) export class NodeVersionsDialogComponent { diff --git a/src/app/ui/_layout.scss b/src/app/ui/_layout.scss deleted file mode 100644 index ad9e7e81d1..0000000000 --- a/src/app/ui/_layout.scss +++ /dev/null @@ -1,56 +0,0 @@ -@import 'mixins'; - -$app-layout--header-height: 65px; -$app-layout--side-width: 320px; -$app-inner-layout--header-height: 48px; -$app-inner-layout--footer-height: 48px; -$alfresco-divider-color: rgba($alfresco-black, .07); -$alfresco-gray-background: #fafafa; - -.layout { - @include flex-column; -} - -.inner-layout { - @include flex-column; - - &__header { - display: flex; - align-items: center; - flex: 0 0 $app-layout--header-height; - flex-basis: $app-inner-layout--header-height; - background: $alfresco-gray-background; - border-bottom: 1px solid $alfresco-divider-color; - padding: 0 24px; - } - - &__content { - @include flex-row; - } - - &__content--hide { - display: none !important; - } - - &__panel { - @include flex-column; - border-right: 1px solid rgba(0, 0, 0, 0.07); - } - - &__side-panel { - display: block; - height: 100%; - overflow-y: scroll; - max-width: 350px; - width: 350px; - } -} - -.content--scroll { - overflow: auto !important; -} - -app-generic-error { - height: 100%; - width: 100%; -} diff --git a/src/app/ui/_variables.scss b/src/app/ui/_variables.scss deleted file mode 100644 index 02fdf15ec4..0000000000 --- a/src/app/ui/_variables.scss +++ /dev/null @@ -1,6 +0,0 @@ -// Grayscale -$alfresco-white: #fff; -$alfresco-black: #000; - -// Dark -$alfresco-secondary-text-color: rgba($alfresco-black, .54); diff --git a/src/app/ui/application.scss b/src/app/ui/application.scss index e04d525abf..70891f13f7 100644 --- a/src/app/ui/application.scss +++ b/src/app/ui/application.scss @@ -1,5 +1,4 @@ @import 'mixins'; -@import 'variables'; @import 'theme'; $foreground: map-get($theme, foreground); @@ -24,5 +23,3 @@ app-search, ng-component { @include flex-column; } - -@import 'layout'; diff --git a/src/app/ui/custom-theme.scss b/src/app/ui/custom-theme.scss index 1f95358423..f99eea2498 100644 --- a/src/app/ui/custom-theme.scss +++ b/src/app/ui/custom-theme.scss @@ -3,7 +3,13 @@ @import '../components/sidenav/sidenav.component.theme'; @import '../components/about/about.component.theme'; +@import '../components/generic-error/generic-error.component.theme'; +@import '../components/search-input/search-input.component.theme'; +@import '../components/settings/settings.component.theme'; +@import '../components/current-user/current-user.component.theme'; +@import '../components/header/header.component.theme'; @import '../dialogs/node-versions/node-versions.dialog.theme'; + @import './overrides/adf-toolbar.theme'; @import './overrides/adf-search-filter.theme'; @import './overrides/adf-info-drawer.theme'; @@ -14,7 +20,9 @@ @import './overrides/adf-sidenav-layout.theme'; @import './overrides/adf-document-list.theme'; @import './overrides/adf-upload-drag-area.theme'; +@import './overrides/adf-search-sorting-picker.theme'; +@import 'layout'; @import 'snackbar'; $grey-scale: ( @@ -58,18 +66,25 @@ $custom-theme-warn: mat-palette($alfresco-warn); $custom-theme: mat-light-theme($custom-theme-primary, $custom-theme-accent); @mixin custom-theme($theme) { - @include adf-toolbar-theme($custom-theme); - @include adf-search-filter-theme($custom-theme); - @include adf-info-drawer-theme($custom-theme); - @include adf-upload-button-theme($custom-theme); - @include adf-sidebar-action-menu-theme($custom-theme); - @include adf-pagination-theme($custom-theme); - @include adf-sidenav-layout-theme($custom-theme); - @include adf-document-list-theme($custom-theme); - @include adf-upload-drag-area-theme($custom-theme); + @include adf-toolbar-theme($theme); + @include adf-search-filter-theme($theme); + @include adf-info-drawer-theme($theme); + @include adf-upload-button-theme($theme); + @include adf-sidebar-action-menu-theme($theme); + @include adf-pagination-theme($theme); + @include adf-sidenav-layout-theme($theme); + @include adf-document-list-theme($theme); + @include adf-upload-drag-area-theme($theme); + @include adf-search-sorting-picker-theme($theme); - @include aca-node-versions-dialog-theme($custom-theme); - @include snackbar-theme($custom-theme); - @include sidenav-component-theme($custom-theme); - @include aca-about-component-theme($custom-theme); + @include aca-layout-theme($theme); + @include aca-header-theme($theme); + @include aca-search-input-theme($theme); + @include aca-generic-error-theme($theme); + @include aca-node-versions-dialog-theme($theme); + @include aca-settings-theme($theme); + @include snackbar-theme($theme); + @include sidenav-component-theme($theme); + @include aca-about-component-theme($theme); + @include aca-current-user-theme($theme); } diff --git a/src/app/ui/layout.scss b/src/app/ui/layout.scss new file mode 100644 index 0000000000..bb38d0e07f --- /dev/null +++ b/src/app/ui/layout.scss @@ -0,0 +1,55 @@ +@import 'mixins'; + +@mixin aca-layout-theme($theme) { + $foreground: map-get($theme, foreground); + + $app-layout--header-height: 65px; + $app-layout--side-width: 320px; + $app-inner-layout--header-height: 48px; + $app-inner-layout--footer-height: 48px; + $alfresco-divider-color: mat-color($foreground, text, 0.07); + $alfresco-gray-background: #fafafa; + + .layout { + @include flex-column; + } + + .inner-layout { + @include flex-column; + + &__header { + display: flex; + align-items: center; + flex: 0 0 $app-layout--header-height; + flex-basis: $app-inner-layout--header-height; + background: $alfresco-gray-background; + border-bottom: 1px solid $alfresco-divider-color; + padding: 0 24px; + } + + &__content { + @include flex-row; + } + + &__content--hide { + display: none !important; + } + + &__panel { + @include flex-column; + border-right: 1px solid mat-color($foreground, text, 0.07); + } + + &__side-panel { + display: block; + height: 100%; + overflow-y: scroll; + max-width: 350px; + width: 350px; + } + } + + .content--scroll { + overflow: auto !important; + } +} diff --git a/src/app/ui/overrides/adf-search-sorting-picker.theme.scss b/src/app/ui/overrides/adf-search-sorting-picker.theme.scss new file mode 100644 index 0000000000..f83b1b64e2 --- /dev/null +++ b/src/app/ui/overrides/adf-search-sorting-picker.theme.scss @@ -0,0 +1,9 @@ +@mixin adf-search-sorting-picker-theme($theme) { + $foreground: map-get($theme, foreground); + + .adf-search-sorting-picker { + .mat-icon-button { + color: mat-color($foreground, text, 0.54); + } + } +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index cec609fb13..c7b97ea31d 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -152,6 +152,7 @@ }, "MESSAGES": { "ERRORS":{ + "MISSING_CONTENT": "This file / folder no longer exists or you don't have permission to view it.", "GENERIC": "The action was unsuccessful. Try again or contact your IT Team.", "CONFLICT": "This name is already in use, try a different name.", "NODE_MOVE": "Move unsuccessful, a file with the same name already exists.", diff --git a/tslint.json b/tslint.json index b43b9774e4..12d8eaf915 100644 --- a/tslint.json +++ b/tslint.json @@ -127,7 +127,7 @@ ], "use-input-property-decorator": true, "use-output-property-decorator": true, - "use-host-property-decorator": true, + "use-host-property-decorator": false, "no-input-rename": true, "no-output-rename": true, "use-life-cycle-interface": true, From 1c4f658017edba1fb6c8a0d2297faa885de0399f Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sun, 17 Jun 2018 19:12:08 +0100 Subject: [PATCH 111/179] [ACA-1473] fixes for navigation to searched folder (#429) * search effects * "view folder" action * folder navigation actions and effects * navigate to folder on double-click (search results) * update tests * fix tests --- .../location-link/location-link.component.ts | 9 ++- .../search-input.component.spec.ts | 56 +++++++++++-------- .../search-input/search-input.component.ts | 32 +++++++---- src/app/components/search/search.component.ts | 4 +- src/app/store/actions.ts | 1 + src/app/store/actions/router.actions.ts | 16 ++++-- src/app/store/actions/search.actions.ts | 33 +++++++++++ src/app/store/app-store.module.ts | 6 +- src/app/store/effects.ts | 1 + src/app/store/effects/router.effects.ts | 48 +++++++++++++--- src/app/store/effects/search.effects.ts | 43 ++++++++++++++ src/app/testing/app-testing.module.ts | 4 +- 12 files changed, 196 insertions(+), 57 deletions(-) create mode 100644 src/app/store/actions/search.actions.ts create mode 100644 src/app/store/effects/search.effects.ts diff --git a/src/app/components/location-link/location-link.component.ts b/src/app/components/location-link/location-link.component.ts index 0277f76ce1..b72c25fae4 100644 --- a/src/app/components/location-link/location-link.component.ts +++ b/src/app/components/location-link/location-link.component.ts @@ -25,12 +25,12 @@ import { Component, Input, ChangeDetectionStrategy, OnInit, ViewEncapsulation } from '@angular/core'; import { AlfrescoApiService, DataColumn, DataRow, DataTableAdapter } from '@alfresco/adf-core'; -import { PathInfoEntity } from 'alfresco-js-api'; +import { PathInfoEntity, MinimalNodeEntity } from 'alfresco-js-api'; import { Observable } from 'rxjs/Rx'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; -import { NavigateToLocationAction } from '../../store/actions'; +import { NavigateToParentFolder } from '../../store/actions'; @Component({ selector: 'app-location-link', @@ -64,9 +64,8 @@ export class LocationLinkComponent implements OnInit { goToLocation() { if (this.context) { - const { node } = this.context.row; - - this.store.dispatch(new NavigateToLocationAction(node.entry)); + const node: MinimalNodeEntity = this.context.row.node; + this.store.dispatch(new NavigateToParentFolder(node)); } } diff --git a/src/app/components/search-input/search-input.component.spec.ts b/src/app/components/search-input/search-input.component.spec.ts index 62d7101c9d..82de63b77d 100644 --- a/src/app/components/search-input/search-input.component.spec.ts +++ b/src/app/components/search-input/search-input.component.spec.ts @@ -24,23 +24,23 @@ */ import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { TestBed, async } from '@angular/core/testing'; -import { Router } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; +import { TestBed, async, ComponentFixture, fakeAsync, tick } from '@angular/core/testing'; import { SearchInputComponent } from './search-input.component'; -import { TranslateModule } from '@ngx-translate/core'; +import { AppTestingModule } from '../../testing/app-testing.module'; +import { Actions, ofType } from '@ngrx/effects'; +import { ViewNodeAction, VIEW_NODE, NAVIGATE_FOLDER, NavigateToFolder } from '../../store/actions'; +import { map } from 'rxjs/operators'; describe('SearchInputComponent', () => { - let fixture; - let component; - let router: Router; + let fixture: ComponentFixture; + let component: SearchInputComponent; + let actions$: Actions; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - RouterTestingModule, - TranslateModule.forRoot() + AppTestingModule ], declarations: [ SearchInputComponent @@ -49,32 +49,40 @@ describe('SearchInputComponent', () => { }) .compileComponents() .then(() => { + actions$ = TestBed.get(Actions); fixture = TestBed.createComponent(SearchInputComponent); component = fixture.componentInstance; - router = TestBed.get(Router); - fixture.detectChanges(); }); })); describe('onItemClicked()', () => { - it('opens preview if node is file', () => { - spyOn(router, 'navigate').and.stub(); + it('opens preview if node is file', fakeAsync(done => { + actions$.pipe( + ofType(VIEW_NODE), + map(action => { + expect(action.payload.id).toBe('node-id'); + done(); + }) + ); + const node = { entry: { isFile: true, id: 'node-id', parentId: 'parent-id' } }; component.onItemClicked(node); + tick(); + })); - expect(router.navigate['calls'].argsFor(0)[0]) - .toEqual([`/personal-files/${node.entry.parentId}/preview/`, node.entry.id]); - }); - - it('navigates if node is folder', () => { - const node = { entry: { isFolder: true } }; - spyOn(router, 'navigate'); - + it('navigates if node is folder', fakeAsync(done => { + actions$.pipe( + ofType(NAVIGATE_FOLDER), + map(action => { + expect(action.payload.entry.id).toBe('folder-id'); + done(); + }) + ); + const node = { entry: { id: 'folder-id', isFolder: true } }; component.onItemClicked(node); - - expect(router.navigate).toHaveBeenCalled(); - }); + tick(); + })); }); }); diff --git a/src/app/components/search-input/search-input.component.ts b/src/app/components/search-input/search-input.component.ts index 71b90270de..860d87d5e8 100644 --- a/src/app/components/search-input/search-input.component.ts +++ b/src/app/components/search-input/search-input.component.ts @@ -30,6 +30,9 @@ import { } from '@angular/router'; import { MinimalNodeEntity } from 'alfresco-js-api'; import { SearchControlComponent } from '@alfresco/adf-content-services'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../../store/states/app.state'; +import { SearchByTermAction, ViewNodeAction, NavigateToFolder } from '../../store/actions'; @Component({ selector: 'aca-search-input', @@ -46,7 +49,7 @@ export class SearchInputComponent implements OnInit { @ViewChild('searchControl') searchControl: SearchControlComponent; - constructor(private router: Router) { + constructor(private router: Router, private store: Store) { this.router.events.filter(e => e instanceof RouterEvent).subscribe(event => { if (event instanceof NavigationEnd) { this.showInputValue(); @@ -84,10 +87,17 @@ export class SearchInputComponent implements OnInit { onItemClicked(node: MinimalNodeEntity) { if (node && node.entry) { - if (node.entry.isFile) { - this.router.navigate([`/personal-files/${node.entry.parentId}/preview/`, node.entry.id]); - } else if (node.entry.isFolder) { - this.router.navigate([ '/personal-files', node.entry.id ]); + const { id, nodeId, name, isFile, isFolder, parentId } = node.entry; + if (isFile) { + this.store.dispatch(new ViewNodeAction({ + parentId, + id: nodeId || id, + name, + isFile, + isFolder + })); + } else if (isFolder) { + this.store.dispatch(new NavigateToFolder(node)); } } } @@ -98,13 +108,11 @@ export class SearchInputComponent implements OnInit { * @param event Parameters relating to the search */ onSearchSubmit(event: KeyboardEvent) { - const value = (event.target as HTMLInputElement).value; - this.router.navigate(['/search', { - q: value - }]); + const searchTerm = (event.target as HTMLInputElement).value; + this.store.dispatch(new SearchByTermAction(searchTerm)); } - onSearchChange(event: string) { + onSearchChange(searchTerm: string) { if (this.onSearchResults) { if (this.hasOneChange) { @@ -119,8 +127,8 @@ export class SearchInputComponent implements OnInit { } this.navigationTimer = setTimeout(() => { - if (event) { - this.router.navigate(['/search', {q: event}]); + if (searchTerm) { + this.store.dispatch(new SearchByTermAction(searchTerm)); } this.hasOneChange = false; }, 1000); diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index ce672a6a3a..8773b55149 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -31,7 +31,7 @@ import { UserPreferencesService } from '@alfresco/adf-core'; import { PageComponent } from '../page.component'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; -import { NavigateToLocationAction } from '../../store/actions'; +import { NavigateToFolder } from '../../store/actions'; @Component({ selector: 'app-search', @@ -136,7 +136,7 @@ export class SearchComponent extends PageComponent implements OnInit { onNodeDoubleClick(node: MinimalNodeEntity) { if (node && node.entry) { if (node.entry.isFolder) { - this.store.dispatch(new NavigateToLocationAction(node.entry)); + this.store.dispatch(new NavigateToFolder(node)); return; } diff --git a/src/app/store/actions.ts b/src/app/store/actions.ts index 11e24413ab..d3cec5741c 100644 --- a/src/app/store/actions.ts +++ b/src/app/store/actions.ts @@ -28,3 +28,4 @@ export * from './actions/node.actions'; export * from './actions/snackbar.actions'; export * from './actions/router.actions'; export * from './actions/viewer.actions'; +export * from './actions/search.actions'; diff --git a/src/app/store/actions/router.actions.ts b/src/app/store/actions/router.actions.ts index 457b28ef45..2e3faa760b 100644 --- a/src/app/store/actions/router.actions.ts +++ b/src/app/store/actions/router.actions.ts @@ -24,16 +24,24 @@ */ import { Action } from '@ngrx/store'; +import { MinimalNodeEntity } from 'alfresco-js-api'; export const NAVIGATE_ROUTE = 'NAVIGATE_ROUTE'; -export const NAVIGATE_LOCATION = 'NAVIGATE_LOCATION'; +export const NAVIGATE_FOLDER = 'NAVIGATE_FOLDER'; +export const NAVIGATE_PARENT_FOLDER = 'NAVIGATE_PARENT_FOLDER'; export class NavigateRouteAction implements Action { readonly type = NAVIGATE_ROUTE; constructor(public payload: any[]) {} } -export class NavigateToLocationAction implements Action { - readonly type = NAVIGATE_LOCATION; - constructor(public payload: any) {} +export class NavigateToFolder implements Action { + readonly type = NAVIGATE_FOLDER; + constructor(public payload: MinimalNodeEntity) {} +} + + +export class NavigateToParentFolder implements Action { + readonly type = NAVIGATE_PARENT_FOLDER; + constructor(public payload: MinimalNodeEntity) {} } diff --git a/src/app/store/actions/search.actions.ts b/src/app/store/actions/search.actions.ts new file mode 100644 index 0000000000..5d3632bb62 --- /dev/null +++ b/src/app/store/actions/search.actions.ts @@ -0,0 +1,33 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Action } from '@ngrx/store'; + +export const SEARCH_BY_TERM = 'SEARCH_BY_TERM'; + +export class SearchByTermAction implements Action { + readonly type = SEARCH_BY_TERM; + constructor(public payload: string) {} +} diff --git a/src/app/store/app-store.module.ts b/src/app/store/app-store.module.ts index 7000b35374..6c547ee28f 100644 --- a/src/app/store/app-store.module.ts +++ b/src/app/store/app-store.module.ts @@ -36,7 +36,8 @@ import { NodeEffects, RouterEffects, DownloadEffects, - ViewerEffects + ViewerEffects, + SearchEffects } from './effects'; @NgModule({ @@ -51,7 +52,8 @@ import { NodeEffects, RouterEffects, DownloadEffects, - ViewerEffects + ViewerEffects, + SearchEffects ]), !environment.production ? StoreDevtoolsModule.instrument({ maxAge: 25 }) diff --git a/src/app/store/effects.ts b/src/app/store/effects.ts index 463ac16801..c4f6826e8c 100644 --- a/src/app/store/effects.ts +++ b/src/app/store/effects.ts @@ -28,3 +28,4 @@ export * from './effects/node.effects'; export * from './effects/router.effects'; export * from './effects/snackbar.effects'; export * from './effects/viewer.effects'; +export * from './effects/search.effects'; diff --git a/src/app/store/effects/router.effects.ts b/src/app/store/effects/router.effects.ts index 566d65db54..e0f66c4b37 100644 --- a/src/app/store/effects/router.effects.ts +++ b/src/app/store/effects/router.effects.ts @@ -30,10 +30,11 @@ import { MinimalNodeEntryEntity, PathInfoEntity } from 'alfresco-js-api'; import { map } from 'rxjs/operators'; import { NavigateRouteAction, - NavigateToLocationAction, - NAVIGATE_LOCATION, + NavigateToParentFolder, + NAVIGATE_PARENT_FOLDER, NAVIGATE_ROUTE } from '../actions'; +import { NavigateToFolder, NAVIGATE_FOLDER } from '../actions/router.actions'; @Injectable() export class RouterEffects { @@ -48,16 +49,49 @@ export class RouterEffects { ); @Effect({ dispatch: false }) - navigateLocation$ = this.actions$.pipe( - ofType(NAVIGATE_LOCATION), + navigateToFolder$ = this.actions$.pipe( + ofType(NAVIGATE_FOLDER), map(action => { - if (action.payload) { - this.navigateToLocation(action.payload); + if (action.payload && action.payload.entry) { + this.navigateToFolder(action.payload.entry); } }) ); - private navigateToLocation(node: MinimalNodeEntryEntity) { + @Effect({ dispatch: false }) + navigateToParentFolder$ = this.actions$.pipe( + ofType(NAVIGATE_PARENT_FOLDER), + map(action => { + if (action.payload && action.payload.entry) { + this.navigateToParentFolder(action.payload.entry); + } + }) + ); + + private navigateToFolder(node: MinimalNodeEntryEntity) { + let link = null; + const { path, id } = node; + + if (path && path.name && path.elements) { + const isLibraryPath = this.isLibraryContent(path); + + const parent = path.elements[path.elements.length - 1]; + const area = isLibraryPath ? '/libraries' : '/personal-files'; + + if (!isLibraryPath) { + link = [area, id]; + } else { + // parent.id could be 'Site' folder or child as 'documentLibrary' + link = [area, parent.name === 'Sites' ? {} : id]; + } + } + + setTimeout(() => { + this.router.navigate(link); + }, 10); + } + + private navigateToParentFolder(node: MinimalNodeEntryEntity) { let link = null; const { path } = node; diff --git a/src/app/store/effects/search.effects.ts b/src/app/store/effects/search.effects.ts new file mode 100644 index 0000000000..0d5dd150ff --- /dev/null +++ b/src/app/store/effects/search.effects.ts @@ -0,0 +1,43 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Effect, Actions, ofType } from '@ngrx/effects'; +import { Injectable } from '@angular/core'; +import { map } from 'rxjs/operators'; +import { SEARCH_BY_TERM, SearchByTermAction } from '../actions/search.actions'; +import { Router } from '@angular/router'; + +@Injectable() +export class SearchEffects { + constructor(private actions$: Actions, private router: Router) {} + + @Effect({ dispatch: false }) + searchByTerm$ = this.actions$.pipe( + ofType(SEARCH_BY_TERM), + map(action => { + this.router.navigateByUrl('/search;q=' + action.payload); + }) + ); +} diff --git a/src/app/testing/app-testing.module.ts b/src/app/testing/app-testing.module.ts index e061a03dec..4768a150e5 100644 --- a/src/app/testing/app-testing.module.ts +++ b/src/app/testing/app-testing.module.ts @@ -34,13 +34,15 @@ import { StoreModule } from '@ngrx/store'; import { appReducer } from '../store/reducers/app.reducer'; import { INITIAL_STATE } from '../store/states/app.state'; import { RouterTestingModule } from '@angular/router/testing'; +import { EffectsModule } from '@ngrx/effects'; @NgModule({ imports: [ NoopAnimationsModule, HttpClientModule, RouterTestingModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) + StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + EffectsModule.forRoot([]) ], declarations: [ TranslatePipeMock From abd63ba0a463ac7157684260e48f47d83605189d Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 18 Jun 2018 21:59:57 +0300 Subject: [PATCH 112/179] version dialog styling (#431) --- .../node-versions.dialog.theme.scss | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/app/dialogs/node-versions/node-versions.dialog.theme.scss b/src/app/dialogs/node-versions/node-versions.dialog.theme.scss index ab3ec908bf..dbb69e9fcf 100644 --- a/src/app/dialogs/node-versions/node-versions.dialog.theme.scss +++ b/src/app/dialogs/node-versions/node-versions.dialog.theme.scss @@ -7,6 +7,20 @@ } .aca-node-versions-dialog { + .mat-dialog-title { + flex: 0 0 auto; + } + + .mat-dialog-content { + flex: 1 1 auto; + position: relative; + overflow-y: auto; + } + + .mat-dialog-actions { + flex: 0 0 auto; + } + .mat-dialog-title { font-size: 20px; @@ -14,10 +28,12 @@ font-style: normal; font-stretch: normal; line-height: 1.6; + margin: 0; letter-spacing: -0.5px; color: mat-color($foreground, text, 0.87); } + .mat-dialog-actions { padding: 8px 8px 24px 8px; display: -webkit-box; @@ -39,19 +55,20 @@ } .adf-new-version-container { - height: 100%; - - .adf-new-version-uploader-container { - & > .adf-version-upload { - width: 100%; - } - } + height: 350px !important; + } + .mat-dialog-content { + max-height: 36vh; + overflow: hidden; + } + .mat-list-item-content { + padding: 0; + margin: 0 16px; } .adf-version-list-container { - .adf-version-list { height: 180px; overflow: hidden; From 1a53f8d2aa366a9693d46a79ce436ae7d7504eae Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 19 Jun 2018 08:16:53 +0100 Subject: [PATCH 113/179] unified selection state (#433) * selection state * use unified selection state * cleanup tests * remove "console.log" * remove old selection property * remove coma --- .../favorites/favorites.component.html | 32 ++++++------- src/app/components/files/files.component.html | 36 +++++++------- src/app/components/page.component.spec.ts | 48 ------------------- src/app/components/page.component.ts | 43 +++++------------ .../components/preview/preview.component.html | 6 +-- .../recent-files/recent-files.component.html | 32 ++++++------- .../components/search/search.component.html | 24 +++++----- .../shared-files/shared-files.component.html | 36 +++++++------- .../trashcan/trashcan.component.html | 6 +-- src/app/store/reducers/app.reducer.ts | 29 ++++++++++- src/app/store/selectors/app.selectors.ts | 2 +- src/app/store/states/app.state.ts | 10 ++-- src/app/store/states/selection.state.ts | 36 ++++++++++++++ 13 files changed, 171 insertions(+), 169 deletions(-) create mode 100644 src/app/store/states/selection.state.ts diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 891235405a..a6c71fa4e0 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -3,14 +3,14 @@ - + @@ -18,16 +18,16 @@ mat-icon-button color="primary" title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}" - [adfNodeDownload]="selectedNodes"> + [adfNodeDownload]="selection.nodes"> get_app @@ -49,39 +49,39 @@ [overlapTrigger]="false"> @@ -169,7 +169,7 @@
- +
diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index e24f683c7d..446090a0de 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -6,13 +6,13 @@ (navigate)="onBreadcrumbNavigate($event)"> - + @@ -20,16 +20,16 @@ color="primary" mat-icon-button title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}" - [adfNodeDownload]="selectedNodes"> + [adfNodeDownload]="selection.nodes"> get_app @@ -52,40 +52,40 @@ [overlapTrigger]="false"> @@ -167,7 +167,7 @@
- +
diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index 680eee69bd..ee65afb82c 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -24,15 +24,10 @@ */ import { PageComponent } from './page.component'; -import { MinimalNodeEntity } from 'alfresco-js-api'; class TestClass extends PageComponent { node: any; - setSelection(selection: MinimalNodeEntity[] = []) { - this.onSelectionChanged(selection); - } - constructor() { super(null, null, null); } @@ -58,47 +53,4 @@ describe('PageComponent', () => { expect(component.getParentNodeId()).toBe(null); }); }); - - describe('hasSelection()', () => { - it('returns true when it has nodes selected', () => { - component.setSelection([ - { entry: { isFile: true } }, - { entry: { isFile: true } } - ]); - expect(component.hasSelection).toBe(true); - }); - - it('returns false when it has no selections', () => { - component.setSelection([]); - expect(component.hasSelection).toBe(false); - }); - }); - - describe('selectedFile', () => { - it('returns true if selected node is file', () => { - const selection = [ { entry: { isFile: true } } ]; - component.setSelection(selection); - expect(component.selectedFile).toBe(selection[0]); - }); - - it('returns false if selected node is folder', () => { - const selection = [ { entry: { isFile: false, isFolder: true } } ]; - component.setSelection(selection); - expect(component.selectedFile).toBeFalsy(); - }); - }); - - describe('selectedFolder', () => { - it('returns true if selected node is folder', () => { - const selection = [ { entry: { isFile: false, isFolder: true } } ]; - component.setSelection(selection); - expect(component.selectedFolder).toBe(selection[0]); - }); - - it('returns false if selected node is file', () => { - const selection = [ { entry: { isFile: true, isFolder: false } } ]; - component.setSelection(selection); - expect(component.selectedFolder).toBeFalsy(); - }); - }); }); diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index a81857959c..3bb25af10f 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -32,12 +32,13 @@ import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco- import { takeUntil } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs/Rx'; import { SnackbarErrorAction, ViewNodeAction, SetSelectedNodesAction } from '../store/actions'; -import { selectedNodes } from '../store/selectors/app.selectors'; +import { appSelection } from '../store/selectors/app.selectors'; import { AppStore } from '../store/states/app.state'; +import { SelectionState } from '../store/states/selection.state'; export abstract class PageComponent implements OnInit, OnDestroy { - onDestroy$: Subject = new Subject(); + onDestroy$: Subject = new Subject(); @ViewChild(DocumentListComponent) documentList: DocumentListComponent; @@ -45,13 +46,7 @@ export abstract class PageComponent implements OnInit, OnDestroy { title = 'Page'; infoDrawerOpened = false; node: MinimalNodeEntryEntity; - - selectedFolder: MinimalNodeEntity; - selectedFile: MinimalNodeEntity; - - hasSelection = false; - lastSelectedNode: MinimalNodeEntity; - selectedNodes: MinimalNodeEntity[]; + selection: SelectionState; protected subscriptions: Subscription[] = []; @@ -70,33 +65,22 @@ export abstract class PageComponent implements OnInit, OnDestroy { ngOnInit() { this.store - .select(selectedNodes) + .select(appSelection) .pipe(takeUntil(this.onDestroy$)) - .subscribe(selection => this.onSelectionChanged(selection)); + .subscribe(selection => { + this.selection = selection; + if (selection.isEmpty) { + this.infoDrawerOpened = false; + } + }); } ngOnDestroy() { this.subscriptions.forEach(subscription => subscription.unsubscribe()); this.subscriptions = []; - this.onDestroy$.complete(); - } - // Precalculates all the "static state" flags so that UI does not re-evaluate that on every tick - protected onSelectionChanged(selection: MinimalNodeEntity[] = []) { - this.selectedNodes = selection; - this.hasSelection = selection.length > 0; - this.selectedFolder = null; - this.selectedFile = null; - - if (selection.length > 0) { - if (selection.length === 1) { - this.selectedFile = selection.find(entity => entity.entry.isFile); - this.selectedFolder = selection.find(entity => entity.entry.isFolder); - } - } else { - this.lastSelectedNode = null; - this.infoDrawerOpened = false; - } + this.onDestroy$.next(true); + this.onDestroy$.complete(); } showPreview(node: MinimalNodeEntity) { @@ -130,7 +114,6 @@ export abstract class PageComponent implements OnInit, OnDestroy { this.unSelectLockedNodes(documentList); } - this.lastSelectedNode = event.detail.node; this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); } } diff --git a/src/app/components/preview/preview.component.html b/src/app/components/preview/preview.component.html index 666879f6e9..8a19b31519 100644 --- a/src/app/components/preview/preview.component.html +++ b/src/app/components/preview/preview.component.html @@ -35,10 +35,10 @@ diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 70eb1765e8..18ce84406a 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -3,14 +3,14 @@ - + @@ -18,7 +18,7 @@ mat-icon-button color="primary" title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}" - [adfNodeDownload]="selectedNodes"> + [adfNodeDownload]="selection.nodes"> get_app @@ -41,40 +41,40 @@ [overlapTrigger]="false"> @@ -157,7 +157,7 @@
- +
diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 614de260ee..d1af64136e 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -2,13 +2,13 @@
- + @@ -16,7 +16,7 @@ color="primary" mat-icon-button title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}" - [acaDownloadNodes]="selectedNodes"> + [acaDownloadNodes]="selection.nodes"> get_app @@ -38,24 +38,24 @@ @@ -128,7 +128,7 @@
- +
diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 7cce92bfd8..4515253170 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -3,13 +3,13 @@ - + @@ -17,7 +17,7 @@ color="primary" mat-icon-button title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}" - [adfNodeDownload]="selectedNodes"> + [adfNodeDownload]="selection.nodes"> get_app @@ -40,32 +40,32 @@ [overlapTrigger]="false"> @@ -175,7 +175,7 @@
- +
diff --git a/src/app/components/trashcan/trashcan.component.html b/src/app/components/trashcan/trashcan.component.html index 3e0c7d9563..c6b1de7e38 100644 --- a/src/app/components/trashcan/trashcan.component.html +++ b/src/app/components/trashcan/trashcan.component.html @@ -3,11 +3,11 @@ - + @@ -15,7 +15,7 @@ diff --git a/src/app/store/reducers/app.reducer.ts b/src/app/store/reducers/app.reducer.ts index daff5aeb92..19b1d3f3ef 100644 --- a/src/app/store/reducers/app.reducer.ts +++ b/src/app/store/reducers/app.reducer.ts @@ -90,6 +90,33 @@ function updateSelectedNodes( action: SetSelectedNodesAction ): AppState { const newState = Object.assign({}, state); - newState.selectedNodes = [...action.payload]; + const nodes = [...action.payload]; + const count = nodes.length; + const isEmpty = nodes.length === 0; + + let first = null; + let last = null; + let file = null; + let folder = null; + + if (nodes.length > 0) { + first = nodes[0]; + last = nodes[nodes.length - 1]; + + if (nodes.length === 1) { + file = nodes.find(entity => entity.entry.isFile); + folder = nodes.find(entity => entity.entry.isFolder); + } + } + + newState.selection = { + count, + nodes, + isEmpty, + first, + last, + file, + folder + }; return newState; } diff --git a/src/app/store/selectors/app.selectors.ts b/src/app/store/selectors/app.selectors.ts index 068e5ee26e..5d7a7cc647 100644 --- a/src/app/store/selectors/app.selectors.ts +++ b/src/app/store/selectors/app.selectors.ts @@ -30,4 +30,4 @@ export const selectApp = (state: AppStore) => state.app; export const selectHeaderColor = createSelector(selectApp, (state: AppState) => state.headerColor); export const selectAppName = createSelector(selectApp, (state: AppState) => state.appName); export const selectLogoPath = createSelector(selectApp, (state: AppState) => state.logoPath); -export const selectedNodes = createSelector(selectApp, (state: AppState) => state.selectedNodes); +export const appSelection = createSelector(selectApp, (state: AppState) => state.selection); diff --git a/src/app/store/states/app.state.ts b/src/app/store/states/app.state.ts index 3de91e9269..c10145d218 100644 --- a/src/app/store/states/app.state.ts +++ b/src/app/store/states/app.state.ts @@ -23,20 +23,24 @@ * along with Alfresco. If not, see . */ -import { MinimalNodeEntity } from 'alfresco-js-api'; +import { SelectionState } from './selection.state'; export interface AppState { appName: string; headerColor: string; logoPath: string; - selectedNodes: MinimalNodeEntity[]; + selection: SelectionState; } export const INITIAL_APP_STATE: AppState = { appName: 'Alfresco Example Content Application', headerColor: '#2196F3', logoPath: 'assets/images/alfresco-logo-white.svg', - selectedNodes: [] + selection: { + nodes: [], + isEmpty: true, + count: 0 + } }; export interface AppStore { diff --git a/src/app/store/states/selection.state.ts b/src/app/store/states/selection.state.ts new file mode 100644 index 0000000000..9db2061926 --- /dev/null +++ b/src/app/store/states/selection.state.ts @@ -0,0 +1,36 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { MinimalNodeEntity } from 'alfresco-js-api'; + +export interface SelectionState { + count: number; + nodes: MinimalNodeEntity[]; + isEmpty: boolean; + first?: MinimalNodeEntity; + last?: MinimalNodeEntity; + folder?: MinimalNodeEntity; + file?: MinimalNodeEntity; +} From bf3c86f5f5f1688f90f1793252b98a6535dd6662 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Tue, 19 Jun 2018 11:11:13 +0300 Subject: [PATCH 114/179] tooltip (#434) --- src/app/components/sidenav/sidenav.component.html | 4 ++-- src/assets/i18n/en.json | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index e688033965..97a6211a08 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -1,9 +1,9 @@
- + arrow_drop_down
- queue + queue
+ + + +
+ clear + +
+
+
+
+ + + + + + + + + +

+ {{ item?.entry.name }} +

+ +

+
+

{{item?.entry.createdByUser.displayName}}

+
+ + + + +

{{ 'SEARCH.RESULTS.NONE' | translate:{searchTerm: searchTerm} }}

+
+
+
+
+
diff --git a/src/app/components/search-input-control/search-input-control.component.scss b/src/app/components/search-input-control/search-input-control.component.scss new file mode 100644 index 0000000000..cb1dd538d3 --- /dev/null +++ b/src/app/components/search-input-control/search-input-control.component.scss @@ -0,0 +1,8 @@ +.adf-clear-search-icon-wrapper { + width: 1em; + + .mat-icon { + font-size: 110%; + cursor: pointer; + } +} diff --git a/src/app/components/search-input-control/search-input-control.component.ts b/src/app/components/search-input-control/search-input-control.component.ts new file mode 100644 index 0000000000..496cb1d5b0 --- /dev/null +++ b/src/app/components/search-input-control/search-input-control.component.ts @@ -0,0 +1,275 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { ThumbnailService } from '@alfresco/adf-core'; +import { animate, state, style, transition, trigger } from '@angular/animations'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, + QueryList, ViewEncapsulation, ViewChild, ViewChildren, ElementRef, TemplateRef, ContentChild } from '@angular/core'; +import { MinimalNodeEntity, QueryBody } from 'alfresco-js-api'; +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; +import { MatListItem } from '@angular/material'; +import { debounceTime } from 'rxjs/operators'; +import { EmptySearchResultComponent, SearchComponent } from '@alfresco/adf-content-services'; + +@Component({ + selector: 'app-search-input-control', + templateUrl: './search-input-control.component.html', + styleUrls: ['./search-input-control.component.scss'], + animations: [ + trigger('transitionMessages', [ + state('active', style({ transform: 'translateX(0%)', 'margin-left': '13px' })), + state('inactive', style({ transform: 'translateX(81%)'})), + state('no-animation', style({ transform: 'translateX(0%)', width: '100%' })), + transition('inactive => active', + animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')), + transition('active => inactive', + animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')) + ]) + ], + encapsulation: ViewEncapsulation.None, + host: { class: 'adf-search-control' } +}) +export class SearchInputControlComponent implements OnInit, OnDestroy { + + /** Toggles whether to use an expanding search control. If false + * then a regular input is used. + */ + @Input() + expandable = true; + + /** Toggles highlighting of the search term in the results. */ + @Input() + highlight = false; + + /** Type of the input field to render, e.g. "search" or "text" (default). */ + @Input() + inputType = 'text'; + + /** Toggles auto-completion of the search input field. */ + @Input() + autocomplete = false; + + /** Toggles "find-as-you-type" suggestions for possible matches. */ + @Input() + liveSearchEnabled = true; + + /** Maximum number of results to show in the live search. */ + @Input() + liveSearchMaxResults = 5; + + /** @deprecated in 2.1.0 */ + @Input() + customQueryBody: QueryBody; + + /** Emitted when the search is submitted pressing ENTER button. + * The search term is provided as value of the event. + */ + @Output() + submit: EventEmitter = new EventEmitter(); + + /** Emitted when the search term is changed. The search term is provided + * in the 'value' property of the returned object. If the term is less + * than three characters in length then the term is truncated to an empty + * string. + */ + @Output() + searchChange: EventEmitter = new EventEmitter(); + + /** Emitted when a file item from the list of "find-as-you-type" results is selected. */ + @Output() + optionClicked: EventEmitter = new EventEmitter(); + + @ViewChild('search') + searchAutocomplete: SearchComponent; + + @ViewChild('searchInput') + searchInput: ElementRef; + + @ViewChildren(MatListItem) + private listResultElement: QueryList; + + @ContentChild(EmptySearchResultComponent) + emptySearchTemplate: EmptySearchResultComponent; + + searchTerm = ''; + subscriptAnimationState: string; + noSearchResultTemplate: TemplateRef = null; + skipToggle = false; + + private toggleSearch = new Subject(); + private focusSubject = new Subject(); + + constructor(private thumbnailService: ThumbnailService) { + + this.toggleSearch.asObservable().pipe(debounceTime(200)).subscribe(() => { + if (this.expandable && !this.skipToggle) { + this.subscriptAnimationState = this.subscriptAnimationState === 'inactive' ? 'active' : 'inactive'; + + if (this.subscriptAnimationState === 'inactive') { + this.searchTerm = ''; + this.searchAutocomplete.resetResults(); + if ( document.activeElement.id === this.searchInput.nativeElement.id) { + this.searchInput.nativeElement.blur(); + } + } + } + this.skipToggle = false; + }); + } + + applySearchFocus(animationDoneEvent) { + if (animationDoneEvent.toState === 'active') { + this.searchInput.nativeElement.focus(); + } + } + + ngOnInit() { + this.subscriptAnimationState = this.expandable ? 'inactive' : 'no-animation'; + this.setupFocusEventHandlers(); + } + + isNoSearchTemplatePresent(): boolean { + return this.emptySearchTemplate ? true : false; + } + + ngOnDestroy(): void { + if (this.focusSubject) { + this.focusSubject.unsubscribe(); + this.focusSubject = null; + } + + if (this.toggleSearch) { + this.toggleSearch.unsubscribe(); + this.toggleSearch = null; + } + } + + searchSubmit(event: any) { + this.submit.emit(event); + this.toggleSearchBar(); + } + + inputChange(event: any) { + this.searchChange.emit(event); + } + + getAutoComplete(): string { + return this.autocomplete ? 'on' : 'off'; + } + + getMimeTypeIcon(node: MinimalNodeEntity): string { + let mimeType; + + if (node.entry.content && node.entry.content.mimeType) { + mimeType = node.entry.content.mimeType; + } + if (node.entry.isFolder) { + mimeType = 'folder'; + } + + return this.thumbnailService.getMimeTypeIcon(mimeType); + } + + isSearchBarActive() { + return this.subscriptAnimationState === 'active' && this.liveSearchEnabled; + } + + toggleSearchBar() { + if (this.toggleSearch) { + this.toggleSearch.next(); + } + } + + elementClicked(item: any) { + if (item.entry) { + this.optionClicked.next(item); + this.toggleSearchBar(); + } + } + + onFocus($event): void { + this.focusSubject.next($event); + } + + onBlur($event): void { + this.focusSubject.next($event); + } + + activateToolbar() { + if (!this.isSearchBarActive()) { + this.toggleSearchBar(); + } + } + + selectFirstResult() { + if ( this.listResultElement && this.listResultElement.length > 0) { + const firstElement: MatListItem = this.listResultElement.first; + firstElement._getHostElement().focus(); + } + } + + onRowArrowDown($event: KeyboardEvent): void { + const nextElement: any = this.getNextElementSibling( $event.target); + if (nextElement) { + nextElement.focus(); + } + } + + onRowArrowUp($event: KeyboardEvent): void { + const previousElement: any = this.getPreviousElementSibling( $event.target); + if (previousElement) { + previousElement.focus(); + } else { + this.searchInput.nativeElement.focus(); + this.focusSubject.next(new FocusEvent('focus')); + } + } + + private setupFocusEventHandlers() { + const focusEvents: Observable = this.focusSubject.asObservable() + .debounceTime(50); + focusEvents.filter(($event: any) => { + return this.isSearchBarActive() && ($event.type === 'blur' || $event.type === 'focusout'); + }).subscribe(() => { + this.toggleSearchBar(); + }); + } + + clear(event: any) { + this.searchTerm = ''; + this.searchChange.emit(''); + this.skipToggle = true; + } + + private getNextElementSibling(node: Element): Element { + return node.nextElementSibling; + } + + private getPreviousElementSibling(node: Element): Element { + return node.previousElementSibling; + } + +} diff --git a/src/app/components/search-input/search-input.component.html b/src/app/components/search-input/search-input.component.html index 95fd9b69d5..3b2ba7f960 100644 --- a/src/app/components/search-input/search-input.component.html +++ b/src/app/components/search-input/search-input.component.html @@ -1,15 +1,8 @@ - - - + diff --git a/src/app/components/search-input/search-input.component.ts b/src/app/components/search-input/search-input.component.ts index 860d87d5e8..ad8455fcca 100644 --- a/src/app/components/search-input/search-input.component.ts +++ b/src/app/components/search-input/search-input.component.ts @@ -29,7 +29,7 @@ import { UrlTree } from '@angular/router'; import { MinimalNodeEntity } from 'alfresco-js-api'; -import { SearchControlComponent } from '@alfresco/adf-content-services'; +import { SearchInputControlComponent } from '../search-input-control/search-input-control.component'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; import { SearchByTermAction, ViewNodeAction, NavigateToFolder } from '../../store/actions'; @@ -46,10 +46,15 @@ export class SearchInputComponent implements OnInit { hasNewChange = false; navigationTimer: any; - @ViewChild('searchControl') - searchControl: SearchControlComponent; + @ViewChild('searchInputControl') + searchInputControl: SearchInputControlComponent; constructor(private router: Router, private store: Store) { + } + + ngOnInit() { + this.showInputValue(); + this.router.events.filter(e => e instanceof RouterEvent).subscribe(event => { if (event instanceof NavigationEnd) { this.showInputValue(); @@ -57,10 +62,6 @@ export class SearchInputComponent implements OnInit { }); } - ngOnInit() { - this.showInputValue(); - } - showInputValue() { if (this.onSearchResults) { @@ -73,14 +74,16 @@ export class SearchInputComponent implements OnInit { searchedWord = urlSegments[0].parameters['q']; } - this.searchControl.searchTerm = searchedWord; - this.searchControl.subscriptAnimationState = 'no-animation'; + if (this.searchInputControl) { + this.searchInputControl.searchTerm = searchedWord; + this.searchInputControl.subscriptAnimationState = 'no-animation'; + } } else { - if (this.searchControl.subscriptAnimationState === 'no-animation') { - this.searchControl.subscriptAnimationState = 'active'; - this.searchControl.searchTerm = ''; - this.searchControl.toggleSearchBar(); + if (this.searchInputControl.subscriptAnimationState === 'no-animation') { + this.searchInputControl.subscriptAnimationState = 'active'; + this.searchInputControl.searchTerm = ''; + this.searchInputControl.toggleSearchBar(); } } } @@ -127,9 +130,7 @@ export class SearchInputComponent implements OnInit { } this.navigationTimer = setTimeout(() => { - if (searchTerm) { - this.store.dispatch(new SearchByTermAction(searchTerm)); - } + this.store.dispatch(new SearchByTermAction(searchTerm)); this.hasOneChange = false; }, 1000); } diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index 8773b55149..dca6a02c4c 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -87,6 +87,8 @@ export class SearchComponent extends PageComponent implements OnInit { if (query) { this.queryBuilder.userQuery = query; this.queryBuilder.update(); + } else { + this.onSearchResultLoaded( {list: { pagination: { totalItems: 0 }, entries: []}} ); } }); } From 74aca0711556410b6f30aaff12ff4503fbbae6e7 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 19 Jun 2018 17:25:02 +0100 Subject: [PATCH 117/179] upgrade to latest ADF alpha (#436) --- package-lock.json | 34 ++++--------------- package.json | 4 +-- src/app.config.json | 3 +- .../info-drawer/info-drawer.component.html | 6 +++- .../components/preview/preview.component.html | 6 +++- .../node-versions/node-versions.dialog.html | 7 +++- 6 files changed, 26 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4aaf70d362..436e6b991e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-052668fddc2827b87055e37b43516500a348f9d8", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-052668fddc2827b87055e37b43516500a348f9d8.tgz", - "integrity": "sha512-wAIxDwNWZWAhkJ5lQKUkEISlIUA/8YTVuVx8DlMmGQYp9xTK4xqAVVV/eQ0AV9xsfxK23driAlzk6HageZYhHQ==", + "version": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae.tgz", + "integrity": "sha512-ncSys7iQejfoGXDjZa/sFCue0mE4hT8K1qyPITMk5qeSjpqq2mvu8NZvTLYOh9H9tXoYF8349o6WrHOFopRf0w==", "requires": { - "@alfresco/adf-core": "2.4.0-052668fddc2827b87055e37b43516500a348f9d8", + "@alfresco/adf-core": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -40,16 +40,6 @@ "zone.js": "0.8.14" }, "dependencies": { - "alfresco-js-api": { - "version": "2.4.0-d78bd47d095d373088d67a4fe2aa3bb06c66c14f", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-d78bd47d095d373088d67a4fe2aa3bb06c66c14f.tgz", - "integrity": "sha512-6H80RmDIOV2DrWz/n7t4jzpdQm79rPpWolsV8tRuyJW3U08Nj4WSB8cQ7VYe19sLEZbKtRG3K/DE8xpYZzU1uA==", - "requires": { - "event-emitter": "0.3.4", - "jsrsasign": "^8.0.12", - "superagent": "3.8.2" - } - }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -71,9 +61,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-052668fddc2827b87055e37b43516500a348f9d8", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-052668fddc2827b87055e37b43516500a348f9d8.tgz", - "integrity": "sha512-GJ4+c6NzVa/tfYQFlyP2QG2EjaqY9DyktQt9F9GApMaa0p3aJIvGjcf7+BpyIasWXD63uNCdmmoIOd2pggtubQ==", + "version": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae.tgz", + "integrity": "sha512-+ihUJ9UtdRrGaQrxE/I6CbURh+SGINV9fAO4clCKIHdy4s6i1RVEeLyCTN/dzn5yD2NtzVoSRf+Dz1uS0UZhZQ==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -105,16 +95,6 @@ "zone.js": "0.8.14" }, "dependencies": { - "alfresco-js-api": { - "version": "2.4.0-d78bd47d095d373088d67a4fe2aa3bb06c66c14f", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-d78bd47d095d373088d67a4fe2aa3bb06c66c14f.tgz", - "integrity": "sha512-6H80RmDIOV2DrWz/n7t4jzpdQm79rPpWolsV8tRuyJW3U08Nj4WSB8cQ7VYe19sLEZbKtRG3K/DE8xpYZzU1uA==", - "requires": { - "event-emitter": "0.3.4", - "jsrsasign": "^8.0.12", - "superagent": "3.8.2" - } - }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", diff --git a/package.json b/package.json index 880fa9e425..19638586c1 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-052668fddc2827b87055e37b43516500a348f9d8", - "@alfresco/adf-core": "2.4.0-052668fddc2827b87055e37b43516500a348f9d8", + "@alfresco/adf-content-services": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", + "@alfresco/adf-core": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", diff --git a/src/app.config.json b/src/app.config.json index 2d87d408cc..c9e6c692e1 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -19,8 +19,7 @@ }, "adf-version-manager": { "allowComments": true, - "allowDownload": true, - "allowDelete": true + "allowDownload": true }, "sideNav": { "preserveState": true, diff --git a/src/app/components/info-drawer/info-drawer.component.html b/src/app/components/info-drawer/info-drawer.component.html index f6f75fe038..985ebec34e 100644 --- a/src/app/components/info-drawer/info-drawer.component.html +++ b/src/app/components/info-drawer/info-drawer.component.html @@ -14,7 +14,11 @@ - + + diff --git a/src/app/components/preview/preview.component.html b/src/app/components/preview/preview.component.html index 8a19b31519..4807b59a95 100644 --- a/src/app/components/preview/preview.component.html +++ b/src/app/components/preview/preview.component.html @@ -13,7 +13,11 @@ - + + diff --git a/src/app/dialogs/node-versions/node-versions.dialog.html b/src/app/dialogs/node-versions/node-versions.dialog.html index 4a0dc8e72f..829ea13b13 100644 --- a/src/app/dialogs/node-versions/node-versions.dialog.html +++ b/src/app/dialogs/node-versions/node-versions.dialog.html @@ -1,6 +1,11 @@
{{'VERSION.DIALOG.TITLE' | translate}}
- + +
From 73461df930ba9419e52ee5c0279e868599503704 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 19 Jun 2018 19:48:52 +0100 Subject: [PATCH 118/179] extract material libs to a separate module (#437) --- src/app/app.module.ts | 8 ++----- src/app/material.module.ts | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 src/app/material.module.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index d7536f5e42..0d3efbeef2 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -66,7 +66,6 @@ import { BrowsingFilesService } from './common/services/browsing-files.service'; import { ContentManagementService } from './common/services/content-management.service'; import { NodeActionsService } from './common/services/node-actions.service'; import { NodePermissionService } from './common/services/node-permission.service'; -import { MatMenuModule, MatIconModule, MatButtonModule, MatDialogModule, MatInputModule } from '@angular/material'; import { SearchComponent } from './components/search/search.component'; import { SettingsComponent } from './components/settings/settings.component'; import { HybridAppConfigService } from './common/services/hybrid-app-config.service'; @@ -78,6 +77,7 @@ import { EditFolderDirective } from './directives/edit-folder.directive'; import { CreateFolderDirective } from './directives/create-folder.directive'; import { DownloadNodesDirective } from './directives/download-nodes.directive'; import { AppStoreModule } from './store/app-store.module'; +import { MaterialModule } from './material.module'; @NgModule({ @@ -90,11 +90,7 @@ import { AppStoreModule } from './store/app-store.module'; useHash: true, enableTracing: false // enable for debug only }), - MatMenuModule, - MatIconModule, - MatButtonModule, - MatDialogModule, - MatInputModule, + MaterialModule, CoreModule, ContentModule, ElectronModule, diff --git a/src/app/material.module.ts b/src/app/material.module.ts new file mode 100644 index 0000000000..1743d1a702 --- /dev/null +++ b/src/app/material.module.ts @@ -0,0 +1,44 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { NgModule } from '@angular/core'; +import { + MatMenuModule, + MatIconModule, + MatButtonModule, + MatDialogModule, + MatInputModule +} from '@angular/material'; + +@NgModule({ + imports: [ + MatMenuModule, + MatIconModule, + MatButtonModule, + MatDialogModule, + MatInputModule + ] +}) +export class MaterialModule {} From c77954099dd02adb11911c2d872cf8a1ce26d98e Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 20 Jun 2018 07:21:59 +0100 Subject: [PATCH 119/179] upgrade ADF libs (#440) --- package-lock.json | 44 ++++++++++++++++++++++++++++++++------------ package.json | 6 +++--- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 436e6b991e..c883e33a85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae.tgz", - "integrity": "sha512-ncSys7iQejfoGXDjZa/sFCue0mE4hT8K1qyPITMk5qeSjpqq2mvu8NZvTLYOh9H9tXoYF8349o6WrHOFopRf0w==", + "version": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518.tgz", + "integrity": "sha512-on1ILp40rR8slwQxW2AllYAil2fJdtv6trwU9USmlfis/VLu8V6TVdCFLHgazYRCnoCN7iFGjzPRWCq8I7IAWg==", "requires": { - "@alfresco/adf-core": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", + "@alfresco/adf-core": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-d78bd47d095d373088d67a4fe2aa3bb06c66c14f", + "alfresco-js-api": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -40,6 +40,16 @@ "zone.js": "0.8.14" }, "dependencies": { + "alfresco-js-api": { + "version": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67.tgz", + "integrity": "sha512-tassYFxqiNGK8DrXIkGldn78FgaMBD13y8v3XsLv2c8B8ZU4mspXNNKxy5vQSYqZZtAmWBMT24KdQijThbZoXA==", + "requires": { + "event-emitter": "0.3.4", + "jsrsasign": "^8.0.12", + "superagent": "3.8.2" + } + }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -61,9 +71,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae.tgz", - "integrity": "sha512-+ihUJ9UtdRrGaQrxE/I6CbURh+SGINV9fAO4clCKIHdy4s6i1RVEeLyCTN/dzn5yD2NtzVoSRf+Dz1uS0UZhZQ==", + "version": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518.tgz", + "integrity": "sha512-VTqMlbejmVIc7usVIoGX2dRDAyyW+pwBQyPFbLeq7OfT4Ycs9weZ5mW92HVr4qEIXnX/ExwWXd6z06XYsITbAg==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -79,7 +89,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-d78bd47d095d373088d67a4fe2aa3bb06c66c14f", + "alfresco-js-api": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -95,6 +105,16 @@ "zone.js": "0.8.14" }, "dependencies": { + "alfresco-js-api": { + "version": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67.tgz", + "integrity": "sha512-tassYFxqiNGK8DrXIkGldn78FgaMBD13y8v3XsLv2c8B8ZU4mspXNNKxy5vQSYqZZtAmWBMT24KdQijThbZoXA==", + "requires": { + "event-emitter": "0.3.4", + "jsrsasign": "^8.0.12", + "superagent": "3.8.2" + } + }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -656,9 +676,9 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "alfresco-js-api": { - "version": "2.4.0-d78bd47d095d373088d67a4fe2aa3bb06c66c14f", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-d78bd47d095d373088d67a4fe2aa3bb06c66c14f.tgz", - "integrity": "sha512-6H80RmDIOV2DrWz/n7t4jzpdQm79rPpWolsV8tRuyJW3U08Nj4WSB8cQ7VYe19sLEZbKtRG3K/DE8xpYZzU1uA==", + "version": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67.tgz", + "integrity": "sha512-tassYFxqiNGK8DrXIkGldn78FgaMBD13y8v3XsLv2c8B8ZU4mspXNNKxy5vQSYqZZtAmWBMT24KdQijThbZoXA==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", diff --git a/package.json b/package.json index 19638586c1..50abdc70e3 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", - "@alfresco/adf-core": "2.4.0-ea4c9fe9aa56612fde3969d570ed50f36f0f63ae", + "@alfresco/adf-content-services": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", + "@alfresco/adf-core": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -48,7 +48,7 @@ "@ngrx/store-devtools": "^5.2.0", "@ngstack/electron": "0.1.0", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-d78bd47d095d373088d67a4fe2aa3bb06c66c14f", + "alfresco-js-api": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", "core-js": "2.5.3", "cspell": "^2.1.12", "hammerjs": "2.0.8", From 9e08b8a232eeca74c88a8d5005b9a80eda4b718d Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 20 Jun 2018 12:13:29 +0100 Subject: [PATCH 120/179] app directives (#439) * pagination directive * document list directive * cleanup code * cleanup code * unified includeFields --- src/app/app.module.ts | 9 +- .../favorites/favorites.component.html | 14 +- .../favorites/favorites.component.ts | 43 +++-- src/app/components/files/files.component.html | 14 +- src/app/components/files/files.component.ts | 24 +-- .../libraries/libraries.component.html | 12 +- .../libraries/libraries.component.ts | 9 +- src/app/components/page.component.spec.ts | 2 +- src/app/components/page.component.ts | 60 +------ .../components/preview/preview.component.ts | 6 +- .../recent-files/recent-files.component.html | 14 +- .../recent-files/recent-files.component.ts | 9 +- .../components/search/search.component.html | 5 +- src/app/components/search/search.component.ts | 9 +- .../shared-files/shared-files.component.html | 14 +- .../shared-files/shared-files.component.ts | 11 +- .../trashcan/trashcan.component.html | 14 +- .../components/trashcan/trashcan.component.ts | 14 +- src/app/directives/document-list.directive.ts | 158 ++++++++++++++++++ src/app/directives/pagination.directive.ts | 65 +++++++ .../sorting-preference-key.directive.ts | 64 ------- 21 files changed, 305 insertions(+), 265 deletions(-) create mode 100644 src/app/directives/document-list.directive.ts create mode 100644 src/app/directives/pagination.directive.ts delete mode 100644 src/app/directives/sorting-preference-key.directive.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 0d3efbeef2..2a7127cb72 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -69,7 +69,6 @@ import { NodePermissionService } from './common/services/node-permission.service import { SearchComponent } from './components/search/search.component'; import { SettingsComponent } from './components/settings/settings.component'; import { HybridAppConfigService } from './common/services/hybrid-app-config.service'; -import { SortingPreferenceKeyDirective } from './directives/sorting-preference-key.directive'; import { PageTitleService as AcaPageTitleService } from './common/services/page-title.service'; import { InfoDrawerComponent } from './components/info-drawer/info-drawer.component'; @@ -77,9 +76,10 @@ import { EditFolderDirective } from './directives/edit-folder.directive'; import { CreateFolderDirective } from './directives/create-folder.directive'; import { DownloadNodesDirective } from './directives/download-nodes.directive'; import { AppStoreModule } from './store/app-store.module'; +import { PaginationDirective } from './directives/pagination.directive'; +import { DocumentListDirective } from './directives/document-list.directive'; import { MaterialModule } from './material.module'; - @NgModule({ imports: [ BrowserModule, @@ -127,11 +127,12 @@ import { MaterialModule } from './material.module'; NodeVersionsDialogComponent, SearchComponent, SettingsComponent, - SortingPreferenceKeyDirective, InfoDrawerComponent, EditFolderDirective, CreateFolderDirective, - DownloadNodesDirective + DownloadNodesDirective, + PaginationDirective, + DocumentListDirective ], providers: [ { provide: PageTitleService, useClass: AcaPageTitleService }, diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index a6c71fa4e0..9959a67e3c 100644 --- a/src/app/components/favorites/favorites.component.html +++ b/src/app/components/favorites/favorites.component.html @@ -90,17 +90,12 @@
- + (node-dblclick)="onNodeDoubleClick($event.detail?.node)"> @@ -161,10 +156,7 @@ - +
diff --git a/src/app/components/favorites/favorites.component.ts b/src/app/components/favorites/favorites.component.ts index 29ea2e3265..3d4a7912d7 100644 --- a/src/app/components/favorites/favorites.component.ts +++ b/src/app/components/favorites/favorites.component.ts @@ -23,30 +23,33 @@ * along with Alfresco. If not, see . */ +import { NodesApiService } from '@alfresco/adf-core'; import { Component, OnInit } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; -import { MinimalNodeEntryEntity, PathElementEntity, PathInfo, MinimalNodeEntity } from 'alfresco-js-api'; -import { NodesApiService, UserPreferencesService } from '@alfresco/adf-core'; - +import { Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { + MinimalNodeEntity, + MinimalNodeEntryEntity, + PathElementEntity, + PathInfo +} from 'alfresco-js-api'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; -import { PageComponent } from '../page.component'; -import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; +import { PageComponent } from '../page.component'; @Component({ templateUrl: './favorites.component.html' }) export class FavoritesComponent extends PageComponent implements OnInit { - - constructor(private router: Router, - route: ActivatedRoute, - store: Store, - private nodesApi: NodesApiService, - private content: ContentManagementService, - public permission: NodePermissionService, - preferences: UserPreferencesService) { - super(preferences, route, store); + constructor( + private router: Router, + store: Store, + private nodesApi: NodesApiService, + private content: ContentManagementService, + public permission: NodePermissionService + ) { + super(store); } ngOnInit() { @@ -65,15 +68,19 @@ export class FavoritesComponent extends PageComponent implements OnInit { // TODO: rework as it will fail on non-English setups const isSitePath = (path: PathInfo): boolean => { - return path.elements.some(({ name }: PathElementEntity) => (name === 'Sites')); + return path.elements.some( + ({ name }: PathElementEntity) => name === 'Sites' + ); }; if (isFolder) { this.nodesApi .getNode(id) .subscribe(({ path }: MinimalNodeEntryEntity) => { - const routeUrl = isSitePath(path) ? '/libraries' : '/personal-files'; - this.router.navigate([ routeUrl, id ]); + const routeUrl = isSitePath(path) + ? '/libraries' + : '/personal-files'; + this.router.navigate([routeUrl, id]); }); } } diff --git a/src/app/components/files/files.component.html b/src/app/components/files/files.component.html index 446090a0de..56515fd14b 100644 --- a/src/app/components/files/files.component.html +++ b/src/app/components/files/files.component.html @@ -103,19 +103,14 @@ [parentId]="node?.id" [disabled]="!permission.check(node, ['create'])"> - + (node-dblclick)="onNodeDoubleClick($event.detail?.node)"> - +
diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index beabc58fa9..ea0cc71526 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -23,23 +23,18 @@ * along with Alfresco. If not, see . */ +import { AlfrescoApiService, FileUploadEvent, NodesApiService, UploadService } from '@alfresco/adf-core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { ActivatedRoute, Params, Router } from '@angular/router'; +import { Store } from '@ngrx/store'; +import { MinimalNodeEntity, MinimalNodeEntryEntity, NodePaging, PathElement, PathElementEntity } from 'alfresco-js-api'; import { Observable } from 'rxjs/Rx'; -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { Router, ActivatedRoute, Params } from '@angular/router'; -import { MinimalNodeEntity, MinimalNodeEntryEntity, PathElementEntity, NodePaging, PathElement } from 'alfresco-js-api'; -import { - UploadService, FileUploadEvent, NodesApiService, - AlfrescoApiService, UserPreferencesService -} from '@alfresco/adf-core'; - import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodeActionsService } from '../../common/services/node-actions.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; - -import { PageComponent } from '../page.component'; -import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; +import { PageComponent } from '../page.component'; @Component({ templateUrl: './files.component.html' @@ -51,7 +46,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { private nodePath: PathElement[]; constructor(private router: Router, - route: ActivatedRoute, + private route: ActivatedRoute, store: Store, private nodesApi: NodesApiService, private nodeActionsService: NodeActionsService, @@ -59,9 +54,8 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { private contentManagementService: ContentManagementService, private browsingFilesService: BrowsingFilesService, private apiService: AlfrescoApiService, - public permission: NodePermissionService, - preferences: UserPreferencesService) { - super(preferences, route, store); + public permission: NodePermissionService) { + super(store); } ngOnInit() { diff --git a/src/app/components/libraries/libraries.component.html b/src/app/components/libraries/libraries.component.html index 21021940c4..c78715378a 100644 --- a/src/app/components/libraries/libraries.component.html +++ b/src/app/components/libraries/libraries.component.html @@ -8,16 +8,11 @@
- @@ -67,10 +62,7 @@ - +
diff --git a/src/app/components/libraries/libraries.component.ts b/src/app/components/libraries/libraries.component.ts index 74cfc73df3..19e5a24302 100644 --- a/src/app/components/libraries/libraries.component.ts +++ b/src/app/components/libraries/libraries.component.ts @@ -25,7 +25,7 @@ import { Component } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { NodesApiService, UserPreferencesService } from '@alfresco/adf-core'; +import { NodesApiService } from '@alfresco/adf-core'; import { ShareDataRow } from '@alfresco/adf-content-services'; import { PageComponent } from '../page.component'; @@ -38,11 +38,10 @@ import { AppStore } from '../../store/states/app.state'; export class LibrariesComponent extends PageComponent { constructor(private nodesApi: NodesApiService, - route: ActivatedRoute, + private route: ActivatedRoute, store: Store, - private router: Router, - preferences: UserPreferencesService) { - super(preferences, route, store); + private router: Router) { + super(store); } makeLibraryTooltip(library: any): string { diff --git a/src/app/components/page.component.spec.ts b/src/app/components/page.component.spec.ts index ee65afb82c..d44f5a257f 100644 --- a/src/app/components/page.component.spec.ts +++ b/src/app/components/page.component.spec.ts @@ -29,7 +29,7 @@ class TestClass extends PageComponent { node: any; constructor() { - super(null, null, null); + super(null); } } diff --git a/src/app/components/page.component.ts b/src/app/components/page.component.ts index 3bb25af10f..7656121932 100644 --- a/src/app/components/page.component.ts +++ b/src/app/components/page.component.ts @@ -24,11 +24,10 @@ */ import { DocumentListComponent, ShareDataRow } from '@alfresco/adf-content-services'; -import { FileUploadErrorEvent, UserPreferencesService } from '@alfresco/adf-core'; +import { FileUploadErrorEvent } from '@alfresco/adf-core'; import { OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; import { Store } from '@ngrx/store'; -import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco-js-api'; +import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; import { takeUntil } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs/Rx'; import { SnackbarErrorAction, ViewNodeAction, SetSelectedNodesAction } from '../store/actions'; @@ -50,18 +49,11 @@ export abstract class PageComponent implements OnInit, OnDestroy { protected subscriptions: Subscription[] = []; - get sortingPreferenceKey(): string { - return this.route.snapshot.data.sortingPreferenceKey; - } - static isLockedNode(node) { return node.isLocked || (node.properties && node.properties['cm:lockType'] === 'READ_ONLY_LOCK'); } - constructor(protected preferences: UserPreferencesService, - protected route: ActivatedRoute, - protected store: Store) { - } + constructor(protected store: Store) {} ngOnInit() { this.store @@ -102,52 +94,6 @@ export abstract class PageComponent implements OnInit, OnDestroy { return this.node ? this.node.id : null; } - onChangePageSize(event: Pagination): void { - this.preferences.paginationSize = event.maxItems; - } - - onNodeSelect(event: CustomEvent, documentList: DocumentListComponent) { - if (!!event.detail && !!event.detail.node) { - - const node: MinimalNodeEntryEntity = event.detail.node.entry; - if (node && PageComponent.isLockedNode(node)) { - this.unSelectLockedNodes(documentList); - } - - this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); - } - } - - onDocumentListReady(event: CustomEvent, documentList: DocumentListComponent) { - this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); - } - - onNodeUnselect(event: CustomEvent, documentList: DocumentListComponent) { - this.store.dispatch(new SetSelectedNodesAction(documentList.selection)); - } - - unSelectLockedNodes(documentList: DocumentListComponent) { - documentList.selection = documentList.selection.filter(item => !PageComponent.isLockedNode(item.entry)); - - const dataTable = documentList.dataTable; - if (dataTable && dataTable.data) { - const rows = dataTable.data.getRows(); - - if (rows && rows.length > 0) { - rows.forEach(r => { - if (this.isLockedRow(r)) { - r.isSelected = false; - } - }); - } - } - } - - isLockedRow(row) { - return row.getValue('isLocked') || - (row.getValue('properties') && row.getValue('properties')['cm:lockType'] === 'READ_ONLY_LOCK'); - } - imageResolver(row: ShareDataRow): string | null { const entry: MinimalNodeEntryEntity = row.node.entry; diff --git a/src/app/components/preview/preview.component.ts b/src/app/components/preview/preview.component.ts index cd603cd73e..dd66d74e63 100644 --- a/src/app/components/preview/preview.component.ts +++ b/src/app/components/preview/preview.component.ts @@ -58,13 +58,13 @@ export class PreviewComponent extends PageComponent implements OnInit { constructor( private uploadService: UploadService, private apiService: AlfrescoApiService, - preferences: UserPreferencesService, - route: ActivatedRoute, + private preferences: UserPreferencesService, + private route: ActivatedRoute, private router: Router, store: Store, public permission: NodePermissionService) { - super(preferences, route, store); + super(store); } ngOnInit() { diff --git a/src/app/components/recent-files/recent-files.component.html b/src/app/components/recent-files/recent-files.component.html index 18ce84406a..67f5fea8c3 100644 --- a/src/app/components/recent-files/recent-files.component.html +++ b/src/app/components/recent-files/recent-files.component.html @@ -84,18 +84,13 @@
- + (node-dblclick)="onNodeDoubleClick($event.detail?.node)"> @@ -149,10 +144,7 @@ - +
diff --git a/src/app/components/recent-files/recent-files.component.ts b/src/app/components/recent-files/recent-files.component.ts index cb5244acb3..f9581e608f 100644 --- a/src/app/components/recent-files/recent-files.component.ts +++ b/src/app/components/recent-files/recent-files.component.ts @@ -24,9 +24,8 @@ */ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; import { MinimalNodeEntity } from 'alfresco-js-api'; -import { UserPreferencesService, UploadService } from '@alfresco/adf-core'; +import { UploadService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { PageComponent } from '../page.component'; @@ -40,13 +39,11 @@ import { AppStore } from '../../store/states/app.state'; export class RecentFilesComponent extends PageComponent implements OnInit { constructor( - route: ActivatedRoute, store: Store, private uploadService: UploadService, private content: ContentManagementService, - public permission: NodePermissionService, - preferences: UserPreferencesService) { - super(preferences, route, store); + public permission: NodePermissionService) { + super(store); } ngOnInit() { diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index d1af64136e..4e46297d93 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -88,10 +88,7 @@ [sortingMode]="'server'" [sorting]="sorting" [node]="data" - (node-dblclick)="onNodeDoubleClick($event.detail?.node)" - (ready)="onDocumentListReady($event, documentList)" - (node-select)="onNodeSelect($event, documentList)" - (node-unselect)="onNodeUnselect($event, documentList)"> + (node-dblclick)="onNodeDoubleClick($event.detail?.node)"> , - preferences: UserPreferencesService, - route: ActivatedRoute) { - super(preferences, route, store); + private route: ActivatedRoute, + store: Store + ) { + super(store); queryBuilder.paging = { skipCount: 0, diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 4515253170..33a296a859 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -92,16 +92,11 @@
- + (node-dblclick)="showPreview($event.detail?.node)"> @@ -167,10 +162,7 @@ - +
diff --git a/src/app/components/shared-files/shared-files.component.ts b/src/app/components/shared-files/shared-files.component.ts index b2cf92a82f..535f8948f7 100644 --- a/src/app/components/shared-files/shared-files.component.ts +++ b/src/app/components/shared-files/shared-files.component.ts @@ -24,8 +24,7 @@ */ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { UserPreferencesService, UploadService } from '@alfresco/adf-core'; +import { UploadService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; @@ -38,13 +37,11 @@ import { AppStore } from '../../store/states/app.state'; }) export class SharedFilesComponent extends PageComponent implements OnInit { - constructor(route: ActivatedRoute, - store: Store, + constructor(store: Store, private uploadService: UploadService, private content: ContentManagementService, - public permission: NodePermissionService, - preferences: UserPreferencesService) { - super(preferences, route, store); + public permission: NodePermissionService) { + super(store); } ngOnInit() { diff --git a/src/app/components/trashcan/trashcan.component.html b/src/app/components/trashcan/trashcan.component.html index 711dc36f54..6d081f8d62 100644 --- a/src/app/components/trashcan/trashcan.component.html +++ b/src/app/components/trashcan/trashcan.component.html @@ -24,16 +24,11 @@
- + [sorting]="[ 'archivedAt', 'desc' ]"> @@ -96,10 +91,7 @@ - +
diff --git a/src/app/components/trashcan/trashcan.component.ts b/src/app/components/trashcan/trashcan.component.ts index 4f817b4637..b914eeab97 100644 --- a/src/app/components/trashcan/trashcan.component.ts +++ b/src/app/components/trashcan/trashcan.component.ts @@ -24,9 +24,7 @@ */ import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { Pagination } from 'alfresco-js-api'; -import { UserPreferencesService, PeopleContentService } from '@alfresco/adf-core'; +import { PeopleContentService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { PageComponent } from '../page.component'; import { Store } from '@ngrx/store'; @@ -40,10 +38,8 @@ export class TrashcanComponent extends PageComponent implements OnInit { constructor(private contentManagementService: ContentManagementService, private peopleApi: PeopleContentService, - preferences: UserPreferencesService, - store: Store, - route: ActivatedRoute) { - super(preferences, route, store); + store: Store) { + super(store); } ngOnInit() { @@ -57,10 +53,6 @@ export class TrashcanComponent extends PageComponent implements OnInit { ); } - onChangePageSize(event: Pagination): void { - this.preferences.paginationSize = event.maxItems; - } - private isUserAdmin(user) { if (user && user.capabilities) { this.userIsAdmin = user.capabilities.isAdmin; diff --git a/src/app/directives/document-list.directive.ts b/src/app/directives/document-list.directive.ts new file mode 100644 index 0000000000..d0bcddae29 --- /dev/null +++ b/src/app/directives/document-list.directive.ts @@ -0,0 +1,158 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Directive, OnDestroy, OnInit, HostListener } from '@angular/core'; +import { DocumentListComponent } from '@alfresco/adf-content-services'; +import { ActivatedRoute } from '@angular/router'; +import { UserPreferencesService } from '@alfresco/adf-core'; +import { Subscription } from 'rxjs/Rx'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../store/states/app.state'; +import { SetSelectedNodesAction } from '../store/actions'; +import { MinimalNodeEntryEntity } from 'alfresco-js-api'; + +@Directive({ + selector: '[acaDocumentList]' +}) +export class DocumentListDirective implements OnInit, OnDestroy { + private subscriptions: Subscription[] = []; + + get sortingPreferenceKey(): string { + return this.route.snapshot.data.sortingPreferenceKey; + } + + constructor( + private store: Store, + private documentList: DocumentListComponent, + private preferences: UserPreferencesService, + private route: ActivatedRoute + ) {} + + ngOnInit() { + this.documentList.includeFields = ['isFavorite']; + + if (this.sortingPreferenceKey) { + const current = this.documentList.sorting; + + const key = this.preferences.get( + `${this.sortingPreferenceKey}.sorting.key`, + current[0] + ); + const direction = this.preferences.get( + `${this.sortingPreferenceKey}.sorting.direction`, + current[1] + ); + + this.documentList.sorting = [key, direction]; + // TODO: bug in ADF, the `sorting` binding is not updated when changed from code + this.documentList.data.setSorting({ key, direction }); + } + + this.subscriptions.push( + this.documentList.ready.subscribe(() => this.onReady()) + ); + } + + ngOnDestroy() { + this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions = []; + } + + @HostListener('sorting-changed', ['$event']) + onSortingChanged(event: CustomEvent) { + if (this.sortingPreferenceKey) { + this.preferences.set( + `${this.sortingPreferenceKey}.sorting.key`, + event.detail.key + ); + this.preferences.set( + `${this.sortingPreferenceKey}.sorting.direction`, + event.detail.direction + ); + } + } + + @HostListener('node-select', ['$event']) + onNodeSelect(event: CustomEvent) { + if (!!event.detail && !!event.detail.node) { + const node: MinimalNodeEntryEntity = event.detail.node.entry; + if (node && this.isLockedNode(node)) { + this.unSelectLockedNodes(this.documentList); + } + + this.store.dispatch( + new SetSelectedNodesAction(this.documentList.selection) + ); + } + } + + @HostListener('node-unselect') + onNodeUnselect() { + this.store.dispatch( + new SetSelectedNodesAction(this.documentList.selection) + ); + } + + onReady() { + this.store.dispatch( + new SetSelectedNodesAction(this.documentList.selection) + ); + } + + private isLockedNode(node): boolean { + return ( + node.isLocked || + (node.properties && + node.properties['cm:lockType'] === 'READ_ONLY_LOCK') + ); + } + + private isLockedRow(row): boolean { + return ( + row.getValue('isLocked') || + (row.getValue('properties') && + row.getValue('properties')['cm:lockType'] === 'READ_ONLY_LOCK') + ); + } + + private unSelectLockedNodes(documentList: DocumentListComponent) { + documentList.selection = documentList.selection.filter( + item => !this.isLockedNode(item.entry) + ); + + const dataTable = documentList.dataTable; + if (dataTable && dataTable.data) { + const rows = dataTable.data.getRows(); + + if (rows && rows.length > 0) { + rows.forEach(r => { + if (this.isLockedRow(r)) { + r.isSelected = false; + } + }); + } + } + } +} diff --git a/src/app/directives/pagination.directive.ts b/src/app/directives/pagination.directive.ts new file mode 100644 index 0000000000..94155d8924 --- /dev/null +++ b/src/app/directives/pagination.directive.ts @@ -0,0 +1,65 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Directive, OnInit, OnDestroy } from '@angular/core'; +import { + PaginationComponent, + UserPreferencesService, + PaginationModel, + AppConfigService +} from '@alfresco/adf-core'; +import { Subscription } from 'rxjs/Rx'; + +@Directive({ + selector: '[acaPagination]' +}) +export class PaginationDirective implements OnInit, OnDestroy { + private subscriptions: Subscription[] = []; + + constructor( + private pagination: PaginationComponent, + private preferences: UserPreferencesService, + private config: AppConfigService + ) {} + + ngOnInit() { + this.pagination.supportedPageSizes = this.config.get( + 'pagination.supportedPageSizes' + ); + + this.subscriptions.push( + this.pagination.changePageSize.subscribe( + (event: PaginationModel) => { + this.preferences.paginationSize = event.maxItems; + } + ) + ); + } + + ngOnDestroy() { + this.subscriptions.forEach(subscription => subscription.unsubscribe()); + this.subscriptions = []; + } +} diff --git a/src/app/directives/sorting-preference-key.directive.ts b/src/app/directives/sorting-preference-key.directive.ts deleted file mode 100644 index 8fe4709b72..0000000000 --- a/src/app/directives/sorting-preference-key.directive.ts +++ /dev/null @@ -1,64 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2018 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { Directive, Input, OnInit, HostListener } from '@angular/core'; -import { DocumentListComponent } from '@alfresco/adf-content-services'; -import { UserPreferencesService } from '@alfresco/adf-core'; - -@Directive({ - selector: '[acaSortingPreferenceKey]', -}) -export class SortingPreferenceKeyDirective implements OnInit { - - // tslint:disable-next-line:no-input-rename - @Input('acaSortingPreferenceKey') - preferenceKey: string; - - constructor( - private documentList: DocumentListComponent, - private userPreferencesService: UserPreferencesService) { - } - - @HostListener('sorting-changed', ['$event']) - onSortingChanged(event: CustomEvent) { - if (this.preferenceKey) { - this.userPreferencesService.set(`${this.preferenceKey}.sorting.key`, event.detail.key); - this.userPreferencesService.set(`${this.preferenceKey}.sorting.direction`, event.detail.direction); - } - } - - ngOnInit() { - if (this.preferenceKey) { - const current = this.documentList.sorting; - - const key = this.userPreferencesService.get(`${this.preferenceKey}.sorting.key`, current[0]); - const direction = this.userPreferencesService.get(`${this.preferenceKey}.sorting.direction`, current[1]); - - this.documentList.sorting = [key, direction]; - // TODO: bug in ADF, the `sorting` binding is not updated when changed from code - this.documentList.data.setSorting({ key, direction }); - } - } -} From fec3f8aaf752cb20c0085f3056ce308c9a2cc2ff Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 20 Jun 2018 15:43:20 +0300 Subject: [PATCH 121/179] User profile state (#438) * user data * fix missing store selector * profile state * use ProfileStatus * remove tests * test fixes --- e2e/suites/list-views/trash.test.ts | 4 +- src/app/app.module.ts | 4 +- src/app/app.routes.ts | 3 + src/app/common/services/profile.resolver.ts | 56 ++++++++++++ .../current-user/current-user.component.html | 4 +- .../current-user.component.spec.ts | 90 ------------------- .../current-user/current-user.component.ts | 34 ++----- .../trashcan/trashcan.component.html | 2 +- .../components/trashcan/trashcan.component.ts | 16 +--- src/app/store/actions.ts | 1 + src/app/store/actions/user.actions.ts | 33 +++++++ src/app/store/reducers/app.reducer.ts | 32 ++++++- src/app/store/selectors/app.selectors.ts | 1 + src/app/store/states/app.state.ts | 8 ++ src/app/store/states/profile.state.ts | 33 +++++++ 15 files changed, 186 insertions(+), 135 deletions(-) create mode 100644 src/app/common/services/profile.resolver.ts delete mode 100644 src/app/components/current-user/current-user.component.spec.ts create mode 100644 src/app/store/actions/user.actions.ts create mode 100644 src/app/store/states/profile.state.ts diff --git a/e2e/suites/list-views/trash.test.ts b/e2e/suites/list-views/trash.test.ts index 8af8827bf0..df378e765f 100755 --- a/e2e/suites/list-views/trash.test.ts +++ b/e2e/suites/list-views/trash.test.ts @@ -132,10 +132,10 @@ describe('Trash', () => { }); it('has the correct columns', () => { - const labels = [ 'Name', 'Location', 'Size', 'Deleted', 'Deleted by' ]; + const labels = [ 'Name', 'Location', 'Size', 'Deleted']; const elements = labels.map(label => dataTable.getColumnHeaderByLabel(label)); - expect(dataTable.getColumnHeaders().count()).toBe(5 + 1, 'Incorrect number of columns'); + expect(dataTable.getColumnHeaders().count()).toBe(4 + 1, 'Incorrect number of columns'); elements.forEach((element, index) => { expect(element.isPresent()).toBe(true, `"${labels[index]}" is missing`); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 2a7127cb72..d3b59831ae 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -70,6 +70,7 @@ import { SearchComponent } from './components/search/search.component'; import { SettingsComponent } from './components/settings/settings.component'; import { HybridAppConfigService } from './common/services/hybrid-app-config.service'; import { PageTitleService as AcaPageTitleService } from './common/services/page-title.service'; +import { ProfileResolver } from './common/services/profile.resolver'; import { InfoDrawerComponent } from './components/info-drawer/info-drawer.component'; import { EditFolderDirective } from './directives/edit-folder.directive'; @@ -148,7 +149,8 @@ import { MaterialModule } from './material.module'; BrowsingFilesService, ContentManagementService, NodeActionsService, - NodePermissionService + NodePermissionService, + ProfileResolver ], entryComponents: [ NodeVersionsDialogComponent diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 595fe76543..0a4b610a06 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -42,6 +42,8 @@ import { GenericErrorComponent } from './components/generic-error/generic-error. import { SearchComponent } from './components/search/search.component'; import { SettingsComponent } from './components/settings/settings.component'; +import { ProfileResolver } from './common/services/profile.resolver'; + export const APP_ROUTES: Routes = [ { path: 'login', @@ -60,6 +62,7 @@ export const APP_ROUTES: Routes = [ { path: '', component: LayoutComponent, + resolve: { profile: ProfileResolver }, children: [ { path: '', diff --git a/src/app/common/services/profile.resolver.ts b/src/app/common/services/profile.resolver.ts new file mode 100644 index 0000000000..ec169d83d3 --- /dev/null +++ b/src/app/common/services/profile.resolver.ts @@ -0,0 +1,56 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Store } from '@ngrx/store'; +import { Injectable } from '@angular/core'; +import { Resolve } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; + +import { AppStore } from '../../store/states/app.state'; +import { SetUserAction } from '../../store/actions/user.actions'; +import { selectUser } from '../../store/selectors/app.selectors'; +import { PeopleContentService } from '@alfresco/adf-core'; + +@Injectable() +export class ProfileResolver implements Resolve { + constructor(private store: Store, private peopleApi: PeopleContentService) { } + + resolve(): Observable { + + this.init(); + + return this.profileLoaded(); + } + + profileLoaded(): Observable { + return this.store.select(selectUser).take(1); + } + + init(): void { + this.peopleApi.getCurrentPerson().subscribe((person: any) => { + this.store.dispatch(new SetUserAction(person.entry)); + }); + } +} diff --git a/src/app/components/current-user/current-user.component.html b/src/app/components/current-user/current-user.component.html index c2eeef62ec..17d9c756d0 100644 --- a/src/app/components/current-user/current-user.component.html +++ b/src/app/components/current-user/current-user.component.html @@ -1,9 +1,9 @@
-
{{ userName }}
+
{{ user?.userName }}
- {{ userInitials }} + {{ user?.initials }}
diff --git a/src/app/components/current-user/current-user.component.spec.ts b/src/app/components/current-user/current-user.component.spec.ts deleted file mode 100644 index 88f025232c..0000000000 --- a/src/app/components/current-user/current-user.component.spec.ts +++ /dev/null @@ -1,90 +0,0 @@ -/*! - * @license - * Alfresco Example Content Application - * - * Copyright (C) 2005 - 2018 Alfresco Software Limited - * - * This file is part of the Alfresco Example Content Application. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * The Alfresco Example Content Application is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * The Alfresco Example Content Application is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { TestBed, async } from '@angular/core/testing'; -import { Observable } from 'rxjs/Rx'; -import { MatMenuModule } from '@angular/material'; -import { - AlfrescoApiService, - AppConfigService, - StorageService, - PeopleContentService, - UserPreferencesService, - AppConfigPipe - } from '@alfresco/adf-core'; - -import { CurrentUserComponent } from './current-user.component'; -import { AppTestingModule } from '../../testing/app-testing.module'; - -describe('CurrentUserComponent', () => { - let fixture; - let component; - let peopleApi: PeopleContentService; - let user; - - beforeEach(() => { - user = { entry: { firstName: 'joe', lastName: 'doe' } }; - }); - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - AppTestingModule, - MatMenuModule - ], - declarations: [ - CurrentUserComponent, - AppConfigPipe - ], - providers: [ - AlfrescoApiService, - AppConfigService, - StorageService, - PeopleContentService, - UserPreferencesService - ], - schemas: [ NO_ERRORS_SCHEMA ] - }) - .compileComponents() - .then(() => { - fixture = TestBed.createComponent(CurrentUserComponent); - component = fixture.componentInstance; - peopleApi = TestBed.get(PeopleContentService); - - spyOn(peopleApi, 'getCurrentPerson').and.returnValue(Observable.of(user)); - - fixture.detectChanges(); - }); - })); - - it('updates user data', () => { - expect(component.user).toBe(user.entry); - }); - - it('get user initials', () => { - expect(component.userInitials).toBe('jd'); - }); -}); diff --git a/src/app/components/current-user/current-user.component.ts b/src/app/components/current-user/current-user.component.ts index 996646cf54..014207cc5f 100644 --- a/src/app/components/current-user/current-user.component.ts +++ b/src/app/components/current-user/current-user.component.ts @@ -24,9 +24,13 @@ */ import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core'; -import { PeopleContentService } from '@alfresco/adf-core'; import { Subscription } from 'rxjs/Rx'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../../store/states/app.state'; +import { selectUser } from '../../store/selectors/app.selectors'; +import { ProfileState } from '../../store/states/profile.state'; + @Component({ selector: 'aca-current-user', templateUrl: './current-user.component.html', @@ -36,39 +40,17 @@ import { Subscription } from 'rxjs/Rx'; export class CurrentUserComponent implements OnInit, OnDestroy { private subscriptions: Subscription[] = []; - user: any = null; + user: ProfileState; - constructor( - private peopleApi: PeopleContentService - ) {} + constructor(private store: Store) {} ngOnInit() { this.subscriptions = this.subscriptions.concat([ - this.peopleApi.getCurrentPerson().subscribe((person: any) => this.user = person.entry) + this.store.select(selectUser).subscribe((user) => this.user = user) ]); } ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } - - get userFirstName(): string { - const { user } = this; - return user ? (user.firstName || '') : ''; - } - - get userLastName(): string { - const { user } = this; - return user ? (user.lastName || '') : ''; - } - - get userName(): string { - const { userFirstName: first, userLastName: last } = this; - return `${first} ${last}`; - } - - get userInitials(): string { - const { userFirstName: first, userLastName: last } = this; - return [ first[0], last[0] ].join(''); - } } diff --git a/src/app/components/trashcan/trashcan.component.html b/src/app/components/trashcan/trashcan.component.html index 6d081f8d62..b9a6700d11 100644 --- a/src/app/components/trashcan/trashcan.component.html +++ b/src/app/components/trashcan/trashcan.component.html @@ -82,7 +82,7 @@ diff --git a/src/app/components/trashcan/trashcan.component.ts b/src/app/components/trashcan/trashcan.component.ts index b914eeab97..f754cf3f48 100644 --- a/src/app/components/trashcan/trashcan.component.ts +++ b/src/app/components/trashcan/trashcan.component.ts @@ -24,20 +24,20 @@ */ import { Component, OnInit } from '@angular/core'; -import { PeopleContentService } from '@alfresco/adf-core'; import { ContentManagementService } from '../../common/services/content-management.service'; import { PageComponent } from '../page.component'; import { Store } from '@ngrx/store'; +import { selectUser } from '../../store/selectors/app.selectors'; import { AppStore } from '../../store/states/app.state'; +import { ProfileState } from '../../store/states/profile.state'; @Component({ templateUrl: './trashcan.component.html' }) export class TrashcanComponent extends PageComponent implements OnInit { - userIsAdmin: boolean; + user: ProfileState; constructor(private contentManagementService: ContentManagementService, - private peopleApi: PeopleContentService, store: Store) { super(store); } @@ -49,15 +49,7 @@ export class TrashcanComponent extends PageComponent implements OnInit { this.contentManagementService.nodesRestored.subscribe(() => this.reload()), this.contentManagementService.nodesPurged.subscribe(() => this.reload()), this.contentManagementService.nodesRestored.subscribe(() => this.reload()), - this.peopleApi.getCurrentPerson().subscribe((user: any) => this.isUserAdmin(user)) + this.store.select(selectUser).subscribe((user) => this.user = user) ); } - - private isUserAdmin(user) { - if (user && user.capabilities) { - this.userIsAdmin = user.capabilities.isAdmin; - } else { - this.userIsAdmin = true; - } - } } diff --git a/src/app/store/actions.ts b/src/app/store/actions.ts index d3cec5741c..cb5ff1eee0 100644 --- a/src/app/store/actions.ts +++ b/src/app/store/actions.ts @@ -29,3 +29,4 @@ export * from './actions/snackbar.actions'; export * from './actions/router.actions'; export * from './actions/viewer.actions'; export * from './actions/search.actions'; +export * from './actions/user.actions'; diff --git a/src/app/store/actions/user.actions.ts b/src/app/store/actions/user.actions.ts new file mode 100644 index 0000000000..447bf6c39d --- /dev/null +++ b/src/app/store/actions/user.actions.ts @@ -0,0 +1,33 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Action } from '@ngrx/store'; + +export const SET_USER = 'SET_USER'; + +export class SetUserAction implements Action { + readonly type = SET_USER; + constructor(public payload: any) { } +} diff --git a/src/app/store/reducers/app.reducer.ts b/src/app/store/reducers/app.reducer.ts index 19b1d3f3ef..03e736edc0 100644 --- a/src/app/store/reducers/app.reducer.ts +++ b/src/app/store/reducers/app.reducer.ts @@ -33,7 +33,9 @@ import { SET_LOGO_PATH, SetLogoPathAction, SET_SELECTED_NODES, - SetSelectedNodesAction + SetSelectedNodesAction, + SET_USER, + SetUserAction } from '../actions'; export function appReducer( @@ -57,6 +59,11 @@ export function appReducer( action )); break; + case SET_USER: + newState = updateUser(state, ( + action + )); + break; default: newState = Object.assign({}, state); } @@ -85,6 +92,29 @@ function updateLogoPath(state: AppState, action: SetLogoPathAction): AppState { return newState; } +function updateUser(state: AppState, action: SetUserAction): AppState { + const newState = Object.assign({}, state); + const user = action.payload; + + const id = user.id; + const firstName = user.firstName || ''; + const lastName = user.lastName || ''; + const userName = `${firstName} ${lastName}`; + const initials = [ firstName[0], lastName[0] ].join(''); + const isAdmin = user.capabilities ? user.capabilities.isAdmin : true; + + newState.user = { + firstName, + lastName, + userName, + initials, + isAdmin, + id + }; + + return newState; +} + function updateSelectedNodes( state: AppState, action: SetSelectedNodesAction diff --git a/src/app/store/selectors/app.selectors.ts b/src/app/store/selectors/app.selectors.ts index 5d7a7cc647..c5ce779e06 100644 --- a/src/app/store/selectors/app.selectors.ts +++ b/src/app/store/selectors/app.selectors.ts @@ -31,3 +31,4 @@ export const selectHeaderColor = createSelector(selectApp, (state: AppState) => export const selectAppName = createSelector(selectApp, (state: AppState) => state.appName); export const selectLogoPath = createSelector(selectApp, (state: AppState) => state.logoPath); export const appSelection = createSelector(selectApp, (state: AppState) => state.selection); +export const selectUser = createSelector(selectApp, (state: AppState) => state.user); diff --git a/src/app/store/states/app.state.ts b/src/app/store/states/app.state.ts index c10145d218..46848f8940 100644 --- a/src/app/store/states/app.state.ts +++ b/src/app/store/states/app.state.ts @@ -24,18 +24,26 @@ */ import { SelectionState } from './selection.state'; +import { ProfileState } from './profile.state'; export interface AppState { appName: string; headerColor: string; logoPath: string; selection: SelectionState; + user: ProfileState; } export const INITIAL_APP_STATE: AppState = { appName: 'Alfresco Example Content Application', headerColor: '#2196F3', logoPath: 'assets/images/alfresco-logo-white.svg', + user: { + isAdmin: true, // 5.2.x + id: null, + firstName: '', + lastName: '' + }, selection: { nodes: [], isEmpty: true, diff --git a/src/app/store/states/profile.state.ts b/src/app/store/states/profile.state.ts new file mode 100644 index 0000000000..2113d51c96 --- /dev/null +++ b/src/app/store/states/profile.state.ts @@ -0,0 +1,33 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +export interface ProfileState { + id: string; + isAdmin: boolean; + firstName: string; + lastName: string; + userName?: string; + initials?: string; +} From 7516e98c9ec031d29975e616ced989d6832b74b4 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 20 Jun 2018 19:52:46 +0100 Subject: [PATCH 122/179] migrate to adf debug app config --- src/app/app.module.ts | 5 +-- .../services/hybrid-app-config.service.ts | 37 ------------------- 2 files changed, 2 insertions(+), 40 deletions(-) delete mode 100644 src/app/common/services/hybrid-app-config.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index d3b59831ae..d7fe07e741 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -28,7 +28,7 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { TRANSLATION_PROVIDER, CoreModule, AppConfigService, PageTitleService } from '@alfresco/adf-core'; +import { TRANSLATION_PROVIDER, CoreModule, AppConfigService, PageTitleService, DebugAppConfigService } from '@alfresco/adf-core'; import { ContentModule } from '@alfresco/adf-content-services'; import { ElectronModule } from '@ngstack/electron'; @@ -68,7 +68,6 @@ import { NodeActionsService } from './common/services/node-actions.service'; import { NodePermissionService } from './common/services/node-permission.service'; import { SearchComponent } from './components/search/search.component'; import { SettingsComponent } from './components/settings/settings.component'; -import { HybridAppConfigService } from './common/services/hybrid-app-config.service'; import { PageTitleService as AcaPageTitleService } from './common/services/page-title.service'; import { ProfileResolver } from './common/services/profile.resolver'; @@ -137,7 +136,7 @@ import { MaterialModule } from './material.module'; ], providers: [ { provide: PageTitleService, useClass: AcaPageTitleService }, - { provide: AppConfigService, useClass: HybridAppConfigService }, + { provide: AppConfigService, useClass: DebugAppConfigService }, { provide: TRANSLATION_PROVIDER, multi: true, diff --git a/src/app/common/services/hybrid-app-config.service.ts b/src/app/common/services/hybrid-app-config.service.ts deleted file mode 100644 index 9aa53e017c..0000000000 --- a/src/app/common/services/hybrid-app-config.service.ts +++ /dev/null @@ -1,37 +0,0 @@ -/*! - * @license - * Copyright 2016 Alfresco Software, Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { AppConfigService, StorageService } from '@alfresco/adf-core'; - -@Injectable() -export class HybridAppConfigService extends AppConfigService { - - constructor(private storage: StorageService, http: HttpClient) { - super(http); - } - - /** @override */ - get(key: string, defaultValue?: T): T { - if (key === 'ecmHost' || key === 'bpmHost') { - return ( this.storage.getItem(key) || super.get(key)); - } - return super.get(key, defaultValue); - } - -} From 18d7adcb0428f410a9e1b89e026401316c161014 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Thu, 21 Jun 2018 11:37:16 +0300 Subject: [PATCH 123/179] use acaDocumentList for events (#442) --- src/app/components/search/search.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 4e46297d93..2818a94b21 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -83,6 +83,7 @@ Date: Thu, 21 Jun 2018 11:56:38 +0300 Subject: [PATCH 124/179] change link tag (#443) --- src/app/components/custom-dl-row/custom-dl-row.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/custom-dl-row/custom-dl-row.component.html b/src/app/components/custom-dl-row/custom-dl-row.component.html index aeaeb0c4b0..154a8f24bd 100644 --- a/src/app/components/custom-dl-row/custom-dl-row.component.html +++ b/src/app/components/custom-dl-row/custom-dl-row.component.html @@ -1,6 +1,6 @@
- {{ name }} + {{ name }} {{ name }} From 6b62151ad9f61d4d319d190995b98514ab9ec226 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 21 Jun 2018 10:11:23 +0100 Subject: [PATCH 125/179] update loading indicator --- src/index.html | 75 ++++++++++++++++++++------------------------------ 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/src/index.html b/src/index.html index e81f5cdb1b..ac09ad06bc 100644 --- a/src/index.html +++ b/src/index.html @@ -9,61 +9,46 @@
-
-
-
-
-
+
+
+
+
From 4bcdab811622fbaec1951466e75e1d94a39837d3 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 21 Jun 2018 12:46:47 +0100 Subject: [PATCH 126/179] [ACA-1482] debounce list reloads upon upload (#444) * debounce list reloads upon upload * upload reload improvements --- src/app/components/files/files.component.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index ea0cc71526..1f03ce7231 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -96,8 +96,8 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { contentManagementService.nodesDeleted.subscribe(() => this.documentList.reload()), contentManagementService.nodesMoved.subscribe(() => this.documentList.reload()), contentManagementService.nodesRestored.subscribe(() => this.documentList.reload()), - uploadService.fileUploadComplete.subscribe(file => this.onFileUploadedEvent(file)), - uploadService.fileUploadDeleted.subscribe((file) => this.onFileUploadedEvent(file)), + uploadService.fileUploadComplete.debounceTime(300).subscribe(file => this.onFileUploadedEvent(file)), + uploadService.fileUploadDeleted.debounceTime(300).subscribe((file) => this.onFileUploadedEvent(file)), uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error)) ]); } @@ -162,6 +162,15 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { } onFileUploadedEvent(event: FileUploadEvent) { + const node: MinimalNodeEntity = event.file.data; + + // check root and child nodes + if (node && node.entry && node.entry.parentId === this.getParentNodeId()) { + this.documentList.reload(); + return; + } + + // check the child nodes to show dropped folder if (event && event.file.options.parentId === this.getParentNodeId()) { this.documentList.reload(); } From 759fa23ed4bca3a72da7d33c62395d64a36957ac Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 21 Jun 2018 16:54:56 +0100 Subject: [PATCH 127/179] special ifExperimental directive to toggle features (#445) --- src/app.config.json | 1 + src/app/app.module.ts | 4 +- src/app/directives/experimental.directive.ts | 52 ++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/app/directives/experimental.directive.ts diff --git a/src/app.config.json b/src/app.config.json index c9e6c692e1..01f23c2215 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -8,6 +8,7 @@ "copyright": "© 2017 - 2018 Alfresco Software, Inc. All rights reserved." }, + "experimental": {}, "headerColor": "#2196F3", "languagePicker": false, "pagination": { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index d7fe07e741..a5cbd78fc8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -79,6 +79,7 @@ import { AppStoreModule } from './store/app-store.module'; import { PaginationDirective } from './directives/pagination.directive'; import { DocumentListDirective } from './directives/document-list.directive'; import { MaterialModule } from './material.module'; +import { ExperimentalDirective } from './directives/experimental.directive'; @NgModule({ imports: [ @@ -132,7 +133,8 @@ import { MaterialModule } from './material.module'; CreateFolderDirective, DownloadNodesDirective, PaginationDirective, - DocumentListDirective + DocumentListDirective, + ExperimentalDirective ], providers: [ { provide: PageTitleService, useClass: AcaPageTitleService }, diff --git a/src/app/directives/experimental.directive.ts b/src/app/directives/experimental.directive.ts new file mode 100644 index 0000000000..1370a71366 --- /dev/null +++ b/src/app/directives/experimental.directive.ts @@ -0,0 +1,52 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Directive, TemplateRef, ViewContainerRef, Input } from '@angular/core'; +import { AppConfigService } from '@alfresco/adf-core'; +import { environment } from '../../environments/environment'; + +@Directive({ + // tslint:disable-next-line:directive-selector + selector: '[ifExperimental]' +}) +export class ExperimentalDirective { + constructor( + private templateRef: TemplateRef, + private viewContainerRef: ViewContainerRef, + private config: AppConfigService + ) {} + + @Input() set ifExperimental(featureKey: string) { + if (!environment.production) { + const value = this.config.get(`experimental.${featureKey}`); + if (value) { + this.viewContainerRef.createEmbeddedView(this.templateRef); + return; + } + } + + this.viewContainerRef.clear(); + } +} From 02647c003a56594b9fc2ea12ecb04f8ecdde10ac Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 21 Jun 2018 17:58:28 +0100 Subject: [PATCH 128/179] redirect to login when reloading page with expired ticket (#446) --- src/app/app.component.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index d8bc2b3fe4..c34e999e2e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -25,7 +25,9 @@ import { Component, OnInit, EventEmitter } from '@angular/core'; import { Router, ActivatedRoute, NavigationEnd } from '@angular/router'; -import { PageTitleService, AppConfigService, FileModel, UploadService } from '@alfresco/adf-core'; +import { + PageTitleService, AppConfigService, FileModel, UploadService, + AuthenticationService, AlfrescoApiService } from '@alfresco/adf-core'; import { ElectronService } from '@ngstack/electron'; import { Store } from '@ngrx/store'; import { AppStore } from './store/states/app.state'; @@ -43,11 +45,21 @@ export class AppComponent implements OnInit { private pageTitle: PageTitleService, private store: Store, private config: AppConfigService, + private alfrescoApiService: AlfrescoApiService, + private authenticationService: AuthenticationService, private electronService: ElectronService, private uploadService: UploadService) { } ngOnInit() { + this.alfrescoApiService.getInstance().on('error', (error) => { + if (error.status === 401) { + if (!this.authenticationService.isLoggedIn()) { + this.router.navigate(['/login']); + } + } + }); + this.loadAppSettings(); From 045c4ee9a2a42ada383ca254d630989b18853f2e Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 21 Jun 2018 19:56:08 +0100 Subject: [PATCH 129/179] library effects and actions (#441) * library effects and actions * single selection and test fixes * navigate to site route * add experimental flag * disable test * update tests --- .../actions/toolbar-single-selection.test.ts | 2 +- src/app.config.json | 4 +- .../directives/node-restore.directive.ts | 13 ++-- .../services/content-management.service.ts | 1 + .../libraries/libraries.component.html | 21 +++++- .../libraries/libraries.component.spec.ts | 9 ++- .../libraries/libraries.component.ts | 22 +++++- src/app/store/actions.ts | 1 + src/app/store/actions/library.actions.ts | 33 +++++++++ src/app/store/app-store.module.ts | 6 +- src/app/store/effects.ts | 1 + src/app/store/effects/library.effects.ts | 71 +++++++++++++++++++ src/assets/i18n/en.json | 6 +- 13 files changed, 174 insertions(+), 16 deletions(-) create mode 100644 src/app/store/actions/library.actions.ts create mode 100644 src/app/store/effects/library.effects.ts diff --git a/e2e/suites/actions/toolbar-single-selection.test.ts b/e2e/suites/actions/toolbar-single-selection.test.ts index 5404e40622..d97d7f65b0 100755 --- a/e2e/suites/actions/toolbar-single-selection.test.ts +++ b/e2e/suites/actions/toolbar-single-selection.test.ts @@ -99,7 +99,7 @@ describe('Toolbar actions - single selection : ', () => { .then(done); }); - it('actions not displayed for top level of File Libraries', () => { + xit('actions not displayed for top level of File Libraries', () => { page.sidenav.navigateToLinkByLabel(SIDEBAR_LABELS.FILE_LIBRARIES) .then(() => dataTable.waitForHeader()) .then(() => dataTable.clickOnItemName(userSite)) diff --git a/src/app.config.json b/src/app.config.json index 01f23c2215..5aa7fd0072 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -8,7 +8,9 @@ "copyright": "© 2017 - 2018 Alfresco Software, Inc. All rights reserved." }, - "experimental": {}, + "experimental": { + "libraries": true + }, "headerColor": "#2196F3", "languagePicker": false, "pagination": { diff --git a/src/app/common/directives/node-restore.directive.ts b/src/app/common/directives/node-restore.directive.ts index 8773f583aa..e5e4c1c74a 100644 --- a/src/app/common/directives/node-restore.directive.ts +++ b/src/app/common/directives/node-restore.directive.ts @@ -29,6 +29,7 @@ import { Observable } from 'rxjs/Rx'; import { AlfrescoApiService } from '@alfresco/adf-core'; import { MinimalNodeEntity, + MinimalNodeEntryEntity, PathInfoEntity, DeletedNodesPaging } from 'alfresco-js-api'; @@ -230,12 +231,12 @@ export class NodeRestoreDirective { if (message) { if (status.oneSucceeded && !status.someFailed) { + const isSite = this.isSite(status.success[0].entry); const path: PathInfoEntity = status.success[0].entry.path; const parent = path.elements[path.elements.length - 1]; - const navigate = new NavigateRouteAction([ - '/personal-files', - parent.id - ]); + const route = isSite ? ['/libraries'] : ['/personal-files', parent.id]; + + const navigate = new NavigateRouteAction(route); message.userAction = new SnackbarUserAction( 'APP.ACTIONS.VIEW', @@ -247,6 +248,10 @@ export class NodeRestoreDirective { } } + private isSite(entry: MinimalNodeEntryEntity): boolean { + return entry.nodeType === 'st:site'; + } + private refresh(): void { this.contentManagementService.nodesRestored.next(); } diff --git a/src/app/common/services/content-management.service.ts b/src/app/common/services/content-management.service.ts index e1c47d5f71..032b8231be 100644 --- a/src/app/common/services/content-management.service.ts +++ b/src/app/common/services/content-management.service.ts @@ -34,4 +34,5 @@ export class ContentManagementService { nodesRestored = new Subject(); folderEdited = new Subject(); folderCreated = new Subject(); + siteDeleted = new Subject(); } diff --git a/src/app/components/libraries/libraries.component.html b/src/app/components/libraries/libraries.component.html index c78715378a..133da22a22 100644 --- a/src/app/components/libraries/libraries.component.html +++ b/src/app/components/libraries/libraries.component.html @@ -2,7 +2,24 @@
- + + + + + + +
@@ -10,7 +27,7 @@
diff --git a/src/app/components/libraries/libraries.component.spec.ts b/src/app/components/libraries/libraries.component.spec.ts index fe9e624c58..5837222113 100644 --- a/src/app/components/libraries/libraries.component.spec.ts +++ b/src/app/components/libraries/libraries.component.spec.ts @@ -47,6 +47,8 @@ import { LibrariesComponent } from './libraries.component'; import { StoreModule } from '@ngrx/store'; import { appReducer } from '../../store/reducers/app.reducer'; import { INITIAL_STATE } from '../../store/states/app.state'; +import { ContentManagementService } from '../../common/services/content-management.service'; +import { ExperimentalDirective } from '../../directives/experimental.directive'; describe('Libraries Routed Component', () => { let fixture: ComponentFixture; @@ -91,7 +93,8 @@ describe('Libraries Routed Component', () => { NodeFavoriteDirective, DocumentListComponent, LibrariesComponent, - AppConfigPipe + AppConfigPipe, + ExperimentalDirective ], providers: [ { provide: TranslationService, useClass: TranslationMock }, @@ -105,7 +108,9 @@ describe('Libraries Routed Component', () => { NodesApiService, DocumentListService, ThumbnailService, - CustomResourcesService + CustomResourcesService, + + ContentManagementService ], schemas: [ NO_ERRORS_SCHEMA ] }) diff --git a/src/app/components/libraries/libraries.component.ts b/src/app/components/libraries/libraries.component.ts index 19e5a24302..125b9c9841 100644 --- a/src/app/components/libraries/libraries.component.ts +++ b/src/app/components/libraries/libraries.component.ts @@ -23,7 +23,7 @@ * along with Alfresco. If not, see . */ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { NodesApiService } from '@alfresco/adf-core'; import { ShareDataRow } from '@alfresco/adf-content-services'; @@ -31,19 +31,31 @@ import { ShareDataRow } from '@alfresco/adf-content-services'; import { PageComponent } from '../page.component'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; +import { DeleteLibraryAction } from '../../store/actions'; +import { SiteEntry } from 'alfresco-js-api'; +import { ContentManagementService } from '../../common/services/content-management.service'; @Component({ templateUrl: './libraries.component.html' }) -export class LibrariesComponent extends PageComponent { +export class LibrariesComponent extends PageComponent implements OnInit { constructor(private nodesApi: NodesApiService, private route: ActivatedRoute, + private content: ContentManagementService, store: Store, private router: Router) { super(store); } + ngOnInit() { + super.ngOnInit(); + + this.subscriptions.push( + this.content.siteDeleted.subscribe(() => this.reload()) + ); + } + makeLibraryTooltip(library: any): string { const { description, title } = library; @@ -84,4 +96,10 @@ export class LibrariesComponent extends PageComponent { }); } } + + deleteLibrary(node: SiteEntry) { + if (node && node.entry) { + this.store.dispatch(new DeleteLibraryAction(node.entry.id)); + } + } } diff --git a/src/app/store/actions.ts b/src/app/store/actions.ts index cb5ff1eee0..013545cb3e 100644 --- a/src/app/store/actions.ts +++ b/src/app/store/actions.ts @@ -30,3 +30,4 @@ export * from './actions/router.actions'; export * from './actions/viewer.actions'; export * from './actions/search.actions'; export * from './actions/user.actions'; +export * from './actions/library.actions'; diff --git a/src/app/store/actions/library.actions.ts b/src/app/store/actions/library.actions.ts new file mode 100644 index 0000000000..d2fad4aef3 --- /dev/null +++ b/src/app/store/actions/library.actions.ts @@ -0,0 +1,33 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Action } from '@ngrx/store'; + +export const DELETE_LIBRARY = 'DELETE_LIBRARY'; + +export class DeleteLibraryAction implements Action { + readonly type = DELETE_LIBRARY; + constructor(public payload: string) {} +} diff --git a/src/app/store/app-store.module.ts b/src/app/store/app-store.module.ts index 6c547ee28f..2fff5f17b3 100644 --- a/src/app/store/app-store.module.ts +++ b/src/app/store/app-store.module.ts @@ -37,7 +37,8 @@ import { RouterEffects, DownloadEffects, ViewerEffects, - SearchEffects + SearchEffects, + SiteEffects } from './effects'; @NgModule({ @@ -53,7 +54,8 @@ import { RouterEffects, DownloadEffects, ViewerEffects, - SearchEffects + SearchEffects, + SiteEffects ]), !environment.production ? StoreDevtoolsModule.instrument({ maxAge: 25 }) diff --git a/src/app/store/effects.ts b/src/app/store/effects.ts index c4f6826e8c..3c773fee26 100644 --- a/src/app/store/effects.ts +++ b/src/app/store/effects.ts @@ -29,3 +29,4 @@ export * from './effects/router.effects'; export * from './effects/snackbar.effects'; export * from './effects/viewer.effects'; export * from './effects/search.effects'; +export * from './effects/library.effects'; diff --git a/src/app/store/effects/library.effects.ts b/src/app/store/effects/library.effects.ts new file mode 100644 index 0000000000..71e07894b8 --- /dev/null +++ b/src/app/store/effects/library.effects.ts @@ -0,0 +1,71 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Effect, Actions, ofType } from '@ngrx/effects'; +import { Injectable } from '@angular/core'; +import { map } from 'rxjs/operators'; +import { DeleteLibraryAction, DELETE_LIBRARY } from '../actions'; +import { AlfrescoApiService } from '@alfresco/adf-core'; +import { + SnackbarInfoAction, + SnackbarErrorAction +} from '../actions/snackbar.actions'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../states/app.state'; +import { ContentManagementService } from '../../common/services/content-management.service'; + +@Injectable() +export class SiteEffects { + constructor( + private actions$: Actions, + private store: Store, + private apiService: AlfrescoApiService, + private content: ContentManagementService + ) {} + + @Effect({ dispatch: false }) + deleteLibrary$ = this.actions$.pipe( + ofType(DELETE_LIBRARY), + map(action => { + this.apiService.sitesApi.deleteSite(action.payload).then( + () => { + this.content.siteDeleted.next(action.payload); + this.store.dispatch( + new SnackbarInfoAction( + 'APP.MESSAGES.INFO.LIBRARY_DELETED' + ) + ); + }, + err => { + this.store.dispatch( + new SnackbarErrorAction( + 'APP.MESSAGES.ERRORS.DELETE_LIBRARY_FAILED' + ) + ); + } + ); + }) + ); +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 0b15b0b788..51afdae0c7 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -174,7 +174,8 @@ "LOCATION_MISSING": "Can't restore {{ name }}, the original location no longer exists", "GENERIC": "There was a problem restoring {{ name }}" } - } + }, + "DELETE_LIBRARY_FAILED": "Cannot delete the library" }, "UPLOAD": { "ERROR": { @@ -218,7 +219,8 @@ "PLURAL": "Partially moved {{ partially }} items.", "FAIL": "{{ failed }} couldn't be moved." } - } + }, + "LIBRARY_DELETED": "Library deleted" } }, "CONTENT_METADATA": { From bc554bb8d304f3956b5564506a7f0cd567cd0275 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 22 Jun 2018 04:59:53 +0100 Subject: [PATCH 130/179] simplify user component (#447) * simplify user component * language picker selector --- src/app/app.component.ts | 4 ++- .../current-user/current-user.component.html | 8 ++--- .../current-user/current-user.component.ts | 30 +++++++------------ src/app/store/actions/app.actions.ts | 6 ++++ src/app/store/app-store.module.ts | 2 +- src/app/store/reducers/app.reducer.ts | 20 +++++++++++-- src/app/store/selectors/app.selectors.ts | 13 ++++---- src/app/store/states.ts | 28 +++++++++++++++++ src/app/store/states/app.state.ts | 2 ++ 9 files changed, 79 insertions(+), 34 deletions(-) create mode 100644 src/app/store/states.ts diff --git a/src/app/app.component.ts b/src/app/app.component.ts index c34e999e2e..c65451ac09 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -31,7 +31,7 @@ import { import { ElectronService } from '@ngstack/electron'; import { Store } from '@ngrx/store'; import { AppStore } from './store/states/app.state'; -import { SetHeaderColorAction, SetAppNameAction, SetLogoPathAction } from './store/actions'; +import { SetHeaderColorAction, SetAppNameAction, SetLogoPathAction, SetLanguagePickerAction } from './store/actions'; @Component({ selector: 'app-root', @@ -115,5 +115,7 @@ export class AppComponent implements OnInit { if (logoPath) { this.store.dispatch(new SetLogoPathAction(logoPath)); } + const languagePicker = this.config.get('languagePicker'); + this.store.dispatch(new SetLanguagePickerAction(languagePicker)); } } diff --git a/src/app/components/current-user/current-user.component.html b/src/app/components/current-user/current-user.component.html index 17d9c756d0..46858be8c0 100644 --- a/src/app/components/current-user/current-user.component.html +++ b/src/app/components/current-user/current-user.component.html @@ -1,14 +1,14 @@ -
-
{{ user?.userName }}
+
+
{{ (profile$ | async)?.userName }}
- {{ user?.initials }} + {{ (profile$ | async)?.initials }}
- diff --git a/src/app/components/current-user/current-user.component.ts b/src/app/components/current-user/current-user.component.ts index 014207cc5f..2f10576f67 100644 --- a/src/app/components/current-user/current-user.component.ts +++ b/src/app/components/current-user/current-user.component.ts @@ -23,13 +23,11 @@ * along with Alfresco. If not, see . */ -import { Component, OnInit, OnDestroy, ViewEncapsulation } from '@angular/core'; -import { Subscription } from 'rxjs/Rx'; - +import { Component, ViewEncapsulation } from '@angular/core'; import { Store } from '@ngrx/store'; -import { AppStore } from '../../store/states/app.state'; -import { selectUser } from '../../store/selectors/app.selectors'; -import { ProfileState } from '../../store/states/profile.state'; +import { Observable } from 'rxjs/Rx'; +import { selectUser, appLanguagePicker } from '../../store/selectors/app.selectors'; +import { AppStore, ProfileState } from '../../store/states'; @Component({ selector: 'aca-current-user', @@ -37,20 +35,12 @@ import { ProfileState } from '../../store/states/profile.state'; encapsulation: ViewEncapsulation.None, host: { class: 'aca-current-user' } }) -export class CurrentUserComponent implements OnInit, OnDestroy { - private subscriptions: Subscription[] = []; - - user: ProfileState; - - constructor(private store: Store) {} - - ngOnInit() { - this.subscriptions = this.subscriptions.concat([ - this.store.select(selectUser).subscribe((user) => this.user = user) - ]); - } +export class CurrentUserComponent { + profile$: Observable; + languagePicker$: Observable; - ngOnDestroy() { - this.subscriptions.forEach(s => s.unsubscribe()); + constructor(store: Store) { + this.profile$ = store.select(selectUser); + this.languagePicker$ = store.select(appLanguagePicker); } } diff --git a/src/app/store/actions/app.actions.ts b/src/app/store/actions/app.actions.ts index 7b800f8fd9..c73a019f51 100644 --- a/src/app/store/actions/app.actions.ts +++ b/src/app/store/actions/app.actions.ts @@ -28,6 +28,7 @@ import { Action } from '@ngrx/store'; export const SET_APP_NAME = 'SET_APP_NAME'; export const SET_HEADER_COLOR = 'SET_HEADER_COLOR'; export const SET_LOGO_PATH = 'SET_LOGO_PATH'; +export const SET_LANGUAGE_PICKER = 'SET_LANGUAGE_PICKER'; export class SetAppNameAction implements Action { readonly type = SET_APP_NAME; @@ -43,3 +44,8 @@ export class SetLogoPathAction implements Action { readonly type = SET_LOGO_PATH; constructor(public payload: string) {} } + +export class SetLanguagePickerAction implements Action { + readonly type = SET_LANGUAGE_PICKER; + constructor(public payload: boolean) {} +} diff --git a/src/app/store/app-store.module.ts b/src/app/store/app-store.module.ts index 2fff5f17b3..ecf31fd66f 100644 --- a/src/app/store/app-store.module.ts +++ b/src/app/store/app-store.module.ts @@ -26,7 +26,7 @@ import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; import { appReducer } from './reducers/app.reducer'; -import { INITIAL_STATE } from './states/app.state'; +import { INITIAL_STATE } from './states'; import { StoreRouterConnectingModule } from '@ngrx/router-store'; import { EffectsModule } from '@ngrx/effects'; import { environment } from '../../environments/environment'; diff --git a/src/app/store/reducers/app.reducer.ts b/src/app/store/reducers/app.reducer.ts index 03e736edc0..f8d234372d 100644 --- a/src/app/store/reducers/app.reducer.ts +++ b/src/app/store/reducers/app.reducer.ts @@ -37,6 +37,10 @@ import { SET_USER, SetUserAction } from '../actions'; +import { + SET_LANGUAGE_PICKER, + SetLanguagePickerAction +} from '../actions/app.actions'; export function appReducer( state: AppState = INITIAL_APP_STATE, @@ -60,7 +64,10 @@ export function appReducer( )); break; case SET_USER: - newState = updateUser(state, ( + newState = updateUser(state, action); + break; + case SET_LANGUAGE_PICKER: + newState = updateLanguagePicker(state, ( action )); break; @@ -80,6 +87,15 @@ function updateHeaderColor( return newState; } +function updateLanguagePicker( + state: AppState, + action: SetLanguagePickerAction +): AppState { + const newState = Object.assign({}, state); + newState.languagePicker = action.payload; + return newState; +} + function updateAppName(state: AppState, action: SetAppNameAction): AppState { const newState = Object.assign({}, state); newState.appName = action.payload; @@ -100,7 +116,7 @@ function updateUser(state: AppState, action: SetUserAction): AppState { const firstName = user.firstName || ''; const lastName = user.lastName || ''; const userName = `${firstName} ${lastName}`; - const initials = [ firstName[0], lastName[0] ].join(''); + const initials = [firstName[0], lastName[0]].join(''); const isAdmin = user.capabilities ? user.capabilities.isAdmin : true; newState.user = { diff --git a/src/app/store/selectors/app.selectors.ts b/src/app/store/selectors/app.selectors.ts index c5ce779e06..8fe15c58ce 100644 --- a/src/app/store/selectors/app.selectors.ts +++ b/src/app/store/selectors/app.selectors.ts @@ -24,11 +24,12 @@ */ import { createSelector } from '@ngrx/store'; -import { AppStore, AppState } from '../states/app.state'; +import { AppStore } from '../states/app.state'; export const selectApp = (state: AppStore) => state.app; -export const selectHeaderColor = createSelector(selectApp, (state: AppState) => state.headerColor); -export const selectAppName = createSelector(selectApp, (state: AppState) => state.appName); -export const selectLogoPath = createSelector(selectApp, (state: AppState) => state.logoPath); -export const appSelection = createSelector(selectApp, (state: AppState) => state.selection); -export const selectUser = createSelector(selectApp, (state: AppState) => state.user); +export const selectHeaderColor = createSelector(selectApp, state => state.headerColor); +export const selectAppName = createSelector(selectApp, state => state.appName); +export const selectLogoPath = createSelector(selectApp, state => state.logoPath); +export const appSelection = createSelector(selectApp, state => state.selection); +export const appLanguagePicker = createSelector(selectApp, state => state.languagePicker); +export const selectUser = createSelector(selectApp, state => state.user); diff --git a/src/app/store/states.ts b/src/app/store/states.ts new file mode 100644 index 0000000000..7309f63a59 --- /dev/null +++ b/src/app/store/states.ts @@ -0,0 +1,28 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +export * from './states/app.state'; +export * from './states/profile.state'; +export * from './states/selection.state'; diff --git a/src/app/store/states/app.state.ts b/src/app/store/states/app.state.ts index 46848f8940..e63212685a 100644 --- a/src/app/store/states/app.state.ts +++ b/src/app/store/states/app.state.ts @@ -30,6 +30,7 @@ export interface AppState { appName: string; headerColor: string; logoPath: string; + languagePicker: boolean; selection: SelectionState; user: ProfileState; } @@ -38,6 +39,7 @@ export const INITIAL_APP_STATE: AppState = { appName: 'Alfresco Example Content Application', headerColor: '#2196F3', logoPath: 'assets/images/alfresco-logo-white.svg', + languagePicker: false, user: { isAdmin: true, // 5.2.x id: null, From 265781c540f4927d5c3dd97f65366a4b63c281c2 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Fri, 22 Jun 2018 08:45:11 +0300 Subject: [PATCH 131/179] use custom pagination options (#448) --- src/app/components/search/search.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index 2818a94b21..dca4e21e75 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -119,6 +119,7 @@ From daf70820797cf852450843d6f0150d67f9603d72 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 22 Jun 2018 14:20:33 +0100 Subject: [PATCH 132/179] settings enhancements (#449) * settings enhancements * save state to local storage * improve settings dialog * toggle library features from settings * fixes for app config service --- src/app.config.json | 2 +- .../settings/settings.component.html | 49 ++++++++++++++----- .../components/settings/settings.component.ts | 42 ++++++++++------ src/app/directives/experimental.directive.ts | 15 ++++-- src/assets/i18n/en.json | 2 + 5 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/app.config.json b/src/app.config.json index 5aa7fd0072..56759d2488 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -9,7 +9,7 @@ "© 2017 - 2018 Alfresco Software, Inc. All rights reserved." }, "experimental": { - "libraries": true + "libraries": false }, "headerColor": "#2196F3", "languagePicker": false, diff --git a/src/app/components/settings/settings.component.html b/src/app/components/settings/settings.component.html index 89c2e8cb78..c17358f9ef 100644 --- a/src/app/components/settings/settings.component.html +++ b/src/app/components/settings/settings.component.html @@ -1,18 +1,18 @@ - + - - {{ appName }} + + {{ appName$ | async }} -
- - - - {{ 'APP.SETTINGS.REPOSITORY-SETTINGS' | translate }} - + + + + {{ 'APP.SETTINGS.REPOSITORY-SETTINGS' | translate }} + +
+ +
-
-
- + + + + {{ 'APP.SETTINGS.APPLICATION-SETTINGS' | translate }} + + + + Language Picker + + + + + + + {{ 'APP.SETTINGS.EXPERIMENTAL-FEATURES' | translate }} + + + + Library Management + + + diff --git a/src/app/components/settings/settings.component.ts b/src/app/components/settings/settings.component.ts index 27507dd1af..e2ff08280a 100644 --- a/src/app/components/settings/settings.component.ts +++ b/src/app/components/settings/settings.component.ts @@ -23,10 +23,15 @@ * along with Alfresco. If not, see . */ -import { Component, ViewEncapsulation, SecurityContext, OnInit } from '@angular/core'; +import { Component, ViewEncapsulation, OnInit } from '@angular/core'; import { AppConfigService, StorageService, SettingsService } from '@alfresco/adf-core'; -import { DomSanitizer } from '@angular/platform-browser'; import { Validators, FormGroup, FormBuilder } from '@angular/forms'; +import { Observable } from 'rxjs/Rx'; +import { Store } from '@ngrx/store'; +import { AppStore } from '../../store/states'; +import { appLanguagePicker, selectHeaderColor, selectAppName } from '../../store/selectors/app.selectors'; +import { MatCheckboxChange } from '@angular/material'; +import { SetLanguagePickerAction } from '../../store/actions'; @Component({ selector: 'aca-settings', @@ -37,38 +42,38 @@ import { Validators, FormGroup, FormBuilder } from '@angular/forms'; export class SettingsComponent implements OnInit { private defaultPath = '/assets/images/alfresco-logo-white.svg'; - private defaultBackgroundColor = '#2196F3'; form: FormGroup; + appName$: Observable; + headerColor$: Observable; + languagePicker$: Observable; + libraries: boolean; + constructor( + private store: Store, private appConfig: AppConfigService, - private sanitizer: DomSanitizer, private settingsService: SettingsService, private storage: StorageService, private fb: FormBuilder) { - + this.appName$ = store.select(selectAppName); + this.languagePicker$ = store.select(appLanguagePicker); + this.headerColor$ = store.select(selectHeaderColor); } - get appName(): string { - return this.appConfig.get('application.name'); - } - get logo() { return this.appConfig.get('application.logo', this.defaultPath); } - get backgroundColor() { - const color = this.appConfig.get('headerColor', this.defaultBackgroundColor); - return this.sanitizer.sanitize(SecurityContext.STYLE, color); - } - ngOnInit() { this.form = this.fb.group({ ecmHost: ['', [Validators.required, Validators.pattern('^(http|https):\/\/.*[^/]$')]] }); this.reset(); + + const libraries = this.appConfig.get('experimental.libraries'); + this.libraries = (libraries === true || libraries === 'true'); } apply(model: any, isValid: boolean) { @@ -83,4 +88,13 @@ export class SettingsComponent implements OnInit { ecmHost: this.storage.getItem('ecmHost') || this.settingsService.ecmHost }); } + + onLanguagePickerValueChanged(event: MatCheckboxChange) { + this.storage.setItem('languagePicker', event.checked.toString()); + this.store.dispatch(new SetLanguagePickerAction(event.checked)); + } + + onChangeLibrariesFeature(event: MatCheckboxChange) { + this.storage.setItem('experimental.libraries', event.checked.toString()); + } } diff --git a/src/app/directives/experimental.directive.ts b/src/app/directives/experimental.directive.ts index 1370a71366..3546f8c50d 100644 --- a/src/app/directives/experimental.directive.ts +++ b/src/app/directives/experimental.directive.ts @@ -24,7 +24,7 @@ */ import { Directive, TemplateRef, ViewContainerRef, Input } from '@angular/core'; -import { AppConfigService } from '@alfresco/adf-core'; +import { AppConfigService, StorageService } from '@alfresco/adf-core'; import { environment } from '../../environments/environment'; @Directive({ @@ -35,13 +35,22 @@ export class ExperimentalDirective { constructor( private templateRef: TemplateRef, private viewContainerRef: ViewContainerRef, + private storage: StorageService, private config: AppConfigService ) {} @Input() set ifExperimental(featureKey: string) { + const key = `experimental.${featureKey}`; + + const override = this.storage.getItem(key); + if (override === 'true') { + this.viewContainerRef.createEmbeddedView(this.templateRef); + return; + } + if (!environment.production) { - const value = this.config.get(`experimental.${featureKey}`); - if (value) { + const value = this.config.get(key); + if (value === true || value === 'true') { this.viewContainerRef.createEmbeddedView(this.templateRef); return; } diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 51afdae0c7..c9f2ee408e 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -4,7 +4,9 @@ "SIGN_IN": "Sign in", "SIGN_OUT": "Sign out", "SETTINGS": { + "APPLICATION-SETTINGS": "Application Settings", "REPOSITORY-SETTINGS": "Repository Settings", + "EXPERIMENTAL-FEATURES": "Experimental Features", "INVALID-VALUE-FORMAT": "Invalid value format", "REQUIRED-FIELD": "This field is required", "RESET": "Reset", From 5d9eb2f94d33a3658355ab45af68d48850ebecaf Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Fri, 22 Jun 2018 17:32:57 +0300 Subject: [PATCH 133/179] [ACA] improve reload on upload (#450) --- src/app/components/files/files.component.ts | 28 ++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index 1f03ce7231..4a961245d4 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -172,8 +172,34 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { // check the child nodes to show dropped folder if (event && event.file.options.parentId === this.getParentNodeId()) { - this.documentList.reload(); + this.displayFolderParent(event.file.options.path, 0); + return; + } + + if (event && event.file.options.parentId) { + if (this.nodePath) { + const correspondingNodePath = this.nodePath.find(pathItem => pathItem.id === event.file.options.parentId); + + // check if the current folder has the 'trigger-upload-folder' as one of its parents + if (correspondingNodePath) { + const correspondingIndex = this.nodePath.length - this.nodePath.indexOf(correspondingNodePath); + this.displayFolderParent(event.file.options.path, correspondingIndex); + } + } + } + } + + displayFolderParent(filePath = '', index) { + const parentName = filePath.split('/')[index]; + const currentFoldersDisplayed: any = this.documentList.data.getRows() || []; + + const alreadyDisplayedParentFolder = currentFoldersDisplayed.find( + row => row.node.entry.isFolder && row.node.entry.name === parentName); + + if (alreadyDisplayedParentFolder) { + return; } + this.documentList.reload(); } onContentCopied(nodes: MinimalNodeEntity[]) { From ccc28fb8a5ec4355ecb71e6948f761277aa2ef51 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 22 Jun 2018 15:55:52 +0100 Subject: [PATCH 134/179] upgrade to latest ADF libs (#451) --- package-lock.json | 36 ++++++++++++++++++------------------ package.json | 6 +++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index c883e33a85..00a4513df0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518.tgz", - "integrity": "sha512-on1ILp40rR8slwQxW2AllYAil2fJdtv6trwU9USmlfis/VLu8V6TVdCFLHgazYRCnoCN7iFGjzPRWCq8I7IAWg==", + "version": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d.tgz", + "integrity": "sha512-LLSn2hnfs7AW6RwPRj4TL7DlVGAjRrUewTyjfbh0Qtdo5mSI/MAbakEZujLyHCxM3Px7ffo0syLsumwgdAjkvw==", "requires": { - "@alfresco/adf-core": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", + "@alfresco/adf-core": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", + "alfresco-js-api": "2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -41,9 +41,9 @@ }, "dependencies": { "alfresco-js-api": { - "version": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67.tgz", - "integrity": "sha512-tassYFxqiNGK8DrXIkGldn78FgaMBD13y8v3XsLv2c8B8ZU4mspXNNKxy5vQSYqZZtAmWBMT24KdQijThbZoXA==", + "version": "2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24.tgz", + "integrity": "sha512-VGyFRSyMYH9la9oEs66gJ0u9OKzzRXY6FzBWXRkTMCqbVSzUCdSIXiOE2h7I6S0h66OVBg73oIbpZRPIIRNPyA==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", @@ -71,9 +71,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518.tgz", - "integrity": "sha512-VTqMlbejmVIc7usVIoGX2dRDAyyW+pwBQyPFbLeq7OfT4Ycs9weZ5mW92HVr4qEIXnX/ExwWXd6z06XYsITbAg==", + "version": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d.tgz", + "integrity": "sha512-YbgwBCp6GMyvKb11tmY7u5IYhI8eWLGakxEs41G/EZDLvPIMorP8Wc3J4pHwBVFe0kaYd1MfO1QXCG7ZNv1zQQ==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -89,7 +89,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", + "alfresco-js-api": "2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -106,9 +106,9 @@ }, "dependencies": { "alfresco-js-api": { - "version": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67.tgz", - "integrity": "sha512-tassYFxqiNGK8DrXIkGldn78FgaMBD13y8v3XsLv2c8B8ZU4mspXNNKxy5vQSYqZZtAmWBMT24KdQijThbZoXA==", + "version": "2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24.tgz", + "integrity": "sha512-VGyFRSyMYH9la9oEs66gJ0u9OKzzRXY6FzBWXRkTMCqbVSzUCdSIXiOE2h7I6S0h66OVBg73oIbpZRPIIRNPyA==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", @@ -676,9 +676,9 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "alfresco-js-api": { - "version": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67.tgz", - "integrity": "sha512-tassYFxqiNGK8DrXIkGldn78FgaMBD13y8v3XsLv2c8B8ZU4mspXNNKxy5vQSYqZZtAmWBMT24KdQijThbZoXA==", + "version": "2.4.0-2cdf2936b16945e97b5efb9b6570b5641911298a", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-2cdf2936b16945e97b5efb9b6570b5641911298a.tgz", + "integrity": "sha512-GpRFkU/WPsyiMP3yJMEhNTmiS+QLGmvhUKR6VdoQEcSc53m26bcMhZqB4IgpKAcLXnm6OBnNM5fWqxNjv3+U6g==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", diff --git a/package.json b/package.json index 50abdc70e3..5df9bc7ee8 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", - "@alfresco/adf-core": "2.4.0-0fae46b50baa0c24c65d5d700e4aed14cf859518", + "@alfresco/adf-content-services": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", + "@alfresco/adf-core": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -48,7 +48,7 @@ "@ngrx/store-devtools": "^5.2.0", "@ngstack/electron": "0.1.0", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-31ede1dc5d8f95d7184c1cf944490883f4982d67", + "alfresco-js-api": "2.4.0-2cdf2936b16945e97b5efb9b6570b5641911298a", "core-js": "2.5.3", "cspell": "^2.1.12", "hammerjs": "2.0.8", From 1bc652d9232b80c181d33b5c5d4b152ce4f4d434 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sat, 23 Jun 2018 08:47:32 +0100 Subject: [PATCH 135/179] upgrade ADF libs (#452) --- package-lock.json | 36 ++++++++++++++++++------------------ package.json | 6 +++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 00a4513df0..8bbe78c5dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d.tgz", - "integrity": "sha512-LLSn2hnfs7AW6RwPRj4TL7DlVGAjRrUewTyjfbh0Qtdo5mSI/MAbakEZujLyHCxM3Px7ffo0syLsumwgdAjkvw==", + "version": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4.tgz", + "integrity": "sha512-u7aDRhCLD8BxXgsPXcmPj6i1wTQ5jInpPHci1iTTapF7kWATjWWu9MsbV9WBmtmxlllcMwrDb/hg4DJj28bslw==", "requires": { - "@alfresco/adf-core": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", + "@alfresco/adf-core": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24", + "alfresco-js-api": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -41,9 +41,9 @@ }, "dependencies": { "alfresco-js-api": { - "version": "2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24.tgz", - "integrity": "sha512-VGyFRSyMYH9la9oEs66gJ0u9OKzzRXY6FzBWXRkTMCqbVSzUCdSIXiOE2h7I6S0h66OVBg73oIbpZRPIIRNPyA==", + "version": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b.tgz", + "integrity": "sha512-aRwa7PE1ZvMqW4FquRCJbCCtt7FNE9RVGjH2wjr80duX3PUkH/2GXEGtImLGQFRRgkX47ZfnB3D/3gDY9u4Vmw==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", @@ -71,9 +71,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d.tgz", - "integrity": "sha512-YbgwBCp6GMyvKb11tmY7u5IYhI8eWLGakxEs41G/EZDLvPIMorP8Wc3J4pHwBVFe0kaYd1MfO1QXCG7ZNv1zQQ==", + "version": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4.tgz", + "integrity": "sha512-sI18hpQaGhsWm0KHiFHJAh2hUWSMrQFCqNcSwoivZntJqkzAUV9YpdAgzHB5Usl9b/L0kcbJJlgRTWytT5nVbg==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -89,7 +89,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24", + "alfresco-js-api": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -106,9 +106,9 @@ }, "dependencies": { "alfresco-js-api": { - "version": "2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-7b4280f696d678984c21f6abbbac1e9c1cb33c24.tgz", - "integrity": "sha512-VGyFRSyMYH9la9oEs66gJ0u9OKzzRXY6FzBWXRkTMCqbVSzUCdSIXiOE2h7I6S0h66OVBg73oIbpZRPIIRNPyA==", + "version": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b.tgz", + "integrity": "sha512-aRwa7PE1ZvMqW4FquRCJbCCtt7FNE9RVGjH2wjr80duX3PUkH/2GXEGtImLGQFRRgkX47ZfnB3D/3gDY9u4Vmw==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", @@ -676,9 +676,9 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "alfresco-js-api": { - "version": "2.4.0-2cdf2936b16945e97b5efb9b6570b5641911298a", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-2cdf2936b16945e97b5efb9b6570b5641911298a.tgz", - "integrity": "sha512-GpRFkU/WPsyiMP3yJMEhNTmiS+QLGmvhUKR6VdoQEcSc53m26bcMhZqB4IgpKAcLXnm6OBnNM5fWqxNjv3+U6g==", + "version": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b.tgz", + "integrity": "sha512-aRwa7PE1ZvMqW4FquRCJbCCtt7FNE9RVGjH2wjr80duX3PUkH/2GXEGtImLGQFRRgkX47ZfnB3D/3gDY9u4Vmw==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", diff --git a/package.json b/package.json index 5df9bc7ee8..688d016f74 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", - "@alfresco/adf-core": "2.4.0-9ee34e404e443ead074158d20fb072e23a80ff0d", + "@alfresco/adf-content-services": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", + "@alfresco/adf-core": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -48,7 +48,7 @@ "@ngrx/store-devtools": "^5.2.0", "@ngstack/electron": "0.1.0", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-2cdf2936b16945e97b5efb9b6570b5641911298a", + "alfresco-js-api": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", "core-js": "2.5.3", "cspell": "^2.1.12", "hammerjs": "2.0.8", From e846d97317e4085a5645b9a587e43fe8080092c2 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sat, 23 Jun 2018 17:30:20 +0100 Subject: [PATCH 136/179] remove electron demo code (#453) * remove electron demo code * remove unused property * cleanup tests * cleanup sidenav tests * cleanup trashcan tests * remove fdescribe --- package-lock.json | 8 --- package.json | 1 - src/app/app.component.ts | 29 ++--------- src/app/app.module.ts | 2 - .../components/sidenav/sidenav.component.html | 15 ------ .../sidenav/sidenav.component.spec.ts | 24 +++------ .../components/sidenav/sidenav.component.ts | 11 +--- .../trashcan/trashcan.component.spec.ts | 52 +++++++------------ src/app/material.module.ts | 14 ++++- src/app/testing/app-testing.module.ts | 3 +- 10 files changed, 44 insertions(+), 115 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8bbe78c5dd..9f93b9d75e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -467,14 +467,6 @@ "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-5.2.0.tgz", "integrity": "sha1-L/+RapqjSTdYJncrNZ27ZLnl1iI=" }, - "@ngstack/electron": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@ngstack/electron/-/electron-0.1.0.tgz", - "integrity": "sha512-uqBNDkeATuZQm1eVXjB3rok9zFLMaJzfNl1tVnlqMwfaGA9FIe90nquvIZnL/scHbno89weGGxg4JeHLgsRMLA==", - "requires": { - "tslib": "^1.7.1" - } - }, "@ngtools/json-schema": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.2.0.tgz", diff --git a/package.json b/package.json index 688d016f74..3bdac297f8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "@ngrx/router-store": "^5.2.0", "@ngrx/store": "^5.2.0", "@ngrx/store-devtools": "^5.2.0", - "@ngstack/electron": "0.1.0", "@ngx-translate/core": "9.1.1", "alfresco-js-api": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", "core-js": "2.5.3", diff --git a/src/app/app.component.ts b/src/app/app.component.ts index c65451ac09..74d5e6aa43 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -23,12 +23,11 @@ * along with Alfresco. If not, see . */ -import { Component, OnInit, EventEmitter } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute, NavigationEnd } from '@angular/router'; import { - PageTitleService, AppConfigService, FileModel, UploadService, + PageTitleService, AppConfigService, AuthenticationService, AlfrescoApiService } from '@alfresco/adf-core'; -import { ElectronService } from '@ngstack/electron'; import { Store } from '@ngrx/store'; import { AppStore } from './store/states/app.state'; import { SetHeaderColorAction, SetAppNameAction, SetLogoPathAction, SetLanguagePickerAction } from './store/actions'; @@ -46,9 +45,7 @@ export class AppComponent implements OnInit { private store: Store, private config: AppConfigService, private alfrescoApiService: AlfrescoApiService, - private authenticationService: AuthenticationService, - private electronService: ElectronService, - private uploadService: UploadService) { + private authenticationService: AuthenticationService) { } ngOnInit() { @@ -80,26 +77,6 @@ export class AppComponent implements OnInit { pageTitle.setTitle(data.title || ''); }); - - this.electronService.on('app:navigateRoute', (event: any, ...args: string[]) => { - this.router.navigate([...args]); - }); - - this.electronService.on('app:upload', (event: any, files: any[] = []) => { - const models = files.map(fileInfo => { - const file = new File([fileInfo.data], fileInfo.name); - - return new FileModel(file, { - path: fileInfo.path, - parentId: fileInfo.parentId - }); - }); - - if (models.length > 0) { - this.uploadService.addToQueue(...models); - this.uploadService.uploadFilesInTheQueue(new EventEmitter()); - } - }); } private loadAppSettings() { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a5cbd78fc8..80542533f1 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -30,7 +30,6 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { TRANSLATION_PROVIDER, CoreModule, AppConfigService, PageTitleService, DebugAppConfigService } from '@alfresco/adf-core'; import { ContentModule } from '@alfresco/adf-content-services'; -import { ElectronModule } from '@ngstack/electron'; import { AppComponent } from './app.component'; import { APP_ROUTES } from './app.routes'; @@ -94,7 +93,6 @@ import { ExperimentalDirective } from './directives/experimental.directive'; MaterialModule, CoreModule, ContentModule, - ElectronModule, AppStoreModule ], declarations: [ diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index 97a6211a08..00648da12e 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -34,7 +34,6 @@ - -
diff --git a/src/app/components/sidenav/sidenav.component.spec.ts b/src/app/components/sidenav/sidenav.component.spec.ts index 84cfa138ae..47725c12d3 100644 --- a/src/app/components/sidenav/sidenav.component.spec.ts +++ b/src/app/components/sidenav/sidenav.component.spec.ts @@ -24,25 +24,20 @@ */ import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { TestBed, async } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { MatMenuModule, MatSnackBarModule } from '@angular/material'; -import { AppConfigService, TranslationService, TranslationMock, CoreModule } from '@alfresco/adf-core'; +import { TestBed, async, ComponentFixture } from '@angular/core/testing'; +import { AppConfigService, CoreModule } from '@alfresco/adf-core'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { SidenavComponent } from './sidenav.component'; -import { ElectronModule } from '@ngstack/electron'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { StoreModule } from '@ngrx/store'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; import { EffectsModule } from '@ngrx/effects'; import { NodeEffects } from '../../store/effects/node.effects'; import { ContentManagementService } from '../../common/services/content-management.service'; +import { AppTestingModule } from '../../testing/app-testing.module'; +import { MaterialModule } from '../../material.module'; describe('SidenavComponent', () => { - let fixture; + let fixture: ComponentFixture; let component: SidenavComponent; let browsingService: BrowsingFilesService; let appConfig: AppConfigService; @@ -58,20 +53,15 @@ describe('SidenavComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - NoopAnimationsModule, + AppTestingModule, + MaterialModule, CoreModule.forRoot(), - MatMenuModule, - MatSnackBarModule, - RouterTestingModule, - ElectronModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), EffectsModule.forRoot([NodeEffects]) ], declarations: [ SidenavComponent ], providers: [ - { provide: TranslationService, useClass: TranslationMock }, NodePermissionService, BrowsingFilesService, ContentManagementService diff --git a/src/app/components/sidenav/sidenav.component.ts b/src/app/components/sidenav/sidenav.component.ts index 0df82e90a5..b667661a7f 100644 --- a/src/app/components/sidenav/sidenav.component.ts +++ b/src/app/components/sidenav/sidenav.component.ts @@ -31,7 +31,6 @@ import { AppConfigService } from '@alfresco/adf-core'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; -import { ElectronService } from '@ngstack/electron'; @Component({ selector: 'app-sidenav', @@ -41,7 +40,6 @@ import { ElectronService } from '@ngstack/electron'; export class SidenavComponent implements OnInit, OnDestroy { @Input() showLabel: boolean; - isDesktopApp = false; node: MinimalNodeEntryEntity = null; navigation = []; @@ -50,8 +48,7 @@ export class SidenavComponent implements OnInit, OnDestroy { constructor( private browsingFilesService: BrowsingFilesService, private appConfig: AppConfigService, - public permission: NodePermissionService, - private electronService: ElectronService + public permission: NodePermissionService ) {} ngOnInit() { @@ -61,8 +58,6 @@ export class SidenavComponent implements OnInit, OnDestroy { this.browsingFilesService.onChangeParent .subscribe((node: MinimalNodeEntryEntity) => this.node = node) ]); - - this.isDesktopApp = this.electronService.isDesktopApp; } ngOnDestroy() { @@ -75,8 +70,4 @@ export class SidenavComponent implements OnInit, OnDestroy { return Object.keys(data).map((key) => data[key]); } - - uploadFolderDesktop() { - this.electronService.send('core:uploadFolder', this.node.id); - } } diff --git a/src/app/components/trashcan/trashcan.component.spec.ts b/src/app/components/trashcan/trashcan.component.spec.ts index b50695abc1..441a3af0aa 100644 --- a/src/app/components/trashcan/trashcan.component.spec.ts +++ b/src/app/components/trashcan/trashcan.component.spec.ts @@ -23,11 +23,9 @@ * along with Alfresco. If not, see . */ import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientModule } from '@angular/common/http'; -import { TestBed, async, ComponentFixture } from '@angular/core/testing'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; import { - NotificationService, TranslationService, TranslationMock, + NotificationService, NodesApiService, AlfrescoApiService, ContentService, UserPreferencesService, LogService, AppConfigService, StorageService, CookieService, ThumbnailService, @@ -35,16 +33,12 @@ import { NodeFavoriteDirective, DataTableComponent, AppConfigPipe, PeopleContentService } from '@alfresco/adf-core'; import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; import { DocumentListService } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; import { TrashcanComponent } from './trashcan.component'; -import { StoreModule } from '@ngrx/store'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; +import { AppTestingModule } from '../../testing/app-testing.module'; +import { MaterialModule } from '../../material.module'; describe('TrashcanComponent', () => { let fixture: ComponentFixture; @@ -62,16 +56,11 @@ describe('TrashcanComponent', () => { }; }); - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ imports: [ - MatMenuModule, - NoopAnimationsModule, - HttpClientModule, - TranslateModule.forRoot(), - RouterTestingModule, - MatSnackBarModule, MatIconModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) + AppTestingModule, + MaterialModule, ], declarations: [ DataTableComponent, @@ -83,7 +72,6 @@ describe('TrashcanComponent', () => { AppConfigPipe ], providers: [ - { provide: TranslationService, useClass: TranslationMock }, AuthenticationService, UserPreferencesService, PeopleContentService, @@ -99,22 +87,20 @@ describe('TrashcanComponent', () => { CustomResourcesService ], schemas: [ NO_ERRORS_SCHEMA ] - }) - .compileComponents() - .then(() => { - fixture = TestBed.createComponent(TrashcanComponent); - component = fixture.componentInstance; + }); - alfrescoApi = TestBed.get(AlfrescoApiService); - alfrescoApi.reset(); - contentService = TestBed.get(ContentManagementService); + fixture = TestBed.createComponent(TrashcanComponent); + component = fixture.componentInstance; - component.documentList = { - reload: jasmine.createSpy('reload'), - resetSelection: jasmine.createSpy('resetSelection') - }; - }); - })); + alfrescoApi = TestBed.get(AlfrescoApiService); + alfrescoApi.reset(); + contentService = TestBed.get(ContentManagementService); + + component.documentList = { + reload: jasmine.createSpy('reload'), + resetSelection: jasmine.createSpy('resetSelection') + }; + }); beforeEach(() => { spyOn(alfrescoApi.nodesApi, 'getDeletedNodes').and.returnValue(Promise.resolve(page)); diff --git a/src/app/material.module.ts b/src/app/material.module.ts index 1743d1a702..c0c3e20320 100644 --- a/src/app/material.module.ts +++ b/src/app/material.module.ts @@ -29,7 +29,8 @@ import { MatIconModule, MatButtonModule, MatDialogModule, - MatInputModule + MatInputModule, + MatSnackBarModule } from '@angular/material'; @NgModule({ @@ -38,7 +39,16 @@ import { MatIconModule, MatButtonModule, MatDialogModule, - MatInputModule + MatInputModule, + MatSnackBarModule + ], + exports: [ + MatMenuModule, + MatIconModule, + MatButtonModule, + MatDialogModule, + MatInputModule, + MatSnackBarModule ] }) export class MaterialModule {} diff --git a/src/app/testing/app-testing.module.ts b/src/app/testing/app-testing.module.ts index 4768a150e5..71be7cb260 100644 --- a/src/app/testing/app-testing.module.ts +++ b/src/app/testing/app-testing.module.ts @@ -48,7 +48,8 @@ import { EffectsModule } from '@ngrx/effects'; TranslatePipeMock ], exports: [ - TranslatePipeMock + TranslatePipeMock, + RouterTestingModule ], providers: [ { provide: TranslationService, useClass: TranslationMock }, From ac6e96530f95a05114e122cbee28466535e2c8ff Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Sun, 24 Jun 2018 17:33:50 +0100 Subject: [PATCH 137/179] unit test cleanup (#454) * auth mock * avoid using jasmine * cleanup preview tests * cleanup recent files tests * cleanup shared files tests * remove fdescribe * update tests * move adf services to single place * move app specific services to single place * cleanup directive tests * cleanup directive tests * update directive tests --- .../directives/node-copy.directive.spec.ts | 50 +---------- .../directives/node-delete.directive.spec.ts | 13 +-- .../directives/node-move.directive.spec.ts | 30 ++----- .../common/directives/node-move.directive.ts | 2 +- .../node-permanent-delete.directive.spec.ts | 45 ++++------ .../directives/node-restore.directive.spec.ts | 28 +------ .../favorites/favorites.component.spec.ts | 58 ++++--------- .../components/files/files.component.spec.ts | 84 ++++++------------- .../header/header.component.spec.ts | 8 +- .../layout/layout.component.spec.ts | 29 +------ .../libraries/libraries.component.spec.ts | 70 ++++------------ .../components/login/login.component.spec.ts | 43 +++------- .../preview/preview.component.spec.ts | 27 ++---- .../recent-files.component.spec.ts | 72 ++++------------ .../shared-files.component.spec.ts | 69 +++------------ .../sidenav/sidenav.component.spec.ts | 13 +-- .../trashcan/trashcan.component.spec.ts | 34 ++------ src/app/testing/app-testing.module.ts | 76 ++++++++++++++--- src/app/testing/translation.service.ts | 9 ++ 19 files changed, 220 insertions(+), 540 deletions(-) diff --git a/src/app/common/directives/node-copy.directive.spec.ts b/src/app/common/directives/node-copy.directive.spec.ts index 0d26ead0c1..0be679d6c3 100644 --- a/src/app/common/directives/node-copy.directive.spec.ts +++ b/src/app/common/directives/node-copy.directive.spec.ts @@ -26,23 +26,11 @@ import { Component, DebugElement } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; - import { Observable } from 'rxjs/Rx'; - -import { - TranslationService, NodesApiService, NotificationService, AlfrescoApiService, TranslationMock, - AppConfigService, StorageService, CookieService, ContentService, AuthenticationService, - UserPreferencesService, LogService, ThumbnailService -} from '@alfresco/adf-core'; -import { TranslateModule } from '@ngx-translate/core'; -import { HttpClientModule } from '@angular/common/http'; - +import { NodesApiService, NotificationService } from '@alfresco/adf-core'; import { NodeActionsService } from '../services/node-actions.service'; import { NodeCopyDirective } from './node-copy.directive'; -import { ContentManagementService } from '../services/content-management.service'; -import { MatSnackBarModule, MatDialogModule, MatIconModule } from '@angular/material'; -import { DocumentListService } from '@alfresco/adf-content-services'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { AppTestingModule } from '../../testing/app-testing.module'; @Component({ template: '
' @@ -58,38 +46,13 @@ describe('NodeCopyDirective', () => { let notificationService: NotificationService; let nodesApiService: NodesApiService; let service: NodeActionsService; - let translationService: TranslationService; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - NoopAnimationsModule, - HttpClientModule, - TranslateModule.forRoot(), - MatSnackBarModule, - MatDialogModule, - MatIconModule - ], + imports: [ AppTestingModule ], declarations: [ TestComponent, NodeCopyDirective - ], - providers: [ - AlfrescoApiService, - AuthenticationService, - AppConfigService, - StorageService, - ContentService, - UserPreferencesService, - LogService, - CookieService, - NotificationService, - NodesApiService, - NodeActionsService, - { provide: TranslationService, useClass: TranslationMock }, - ContentManagementService, - DocumentListService, - ThumbnailService ] }); @@ -99,13 +62,6 @@ describe('NodeCopyDirective', () => { notificationService = TestBed.get(NotificationService); nodesApiService = TestBed.get(NodesApiService); service = TestBed.get(NodeActionsService); - translationService = TestBed.get(TranslationService); - }); - - beforeEach(() => { - spyOn(translationService, 'get').and.callFake((key) => { - return Observable.of(key); - }); }); describe('Copy node action', () => { diff --git a/src/app/common/directives/node-delete.directive.spec.ts b/src/app/common/directives/node-delete.directive.spec.ts index 15de3820c2..6a1c3f8667 100644 --- a/src/app/common/directives/node-delete.directive.spec.ts +++ b/src/app/common/directives/node-delete.directive.spec.ts @@ -25,14 +25,10 @@ import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { CoreModule, AlfrescoApiService } from '@alfresco/adf-core'; +import { AlfrescoApiService } from '@alfresco/adf-core'; import { Component, DebugElement } from '@angular/core'; import { NodeDeleteDirective } from './node-delete.directive'; -import { ContentManagementService } from '../services/content-management.service'; -import { StoreModule } from '@ngrx/store'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; import { EffectsModule, Actions, ofType } from '@ngrx/effects'; import { NodeEffects } from '../../store/effects/node.effects'; import { @@ -40,6 +36,7 @@ import { SnackbarErrorAction, SnackbarWarningAction, SNACKBAR_WARNING } from '../../store/actions'; import { map } from 'rxjs/operators'; +import { AppTestingModule } from '../../testing/app-testing.module'; @Component({ template: '
' @@ -58,16 +55,12 @@ describe('NodeDeleteDirective', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ - CoreModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + AppTestingModule, EffectsModule.forRoot([NodeEffects]) ], declarations: [ NodeDeleteDirective, TestComponent - ], - providers: [ - ContentManagementService ] }); diff --git a/src/app/common/directives/node-move.directive.spec.ts b/src/app/common/directives/node-move.directive.spec.ts index 342abe7eda..32e3404aff 100644 --- a/src/app/common/directives/node-move.directive.spec.ts +++ b/src/app/common/directives/node-move.directive.spec.ts @@ -27,20 +27,14 @@ import { Component, DebugElement } from '@angular/core'; import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { Observable } from 'rxjs/Rx'; -import { TranslationService, NodesApiService, NotificationService, CoreModule } from '@alfresco/adf-core'; -import { DocumentListService } from '@alfresco/adf-content-services'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; - +import { NodesApiService, NotificationService, TranslationService } from '@alfresco/adf-core'; import { NodeActionsService } from '../services/node-actions.service'; import { NodeMoveDirective } from './node-move.directive'; -import { ContentManagementService } from '../services/content-management.service'; -import { StoreModule } from '@ngrx/store'; import { EffectsModule, Actions, ofType } from '@ngrx/effects'; -import { appReducer } from '../../store/reducers/app.reducer'; import { NodeEffects } from '../../store/effects/node.effects'; -import { INITIAL_STATE } from '../../store/states/app.state'; import { SnackbarErrorAction, SNACKBAR_ERROR } from '../../store/actions'; import { map } from 'rxjs/operators'; +import { AppTestingModule } from '../../testing/app-testing.module'; @Component({ template: '
' @@ -56,28 +50,23 @@ describe('NodeMoveDirective', () => { let notificationService: NotificationService; let nodesApiService: NodesApiService; let service: NodeActionsService; - let translationService: TranslationService; let actions$: Actions; + let translationService: TranslationService; beforeEach(() => { TestBed.configureTestingModule({ imports: [ - BrowserAnimationsModule, - CoreModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + AppTestingModule, EffectsModule.forRoot([NodeEffects]) ], declarations: [ NodeMoveDirective, TestComponent - ], - providers: [ - DocumentListService, - ContentManagementService, - NodeActionsService ] }); + translationService = TestBed.get(TranslationService); + actions$ = TestBed.get(Actions); fixture = TestBed.createComponent(TestComponent); component = fixture.componentInstance; @@ -85,19 +74,18 @@ describe('NodeMoveDirective', () => { notificationService = TestBed.get(NotificationService); nodesApiService = TestBed.get(NodesApiService); service = TestBed.get(NodeActionsService); - translationService = TestBed.get(TranslationService); }); beforeEach(() => { - spyOn(translationService, 'get').and.callFake((keysArray) => { + spyOn(translationService, 'instant').and.callFake((keysArray) => { if (Array.isArray(keysArray)) { const processedKeys = {}; keysArray.forEach((key) => { processedKeys[key] = key; }); - return Observable.of(processedKeys); + return processedKeys; } else { - return Observable.of(keysArray); + return keysArray; } }); }); diff --git a/src/app/common/directives/node-move.directive.ts b/src/app/common/directives/node-move.directive.ts index 2c7914f697..e95cca93cb 100644 --- a/src/app/common/directives/node-move.directive.ts +++ b/src/app/common/directives/node-move.directive.ts @@ -123,7 +123,7 @@ export class NodeMoveDirective { errorMessage = this.getErrorMessage(info); } - const undo = (succeeded + partiallySucceeded > 0) ? this.translation.translate.instant('APP.ACTIONS.UNDO') : ''; + const undo = (succeeded + partiallySucceeded > 0) ? this.translation.instant('APP.ACTIONS.UNDO') : ''; const withUndo = errorMessage ? '' : '_WITH_UNDO'; failedMessage = errorMessage ? errorMessage : failedMessage; diff --git a/src/app/common/directives/node-permanent-delete.directive.spec.ts b/src/app/common/directives/node-permanent-delete.directive.spec.ts index db10f13291..66f6ad5d5f 100644 --- a/src/app/common/directives/node-permanent-delete.directive.spec.ts +++ b/src/app/common/directives/node-permanent-delete.directive.spec.ts @@ -24,17 +24,13 @@ */ import { Component, DebugElement } from '@angular/core'; -import { TestBed, ComponentFixture, async, fakeAsync, tick } from '@angular/core/testing'; +import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { Observable } from 'rxjs/Rx'; -import { AlfrescoApiService, CoreModule } from '@alfresco/adf-core'; +import { AlfrescoApiService } from '@alfresco/adf-core'; import { NodePermanentDeleteDirective } from './node-permanent-delete.directive'; -import { MatDialogModule, MatDialog } from '@angular/material'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { StoreModule } from '@ngrx/store'; -import { INITIAL_STATE } from '../../store/states/app.state'; -import { appReducer } from '../../store/reducers/app.reducer'; +import { MatDialog } from '@angular/material'; import { Actions, ofType, EffectsModule } from '@ngrx/effects'; import { SNACKBAR_INFO, SnackbarWarningAction, SnackbarInfoAction, @@ -42,7 +38,7 @@ import { } from '../../store/actions'; import { map } from 'rxjs/operators'; import { NodeEffects } from '../../store/effects/node.effects'; -import { ContentManagementService } from '../services/content-management.service'; +import { AppTestingModule } from '../../testing/app-testing.module'; @Component({ template: `
` @@ -57,43 +53,30 @@ describe('NodePermanentDeleteDirective', () => { let component: TestComponent; let alfrescoApiService: AlfrescoApiService; let dialog: MatDialog; - let actions$: Actions; - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ imports: [ - NoopAnimationsModule, - CoreModule.forRoot(), - MatDialogModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + AppTestingModule, EffectsModule.forRoot([NodeEffects]) ], declarations: [ NodePermanentDeleteDirective, TestComponent - ], - providers: [ - ContentManagementService ] - }) - .compileComponents() - .then(() => { - alfrescoApiService = TestBed.get(AlfrescoApiService); - alfrescoApiService.reset(); - - actions$ = TestBed.get(Actions); + }); - fixture = TestBed.createComponent(TestComponent); - component = fixture.componentInstance; - element = fixture.debugElement.query(By.directive(NodePermanentDeleteDirective)); + alfrescoApiService = TestBed.get(AlfrescoApiService); + alfrescoApiService.reset(); - dialog = TestBed.get(MatDialog); - }); - })); + actions$ = TestBed.get(Actions); - beforeEach(() => { + fixture = TestBed.createComponent(TestComponent); + component = fixture.componentInstance; + element = fixture.debugElement.query(By.directive(NodePermanentDeleteDirective)); + dialog = TestBed.get(MatDialog); spyOn(dialog, 'open').and.returnValue({ afterClosed() { return Observable.of(true); diff --git a/src/app/common/directives/node-restore.directive.spec.ts b/src/app/common/directives/node-restore.directive.spec.ts index 403e282541..d657ff8837 100644 --- a/src/app/common/directives/node-restore.directive.spec.ts +++ b/src/app/common/directives/node-restore.directive.spec.ts @@ -24,24 +24,17 @@ */ import { Component, DebugElement } from '@angular/core'; -import { RouterTestingModule } from '@angular/router/testing'; import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { Observable } from 'rxjs/Rx'; - -import { AlfrescoApiService, TranslationService, CoreModule } from '@alfresco/adf-core'; - +import { AlfrescoApiService } from '@alfresco/adf-core'; import { NodeRestoreDirective } from './node-restore.directive'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ContentManagementService } from '../services/content-management.service'; -import { StoreModule } from '@ngrx/store'; -import { EffectsModule, Actions, ofType } from '@ngrx/effects'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; +import { Actions, ofType } from '@ngrx/effects'; import { SnackbarErrorAction, SNACKBAR_ERROR, SnackbarInfoAction, SNACKBAR_INFO, NavigateRouteAction, NAVIGATE_ROUTE } from '../../store/actions'; import { map } from 'rxjs/operators'; +import { AppTestingModule } from '../../testing/app-testing.module'; @Component({ template: `
` @@ -55,26 +48,16 @@ describe('NodeRestoreDirective', () => { let element: DebugElement; let component: TestComponent; let alfrescoService: AlfrescoApiService; - let translation: TranslationService; let directiveInstance: NodeRestoreDirective; let contentManagementService: ContentManagementService; let actions$: Actions; beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - NoopAnimationsModule, - RouterTestingModule, - CoreModule.forRoot(), - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), - EffectsModule.forRoot([]) - ], + imports: [ AppTestingModule ], declarations: [ NodeRestoreDirective, TestComponent - ], - providers: [ - ContentManagementService ] }); @@ -88,9 +71,6 @@ describe('NodeRestoreDirective', () => { element = fixture.debugElement.query(By.directive(NodeRestoreDirective)); directiveInstance = element.injector.get(NodeRestoreDirective); - translation = TestBed.get(TranslationService); - spyOn(translation, 'instant').and.returnValue(Observable.of('message')); - contentManagementService = TestBed.get(ContentManagementService); }); diff --git a/src/app/components/favorites/favorites.component.spec.ts b/src/app/components/favorites/favorites.component.spec.ts index 9edb6f2953..cdc54ccbc1 100644 --- a/src/app/components/favorites/favorites.component.spec.ts +++ b/src/app/components/favorites/favorites.component.spec.ts @@ -26,20 +26,15 @@ import { Observable } from 'rxjs/Rx'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router } from '@angular/router'; -import { TestBed, async, ComponentFixture } from '@angular/core/testing'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; import { - NodesApiService, AlfrescoApiService, ContentService, - UserPreferencesService, LogService, AppConfigService, - StorageService, CookieService, ThumbnailService, - AuthenticationService, TimeAgoPipe, NodeNameTooltipPipe, + NodesApiService, + AlfrescoApiService, + TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; -import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; - -import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; -import { DocumentListService } from '@alfresco/adf-content-services'; +import { DocumentListComponent } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodePermissionService } from '../../common/services/node-permission.service'; import { FavoritesComponent } from './favorites.component'; import { AppTestingModule } from '../../testing/app-testing.module'; @@ -80,13 +75,9 @@ describe('FavoritesComponent', () => { }; }); - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - AppTestingModule, - MatMenuModule, - MatSnackBarModule, MatIconModule, - ], + imports: [ AppTestingModule ], declarations: [ DataTableComponent, TimeAgoPipe, @@ -96,36 +87,19 @@ describe('FavoritesComponent', () => { FavoritesComponent, AppConfigPipe ], - providers: [ - AuthenticationService, - UserPreferencesService, - AppConfigService, StorageService, CookieService, - AlfrescoApiService, - CustomResourcesService, - LogService, - ContentManagementService, - ContentService, - NodesApiService, - NodePermissionService, - DocumentListService, - ThumbnailService - ], schemas: [ NO_ERRORS_SCHEMA ] - }) - .compileComponents().then(() => { - fixture = TestBed.createComponent(FavoritesComponent); - component = fixture.componentInstance; - - nodesApi = TestBed.get(NodesApiService); - alfrescoApi = TestBed.get(AlfrescoApiService); - alfrescoApi.reset(); - contentService = TestBed.get(ContentManagementService); - router = TestBed.get(Router); }); - })); - beforeEach(() => { + fixture = TestBed.createComponent(FavoritesComponent); + component = fixture.componentInstance; + + nodesApi = TestBed.get(NodesApiService); + alfrescoApi = TestBed.get(AlfrescoApiService); + alfrescoApi.reset(); spyOn(alfrescoApi.favoritesApi, 'getFavorites').and.returnValue(Promise.resolve(page)); + + contentService = TestBed.get(ContentManagementService); + router = TestBed.get(Router); }); describe('Events', () => { diff --git a/src/app/components/files/files.component.spec.ts b/src/app/components/files/files.component.spec.ts index a39ad52bda..226a17007c 100644 --- a/src/app/components/files/files.component.spec.ts +++ b/src/app/components/files/files.component.spec.ts @@ -24,38 +24,25 @@ */ import { Observable } from 'rxjs/Rx'; -import { TestBed, async, fakeAsync, tick } from '@angular/core/testing'; +import { TestBed, fakeAsync, tick, ComponentFixture } from '@angular/core/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientModule } from '@angular/common/http'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { - NotificationService, TranslationService, TranslationMock, - NodesApiService, AlfrescoApiService, ContentService, - UserPreferencesService, LogService, AppConfigService, - StorageService, CookieService, ThumbnailService, AuthenticationService, + NodesApiService, TimeAgoPipe, NodeNameTooltipPipe, FileSizePipe, NodeFavoriteDirective, DataTableComponent, UploadService, AppConfigPipe } from '@alfresco/adf-core'; -import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; -import { MatMenuModule, MatSnackBarModule, MatIconModule, MatDialogModule } from '@angular/material'; -import { DocumentListService } from '@alfresco/adf-content-services'; +import { DocumentListComponent } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; import { NodeActionsService } from '../../common/services/node-actions.service'; -import { NodePermissionService } from '../../common/services/node-permission.service'; - import { FilesComponent } from './files.component'; -import { StoreModule } from '@ngrx/store'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; +import { AppTestingModule } from '../../testing/app-testing.module'; describe('FilesComponent', () => { let node; let page; - let fixture; + let fixture: ComponentFixture; let component: FilesComponent; let contentManagementService: ContentManagementService; let uploadService: UploadService; @@ -64,18 +51,14 @@ describe('FilesComponent', () => { let browsingFilesService: BrowsingFilesService; let nodeActionsService: NodeActionsService; - beforeEach(async(() => { + beforeAll(() => { + // testing only functional-wise not time-wise + Observable.prototype.debounceTime = function () { return this; }; + }); + + beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - MatMenuModule, - NoopAnimationsModule, - HttpClientModule, - TranslateModule.forRoot(), - RouterTestingModule, - MatSnackBarModule, MatIconModule, - MatDialogModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) - ], + imports: [ AppTestingModule ], declarations: [ FilesComponent, DataTableComponent, @@ -90,40 +73,21 @@ describe('FilesComponent', () => { { provide: ActivatedRoute, useValue: { snapshot: { data: { preferencePrefix: 'prefix' } }, params: Observable.of({ folderId: 'someId' }) - } } , - { provide: TranslationService, useClass: TranslationMock }, - AuthenticationService, - UserPreferencesService, - AppConfigService, StorageService, CookieService, - AlfrescoApiService, - LogService, - NotificationService, - ContentManagementService, - ContentService, - NodesApiService, - DocumentListService, - ThumbnailService, - NodeActionsService, - NodePermissionService, - UploadService, - BrowsingFilesService, - CustomResourcesService + } } ], schemas: [ NO_ERRORS_SCHEMA ] - }).compileComponents() - .then(() => { - - fixture = TestBed.createComponent(FilesComponent); - component = fixture.componentInstance; - - contentManagementService = TestBed.get(ContentManagementService); - uploadService = TestBed.get(UploadService); - nodesApi = TestBed.get(NodesApiService); - router = TestBed.get(Router); - browsingFilesService = TestBed.get(BrowsingFilesService); - nodeActionsService = TestBed.get(NodeActionsService); }); - })); + + fixture = TestBed.createComponent(FilesComponent); + component = fixture.componentInstance; + + contentManagementService = TestBed.get(ContentManagementService); + uploadService = TestBed.get(UploadService); + nodesApi = TestBed.get(NodesApiService); + router = TestBed.get(Router); + browsingFilesService = TestBed.get(BrowsingFilesService); + nodeActionsService = TestBed.get(NodeActionsService); + }); beforeEach(() => { node = { id: 'node-id', isFolder: true }; diff --git a/src/app/components/header/header.component.spec.ts b/src/app/components/header/header.component.spec.ts index 2728e3a541..f2a3f88ec6 100644 --- a/src/app/components/header/header.component.spec.ts +++ b/src/app/components/header/header.component.spec.ts @@ -41,16 +41,10 @@ describe('HeaderComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - AppTestingModule - ], + imports: [ AppTestingModule ], declarations: [ HeaderComponent ], - providers: [ - AppConfigService, - PeopleContentService - ], schemas: [ NO_ERRORS_SCHEMA ] }) .overrideProvider(PeopleContentService, { diff --git a/src/app/components/layout/layout.component.spec.ts b/src/app/components/layout/layout.component.spec.ts index f892749062..8a6e3a3513 100644 --- a/src/app/components/layout/layout.component.spec.ts +++ b/src/app/components/layout/layout.component.spec.ts @@ -24,23 +24,14 @@ */ import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { RouterTestingModule } from '@angular/router/testing'; import { TestBed, ComponentFixture } from '@angular/core/testing'; import { MinimalNodeEntryEntity } from 'alfresco-js-api'; -import { TranslateModule } from '@ngx-translate/core'; -import { HttpClientModule } from '@angular/common/http'; -import { - PeopleContentService, AppConfigService, - AuthenticationService, UserPreferencesService, TranslationService, - TranslationMock, StorageService, AlfrescoApiService, CookieService, - LogService -} from '@alfresco/adf-core'; +import { PeopleContentService, AppConfigService, UserPreferencesService } from '@alfresco/adf-core'; import { Observable } from 'rxjs/Observable'; - import { BrowsingFilesService } from '../../common/services/browsing-files.service'; -import { NodePermissionService } from '../../common/services/node-permission.service'; import { LayoutComponent } from './layout.component'; import { SidenavViewsManagerDirective } from './sidenav-views-manager.directive'; +import { AppTestingModule } from '../../testing/app-testing.module'; describe('LayoutComponent', () => { let fixture: ComponentFixture; @@ -58,26 +49,12 @@ describe('LayoutComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - HttpClientModule, - TranslateModule.forRoot(), - RouterTestingModule - ], + imports: [ AppTestingModule ], declarations: [ LayoutComponent, SidenavViewsManagerDirective ], providers: [ - { provide: TranslationService, useClass: TranslationMock }, - AlfrescoApiService, - StorageService, - CookieService, - LogService, - UserPreferencesService, - AuthenticationService, - AppConfigService, - NodePermissionService, - BrowsingFilesService, { provide: PeopleContentService, useValue: { diff --git a/src/app/components/libraries/libraries.component.spec.ts b/src/app/components/libraries/libraries.component.spec.ts index 5837222113..d2e1dfa7a3 100644 --- a/src/app/components/libraries/libraries.component.spec.ts +++ b/src/app/components/libraries/libraries.component.spec.ts @@ -23,34 +23,21 @@ * along with Alfresco. If not, see . */ -import { TestBed, async, ComponentFixture } from '@angular/core/testing'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; import { Observable } from 'rxjs/Rx'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientModule } from '@angular/common/http'; import { - NotificationService, TranslationService, TranslationMock, - NodesApiService, AlfrescoApiService, ContentService, - UserPreferencesService, LogService, AppConfigService, - StorageService, CookieService, ThumbnailService, AuthenticationService, + NodesApiService, AlfrescoApiService, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; -import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; -import { DocumentListService } from '@alfresco/adf-content-services'; +import { DocumentListComponent } from '@alfresco/adf-content-services'; import { ShareDataTableAdapter } from '@alfresco/adf-content-services'; - import { LibrariesComponent } from './libraries.component'; -import { StoreModule } from '@ngrx/store'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; -import { ContentManagementService } from '../../common/services/content-management.service'; import { ExperimentalDirective } from '../../directives/experimental.directive'; +import { AppTestingModule } from '../../testing/app-testing.module'; -describe('Libraries Routed Component', () => { +describe('LibrariesComponent', () => { let fixture: ComponentFixture; let component: LibrariesComponent; let nodesApi: NodesApiService; @@ -75,17 +62,9 @@ describe('Libraries Routed Component', () => { }; }); - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - MatMenuModule, - NoopAnimationsModule, - HttpClientModule, - TranslateModule.forRoot(), - RouterTestingModule, - MatSnackBarModule, MatIconModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) - ], + imports: [ AppTestingModule ], declarations: [ DataTableComponent, TimeAgoPipe, @@ -96,36 +75,17 @@ describe('Libraries Routed Component', () => { AppConfigPipe, ExperimentalDirective ], - providers: [ - { provide: TranslationService, useClass: TranslationMock }, - AuthenticationService, - UserPreferencesService, - AppConfigService, StorageService, CookieService, - AlfrescoApiService, - LogService, - NotificationService, - ContentService, - NodesApiService, - DocumentListService, - ThumbnailService, - CustomResourcesService, - - ContentManagementService - ], schemas: [ NO_ERRORS_SCHEMA ] - }) - .compileComponents().then(() => { - fixture = TestBed.createComponent(LibrariesComponent); - component = fixture.componentInstance; - - nodesApi = TestBed.get(NodesApiService); - alfrescoApi = TestBed.get(AlfrescoApiService); - alfrescoApi.reset(); - router = TestBed.get(Router); }); - })); - beforeEach(() => { + fixture = TestBed.createComponent(LibrariesComponent); + component = fixture.componentInstance; + + nodesApi = TestBed.get(NodesApiService); + alfrescoApi = TestBed.get(AlfrescoApiService); + alfrescoApi.reset(); + router = TestBed.get(Router); + spyOn(alfrescoApi.sitesApi, 'getSites').and.returnValue((Promise.resolve(page))); spyOn(alfrescoApi.peopleApi, 'getSiteMembership').and.returnValue((Promise.resolve({}))); }); diff --git a/src/app/components/login/login.component.spec.ts b/src/app/components/login/login.component.spec.ts index 3c5583b939..7db3e5a826 100644 --- a/src/app/components/login/login.component.spec.ts +++ b/src/app/components/login/login.component.spec.ts @@ -24,19 +24,12 @@ */ import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { RouterTestingModule } from '@angular/router/testing'; import { Router } from '@angular/router'; -import { HttpClientModule } from '@angular/common/http'; -import { TranslateModule } from '@ngx-translate/core'; import { Location } from '@angular/common'; -import { TestBed, async, ComponentFixture } from '@angular/core/testing'; -import { - AuthenticationService, UserPreferencesService, TranslationService, - TranslationMock, AppConfigService, StorageService, AlfrescoApiService, - CookieService, LogService, AppConfigPipe -} from '@alfresco/adf-core'; - +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { AuthenticationService, UserPreferencesService, AppConfigPipe } from '@alfresco/adf-core'; import { LoginComponent } from './login.component'; +import { AppTestingModule } from '../../testing/app-testing.module'; describe('LoginComponent', () => { let fixture: ComponentFixture; @@ -45,27 +38,15 @@ describe('LoginComponent', () => { let auth: AuthenticationService; let location: Location; - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - HttpClientModule, - TranslateModule.forRoot(), - RouterTestingModule - ], + imports: [ AppTestingModule ], declarations: [ LoginComponent, AppConfigPipe ], providers: [ - { provide: TranslationService, useClass: TranslationMock }, - Location, - CookieService, - LogService, - StorageService, - AlfrescoApiService, - AppConfigService, - AuthenticationService, - UserPreferencesService + Location ], schemas: [ NO_ERRORS_SCHEMA ] }); @@ -73,16 +54,16 @@ describe('LoginComponent', () => { fixture = TestBed.createComponent(LoginComponent); router = TestBed.get(Router); + spyOn(router, 'navigateByUrl'); + location = TestBed.get(Location); + spyOn(location, 'forward'); + auth = TestBed.get(AuthenticationService); - userPreference = TestBed.get(UserPreferencesService); - })); + spyOn(auth, 'getRedirect').and.returnValue('/some-url'); - beforeEach(() => { + userPreference = TestBed.get(UserPreferencesService); spyOn(userPreference, 'setStoragePrefix'); - spyOn(router, 'navigateByUrl'); - spyOn(auth, 'getRedirect').and.returnValue('/some-url'); - spyOn(location, 'forward'); }); describe('OnInit()', () => { diff --git a/src/app/components/preview/preview.component.spec.ts b/src/app/components/preview/preview.component.spec.ts index 73f0fdc391..1d650a9388 100644 --- a/src/app/components/preview/preview.component.spec.ts +++ b/src/app/components/preview/preview.component.spec.ts @@ -25,23 +25,13 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; import { TestBed, async, ComponentFixture } from '@angular/core/testing'; -import { - AlfrescoApiService, UserPreferencesService, - TranslationService, TranslationMock, - CoreModule, UploadService -} from '@alfresco/adf-core'; - +import { AlfrescoApiService, UserPreferencesService, AppConfigPipe, NodeFavoriteDirective } from '@alfresco/adf-core'; import { PreviewComponent } from './preview.component'; import { Observable } from 'rxjs/Rx'; -import { NodePermissionService } from '../../common/services/node-permission.service'; -import { ContentManagementService } from '../../common/services/content-management.service'; -import { StoreModule } from '@ngrx/store'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; import { EffectsModule } from '@ngrx/effects'; import { NodeEffects } from '../../store/effects/node.effects'; +import { AppTestingModule } from '../../testing/app-testing.module'; describe('PreviewComponent', () => { @@ -55,20 +45,13 @@ describe('PreviewComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - RouterTestingModule, - CoreModule.forRoot(), - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + AppTestingModule, EffectsModule.forRoot([NodeEffects]) ], - providers: [ - { provide: TranslationService, useClass: TranslationMock }, - NodePermissionService, - ContentManagementService, - UploadService - ], declarations: [ + AppConfigPipe, PreviewComponent, - // NodeFavoriteDirective + NodeFavoriteDirective ], schemas: [ NO_ERRORS_SCHEMA ] }) diff --git a/src/app/components/recent-files/recent-files.component.spec.ts b/src/app/components/recent-files/recent-files.component.spec.ts index 235ab5b297..1f78650442 100644 --- a/src/app/components/recent-files/recent-files.component.spec.ts +++ b/src/app/components/recent-files/recent-files.component.spec.ts @@ -23,31 +23,19 @@ * along with Alfresco. If not, see . */ -import { TestBed, async, ComponentFixture } from '@angular/core/testing'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientModule } from '@angular/common/http'; import { - NotificationService, TranslationService, TranslationMock, - NodesApiService, AlfrescoApiService, ContentService, UploadService, - UserPreferencesService, LogService, AppConfigService, - StorageService, CookieService, ThumbnailService, AuthenticationService, + AlfrescoApiService, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; -import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; -import { DocumentListService } from '@alfresco/adf-content-services'; +import { DocumentListComponent } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodePermissionService } from '../../common/services/node-permission.service'; import { RecentFilesComponent } from './recent-files.component'; -import { StoreModule } from '@ngrx/store'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; +import { AppTestingModule } from '../../testing/app-testing.module'; -describe('RecentFiles Routed Component', () => { +describe('RecentFilesComponent', () => { let fixture: ComponentFixture; let component: RecentFilesComponent; let alfrescoApi: AlfrescoApiService; @@ -63,16 +51,10 @@ describe('RecentFiles Routed Component', () => { }; }); - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ imports: [ - MatMenuModule, - NoopAnimationsModule, - HttpClientModule, - TranslateModule.forRoot(), - RouterTestingModule, - MatSnackBarModule, MatIconModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) + AppTestingModule ], declarations: [ DataTableComponent, @@ -83,41 +65,21 @@ describe('RecentFiles Routed Component', () => { RecentFilesComponent, AppConfigPipe ], - providers: [ - { provide: TranslationService, useClass: TranslationMock }, - AuthenticationService, - UserPreferencesService, - AppConfigService, StorageService, CookieService, - AlfrescoApiService, - LogService, - NotificationService, - ContentManagementService, - NodePermissionService, - ContentService, - NodesApiService, - DocumentListService, - ThumbnailService, - CustomResourcesService, - UploadService - ], schemas: [ NO_ERRORS_SCHEMA ] - }) - .compileComponents().then(() => { - fixture = TestBed.createComponent(RecentFilesComponent); - component = fixture.componentInstance; - - contentService = TestBed.get(ContentManagementService); - alfrescoApi = TestBed.get(AlfrescoApiService); - alfrescoApi.reset(); }); - })); - beforeEach(() => { + fixture = TestBed.createComponent(RecentFilesComponent); + component = fixture.componentInstance; + + contentService = TestBed.get(ContentManagementService); + alfrescoApi = TestBed.get(AlfrescoApiService); + alfrescoApi.reset(); + spyOn(alfrescoApi.peopleApi, 'getPerson').and.returnValue(Promise.resolve({ - entry: { id: 'personId' } - })); + entry: { id: 'personId' } + })); - spyOn(alfrescoApi.searchApi, 'search').and.returnValue(Promise.resolve(page)); + spyOn(alfrescoApi.searchApi, 'search').and.returnValue(Promise.resolve(page)); }); describe('OnInit()', () => { diff --git a/src/app/components/shared-files/shared-files.component.spec.ts b/src/app/components/shared-files/shared-files.component.spec.ts index db7fa5f2f4..4cd7430773 100644 --- a/src/app/components/shared-files/shared-files.component.spec.ts +++ b/src/app/components/shared-files/shared-files.component.spec.ts @@ -23,29 +23,16 @@ * along with Alfresco. If not, see . */ -import { TestBed, async, ComponentFixture } from '@angular/core/testing'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientModule } from '@angular/common/http'; import { - NotificationService, TranslationService, TranslationMock, - NodesApiService, AlfrescoApiService, ContentService, - UserPreferencesService, LogService, AppConfigService, UploadService, - StorageService, CookieService, ThumbnailService, AuthenticationService, + AlfrescoApiService, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; -import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; -import { TranslateModule } from '@ngx-translate/core'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material'; -import { DocumentListService } from '@alfresco/adf-content-services'; +import { DocumentListComponent } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; -import { NodePermissionService } from '../../common/services/node-permission.service'; - import { SharedFilesComponent } from './shared-files.component'; -import { StoreModule } from '@ngrx/store'; -import { appReducer } from '../../store/reducers/app.reducer'; -import { INITIAL_STATE } from '../../store/states/app.state'; +import { AppTestingModule } from '../../testing/app-testing.module'; describe('SharedFilesComponent', () => { let fixture: ComponentFixture; @@ -63,18 +50,10 @@ describe('SharedFilesComponent', () => { }; }); - beforeEach(async(() => { + beforeEach(() => { TestBed .configureTestingModule({ - imports: [ - MatMenuModule, - NoopAnimationsModule, - HttpClientModule, - TranslateModule.forRoot(), - RouterTestingModule, - MatSnackBarModule, MatIconModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }) - ], + imports: [ AppTestingModule ], declarations: [ DataTableComponent, TimeAgoPipe, @@ -84,39 +63,17 @@ describe('SharedFilesComponent', () => { SharedFilesComponent, AppConfigPipe ], - providers: [ - { provide: TranslationService, useClass: TranslationMock }, - AuthenticationService, - UserPreferencesService, - AppConfigService, StorageService, CookieService, - AlfrescoApiService, - LogService, - NotificationService, - ContentManagementService, - NodePermissionService, - ContentService, - NodesApiService, - DocumentListService, - ThumbnailService, - CustomResourcesService, - UploadService - ], schemas: [ NO_ERRORS_SCHEMA ] - }) - .compileComponents() - .then(() => { - fixture = TestBed.createComponent(SharedFilesComponent); - component = fixture.componentInstance; - - contentService = TestBed.get(ContentManagementService); - alfrescoApi = TestBed.get(AlfrescoApiService); - alfrescoApi.reset(); }); - })); + fixture = TestBed.createComponent(SharedFilesComponent); + component = fixture.componentInstance; - beforeEach(() => { - spyOn(alfrescoApi.sharedLinksApi, 'findSharedLinks').and.returnValue(Promise.resolve(page)); + contentService = TestBed.get(ContentManagementService); + alfrescoApi = TestBed.get(AlfrescoApiService); + alfrescoApi.reset(); + + spyOn(alfrescoApi.sharedLinksApi, 'findSharedLinks').and.returnValue(Promise.resolve(page)); }); describe('OnInit', () => { diff --git a/src/app/components/sidenav/sidenav.component.spec.ts b/src/app/components/sidenav/sidenav.component.spec.ts index 47725c12d3..b237127e53 100644 --- a/src/app/components/sidenav/sidenav.component.spec.ts +++ b/src/app/components/sidenav/sidenav.component.spec.ts @@ -25,16 +25,12 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { TestBed, async, ComponentFixture } from '@angular/core/testing'; -import { AppConfigService, CoreModule } from '@alfresco/adf-core'; +import { AppConfigService } from '@alfresco/adf-core'; import { BrowsingFilesService } from '../../common/services/browsing-files.service'; -import { NodePermissionService } from '../../common/services/node-permission.service'; - import { SidenavComponent } from './sidenav.component'; import { EffectsModule } from '@ngrx/effects'; import { NodeEffects } from '../../store/effects/node.effects'; -import { ContentManagementService } from '../../common/services/content-management.service'; import { AppTestingModule } from '../../testing/app-testing.module'; -import { MaterialModule } from '../../material.module'; describe('SidenavComponent', () => { let fixture: ComponentFixture; @@ -54,18 +50,11 @@ describe('SidenavComponent', () => { TestBed.configureTestingModule({ imports: [ AppTestingModule, - MaterialModule, - CoreModule.forRoot(), EffectsModule.forRoot([NodeEffects]) ], declarations: [ SidenavComponent ], - providers: [ - NodePermissionService, - BrowsingFilesService, - ContentManagementService - ], schemas: [ NO_ERRORS_SCHEMA ] }) .compileComponents() diff --git a/src/app/components/trashcan/trashcan.component.spec.ts b/src/app/components/trashcan/trashcan.component.spec.ts index 441a3af0aa..111b3a632f 100644 --- a/src/app/components/trashcan/trashcan.component.spec.ts +++ b/src/app/components/trashcan/trashcan.component.spec.ts @@ -25,20 +25,14 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { TestBed, ComponentFixture } from '@angular/core/testing'; import { - NotificationService, - NodesApiService, AlfrescoApiService, ContentService, - UserPreferencesService, LogService, AppConfigService, - StorageService, CookieService, ThumbnailService, - AuthenticationService, TimeAgoPipe, NodeNameTooltipPipe, - NodeFavoriteDirective, DataTableComponent, AppConfigPipe, PeopleContentService + AlfrescoApiService, + TimeAgoPipe, NodeNameTooltipPipe, + NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; -import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services'; -import { DocumentListService } from '@alfresco/adf-content-services'; +import { DocumentListComponent } from '@alfresco/adf-content-services'; import { ContentManagementService } from '../../common/services/content-management.service'; - import { TrashcanComponent } from './trashcan.component'; import { AppTestingModule } from '../../testing/app-testing.module'; -import { MaterialModule } from '../../material.module'; describe('TrashcanComponent', () => { let fixture: ComponentFixture; @@ -58,10 +52,7 @@ describe('TrashcanComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [ - AppTestingModule, - MaterialModule, - ], + imports: [ AppTestingModule ], declarations: [ DataTableComponent, TimeAgoPipe, @@ -71,21 +62,6 @@ describe('TrashcanComponent', () => { TrashcanComponent, AppConfigPipe ], - providers: [ - AuthenticationService, - UserPreferencesService, - PeopleContentService, - AppConfigService, StorageService, CookieService, - AlfrescoApiService, - LogService, - NotificationService, - ContentManagementService, - ContentService, - NodesApiService, - DocumentListService, - ThumbnailService, - CustomResourcesService - ], schemas: [ NO_ERRORS_SCHEMA ] }); diff --git a/src/app/testing/app-testing.module.ts b/src/app/testing/app-testing.module.ts index 71be7cb260..09d14c24da 100644 --- a/src/app/testing/app-testing.module.ts +++ b/src/app/testing/app-testing.module.ts @@ -24,10 +24,26 @@ */ import { NgModule } from '@angular/core'; -import { TranslatePipe, TranslateService } from '@ngx-translate/core'; +import { TranslateService, TranslatePipe } from '@ngx-translate/core'; import { TranslatePipeMock } from './translate-pipe.directive'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { TranslationService, TranslationMock } from '@alfresco/adf-core'; +import { + TranslationService, + TranslationMock, + AuthenticationService, + UserPreferencesService, + AppConfigService, + StorageService, + CookieService, + AlfrescoApiService, + LogService, + NotificationService, + NodesApiService, + ContentService, + ThumbnailService, + UploadService, + PeopleContentService +} from '@alfresco/adf-core'; import { HttpClientModule } from '@angular/common/http'; import { TranslateServiceMock } from './translation.service'; import { StoreModule } from '@ngrx/store'; @@ -35,26 +51,64 @@ import { appReducer } from '../store/reducers/app.reducer'; import { INITIAL_STATE } from '../store/states/app.state'; import { RouterTestingModule } from '@angular/router/testing'; import { EffectsModule } from '@ngrx/effects'; +import { + CustomResourcesService, + DocumentListService +} from '@alfresco/adf-content-services'; +import { MaterialModule } from '../material.module'; +import { ContentManagementService } from '../common/services/content-management.service'; +import { NodeActionsService } from '../common/services/node-actions.service'; +import { NodePermissionService } from '../common/services/node-permission.service'; +import { BrowsingFilesService } from '../common/services/browsing-files.service'; @NgModule({ imports: [ NoopAnimationsModule, HttpClientModule, RouterTestingModule, - StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }), + MaterialModule, + StoreModule.forRoot( + { app: appReducer }, + { initialState: INITIAL_STATE } + ), EffectsModule.forRoot([]) ], - declarations: [ - TranslatePipeMock - ], - exports: [ - TranslatePipeMock, - RouterTestingModule - ], + declarations: [TranslatePipeMock], + exports: [TranslatePipeMock, RouterTestingModule, MaterialModule], providers: [ { provide: TranslationService, useClass: TranslationMock }, { provide: TranslateService, useClass: TranslateServiceMock }, - { provide: TranslatePipe, useClass: TranslatePipeMock } + { provide: TranslatePipe, useClass: TranslatePipeMock }, + { + provide: AuthenticationService, + useValue: { + isEcmLoggedIn(): boolean { + return true; + }, + getRedirect(): string { + return null; + } + } + }, + UserPreferencesService, + AppConfigService, + StorageService, + CookieService, + AlfrescoApiService, + LogService, + NotificationService, + NodesApiService, + ContentService, + ThumbnailService, + UploadService, + CustomResourcesService, + DocumentListService, + PeopleContentService, + + ContentManagementService, + NodeActionsService, + NodePermissionService, + BrowsingFilesService ] }) export class AppTestingModule {} diff --git a/src/app/testing/translation.service.ts b/src/app/testing/translation.service.ts index 09dbd495be..1d6b30312f 100644 --- a/src/app/testing/translation.service.ts +++ b/src/app/testing/translation.service.ts @@ -25,10 +25,19 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { Observable } from 'rxjs/Observable'; @Injectable() export class TranslateServiceMock extends TranslateService { constructor() { super(null, null, null, null, null); } + + get(key: string | Array, interpolateParams?: Object): Observable { + return Observable.of(key); + } + + instant(key: string | Array, interpolateParams?: Object): string | any { + return key; + } } From af547aac3149602f59cf08b9278b98d870f73913 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 25 Jun 2018 08:37:21 +0100 Subject: [PATCH 138/179] content api service (#455) * introduce content-api service * upgrade files component * upgrade directives * upgrade directives * update directives * fix profile resolver call ordering issue * fix reducer * update services * extra apis * update about page * update preview component * code updates --- src/app/app.module.ts | 4 +- .../directives/node-copy.directive.spec.ts | 26 +- .../common/directives/node-copy.directive.ts | 7 +- .../directives/node-delete.directive.spec.ts | 31 ++- .../directives/node-move.directive.spec.ts | 23 +- .../common/directives/node-move.directive.ts | 9 +- .../node-permanent-delete.directive.spec.ts | 50 ++-- .../directives/node-restore.directive.spec.ts | 53 ++-- .../directives/node-restore.directive.ts | 19 +- .../directives/node-unshare.directive.ts | 19 +- .../directives/node-versions.directive.ts | 13 +- .../services/content-management.service.ts | 1 + .../services/node-actions.service.spec.ts | 44 +--- .../common/services/node-actions.service.ts | 7 +- src/app/common/services/profile.resolver.ts | 35 ++- src/app/components/about/about.component.html | 4 +- src/app/components/about/about.component.ts | 21 +- .../favorites/favorites.component.spec.ts | 9 +- .../favorites/favorites.component.ts | 7 +- .../components/files/files.component.spec.ts | 45 ++-- src/app/components/files/files.component.ts | 39 +-- .../info-drawer/info-drawer.component.ts | 16 +- .../libraries/libraries.component.spec.ts | 10 +- .../libraries/libraries.component.ts | 9 +- .../location-link/location-link.component.ts | 17 +- .../preview/preview.component.spec.ts | 123 +++++----- .../components/preview/preview.component.ts | 27 +-- .../shared-files/shared-files.component.html | 3 +- .../shared-files/shared-files.component.ts | 1 + src/app/services/content-api.service.ts | 229 ++++++++++++++++++ src/app/store/actions/user.actions.ts | 3 +- src/app/store/effects/download.effects.ts | 6 +- src/app/store/effects/library.effects.ts | 8 +- src/app/store/effects/node.effects.ts | 15 +- src/app/store/reducers/app.reducer.ts | 4 +- src/app/testing/app-testing.module.ts | 8 +- 36 files changed, 552 insertions(+), 393 deletions(-) create mode 100644 src/app/services/content-api.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 80542533f1..f5f07237df 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -79,6 +79,7 @@ import { PaginationDirective } from './directives/pagination.directive'; import { DocumentListDirective } from './directives/document-list.directive'; import { MaterialModule } from './material.module'; import { ExperimentalDirective } from './directives/experimental.directive'; +import { ContentApiService } from './services/content-api.service'; @NgModule({ imports: [ @@ -149,7 +150,8 @@ import { ExperimentalDirective } from './directives/experimental.directive'; ContentManagementService, NodeActionsService, NodePermissionService, - ProfileResolver + ProfileResolver, + ContentApiService ], entryComponents: [ NodeVersionsDialogComponent diff --git a/src/app/common/directives/node-copy.directive.spec.ts b/src/app/common/directives/node-copy.directive.spec.ts index 0be679d6c3..e9d115b158 100644 --- a/src/app/common/directives/node-copy.directive.spec.ts +++ b/src/app/common/directives/node-copy.directive.spec.ts @@ -27,10 +27,11 @@ import { Component, DebugElement } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { Observable } from 'rxjs/Rx'; -import { NodesApiService, NotificationService } from '@alfresco/adf-core'; +import { NotificationService } from '@alfresco/adf-core'; import { NodeActionsService } from '../services/node-actions.service'; import { NodeCopyDirective } from './node-copy.directive'; import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; @Component({ template: '
' @@ -44,8 +45,8 @@ describe('NodeCopyDirective', () => { let component: TestComponent; let element: DebugElement; let notificationService: NotificationService; - let nodesApiService: NodesApiService; let service: NodeActionsService; + let contentApi: ContentApiService; beforeEach(() => { TestBed.configureTestingModule({ @@ -56,11 +57,12 @@ describe('NodeCopyDirective', () => { ] }); + contentApi = TestBed.get(ContentApiService); + fixture = TestBed.createComponent(TestComponent); component = fixture.componentInstance; element = fixture.debugElement.query(By.directive(NodeCopyDirective)); notificationService = TestBed.get(NotificationService); - nodesApiService = TestBed.get(NodesApiService); service = TestBed.get(NodeActionsService); }); @@ -233,7 +235,7 @@ describe('NodeCopyDirective', () => { }); it('should delete the newly created node on Undo action', () => { - spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.of(null)); + spyOn(contentApi, 'deleteNode').and.returnValue(Observable.of(null)); component.selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }]; const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }]; @@ -247,11 +249,11 @@ describe('NodeCopyDirective', () => { 'APP.MESSAGES.INFO.NODE_COPY.SINGULAR', 'APP.ACTIONS.UNDO', 10000 ); - expect(nodesApiService.deleteNode).toHaveBeenCalledWith(createdItems[0].entry.id, { permanent: true }); + expect(contentApi.deleteNode).toHaveBeenCalledWith(createdItems[0].entry.id, { permanent: true }); }); it('should delete also the node created inside an already existing folder from destination', () => { - const spyOnDeleteNode = spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.of(null)); + const spyOnDeleteNode = spyOn(contentApi, 'deleteNode').and.returnValue(Observable.of(null)); component.selection = [ { entry: { id: 'node-to-copy-1', name: 'name1' } }, @@ -277,7 +279,7 @@ describe('NodeCopyDirective', () => { }); it('notifies when error occurs on Undo action', () => { - spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.throw(null)); + spyOn(contentApi, 'deleteNode').and.returnValue(Observable.throw(null)); component.selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }]; const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }]; @@ -287,14 +289,14 @@ describe('NodeCopyDirective', () => { service.contentCopied.next(createdItems); expect(service.copyNodes).toHaveBeenCalled(); - expect(nodesApiService.deleteNode).toHaveBeenCalled(); + expect(contentApi.deleteNode).toHaveBeenCalled(); expect(notificationService.openSnackMessageAction['calls'].allArgs()) .toEqual([['APP.MESSAGES.INFO.NODE_COPY.SINGULAR', 'APP.ACTIONS.UNDO', 10000], ['APP.MESSAGES.ERRORS.GENERIC', '', 3000]]); }); it('notifies when some error of type Error occurs on Undo action', () => { - spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.throw(new Error('oops!'))); + spyOn(contentApi, 'deleteNode').and.returnValue(Observable.throw(new Error('oops!'))); component.selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }]; const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }]; @@ -304,14 +306,14 @@ describe('NodeCopyDirective', () => { service.contentCopied.next(createdItems); expect(service.copyNodes).toHaveBeenCalled(); - expect(nodesApiService.deleteNode).toHaveBeenCalled(); + expect(contentApi.deleteNode).toHaveBeenCalled(); expect(notificationService.openSnackMessageAction['calls'].allArgs()) .toEqual([['APP.MESSAGES.INFO.NODE_COPY.SINGULAR', 'APP.ACTIONS.UNDO', 10000], ['APP.MESSAGES.ERRORS.GENERIC', '', 3000]]); }); it('notifies permission error when it occurs on Undo action', () => { - spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.throw(new Error(JSON.stringify({error: {statusCode: 403}})))); + spyOn(contentApi, 'deleteNode').and.returnValue(Observable.throw(new Error(JSON.stringify({error: {statusCode: 403}})))); component.selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }]; const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }]; @@ -321,7 +323,7 @@ describe('NodeCopyDirective', () => { service.contentCopied.next(createdItems); expect(service.copyNodes).toHaveBeenCalled(); - expect(nodesApiService.deleteNode).toHaveBeenCalled(); + expect(contentApi.deleteNode).toHaveBeenCalled(); expect(notificationService.openSnackMessageAction['calls'].allArgs()) .toEqual([['APP.MESSAGES.INFO.NODE_COPY.SINGULAR', 'APP.ACTIONS.UNDO', 10000], ['APP.MESSAGES.ERRORS.PERMISSION', '', 3000]]); diff --git a/src/app/common/directives/node-copy.directive.ts b/src/app/common/directives/node-copy.directive.ts index 308403c3b8..461b79382e 100644 --- a/src/app/common/directives/node-copy.directive.ts +++ b/src/app/common/directives/node-copy.directive.ts @@ -26,10 +26,11 @@ import { Directive, HostListener, Input } from '@angular/core'; import { Observable } from 'rxjs/Rx'; -import { TranslationService, NodesApiService, NotificationService } from '@alfresco/adf-core'; +import { TranslationService, NotificationService } from '@alfresco/adf-core'; import { MinimalNodeEntity } from 'alfresco-js-api'; import { NodeActionsService } from '../services/node-actions.service'; import { ContentManagementService } from '../services/content-management.service'; +import { ContentApiService } from '../../services/content-api.service'; @Directive({ selector: '[acaCopyNode]' @@ -47,9 +48,9 @@ export class NodeCopyDirective { constructor( private content: ContentManagementService, + private contentApi: ContentApiService, private notification: NotificationService, private nodeActionsService: NodeActionsService, - private nodesApi: NodesApiService, private translation: TranslationService ) {} @@ -117,7 +118,7 @@ export class NodeCopyDirective { private deleteCopy(nodes: MinimalNodeEntity[]) { const batch = this.nodeActionsService.flatten(nodes) .filter(item => item.entry) - .map(item => this.nodesApi.deleteNode(item.entry.id, { permanent: true })); + .map(item => this.contentApi.deleteNode(item.entry.id, { permanent: true })); Observable.forkJoin(...batch) .subscribe( diff --git a/src/app/common/directives/node-delete.directive.spec.ts b/src/app/common/directives/node-delete.directive.spec.ts index 6a1c3f8667..a9087766b6 100644 --- a/src/app/common/directives/node-delete.directive.spec.ts +++ b/src/app/common/directives/node-delete.directive.spec.ts @@ -25,7 +25,6 @@ import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { AlfrescoApiService } from '@alfresco/adf-core'; import { Component, DebugElement } from '@angular/core'; import { NodeDeleteDirective } from './node-delete.directive'; @@ -37,6 +36,8 @@ import { } from '../../store/actions'; import { map } from 'rxjs/operators'; import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; +import { Observable } from 'rxjs/Rx'; @Component({ template: '
' @@ -49,8 +50,8 @@ describe('NodeDeleteDirective', () => { let component: TestComponent; let fixture: ComponentFixture; let element: DebugElement; - let alfrescoApiService: AlfrescoApiService; let actions$: Actions; + let contentApi: ContentApiService; beforeEach(() => { TestBed.configureTestingModule({ @@ -64,9 +65,7 @@ describe('NodeDeleteDirective', () => { ] }); - alfrescoApiService = TestBed.get(AlfrescoApiService); - alfrescoApiService.reset(); - + contentApi = TestBed.get(ContentApiService); actions$ = TestBed.get(Actions); fixture = TestBed.createComponent(TestComponent); @@ -76,7 +75,7 @@ describe('NodeDeleteDirective', () => { describe('Delete action', () => { it('should raise info message on successful single file deletion', fakeAsync(done => { - spyOn(alfrescoApiService.nodesApi, 'deleteNode').and.returnValue(Promise.resolve(null)); + spyOn(contentApi, 'deleteNode').and.returnValue(Observable.of(null)); actions$.pipe( ofType(SNACKBAR_INFO), @@ -94,7 +93,7 @@ describe('NodeDeleteDirective', () => { })); it('should raise error message on failed single file deletion', fakeAsync(done => { - spyOn(alfrescoApiService.nodesApi, 'deleteNode').and.returnValue(Promise.reject(null)); + spyOn(contentApi, 'deleteNode').and.returnValue(Observable.throw(null)); actions$.pipe( ofType(SNACKBAR_ERROR), @@ -112,7 +111,7 @@ describe('NodeDeleteDirective', () => { })); it('should raise info message on successful multiple files deletion', fakeAsync(done => { - spyOn(alfrescoApiService.nodesApi, 'deleteNode').and.returnValue(Promise.resolve(null)); + spyOn(contentApi, 'deleteNode').and.returnValue(Observable.of(null)); actions$.pipe( ofType(SNACKBAR_INFO), @@ -133,7 +132,7 @@ describe('NodeDeleteDirective', () => { })); it('should raise error message failed multiple files deletion', fakeAsync(done => { - spyOn(alfrescoApiService.nodesApi, 'deleteNode').and.returnValue(Promise.reject(null)); + spyOn(contentApi, 'deleteNode').and.returnValue(Observable.throw(null)); actions$.pipe( ofType(SNACKBAR_ERROR), @@ -154,11 +153,11 @@ describe('NodeDeleteDirective', () => { })); it('should raise warning message when only one file is successful', fakeAsync(done => { - spyOn(alfrescoApiService.nodesApi, 'deleteNode').and.callFake((id) => { + spyOn(contentApi, 'deleteNode').and.callFake((id) => { if (id === '1') { - return Promise.reject(null); + return Observable.throw(null); } else { - return Promise.resolve(null); + return Observable.of(null); } }); @@ -181,17 +180,17 @@ describe('NodeDeleteDirective', () => { })); it('should raise warning message when some files are successfully deleted', fakeAsync(done => { - spyOn(alfrescoApiService.nodesApi, 'deleteNode').and.callFake((id) => { + spyOn(contentApi, 'deleteNode').and.callFake((id) => { if (id === '1') { - return Promise.reject(null); + return Observable.throw(null); } if (id === '2') { - return Promise.resolve(null); + return Observable.of(null); } if (id === '3') { - return Promise.resolve(null); + return Observable.of(null); } }); diff --git a/src/app/common/directives/node-move.directive.spec.ts b/src/app/common/directives/node-move.directive.spec.ts index 32e3404aff..fc9cb7af55 100644 --- a/src/app/common/directives/node-move.directive.spec.ts +++ b/src/app/common/directives/node-move.directive.spec.ts @@ -27,7 +27,7 @@ import { Component, DebugElement } from '@angular/core'; import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { Observable } from 'rxjs/Rx'; -import { NodesApiService, NotificationService, TranslationService } from '@alfresco/adf-core'; +import { NotificationService, TranslationService } from '@alfresco/adf-core'; import { NodeActionsService } from '../services/node-actions.service'; import { NodeMoveDirective } from './node-move.directive'; import { EffectsModule, Actions, ofType } from '@ngrx/effects'; @@ -35,6 +35,7 @@ import { NodeEffects } from '../../store/effects/node.effects'; import { SnackbarErrorAction, SNACKBAR_ERROR } from '../../store/actions'; import { map } from 'rxjs/operators'; import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; @Component({ template: '
' @@ -48,10 +49,10 @@ describe('NodeMoveDirective', () => { let component: TestComponent; let element: DebugElement; let notificationService: NotificationService; - let nodesApiService: NodesApiService; let service: NodeActionsService; let actions$: Actions; let translationService: TranslationService; + let contentApi: ContentApiService; beforeEach(() => { TestBed.configureTestingModule({ @@ -65,6 +66,7 @@ describe('NodeMoveDirective', () => { ] }); + contentApi = TestBed.get(ContentApiService); translationService = TestBed.get(TranslationService); actions$ = TestBed.get(Actions); @@ -72,7 +74,6 @@ describe('NodeMoveDirective', () => { component = fixture.componentInstance; element = fixture.debugElement.query(By.directive(NodeMoveDirective)); notificationService = TestBed.get(NotificationService); - nodesApiService = TestBed.get(NodesApiService); service = TestBed.get(NodeActionsService); }); @@ -382,7 +383,7 @@ describe('NodeMoveDirective', () => { it('should restore deleted folder back to initial parent, after succeeded moving all its files', () => { // when folder was deleted after all its children were moved to a folder with the same name from destination - spyOn(nodesApiService, 'restoreNode').and.returnValue(Observable.of(null)); + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.of(null)); const initialParent = 'parent-id-0'; const node = { entry: { id: 'folder-to-move-id', name: 'conflicting-name', parentId: initialParent, isFolder: true } }; @@ -401,13 +402,13 @@ describe('NodeMoveDirective', () => { element.triggerEventHandler('click', null); service.contentMoved.next(movedItems); - expect(nodesApiService.restoreNode).toHaveBeenCalled(); + expect(contentApi.restoreNode).toHaveBeenCalled(); expect(notificationService.openSnackMessageAction) .toHaveBeenCalledWith('APP.MESSAGES.INFO.NODE_MOVE.SINGULAR', 'APP.ACTIONS.UNDO', 10000); }); it('should notify when error occurs on Undo Move action', fakeAsync(done => { - spyOn(nodesApiService, 'restoreNode').and.returnValue(Observable.throw(null)); + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.throw(null)); actions$.pipe( ofType(SNACKBAR_ERROR), @@ -432,11 +433,11 @@ describe('NodeMoveDirective', () => { element.triggerEventHandler('click', null); service.contentMoved.next(movedItems); - expect(nodesApiService.restoreNode).toHaveBeenCalled(); + expect(contentApi.restoreNode).toHaveBeenCalled(); })); it('should notify when some error of type Error occurs on Undo Move action', fakeAsync(done => { - spyOn(nodesApiService, 'restoreNode').and.returnValue(Observable.throw(new Error('oops!'))); + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.throw(new Error('oops!'))); actions$.pipe( ofType(SNACKBAR_ERROR), @@ -460,11 +461,11 @@ describe('NodeMoveDirective', () => { element.triggerEventHandler('click', null); service.contentMoved.next(movedItems); - expect(nodesApiService.restoreNode).toHaveBeenCalled(); + expect(contentApi.restoreNode).toHaveBeenCalled(); })); it('should notify permission error when it occurs on Undo Move action', fakeAsync(done => { - spyOn(nodesApiService, 'restoreNode').and.returnValue(Observable.throw(new Error(JSON.stringify({error: {statusCode: 403}})))); + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.throw(new Error(JSON.stringify({error: {statusCode: 403}})))); actions$.pipe( ofType(SNACKBAR_ERROR), @@ -489,7 +490,7 @@ describe('NodeMoveDirective', () => { service.contentMoved.next(movedItems); expect(service.moveNodes).toHaveBeenCalled(); - expect(nodesApiService.restoreNode).toHaveBeenCalled(); + expect(contentApi.restoreNode).toHaveBeenCalled(); })); }); diff --git a/src/app/common/directives/node-move.directive.ts b/src/app/common/directives/node-move.directive.ts index e95cca93cb..a9b60669be 100644 --- a/src/app/common/directives/node-move.directive.ts +++ b/src/app/common/directives/node-move.directive.ts @@ -25,7 +25,7 @@ import { Directive, HostListener, Input } from '@angular/core'; -import { TranslationService, NodesApiService, NotificationService } from '@alfresco/adf-core'; +import { TranslationService, NotificationService } from '@alfresco/adf-core'; import { MinimalNodeEntity } from 'alfresco-js-api'; import { ContentManagementService } from '../services/content-management.service'; @@ -34,6 +34,7 @@ import { Observable } from 'rxjs/Rx'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; import { SnackbarErrorAction } from '../../store/actions'; +import { ContentApiService } from '../../services/content-api.service'; @Directive({ selector: '[acaMoveNode]' @@ -51,10 +52,10 @@ export class NodeMoveDirective { constructor( private store: Store, + private contentApi: ContentApiService, private content: ContentManagementService, private notification: NotificationService, private nodeActionsService: NodeActionsService, - private nodesApi: NodesApiService, private translation: TranslationService ) {} @@ -173,7 +174,9 @@ export class NodeMoveDirective { const restoreDeletedNodesBatch = this.nodeActionsService.moveDeletedEntries .map((folderEntry) => { - return this.nodesApi.restoreNode(folderEntry.nodeId || folderEntry.id); + return this.contentApi + .restoreNode(folderEntry.nodeId || folderEntry.id) + .map(node => node.entry); }); Observable.zip(...restoreDeletedNodesBatch, Observable.of(null)) diff --git a/src/app/common/directives/node-permanent-delete.directive.spec.ts b/src/app/common/directives/node-permanent-delete.directive.spec.ts index 66f6ad5d5f..efde1230f3 100644 --- a/src/app/common/directives/node-permanent-delete.directive.spec.ts +++ b/src/app/common/directives/node-permanent-delete.directive.spec.ts @@ -27,7 +27,6 @@ import { Component, DebugElement } from '@angular/core'; import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { Observable } from 'rxjs/Rx'; -import { AlfrescoApiService } from '@alfresco/adf-core'; import { NodePermanentDeleteDirective } from './node-permanent-delete.directive'; import { MatDialog } from '@angular/material'; @@ -39,6 +38,7 @@ import { import { map } from 'rxjs/operators'; import { NodeEffects } from '../../store/effects/node.effects'; import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; @Component({ template: `
` @@ -51,9 +51,9 @@ describe('NodePermanentDeleteDirective', () => { let fixture: ComponentFixture; let element: DebugElement; let component: TestComponent; - let alfrescoApiService: AlfrescoApiService; let dialog: MatDialog; let actions$: Actions; + let contentApi: ContentApiService; beforeEach(() => { TestBed.configureTestingModule({ @@ -67,9 +67,7 @@ describe('NodePermanentDeleteDirective', () => { ] }); - alfrescoApiService = TestBed.get(AlfrescoApiService); - alfrescoApiService.reset(); - + contentApi = TestBed.get(ContentApiService); actions$ = TestBed.get(Actions); fixture = TestBed.createComponent(TestComponent); @@ -85,18 +83,18 @@ describe('NodePermanentDeleteDirective', () => { }); it('does not purge nodes if no selection', () => { - spyOn(alfrescoApiService.nodesApi, 'purgeDeletedNode'); + spyOn(contentApi, 'purgeDeletedNode'); component.selection = []; fixture.detectChanges(); element.triggerEventHandler('click', null); - expect(alfrescoApiService.nodesApi.purgeDeletedNode).not.toHaveBeenCalled(); + expect(contentApi.purgeDeletedNode).not.toHaveBeenCalled(); }); it('call purge nodes if selection is not empty', fakeAsync(() => { - spyOn(alfrescoApiService.nodesApi, 'purgeDeletedNode').and.returnValue(Promise.resolve()); + spyOn(contentApi, 'purgeDeletedNode').and.returnValue(Observable.of({})); component.selection = [ { entry: { id: '1' } } ]; @@ -104,7 +102,7 @@ describe('NodePermanentDeleteDirective', () => { element.triggerEventHandler('click', null); tick(); - expect(alfrescoApiService.nodesApi.purgeDeletedNode).toHaveBeenCalled(); + expect(contentApi.purgeDeletedNode).toHaveBeenCalled(); })); describe('notification', () => { @@ -116,17 +114,17 @@ describe('NodePermanentDeleteDirective', () => { }) ); - spyOn(alfrescoApiService.nodesApi, 'purgeDeletedNode').and.callFake((id) => { + spyOn(contentApi, 'purgeDeletedNode').and.callFake((id) => { if (id === '1') { - return Promise.resolve(); + return Observable.of({}); } if (id === '2') { - return Promise.reject({}); + return Observable.throw({}); } if (id === '3') { - return Promise.reject({}); + return Observable.throw({}); } }); @@ -149,21 +147,21 @@ describe('NodePermanentDeleteDirective', () => { }) ); - spyOn(alfrescoApiService.nodesApi, 'purgeDeletedNode').and.callFake((id) => { + spyOn(contentApi, 'purgeDeletedNode').and.callFake((id) => { if (id === '1') { - return Promise.resolve(); + return Observable.of({}); } if (id === '2') { - return Promise.reject({}); + return Observable.throw({}); } if (id === '3') { - return Promise.reject({}); + return Observable.throw({}); } if (id === '4') { - return Promise.resolve(); + return Observable.of({}); } }); @@ -187,7 +185,7 @@ describe('NodePermanentDeleteDirective', () => { }) ); - spyOn(alfrescoApiService.nodesApi, 'purgeDeletedNode').and.returnValue(Promise.resolve()); + spyOn(contentApi, 'purgeDeletedNode').and.returnValue(Observable.of({})); component.selection = [ { entry: { id: '1', name: 'name1' } } @@ -206,7 +204,7 @@ describe('NodePermanentDeleteDirective', () => { }) ); - spyOn(alfrescoApiService.nodesApi, 'purgeDeletedNode').and.returnValue(Promise.reject({})); + spyOn(contentApi, 'purgeDeletedNode').and.returnValue(Observable.throw({})); component.selection = [ { entry: { id: '1', name: 'name1' } } @@ -224,13 +222,13 @@ describe('NodePermanentDeleteDirective', () => { done(); }) ); - spyOn(alfrescoApiService.nodesApi, 'purgeDeletedNode').and.callFake((id) => { + spyOn(contentApi, 'purgeDeletedNode').and.callFake((id) => { if (id === '1') { - return Promise.resolve(); + return Observable.of({}); } if (id === '2') { - return Promise.resolve(); + return Observable.of({}); } }); @@ -251,13 +249,13 @@ describe('NodePermanentDeleteDirective', () => { done(); }) ); - spyOn(alfrescoApiService.nodesApi, 'purgeDeletedNode').and.callFake((id) => { + spyOn(contentApi, 'purgeDeletedNode').and.callFake((id) => { if (id === '1') { - return Promise.reject({}); + return Observable.throw({}); } if (id === '2') { - return Promise.reject({}); + return Observable.throw({}); } }); diff --git a/src/app/common/directives/node-restore.directive.spec.ts b/src/app/common/directives/node-restore.directive.spec.ts index d657ff8837..620c22ec9c 100644 --- a/src/app/common/directives/node-restore.directive.spec.ts +++ b/src/app/common/directives/node-restore.directive.spec.ts @@ -26,7 +26,6 @@ import { Component, DebugElement } from '@angular/core'; import { TestBed, ComponentFixture, fakeAsync, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { AlfrescoApiService } from '@alfresco/adf-core'; import { NodeRestoreDirective } from './node-restore.directive'; import { ContentManagementService } from '../services/content-management.service'; import { Actions, ofType } from '@ngrx/effects'; @@ -35,6 +34,8 @@ import { SnackbarErrorAction, NavigateRouteAction, NAVIGATE_ROUTE } from '../../store/actions'; import { map } from 'rxjs/operators'; import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; +import { Observable } from 'rxjs/Rx'; @Component({ template: `
` @@ -47,10 +48,10 @@ describe('NodeRestoreDirective', () => { let fixture: ComponentFixture; let element: DebugElement; let component: TestComponent; - let alfrescoService: AlfrescoApiService; let directiveInstance: NodeRestoreDirective; let contentManagementService: ContentManagementService; let actions$: Actions; + let contentApi: ContentApiService; beforeEach(() => { TestBed.configureTestingModule({ @@ -63,43 +64,41 @@ describe('NodeRestoreDirective', () => { actions$ = TestBed.get(Actions); - alfrescoService = TestBed.get(AlfrescoApiService); - alfrescoService.reset(); - fixture = TestBed.createComponent(TestComponent); component = fixture.componentInstance; element = fixture.debugElement.query(By.directive(NodeRestoreDirective)); directiveInstance = element.injector.get(NodeRestoreDirective); contentManagementService = TestBed.get(ContentManagementService); + contentApi = TestBed.get(ContentApiService); }); it('does not restore nodes if no selection', () => { - spyOn(alfrescoService.nodesApi, 'restoreNode'); + spyOn(contentApi, 'restoreNode'); component.selection = []; fixture.detectChanges(); element.triggerEventHandler('click', null); - expect(alfrescoService.nodesApi.restoreNode).not.toHaveBeenCalled(); + expect(contentApi.restoreNode).not.toHaveBeenCalled(); }); it('does not restore nodes if selection has nodes without path', () => { - spyOn(alfrescoService.nodesApi, 'restoreNode'); + spyOn(contentApi, 'restoreNode'); component.selection = [ { entry: { id: '1' } } ]; fixture.detectChanges(); element.triggerEventHandler('click', null); - expect(alfrescoService.nodesApi.restoreNode).not.toHaveBeenCalled(); + expect(contentApi.restoreNode).not.toHaveBeenCalled(); }); it('call restore nodes if selection has nodes with path', fakeAsync(() => { spyOn(directiveInstance, 'restoreNotification').and.callFake(() => null); - spyOn(alfrescoService.nodesApi, 'restoreNode').and.returnValue(Promise.resolve()); - spyOn(alfrescoService.nodesApi, 'getDeletedNodes').and.returnValue(Promise.resolve({ + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.of({})); + spyOn(contentApi, 'getDeletedNodes').and.returnValue(Observable.of({ list: { entries: [] } })); @@ -109,14 +108,14 @@ describe('NodeRestoreDirective', () => { element.triggerEventHandler('click', null); tick(); - expect(alfrescoService.nodesApi.restoreNode).toHaveBeenCalled(); + expect(contentApi.restoreNode).toHaveBeenCalled(); })); describe('refresh()', () => { it('dispatch event on finish', fakeAsync(done => { spyOn(directiveInstance, 'restoreNotification').and.callFake(() => null); - spyOn(alfrescoService.nodesApi, 'restoreNode').and.returnValue(Promise.resolve()); - spyOn(alfrescoService.nodesApi, 'getDeletedNodes').and.returnValue(Promise.resolve({ + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.of({})); + spyOn(contentApi, 'getDeletedNodes').and.returnValue(Observable.of({ list: { entries: [] } })); @@ -132,7 +131,7 @@ describe('NodeRestoreDirective', () => { describe('notification', () => { beforeEach(() => { - spyOn(alfrescoService.nodesApi, 'getDeletedNodes').and.returnValue(Promise.resolve({ + spyOn(contentApi, 'getDeletedNodes').and.returnValue(Observable.of({ list: { entries: [] } })); }); @@ -145,17 +144,17 @@ describe('NodeRestoreDirective', () => { map(action => done()) ); - spyOn(alfrescoService.nodesApi, 'restoreNode').and.callFake((id) => { + spyOn(contentApi, 'restoreNode').and.callFake((id) => { if (id === '1') { - return Promise.resolve(); + return Observable.of({}); } if (id === '2') { - return Promise.reject(error); + return Observable.throw(error); } if (id === '3') { - return Promise.reject(error); + return Observable.throw(error); } }); @@ -172,7 +171,7 @@ describe('NodeRestoreDirective', () => { it('should raise error message when restored node exist, error 409', fakeAsync(done => { const error = { message: '{ "error": { "statusCode": 409 } }' }; - spyOn(alfrescoService.nodesApi, 'restoreNode').and.returnValue(Promise.reject(error)); + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.throw(error)); actions$.pipe( ofType(SNACKBAR_ERROR), @@ -191,7 +190,7 @@ describe('NodeRestoreDirective', () => { it('should raise error message when restored node returns different statusCode', fakeAsync(done => { const error = { message: '{ "error": { "statusCode": 404 } }' }; - spyOn(alfrescoService.nodesApi, 'restoreNode').and.returnValue(Promise.reject(error)); + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.throw(error)); actions$.pipe( ofType(SNACKBAR_ERROR), @@ -210,7 +209,7 @@ describe('NodeRestoreDirective', () => { it('should raise error message when restored node location is missing', fakeAsync(done => { const error = { message: '{ "error": { } }' }; - spyOn(alfrescoService.nodesApi, 'restoreNode').and.returnValue(Promise.reject(error)); + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.throw(error)); actions$.pipe( ofType(SNACKBAR_ERROR), @@ -227,13 +226,13 @@ describe('NodeRestoreDirective', () => { })); it('should raise info message when restore multiple nodes', fakeAsync(done => { - spyOn(alfrescoService.nodesApi, 'restoreNode').and.callFake((id) => { + spyOn(contentApi, 'restoreNode').and.callFake((id) => { if (id === '1') { - return Promise.resolve(); + return Observable.of({}); } if (id === '2') { - return Promise.resolve(); + return Observable.of({}); } }); @@ -253,7 +252,7 @@ describe('NodeRestoreDirective', () => { })); xit('should raise info message when restore selected node', fakeAsync(done => { - spyOn(alfrescoService.nodesApi, 'restoreNode').and.returnValue(Promise.resolve()); + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.of({})); actions$.pipe( ofType(SNACKBAR_INFO), @@ -270,7 +269,7 @@ describe('NodeRestoreDirective', () => { })); it('navigate to restore selected node location onAction', fakeAsync(done => { - spyOn(alfrescoService.nodesApi, 'restoreNode').and.returnValue(Promise.resolve()); + spyOn(contentApi, 'restoreNode').and.returnValue(Observable.of({})); actions$.pipe( ofType(NAVIGATE_ROUTE), diff --git a/src/app/common/directives/node-restore.directive.ts b/src/app/common/directives/node-restore.directive.ts index e5e4c1c74a..ddacb0b284 100644 --- a/src/app/common/directives/node-restore.directive.ts +++ b/src/app/common/directives/node-restore.directive.ts @@ -25,8 +25,6 @@ import { Directive, HostListener, Input } from '@angular/core'; import { Observable } from 'rxjs/Rx'; - -import { AlfrescoApiService } from '@alfresco/adf-core'; import { MinimalNodeEntity, MinimalNodeEntryEntity, @@ -44,6 +42,7 @@ import { SnackbarInfoAction, SnackbarUserAction } from '../../store/actions'; +import { ContentApiService } from '../../services/content-api.service'; @Directive({ selector: '[acaRestoreNode]' @@ -59,7 +58,7 @@ export class NodeRestoreDirective { constructor( private store: Store, - private alfrescoApiService: AlfrescoApiService, + private contentApi: ContentApiService, private contentManagementService: ContentManagementService ) {} @@ -84,7 +83,7 @@ export class NodeRestoreDirective { .do(restoredNodes => { status = this.processStatus(restoredNodes); }) - .flatMap(() => this.getDeletedNodes()) + .flatMap(() => this.contentApi.getDeletedNodes()) .subscribe((nodes: DeletedNodesPaging) => { const selectedNodes = this.diff(status.fail, selection, false); const remainingNodes = this.diff( @@ -101,20 +100,10 @@ export class NodeRestoreDirective { }); } - private getDeletedNodes(): Observable { - return Observable.from( - this.alfrescoApiService.nodesApi.getDeletedNodes({ - include: ['path'] - }) - ); - } - private restoreNode(node: MinimalNodeEntity): Observable { const { entry } = node; - return Observable.from( - this.alfrescoApiService.nodesApi.restoreNode(entry.id) - ) + return this.contentApi.restoreNode(entry.id) .map(() => ({ status: 1, entry diff --git a/src/app/common/directives/node-unshare.directive.ts b/src/app/common/directives/node-unshare.directive.ts index 75f4af345d..19fdedfa74 100644 --- a/src/app/common/directives/node-unshare.directive.ts +++ b/src/app/common/directives/node-unshare.directive.ts @@ -23,9 +23,10 @@ * along with Alfresco. If not, see . */ -import { Directive, HostListener, Input, ElementRef } from '@angular/core'; -import { AlfrescoApiService } from '@alfresco/adf-core'; +import { Directive, HostListener, Input } from '@angular/core'; import { MinimalNodeEntity } from 'alfresco-js-api'; +import { ContentManagementService } from '../services/content-management.service'; +import { ContentApiService } from '../../services/content-api.service'; @Directive({ selector: '[acaUnshareNode]' @@ -37,8 +38,8 @@ export class NodeUnshareDirective { selection: MinimalNodeEntity[]; constructor( - private apiService: AlfrescoApiService, - private el: ElementRef) { + private contentApi: ContentApiService, + private contentManagement: ContentManagementService) { } @HostListener('click') @@ -49,14 +50,8 @@ export class NodeUnshareDirective { } private async unshareLinks(links: MinimalNodeEntity[]) { - const promises = links.map(link => this.apiService.sharedLinksApi.deleteSharedLink(link.entry.id)); + const promises = links.map(link => this.contentApi.deleteSharedLink(link.entry.id).toPromise()); await Promise.all(promises); - this.emitDone(); + this.contentManagement.linksUnshared.next(); } - - private emitDone() { - const e = new CustomEvent('links-unshared', { bubbles: true }); - this.el.nativeElement.dispatchEvent(e); - } - } diff --git a/src/app/common/directives/node-versions.directive.ts b/src/app/common/directives/node-versions.directive.ts index d3b4103b8c..cb8ff2c22c 100644 --- a/src/app/common/directives/node-versions.directive.ts +++ b/src/app/common/directives/node-versions.directive.ts @@ -24,15 +24,13 @@ */ import { Directive, HostListener, Input } from '@angular/core'; - -import { AlfrescoApiService } from '@alfresco/adf-core'; import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; - import { NodeVersionsDialogComponent } from '../../dialogs/node-versions/node-versions.dialog'; import { MatDialog } from '@angular/material'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; import { SnackbarErrorAction } from '../../store/actions'; +import { ContentApiService } from '../../services/content-api.service'; @Directive({ selector: '[acaNodeVersions]' @@ -48,7 +46,7 @@ export class NodeVersionsDirective { constructor( private store: Store, - private apiService: AlfrescoApiService, + private contentApi: ContentApiService, private dialog: MatDialog ) {} @@ -57,10 +55,9 @@ export class NodeVersionsDirective { let entry = this.node.entry; if (entry.nodeId || (entry).guid) { - entry = await this.apiService.nodesApi.getNodeInfo( - entry.nodeId || (entry).id, - { include: ['allowableOperations'] } - ); + entry = await this.contentApi.getNodeInfo( + entry.nodeId || (entry).id + ).toPromise(); this.openVersionManagerDialog(entry); } else { this.openVersionManagerDialog(entry); diff --git a/src/app/common/services/content-management.service.ts b/src/app/common/services/content-management.service.ts index 032b8231be..0d9e7284a5 100644 --- a/src/app/common/services/content-management.service.ts +++ b/src/app/common/services/content-management.service.ts @@ -35,4 +35,5 @@ export class ContentManagementService { folderEdited = new Subject(); folderCreated = new Subject(); siteDeleted = new Subject(); + linksUnshared = new Subject(); } diff --git a/src/app/common/services/node-actions.service.spec.ts b/src/app/common/services/node-actions.service.spec.ts index c3037f4a39..9902a7ce39 100644 --- a/src/app/common/services/node-actions.service.spec.ts +++ b/src/app/common/services/node-actions.service.spec.ts @@ -24,21 +24,14 @@ */ import { TestBed, async } from '@angular/core/testing'; -import { MatDialog, MatDialogModule, MatIconModule } from '@angular/material'; -import { OverlayModule } from '@angular/cdk/overlay'; +import { MatDialog } from '@angular/material'; import { Observable } from 'rxjs/Rx'; -import { - TranslationMock, AlfrescoApiService, NodesApiService, - TranslationService, ContentService, AuthenticationService, - UserPreferencesService, AppConfigService, StorageService, - CookieService, LogService, ThumbnailService -} from '@alfresco/adf-core'; +import { AlfrescoApiService, TranslationService } from '@alfresco/adf-core'; import { DocumentListService } from '@alfresco/adf-content-services'; - import { NodeActionsService } from './node-actions.service'; import { MinimalNodeEntryEntity } from 'alfresco-js-api'; -import { TranslateModule } from '@ngx-translate/core'; -import { HttpClientModule } from '@angular/common/http'; +import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; class TestNode { entry?: MinimalNodeEntryEntity; @@ -67,10 +60,10 @@ describe('NodeActionsService', () => { const emptyChildrenList = {list: {entries: []}}; let service: NodeActionsService; let apiService: AlfrescoApiService; - let nodesApiService: NodesApiService; let nodesApi; const spyOnSuccess = jasmine.createSpy('spyOnSuccess'); const spyOnError = jasmine.createSpy('spyOnError'); + let contentApi: ContentApiService; const helper = { fakeCopyNode: (isForbidden: boolean = false, nameExistingOnDestination?: string) => { @@ -110,33 +103,16 @@ describe('NodeActionsService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ - MatDialogModule, - MatIconModule, - HttpClientModule, - TranslateModule.forRoot(), - OverlayModule - ], - providers: [ - AlfrescoApiService, - NodesApiService, - { provide: TranslationService, useClass: TranslationMock }, - AuthenticationService, - UserPreferencesService, - AppConfigService, - CookieService, - LogService, - ThumbnailService, - StorageService, - ContentService, - DocumentListService, - NodeActionsService + AppTestingModule ] }); + contentApi = TestBed.get(ContentApiService); + service = TestBed.get(NodeActionsService); apiService = TestBed.get(AlfrescoApiService); apiService.reset(); - nodesApiService = TestBed.get(NodesApiService); + nodesApi = apiService.getInstance().nodes; }); @@ -884,7 +860,7 @@ describe('NodeActionsService', () => { beforeEach(() => { parentFolderToMove = new TestNode('parent-folder', !isFile, 'conflicting-name'); - spyOnDelete = spyOn(nodesApiService, 'deleteNode').and.returnValue(Observable.of(null)); + spyOnDelete = spyOn(contentApi, 'deleteNode').and.returnValue(Observable.of(null)); }); afterEach(() => { diff --git a/src/app/common/services/node-actions.service.ts b/src/app/common/services/node-actions.service.ts index 68e52b0df6..1d49bf082a 100644 --- a/src/app/common/services/node-actions.service.ts +++ b/src/app/common/services/node-actions.service.ts @@ -27,9 +27,10 @@ import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material'; import { Observable, Subject } from 'rxjs/Rx'; -import { AlfrescoApiService, ContentService, NodesApiService, DataColumn, TranslationService } from '@alfresco/adf-core'; +import { AlfrescoApiService, ContentService, DataColumn, TranslationService } from '@alfresco/adf-core'; import { DocumentListService, ContentNodeSelectorComponent, ContentNodeSelectorComponentData } from '@alfresco/adf-content-services'; import { MinimalNodeEntity, MinimalNodeEntryEntity, SitePaging } from 'alfresco-js-api'; +import { ContentApiService } from '../../services/content-api.service'; @Injectable() export class NodeActionsService { @@ -42,10 +43,10 @@ export class NodeActionsService { isSitesDestinationAvailable = false; constructor(private contentService: ContentService, + private contentApi: ContentApiService, private dialog: MatDialog, private documentListService: DocumentListService, private apiService: AlfrescoApiService, - private nodesApi: NodesApiService, private translation: TranslationService) {} /** @@ -422,7 +423,7 @@ export class NodeActionsService { // Check if there's nodeId for Shared Files const nodeEntryId = nodeEntry.nodeId || nodeEntry.id; // delete it from location - return this.nodesApi.deleteNode(nodeEntryId) + return this.contentApi.deleteNode(nodeEntryId) .flatMap(() => { this.moveDeletedEntries.push(nodeEntry); return Observable.of(newContent); diff --git a/src/app/common/services/profile.resolver.ts b/src/app/common/services/profile.resolver.ts index ec169d83d3..85508f0054 100644 --- a/src/app/common/services/profile.resolver.ts +++ b/src/app/common/services/profile.resolver.ts @@ -26,31 +26,26 @@ import { Store } from '@ngrx/store'; import { Injectable } from '@angular/core'; import { Resolve } from '@angular/router'; +import { Person } from 'alfresco-js-api'; import { Observable } from 'rxjs/Observable'; - import { AppStore } from '../../store/states/app.state'; import { SetUserAction } from '../../store/actions/user.actions'; -import { selectUser } from '../../store/selectors/app.selectors'; -import { PeopleContentService } from '@alfresco/adf-core'; +import { ContentApiService } from '../../services/content-api.service'; @Injectable() -export class ProfileResolver implements Resolve { - constructor(private store: Store, private peopleApi: PeopleContentService) { } - - resolve(): Observable { - - this.init(); - - return this.profileLoaded(); - } - - profileLoaded(): Observable { - return this.store.select(selectUser).take(1); - } - - init(): void { - this.peopleApi.getCurrentPerson().subscribe((person: any) => { - this.store.dispatch(new SetUserAction(person.entry)); +export class ProfileResolver implements Resolve { + constructor( + private store: Store, + private contentApi: ContentApiService + ) {} + + resolve(): Observable { + return new Observable(observer => { + this.contentApi.getPerson('-me-').subscribe(person => { + this.store.dispatch(new SetUserAction(person.entry)); + observer.next(person.entry); + observer.complete(); + }); }); } } diff --git a/src/app/components/about/about.component.html b/src/app/components/about/about.component.html index ba1e413f5d..dfb666c477 100644 --- a/src/app/components/about/about.component.html +++ b/src/app/components/about/about.component.html @@ -1,9 +1,9 @@
-
+
Alfresco Content Services
-

version: {{ ecmVersion.edition }} {{ ecmVersion.version.display }}

+

version: {{ repository.edition }} {{ repository.version.display }}

diff --git a/src/app/components/about/about.component.ts b/src/app/components/about/about.component.ts index 0c55d3f131..3f4c0ae236 100644 --- a/src/app/components/about/about.component.ts +++ b/src/app/components/about/about.component.ts @@ -25,15 +25,16 @@ import { Component, OnInit } from '@angular/core'; import { Http } from '@angular/http'; -import { DiscoveryApiService } from '@alfresco/adf-core'; -import { EcmProductVersionModel, ObjectDataTableAdapter } from '@alfresco/adf-core'; +import { ObjectDataTableAdapter } from '@alfresco/adf-core'; +import { ContentApiService } from '../../services/content-api.service'; +import { RepositoryInfo } from 'alfresco-js-api'; @Component({ selector: 'app-about', templateUrl: './about.component.html' }) export class AboutComponent implements OnInit { - ecmVersion: EcmProductVersionModel = null; + repository: RepositoryInfo; data: ObjectDataTableAdapter; status: ObjectDataTableAdapter; license: ObjectDataTableAdapter; @@ -42,15 +43,17 @@ export class AboutComponent implements OnInit { releaseVersion = ''; constructor( - private discovery: DiscoveryApiService, + private contentApi: ContentApiService, private http: Http ) {} ngOnInit() { - this.discovery.getEcmProductInfo().subscribe((ecmVers) => { - this.ecmVersion = ecmVers; + this.contentApi.getRepositoryInformation() + .map(node => node.entry.repository) + .subscribe(repository => { + this.repository = repository; - this.modules = new ObjectDataTableAdapter(this.ecmVersion.modules, [ + this.modules = new ObjectDataTableAdapter(repository.modules, [ {type: 'text', key: 'id', title: 'ID', sortable: true}, {type: 'text', key: 'title', title: 'Title', sortable: true}, {type: 'text', key: 'version', title: 'Description', sortable: true}, @@ -60,14 +63,14 @@ export class AboutComponent implements OnInit { {type: 'text', key: 'versionMax', title: 'Version Max', sortable: true} ]); - this.status = new ObjectDataTableAdapter([this.ecmVersion.status], [ + this.status = new ObjectDataTableAdapter([repository.status], [ {type: 'text', key: 'isReadOnly', title: 'Read Only', sortable: true}, {type: 'text', key: 'isAuditEnabled', title: 'Audit Enable', sortable: true}, {type: 'text', key: 'isQuickShareEnabled', title: 'Quick Shared Enable', sortable: true}, {type: 'text', key: 'isThumbnailGenerationEnabled', title: 'Thumbnail Generation', sortable: true} ]); - this.license = new ObjectDataTableAdapter([this.ecmVersion.license], [ + this.license = new ObjectDataTableAdapter([repository.license], [ {type: 'date', key: 'issuedAt', title: 'Issued At', sortable: true}, {type: 'date', key: 'expiresAt', title: 'Expires At', sortable: true}, {type: 'text', key: 'remainingDays', title: 'Remaining Days', sortable: true}, diff --git a/src/app/components/favorites/favorites.component.spec.ts b/src/app/components/favorites/favorites.component.spec.ts index cdc54ccbc1..ae27594cd8 100644 --- a/src/app/components/favorites/favorites.component.spec.ts +++ b/src/app/components/favorites/favorites.component.spec.ts @@ -28,7 +28,6 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router } from '@angular/router'; import { TestBed, ComponentFixture } from '@angular/core/testing'; import { - NodesApiService, AlfrescoApiService, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe @@ -38,13 +37,14 @@ import { ContentManagementService } from '../../common/services/content-manageme import { FavoritesComponent } from './favorites.component'; import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; describe('FavoritesComponent', () => { let fixture: ComponentFixture; let component: FavoritesComponent; - let nodesApi: NodesApiService; let alfrescoApi: AlfrescoApiService; let contentService: ContentManagementService; + let contentApi: ContentApiService; let router: Router; let page; let node; @@ -93,11 +93,12 @@ describe('FavoritesComponent', () => { fixture = TestBed.createComponent(FavoritesComponent); component = fixture.componentInstance; - nodesApi = TestBed.get(NodesApiService); alfrescoApi = TestBed.get(AlfrescoApiService); alfrescoApi.reset(); spyOn(alfrescoApi.favoritesApi, 'getFavorites').and.returnValue(Promise.resolve(page)); + contentApi = TestBed.get(ContentApiService); + contentService = TestBed.get(ContentManagementService); router = TestBed.get(Router); }); @@ -135,7 +136,7 @@ describe('FavoritesComponent', () => { describe('Node navigation', () => { beforeEach(() => { - spyOn(nodesApi, 'getNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of({ entry: node})); spyOn(router, 'navigate'); fixture.detectChanges(); }); diff --git a/src/app/components/favorites/favorites.component.ts b/src/app/components/favorites/favorites.component.ts index 3d4a7912d7..98336e2e78 100644 --- a/src/app/components/favorites/favorites.component.ts +++ b/src/app/components/favorites/favorites.component.ts @@ -23,7 +23,6 @@ * along with Alfresco. If not, see . */ -import { NodesApiService } from '@alfresco/adf-core'; import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; @@ -37,6 +36,7 @@ import { ContentManagementService } from '../../common/services/content-manageme import { NodePermissionService } from '../../common/services/node-permission.service'; import { AppStore } from '../../store/states/app.state'; import { PageComponent } from '../page.component'; +import { ContentApiService } from '../../services/content-api.service'; @Component({ templateUrl: './favorites.component.html' @@ -45,7 +45,7 @@ export class FavoritesComponent extends PageComponent implements OnInit { constructor( private router: Router, store: Store, - private nodesApi: NodesApiService, + private contentApi: ContentApiService, private content: ContentManagementService, public permission: NodePermissionService ) { @@ -74,8 +74,9 @@ export class FavoritesComponent extends PageComponent implements OnInit { }; if (isFolder) { - this.nodesApi + this.contentApi .getNode(id) + .map(node => node.entry) .subscribe(({ path }: MinimalNodeEntryEntity) => { const routeUrl = isSitePath(path) ? '/libraries' diff --git a/src/app/components/files/files.component.spec.ts b/src/app/components/files/files.component.spec.ts index 226a17007c..88868b1508 100644 --- a/src/app/components/files/files.component.spec.ts +++ b/src/app/components/files/files.component.spec.ts @@ -28,7 +28,6 @@ import { TestBed, fakeAsync, tick, ComponentFixture } from '@angular/core/testin import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { - NodesApiService, TimeAgoPipe, NodeNameTooltipPipe, FileSizePipe, NodeFavoriteDirective, DataTableComponent, UploadService, AppConfigPipe } from '@alfresco/adf-core'; @@ -38,6 +37,7 @@ import { BrowsingFilesService } from '../../common/services/browsing-files.servi import { NodeActionsService } from '../../common/services/node-actions.service'; import { FilesComponent } from './files.component'; import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; describe('FilesComponent', () => { let node; @@ -46,10 +46,10 @@ describe('FilesComponent', () => { let component: FilesComponent; let contentManagementService: ContentManagementService; let uploadService: UploadService; - let nodesApi: NodesApiService; let router: Router; let browsingFilesService: BrowsingFilesService; let nodeActionsService: NodeActionsService; + let contentApi: ContentApiService; beforeAll(() => { // testing only functional-wise not time-wise @@ -83,10 +83,10 @@ describe('FilesComponent', () => { contentManagementService = TestBed.get(ContentManagementService); uploadService = TestBed.get(UploadService); - nodesApi = TestBed.get(NodesApiService); router = TestBed.get(Router); browsingFilesService = TestBed.get(BrowsingFilesService); nodeActionsService = TestBed.get(NodeActionsService); + contentApi = TestBed.get(ContentApiService); }); beforeEach(() => { @@ -103,7 +103,7 @@ describe('FilesComponent', () => { describe('Current page is valid', () => { it('should be a valid current page', fakeAsync(() => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of({ entry: node })); spyOn(component, 'fetchNodes').and.returnValue(Observable.throw(null)); component.ngOnInit(); @@ -114,7 +114,7 @@ describe('FilesComponent', () => { })); it('should set current page as invalid path', fakeAsync(() => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of({ entry: node })); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); component.ngOnInit(); @@ -127,7 +127,7 @@ describe('FilesComponent', () => { describe('OnInit', () => { it('should set current node', () => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of({ entry: node })); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); fixture.detectChanges(); @@ -136,7 +136,7 @@ describe('FilesComponent', () => { }); it('should get current node children', () => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of({ entry: node })); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); fixture.detectChanges(); @@ -145,7 +145,7 @@ describe('FilesComponent', () => { }); it('emits onChangeParent event', () => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of({ entry: node })); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); spyOn(browsingFilesService.onChangeParent, 'next').and.callFake((val) => val); @@ -158,7 +158,7 @@ describe('FilesComponent', () => { it('if should navigate to parent if node is not a folder', () => { node.isFolder = false; node.parentId = 'parent-id'; - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of({ entry: node })); spyOn(router, 'navigate'); fixture.detectChanges(); @@ -169,7 +169,7 @@ describe('FilesComponent', () => { describe('refresh on events', () => { beforeEach(() => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of(node)); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); spyOn(component.documentList, 'reload'); @@ -269,25 +269,10 @@ describe('FilesComponent', () => { }); }); - describe('fetchNode()', () => { - beforeEach(() => { - spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); - spyOn(nodesApi, 'getNode').and.returnValue(Observable.of(node)); - - fixture.detectChanges(); - }); - - it('should call getNode api with node id', () => { - component.fetchNode('nodeId'); - - expect(nodesApi.getNode).toHaveBeenCalledWith('nodeId'); - }); - }); - describe('fetchNodes()', () => { beforeEach(() => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); - spyOn(nodesApi, 'getNodeChildren').and.returnValue(Observable.of(page)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNodeChildren').and.returnValue(Observable.of(page)); fixture.detectChanges(); }); @@ -295,13 +280,13 @@ describe('FilesComponent', () => { it('should call getNode api with node id', () => { component.fetchNodes('nodeId'); - expect(nodesApi.getNodeChildren).toHaveBeenCalledWith('nodeId', jasmine.any(Object)); + expect(contentApi.getNodeChildren).toHaveBeenCalledWith('nodeId'); }); }); describe('onBreadcrumbNavigate()', () => { beforeEach(() => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of(node)); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); fixture.detectChanges(); @@ -319,7 +304,7 @@ describe('FilesComponent', () => { describe('Node navigation', () => { beforeEach(() => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of(node)); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); spyOn(router, 'navigate'); diff --git a/src/app/components/files/files.component.ts b/src/app/components/files/files.component.ts index 4a961245d4..726c47567e 100644 --- a/src/app/components/files/files.component.ts +++ b/src/app/components/files/files.component.ts @@ -23,7 +23,7 @@ * along with Alfresco. If not, see . */ -import { AlfrescoApiService, FileUploadEvent, NodesApiService, UploadService } from '@alfresco/adf-core'; +import { FileUploadEvent, UploadService } from '@alfresco/adf-core'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { Store } from '@ngrx/store'; @@ -35,6 +35,7 @@ import { NodeActionsService } from '../../common/services/node-actions.service'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { AppStore } from '../../store/states/app.state'; import { PageComponent } from '../page.component'; +import { ContentApiService } from '../../services/content-api.service'; @Component({ templateUrl: './files.component.html' @@ -47,13 +48,12 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { constructor(private router: Router, private route: ActivatedRoute, + private contentApi: ContentApiService, store: Store, - private nodesApi: NodesApiService, private nodeActionsService: NodeActionsService, private uploadService: UploadService, private contentManagementService: ContentManagementService, private browsingFilesService: BrowsingFilesService, - private apiService: AlfrescoApiService, public permission: NodePermissionService) { super(store); } @@ -69,8 +69,9 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { route.params.subscribe(({ folderId }: Params) => { const nodeId = folderId || data.defaultNodeId; - this.fetchNode(nodeId) - .do((node) => { + this.contentApi.getNode(nodeId) + .map(node => node.entry) + .do(node => { if (node.isFolder) { this.updateCurrentNode(node); } else { @@ -78,14 +79,10 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { } }) .skipWhile(node => !node.isFolder) - .flatMap((node) => this.fetchNodes(node.id)) + .flatMap(node => this.fetchNodes(node.id)) .subscribe( - (page) => { - this.isValidPath = true; - }, - error => { - this.isValidPath = false; - } + () => this.isValidPath = true, + () => this.isValidPath = false ); }); @@ -107,18 +104,8 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { this.browsingFilesService.onChangeParent.next(null); } - fetchNode(nodeId: string): Observable { - return this.nodesApi.getNode(nodeId); - } - - fetchNodes(parentNodeId?: string, options: { maxItems?: number, skipCount?: number } = {}): Observable { - const defaults = { - include: [ 'isLocked', 'path', 'properties', 'allowableOperations' ] - }; - - const queryOptions = Object.assign({}, defaults, options); - - return this.nodesApi.getNodeChildren(parentNodeId, queryOptions); + fetchNodes(parentNodeId?: string): Observable { + return this.contentApi.getNodeChildren(parentNodeId); } navigate(nodeId: string = null) { @@ -246,7 +233,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { if (this.isSiteContainer(node)) { // rename 'documentLibrary' entry to the target site display name // clicking on the breadcrumb entry loads the site content - const parentNode = await this.apiService.nodesApi.getNodeInfo(node.parentId); + const parentNode = await this.contentApi.getNodeInfo(node.parentId).toPromise(); node.name = parentNode.properties['cm:title'] || parentNode.name; // remove the site entry @@ -256,7 +243,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy { const docLib = elements.findIndex(el => el.name === 'documentLibrary'); if (docLib > -1) { const siteFragment = elements[docLib - 1]; - const siteNode = await this.apiService.nodesApi.getNodeInfo(siteFragment.id); + const siteNode = await this.contentApi.getNodeInfo(siteFragment.id).toPromise(); // apply Site Name to the parent fragment siteFragment.name = siteNode.properties['cm:title'] || siteNode.name; diff --git a/src/app/components/info-drawer/info-drawer.component.ts b/src/app/components/info-drawer/info-drawer.component.ts index bc9b56cc3f..708e8a068f 100644 --- a/src/app/components/info-drawer/info-drawer.component.ts +++ b/src/app/components/info-drawer/info-drawer.component.ts @@ -26,7 +26,7 @@ import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api'; import { NodePermissionService } from '../../common/services/node-permission.service'; -import { AlfrescoApiService } from '@alfresco/adf-core'; +import { ContentApiService } from '../../services/content-api.service'; @Component({ selector: 'aca-info-drawer', @@ -67,7 +67,7 @@ export class InfoDrawerComponent implements OnChanges { constructor( public permission: NodePermissionService, - private apiService: AlfrescoApiService + private contentApi: ContentApiService ) {} ngOnChanges(changes: SimpleChanges) { @@ -88,15 +88,13 @@ export class InfoDrawerComponent implements OnChanges { if (nodeId) { this.isLoading = true; - this.apiService.nodesApi - .getNodeInfo(nodeId, { include: ['allowableOperations'] }) - .then((entity: MinimalNodeEntryEntity) => { + this.contentApi.getNodeInfo(nodeId).subscribe( + entity => { this.displayNode = entity; this.isLoading = false; - }) - .catch(() => { - this.isLoading = false; - }); + }, + () => this.isLoading = false + ); } } } diff --git a/src/app/components/libraries/libraries.component.spec.ts b/src/app/components/libraries/libraries.component.spec.ts index d2e1dfa7a3..fe340e2820 100644 --- a/src/app/components/libraries/libraries.component.spec.ts +++ b/src/app/components/libraries/libraries.component.spec.ts @@ -28,7 +28,7 @@ import { Observable } from 'rxjs/Rx'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router } from '@angular/router'; import { - NodesApiService, AlfrescoApiService, + AlfrescoApiService, TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe } from '@alfresco/adf-core'; import { DocumentListComponent } from '@alfresco/adf-content-services'; @@ -36,11 +36,12 @@ import { ShareDataTableAdapter } from '@alfresco/adf-content-services'; import { LibrariesComponent } from './libraries.component'; import { ExperimentalDirective } from '../../directives/experimental.directive'; import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; describe('LibrariesComponent', () => { let fixture: ComponentFixture; let component: LibrariesComponent; - let nodesApi: NodesApiService; + let contentApi: ContentApiService; let alfrescoApi: AlfrescoApiService; let router: Router; let page; @@ -81,13 +82,14 @@ describe('LibrariesComponent', () => { fixture = TestBed.createComponent(LibrariesComponent); component = fixture.componentInstance; - nodesApi = TestBed.get(NodesApiService); alfrescoApi = TestBed.get(AlfrescoApiService); alfrescoApi.reset(); router = TestBed.get(Router); spyOn(alfrescoApi.sitesApi, 'getSites').and.returnValue((Promise.resolve(page))); spyOn(alfrescoApi.peopleApi, 'getSiteMembership').and.returnValue((Promise.resolve({}))); + + contentApi = TestBed.get(ContentApiService); }); describe('makeLibraryTooltip()', () => { @@ -153,7 +155,7 @@ describe('LibrariesComponent', () => { it('navigates to node id', () => { const document = { id: 'documentId' }; - spyOn(nodesApi, 'getNode').and.returnValue(Observable.of(document)); + spyOn(contentApi, 'getNode').and.returnValue(Observable.of({ entry: document })); component.navigate(node.id); diff --git a/src/app/components/libraries/libraries.component.ts b/src/app/components/libraries/libraries.component.ts index 125b9c9841..201bcec1f4 100644 --- a/src/app/components/libraries/libraries.component.ts +++ b/src/app/components/libraries/libraries.component.ts @@ -25,7 +25,6 @@ import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { NodesApiService } from '@alfresco/adf-core'; import { ShareDataRow } from '@alfresco/adf-content-services'; import { PageComponent } from '../page.component'; @@ -34,15 +33,16 @@ import { AppStore } from '../../store/states/app.state'; import { DeleteLibraryAction } from '../../store/actions'; import { SiteEntry } from 'alfresco-js-api'; import { ContentManagementService } from '../../common/services/content-management.service'; +import { ContentApiService } from '../../services/content-api.service'; @Component({ templateUrl: './libraries.component.html' }) export class LibrariesComponent extends PageComponent implements OnInit { - constructor(private nodesApi: NodesApiService, - private route: ActivatedRoute, + constructor(private route: ActivatedRoute, private content: ContentManagementService, + private contentApi: ContentApiService, store: Store, private router: Router) { super(store); @@ -89,8 +89,9 @@ export class LibrariesComponent extends PageComponent implements OnInit { navigate(libraryId: string) { if (libraryId) { - this.nodesApi + this.contentApi .getNode(libraryId, { relativePath: '/documentLibrary' }) + .map(node => node.entry) .subscribe(documentLibrary => { this.router.navigate([ './', documentLibrary.id ], { relativeTo: this.route }); }); diff --git a/src/app/components/location-link/location-link.component.ts b/src/app/components/location-link/location-link.component.ts index b72c25fae4..ed23e74de8 100644 --- a/src/app/components/location-link/location-link.component.ts +++ b/src/app/components/location-link/location-link.component.ts @@ -24,13 +24,14 @@ */ import { Component, Input, ChangeDetectionStrategy, OnInit, ViewEncapsulation } from '@angular/core'; -import { AlfrescoApiService, DataColumn, DataRow, DataTableAdapter } from '@alfresco/adf-core'; +import { DataColumn, DataRow, DataTableAdapter } from '@alfresco/adf-core'; import { PathInfoEntity, MinimalNodeEntity } from 'alfresco-js-api'; import { Observable } from 'rxjs/Rx'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; import { NavigateToParentFolder } from '../../store/actions'; +import { ContentApiService } from '../../services/content-api.service'; @Component({ selector: 'app-location-link', @@ -59,7 +60,7 @@ export class LocationLinkComponent implements OnInit { constructor( private store: Store, - private apiService: AlfrescoApiService) { + private contentApi: ContentApiService) { } goToLocation() { @@ -104,12 +105,12 @@ export class LocationLinkComponent implements OnInit { const fragment = path.elements[path.elements.length - 2]; return new Observable(observer => { - this.apiService.nodesApi.getNodeInfo(fragment.id).then( - (node) => { + this.contentApi.getNodeInfo(fragment.id).subscribe( + node => { observer.next(node.properties['cm:title'] || node.name || fragment.name); observer.complete(); }, - (err) => { + () => { observer.next(fragment.name); observer.complete(); } @@ -132,8 +133,8 @@ export class LocationLinkComponent implements OnInit { const fragment = elements[2]; return new Observable(observer => { - this.apiService.nodesApi.getNodeInfo(fragment.id).then( - (node) => { + this.contentApi.getNodeInfo(fragment.id).subscribe( + node => { elements.splice(0, 2); elements[0].name = node.properties['cm:title'] || node.name || fragment.name; elements.splice(1, 1); @@ -142,7 +143,7 @@ export class LocationLinkComponent implements OnInit { observer.next(elements.map(e => e.name).join('/')); observer.complete(); }, - (err) => { + () => { elements.splice(0, 2); elements.unshift({ id: null, name: 'File Libraries' }); elements.splice(2, 1); diff --git a/src/app/components/preview/preview.component.spec.ts b/src/app/components/preview/preview.component.spec.ts index 1d650a9388..e4c4665100 100644 --- a/src/app/components/preview/preview.component.spec.ts +++ b/src/app/components/preview/preview.component.spec.ts @@ -25,13 +25,14 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; -import { TestBed, async, ComponentFixture } from '@angular/core/testing'; -import { AlfrescoApiService, UserPreferencesService, AppConfigPipe, NodeFavoriteDirective } from '@alfresco/adf-core'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { UserPreferencesService, AppConfigPipe, NodeFavoriteDirective } from '@alfresco/adf-core'; import { PreviewComponent } from './preview.component'; import { Observable } from 'rxjs/Rx'; import { EffectsModule } from '@ngrx/effects'; import { NodeEffects } from '../../store/effects/node.effects'; import { AppTestingModule } from '../../testing/app-testing.module'; +import { ContentApiService } from '../../services/content-api.service'; describe('PreviewComponent', () => { @@ -39,10 +40,10 @@ describe('PreviewComponent', () => { let component: PreviewComponent; let router: Router; let route: ActivatedRoute; - let alfrescoApi: AlfrescoApiService; let preferences: UserPreferencesService; + let contentApi: ContentApiService; - beforeEach(async(() => { + beforeEach(() => { TestBed.configureTestingModule({ imports: [ AppTestingModule, @@ -54,18 +55,16 @@ describe('PreviewComponent', () => { NodeFavoriteDirective ], schemas: [ NO_ERRORS_SCHEMA ] - }) - .compileComponents().then(() => { - fixture = TestBed.createComponent(PreviewComponent); - component = fixture.componentInstance; - - router = TestBed.get(Router); - route = TestBed.get(ActivatedRoute); - alfrescoApi = TestBed.get(AlfrescoApiService); - alfrescoApi.reset(); - preferences = TestBed.get(UserPreferencesService); }); - })); + + fixture = TestBed.createComponent(PreviewComponent); + component = fixture.componentInstance; + + router = TestBed.get(Router); + route = TestBed.get(ActivatedRoute); + preferences = TestBed.get(UserPreferencesService); + contentApi = TestBed.get(ContentApiService); + }); it('should extract the property path root', () => { expect(component.getRootField('some.property.path')).toBe('some'); @@ -339,35 +338,33 @@ describe('PreviewComponent', () => { it('should not display node when id is missing', async () => { spyOn(router, 'navigate').and.stub(); - spyOn(alfrescoApi.nodesApi, 'getNodeInfo').and.returnValue( - Promise.resolve(null) + spyOn(contentApi, 'getNodeInfo').and.returnValue( + Observable.of(null) ); await component.displayNode(null); - expect(alfrescoApi.nodesApi.getNodeInfo).not.toHaveBeenCalled(); + expect(contentApi.getNodeInfo).not.toHaveBeenCalled(); expect(router.navigate).not.toHaveBeenCalled(); }); it('should navigate to original location if node not found', async () => { spyOn(router, 'navigate').and.stub(); - spyOn(alfrescoApi.nodesApi, 'getNodeInfo').and.returnValue( - Promise.resolve(null) + spyOn(contentApi, 'getNodeInfo').and.returnValue( + Observable.of(null) ); component.previewLocation = 'personal-files'; await component.displayNode('folder1'); - expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith( - 'folder1', { include: [ 'allowableOperations' ] } - ); + expect(contentApi.getNodeInfo).toHaveBeenCalledWith('folder1'); expect(router.navigate).toHaveBeenCalledWith(['personal-files', 'folder1']); }); it('should navigate to original location if node is not a File', async () => { spyOn(router, 'navigate').and.stub(); - spyOn(alfrescoApi.nodesApi, 'getNodeInfo').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getNodeInfo').and.returnValue( + Observable.of({ isFile: false }) ); @@ -375,31 +372,27 @@ describe('PreviewComponent', () => { component.previewLocation = 'personal-files'; await component.displayNode('folder1'); - expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith( - 'folder1', { include: [ 'allowableOperations' ] } - ); + expect(contentApi.getNodeInfo).toHaveBeenCalledWith('folder1'); expect(router.navigate).toHaveBeenCalledWith(['personal-files', 'folder1']); }); it('should navigate to original location in case of Alfresco API errors', async () => { spyOn(router, 'navigate').and.stub(); - spyOn(alfrescoApi.nodesApi, 'getNodeInfo').and.returnValue( - Promise.reject('error') + spyOn(contentApi, 'getNodeInfo').and.returnValue( + Observable.throw('error') ); component.previewLocation = 'personal-files'; await component.displayNode('folder1'); - expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith( - 'folder1', { include: [ 'allowableOperations' ] } - ); + expect(contentApi.getNodeInfo).toHaveBeenCalledWith('folder1'); expect(router.navigate).toHaveBeenCalledWith(['personal-files', 'folder1']); }); it('should navigate to original location in case of internal errors', async () => { spyOn(router, 'navigate').and.stub(); - spyOn(alfrescoApi.nodesApi, 'getNodeInfo').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getNodeInfo').and.returnValue( + Observable.of({ isFile: true }) ); @@ -410,17 +403,15 @@ describe('PreviewComponent', () => { component.previewLocation = 'personal-files'; await component.displayNode('folder1'); - expect(alfrescoApi.nodesApi.getNodeInfo).toHaveBeenCalledWith( - 'folder1', { include: [ 'allowableOperations' ] } - ); + expect(contentApi.getNodeInfo).toHaveBeenCalledWith('folder1'); expect(router.navigate).toHaveBeenCalledWith(['personal-files', 'folder1']); }); it('should setup node for displaying', async () => { spyOn(router, 'navigate').and.stub(); spyOn(component, 'getNearestNodes').and.returnValue({ left: 'node1', right: 'node3' }); - spyOn(alfrescoApi.nodesApi, 'getNodeInfo').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getNodeInfo').and.returnValue( + Observable.of({ id: 'node2', parentId: 'parent1', isFile: true @@ -439,8 +430,8 @@ describe('PreviewComponent', () => { preferences.set('personal-files.sorting.key', 'name'); preferences.set('personal-files.sorting.direction', 'desc'); - spyOn(alfrescoApi.nodesApi, 'getNodeChildren').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getNodeChildren').and.returnValue( + Observable.of({ list: { entries: [ { entry: { id: 'node1', name: 'node 1' } }, @@ -458,8 +449,8 @@ describe('PreviewComponent', () => { preferences.set('personal-files.sorting.key', 'missing'); preferences.set('personal-files.sorting.direction', 'desc'); - spyOn(alfrescoApi.nodesApi, 'getNodeChildren').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getNodeChildren').and.returnValue( + Observable.of({ list: { entries: [ { entry: { id: 'node1', name: 'node 1' } }, @@ -481,8 +472,8 @@ describe('PreviewComponent', () => { it('should sort file ids for personal-files with [modifiedAt desc]', async () => { spyOn(preferences, 'get').and.returnValue(null); - spyOn(alfrescoApi.nodesApi, 'getNodeChildren').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getNodeChildren').and.returnValue( + Observable.of({ list: { entries: [ { entry: { id: 'node1', name: 'node 1', modifiedAt: 1 } }, @@ -500,8 +491,8 @@ describe('PreviewComponent', () => { preferences.set('personal-files.sorting.key', 'name'); preferences.set('personal-files.sorting.direction', 'desc'); - spyOn(alfrescoApi.nodesApi, 'getNodeChildren').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getNodeChildren').and.returnValue( + Observable.of({ list: { entries: [ { entry: { id: 'node1', name: 'node 1' } }, @@ -523,8 +514,8 @@ describe('PreviewComponent', () => { it('should sort file ids for libraries with [modifiedAt desc]', async () => { spyOn(preferences, 'get').and.returnValue(null); - spyOn(alfrescoApi.nodesApi, 'getNodeChildren').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getNodeChildren').and.returnValue( + Observable.of({ list: { entries: [ { entry: { id: 'node1', name: 'node 1', modifiedAt: new Date(1) } }, @@ -542,8 +533,8 @@ describe('PreviewComponent', () => { preferences.set('favorites.sorting.key', 'name'); preferences.set('favorites.sorting.direction', 'desc'); - spyOn(alfrescoApi.favoritesApi, 'getFavorites').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getFavorites').and.returnValue( + Observable.of({ list: { entries: [ { entry: { target: { file: { id: 'file3', name: 'file 3' } } } }, @@ -561,8 +552,8 @@ describe('PreviewComponent', () => { it('should sort file ids for favorites with [modifiedAt desc]', async () => { spyOn(preferences, 'get').and.returnValue(null); - spyOn(alfrescoApi.favoritesApi, 'getFavorites').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getFavorites').and.returnValue( + Observable.of({ list: { entries: [ { entry: { target: { file: { id: 'file3', modifiedAt: new Date(3) } } } }, @@ -581,8 +572,8 @@ describe('PreviewComponent', () => { preferences.set('shared.sorting.key', 'name'); preferences.set('shared.sorting.direction', 'asc'); - spyOn(alfrescoApi.sharedLinksApi, 'findSharedLinks').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'findSharedLinks').and.returnValue( + Observable.of({ list: { entries: [ { entry: { nodeId: 'node2', name: 'node 2', modifiedAt: new Date(2) } }, @@ -599,8 +590,8 @@ describe('PreviewComponent', () => { it('should sort file ids for favorites with [modifiedAt desc]', async () => { spyOn(preferences, 'get').and.returnValue(null); - spyOn(alfrescoApi.sharedLinksApi, 'findSharedLinks').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'findSharedLinks').and.returnValue( + Observable.of({ list: { entries: [ { entry: { nodeId: 'node2', name: 'node 2', modifiedAt: new Date(2) } }, @@ -618,14 +609,14 @@ describe('PreviewComponent', () => { preferences.set('recent-files.sorting.key', 'name'); preferences.set('recent-files.sorting.direction', 'asc'); - spyOn(alfrescoApi.peopleApi, 'getPerson').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getPerson').and.returnValue( + Observable.of({ entry: { id: 'user' } }) ); - spyOn(alfrescoApi.searchApi, 'search').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'search').and.returnValue( + Observable.of({ list: { entries: [ { entry: { id: 'node2', name: 'node 2', modifiedAt: new Date(2) } }, @@ -642,14 +633,14 @@ describe('PreviewComponent', () => { it('should sort file ids for favorites with [modifiedAt desc]', async () => { spyOn(preferences, 'get').and.returnValue(null); - spyOn(alfrescoApi.peopleApi, 'getPerson').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'getPerson').and.returnValue( + Observable.of({ entry: { id: 'user' } }) ); - spyOn(alfrescoApi.searchApi, 'search').and.returnValue( - Promise.resolve({ + spyOn(contentApi, 'search').and.returnValue( + Observable.of({ list: { entries: [ { entry: { id: 'node2', name: 'node 2', modifiedAt: new Date(2) } }, diff --git a/src/app/components/preview/preview.component.ts b/src/app/components/preview/preview.component.ts index dd66d74e63..81bbdfdb37 100644 --- a/src/app/components/preview/preview.component.ts +++ b/src/app/components/preview/preview.component.ts @@ -25,13 +25,14 @@ import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { ActivatedRoute, Router, UrlTree, UrlSegmentGroup, UrlSegment, PRIMARY_OUTLET } from '@angular/router'; -import { AlfrescoApiService, UserPreferencesService, ObjectUtils, UploadService } from '@alfresco/adf-core'; +import { UserPreferencesService, ObjectUtils, UploadService } from '@alfresco/adf-core'; import { Node, MinimalNodeEntity } from 'alfresco-js-api'; import { NodePermissionService } from '../../common/services/node-permission.service'; import { Store } from '@ngrx/store'; import { AppStore } from '../../store/states/app.state'; import { DeleteNodesAction } from '../../store/actions'; import { PageComponent } from '../page.component'; +import { ContentApiService } from '../../services/content-api.service'; @Component({ selector: 'app-preview', templateUrl: 'preview.component.html', @@ -56,8 +57,8 @@ export class PreviewComponent extends PageComponent implements OnInit { selectedEntities: MinimalNodeEntity[] = []; constructor( + private contentApi: ContentApiService, private uploadService: UploadService, - private apiService: AlfrescoApiService, private preferences: UserPreferencesService, private route: ActivatedRoute, private router: Router, @@ -105,9 +106,7 @@ export class PreviewComponent extends PageComponent implements OnInit { async displayNode(id: string) { if (id) { try { - this.node = await this.apiService.nodesApi.getNodeInfo(id, { - include: ['allowableOperations'] - }); + this.node = await this.contentApi.getNodeInfo(id).toPromise(); this.selectedEntities = [{ entry: this.node }]; if (this.node && this.node.isFile) { @@ -222,11 +221,11 @@ export class PreviewComponent extends PageComponent implements OnInit { if ((source === 'personal-files' || source === 'libraries') && folderId) { const sortKey = this.preferences.get('personal-files.sorting.key') || 'modifiedAt'; const sortDirection = this.preferences.get('personal-files.sorting.direction') || 'desc'; - const nodes = await this.apiService.nodesApi.getNodeChildren(folderId, { + const nodes = await this.contentApi.getNodeChildren(folderId, { // orderBy: `${sortKey} ${sortDirection}`, fields: ['id', this.getRootField(sortKey)], where: '(isFile=true)' - }); + }).toPromise(); const entries = nodes.list.entries.map(obj => obj.entry); this.sort(entries, sortKey, sortDirection); @@ -235,10 +234,10 @@ export class PreviewComponent extends PageComponent implements OnInit { } if (source === 'favorites') { - const nodes = await this.apiService.favoritesApi.getFavorites('-me-', { + const nodes = await this.contentApi.getFavorites('-me-', { where: '(EXISTS(target/file))', fields: ['target'] - }); + }).toPromise(); const sortKey = this.preferences.get('favorites.sorting.key') || 'modifiedAt'; const sortDirection = this.preferences.get('favorites.sorting.direction') || 'desc'; @@ -252,9 +251,9 @@ export class PreviewComponent extends PageComponent implements OnInit { const sortingKey = this.preferences.get('shared.sorting.key') || 'modifiedAt'; const sortingDirection = this.preferences.get('shared.sorting.direction') || 'desc'; - const nodes = await this.apiService.sharedLinksApi.findSharedLinks({ + const nodes = await this.contentApi.findSharedLinks({ fields: ['nodeId', this.getRootField(sortingKey)] - }); + }).toPromise(); const entries = nodes.list.entries.map(obj => obj.entry); this.sort(entries, sortingKey, sortingDirection); @@ -263,12 +262,12 @@ export class PreviewComponent extends PageComponent implements OnInit { } if (source === 'recent-files') { - const person = await this.apiService.peopleApi.getPerson('-me-'); + const person = await this.contentApi.getPerson('-me-').toPromise(); const username = person.entry.id; const sortingKey = this.preferences.get('recent-files.sorting.key') || 'modifiedAt'; const sortingDirection = this.preferences.get('recent-files.sorting.direction') || 'desc'; - const nodes = await this.apiService.searchApi.search({ + const nodes = await this.contentApi.search({ query: { query: '*', language: 'afts' @@ -284,7 +283,7 @@ export class PreviewComponent extends PageComponent implements OnInit { field: 'cm:modified', ascending: false }] - }); + }).toPromise(); const entries = nodes.list.entries.map(obj => obj.entry); this.sort(entries, sortingKey, sortingDirection); diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 33a296a859..5d8fae5f70 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -65,8 +65,7 @@ diff --git a/src/app/components/shared-files/shared-files.component.ts b/src/app/components/shared-files/shared-files.component.ts index 535f8948f7..01058f99b2 100644 --- a/src/app/components/shared-files/shared-files.component.ts +++ b/src/app/components/shared-files/shared-files.component.ts @@ -51,6 +51,7 @@ export class SharedFilesComponent extends PageComponent implements OnInit { this.content.nodesDeleted.subscribe(() => this.reload()), this.content.nodesMoved.subscribe(() => this.reload()), this.content.nodesRestored.subscribe(() => this.reload()), + this.content.linksUnshared.subscribe(() => this.reload()), this.uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error)) ]); } diff --git a/src/app/services/content-api.service.ts b/src/app/services/content-api.service.ts new file mode 100644 index 0000000000..a5ecff227a --- /dev/null +++ b/src/app/services/content-api.service.ts @@ -0,0 +1,229 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Injectable } from '@angular/core'; +import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core'; +import { Observable } from 'rxjs/Observable'; +import { + MinimalNodeEntity, + NodePaging, + Node, + DeletedNodesPaging, + PersonEntry, + NodeEntry, + DiscoveryEntry, + FavoritePaging, + SharedLinkPaging, + SearchRequest, + ResultSetPaging +} from 'alfresco-js-api'; + +@Injectable() +export class ContentApiService { + constructor( + private api: AlfrescoApiService, + private preferences: UserPreferencesService + ) {} + + /** + * Moves a node to the trashcan. + * @param nodeId ID of the target node + * @param options Optional parameters supported by JS-API + * @returns Empty result that notifies when the deletion is complete + */ + deleteNode( + nodeId: string, + options: { permanent?: boolean } = {} + ): Observable { + return Observable.fromPromise( + this.api.nodesApi.deleteNode(nodeId, options) + ); + } + + /** + * Gets the stored information about a node. + * @param nodeId ID of the target node + * @param options Optional parameters supported by JS-API + * @returns Node information + */ + getNode(nodeId: string, options: any = {}): Observable { + const defaults = { + include: [ + 'path', + 'properties', + 'allowableOperations', + 'permissions' + ] + }; + const queryOptions = Object.assign(defaults, options); + + return Observable.fromPromise( + this.api.nodesApi.getNode(nodeId, queryOptions) + ); + } + + getNodeInfo(nodeId: string, options: any = {}): Observable { + const defaults = { + include: ['allowableOperations'] + }; + const queryOptions = Object.assign(defaults, options); + + return Observable.fromPromise( + this.api.nodesApi.getNodeInfo(nodeId, queryOptions) + ); + } + + /** + * Gets the items contained in a folder node. + * @param nodeId ID of the target node + * @param options Optional parameters supported by JS-API + * @returns List of child items from the folder + */ + getNodeChildren(nodeId: string, options: any = {}): Observable { + const defaults = { + maxItems: this.preferences.paginationSize, + skipCount: 0, + include: [ + 'isLocked', + 'path', + 'properties', + 'allowableOperations', + 'permissions' + ] + }; + const queryOptions = Object.assign(defaults, options); + + return Observable.fromPromise( + this.api.nodesApi.getNodeChildren(nodeId, queryOptions) + ); + } + + deleteSharedLink(linkId: string): Observable { + return Observable.fromPromise( + this.api.sharedLinksApi.deleteSharedLink(linkId) + ); + } + + getDeletedNodes(options: any = {}): Observable { + const defaults = { + include: ['path'] + }; + const queryOptions = Object.assign(defaults, options); + + return Observable.fromPromise( + this.api.nodesApi.getDeletedNodes(queryOptions) + ); + } + + restoreNode(nodeId: string): Observable { + return Observable.fromPromise(this.api.nodesApi.restoreNode(nodeId)); + } + + purgeDeletedNode(nodeId: string): Observable { + return Observable.fromPromise( + this.api.nodesApi.purgeDeletedNode(nodeId) + ); + } + + /** + * Gets information about a user identified by their username. + * @param personId ID of the target user + * @returns User information + */ + getPerson( + personId: string, + options?: { fields?: Array } + ): Observable { + return Observable.fromPromise( + this.api.peopleApi.getPerson(personId, options) + ); + } + + /** + * Copy a node to destination node + * + * @param nodeId The id of the node to be copied + * @param targetParentId The id of the folder-node where the node have to be copied to + * @param name The new name for the copy that would be added on the destination folder + */ + copyNode( + nodeId: string, + targetParentId: string, + name?: string, + opts?: { include?: Array; fields?: Array } + ): Observable { + return Observable.fromPromise( + this.api.nodesApi.copyNode(nodeId, { targetParentId, name }, opts) + ); + } + + /** + * Gets product information for Content Services. + * @returns ProductVersionModel containing product details + */ + getRepositoryInformation(): Observable { + return Observable.fromPromise( + this.api + .getInstance() + .discovery.discoveryApi.getRepositoryInformation() + ); + } + + getFavorites( + personId: string, + opts?: { + skipCount?: number; + maxItems?: number; + where?: string; + fields?: Array; + } + ): Observable { + return Observable.fromPromise( + this.api.favoritesApi.getFavorites(personId, opts) + ); + } + + findSharedLinks(opts?: any): Observable { + return Observable.fromPromise( + this.api.sharedLinksApi.findSharedLinks(opts) + ); + } + + search(request: SearchRequest): Observable { + return Observable.fromPromise( + this.api.searchApi.search(request) + ); + } + + getContentUrl(nodeId: string, attachment?: boolean): string { + return this.api.contentApi.getContentUrl(nodeId, attachment); + } + + deleteSite(siteId?: string, opts?: { permanent?: boolean }): Observable { + return Observable.fromPromise( + this.api.sitesApi.deleteSite(siteId, opts) + ); + } +} diff --git a/src/app/store/actions/user.actions.ts b/src/app/store/actions/user.actions.ts index 447bf6c39d..a128e15112 100644 --- a/src/app/store/actions/user.actions.ts +++ b/src/app/store/actions/user.actions.ts @@ -24,10 +24,11 @@ */ import { Action } from '@ngrx/store'; +import { Person } from 'alfresco-js-api'; export const SET_USER = 'SET_USER'; export class SetUserAction implements Action { readonly type = SET_USER; - constructor(public payload: any) { } + constructor(public payload: Person) { } } diff --git a/src/app/store/effects/download.effects.ts b/src/app/store/effects/download.effects.ts index 20bea20e0d..72a6d1dbb2 100644 --- a/src/app/store/effects/download.effects.ts +++ b/src/app/store/effects/download.effects.ts @@ -24,19 +24,19 @@ */ import { DownloadZipDialogComponent } from '@alfresco/adf-content-services'; -import { AlfrescoApiService } from '@alfresco/adf-core'; import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { map } from 'rxjs/operators'; import { DownloadNodesAction, DOWNLOAD_NODES } from '../actions'; import { NodeInfo } from '../models'; +import { ContentApiService } from '../../services/content-api.service'; @Injectable() export class DownloadEffects { constructor( private actions$: Actions, - private apiService: AlfrescoApiService, + private contentApi: ContentApiService, private dialog: MatDialog ) {} @@ -75,7 +75,7 @@ export class DownloadEffects { private downloadFile(node: NodeInfo) { if (node) { this.download( - this.apiService.contentApi.getContentUrl(node.id, true), + this.contentApi.getContentUrl(node.id, true), node.name ); } diff --git a/src/app/store/effects/library.effects.ts b/src/app/store/effects/library.effects.ts index 71e07894b8..a8df0f9bbb 100644 --- a/src/app/store/effects/library.effects.ts +++ b/src/app/store/effects/library.effects.ts @@ -27,7 +27,6 @@ import { Effect, Actions, ofType } from '@ngrx/effects'; import { Injectable } from '@angular/core'; import { map } from 'rxjs/operators'; import { DeleteLibraryAction, DELETE_LIBRARY } from '../actions'; -import { AlfrescoApiService } from '@alfresco/adf-core'; import { SnackbarInfoAction, SnackbarErrorAction @@ -35,13 +34,14 @@ import { import { Store } from '@ngrx/store'; import { AppStore } from '../states/app.state'; import { ContentManagementService } from '../../common/services/content-management.service'; +import { ContentApiService } from '../../services/content-api.service'; @Injectable() export class SiteEffects { constructor( private actions$: Actions, private store: Store, - private apiService: AlfrescoApiService, + private contentApi: ContentApiService, private content: ContentManagementService ) {} @@ -49,7 +49,7 @@ export class SiteEffects { deleteLibrary$ = this.actions$.pipe( ofType(DELETE_LIBRARY), map(action => { - this.apiService.sitesApi.deleteSite(action.payload).then( + this.contentApi.deleteSite(action.payload).subscribe( () => { this.content.siteDeleted.next(action.payload); this.store.dispatch( @@ -58,7 +58,7 @@ export class SiteEffects { ) ); }, - err => { + () => { this.store.dispatch( new SnackbarErrorAction( 'APP.MESSAGES.ERRORS.DELETE_LIBRARY_FAILED' diff --git a/src/app/store/effects/node.effects.ts b/src/app/store/effects/node.effects.ts index b48f4ea631..c0adad2a33 100644 --- a/src/app/store/effects/node.effects.ts +++ b/src/app/store/effects/node.effects.ts @@ -43,8 +43,8 @@ import { } from '../actions'; import { ContentManagementService } from '../../common/services/content-management.service'; import { Observable } from 'rxjs/Rx'; -import { AlfrescoApiService } from '@alfresco/adf-core'; import { NodeInfo, DeleteStatus, DeletedNodeInfo } from '../models'; +import { ContentApiService } from '../../services/content-api.service'; @Injectable() export class NodeEffects { @@ -52,7 +52,7 @@ export class NodeEffects { private store: Store, private actions$: Actions, private contentManagementService: ContentManagementService, - private alfrescoApiService: AlfrescoApiService + private contentApi: ContentApiService ) {} @Effect({ dispatch: false }) @@ -113,9 +113,7 @@ export class NodeEffects { private deleteNode(node: NodeInfo): Observable { const { id, name } = node; - return Observable.fromPromise( - this.alfrescoApiService.nodesApi.deleteNode(id) - ) + return this.contentApi.deleteNode(id) .map(() => { return { id, @@ -208,9 +206,7 @@ export class NodeEffects { private undoDeleteNode(item: DeletedNodeInfo): Observable { const { id, name } = item; - return Observable.fromPromise( - this.alfrescoApiService.nodesApi.restoreNode(id) - ) + return this.contentApi.restoreNode(id) .map(() => { return { id, @@ -266,9 +262,8 @@ export class NodeEffects { private purgeDeletedNode(node: NodeInfo): Observable { const { id, name } = node; - const promise = this.alfrescoApiService.nodesApi.purgeDeletedNode(id); - return Observable.from(promise) + return this.contentApi.purgeDeletedNode(id) .map(() => ({ status: 1, id, diff --git a/src/app/store/reducers/app.reducer.ts b/src/app/store/reducers/app.reducer.ts index f8d234372d..30c8f83ba1 100644 --- a/src/app/store/reducers/app.reducer.ts +++ b/src/app/store/reducers/app.reducer.ts @@ -117,7 +117,9 @@ function updateUser(state: AppState, action: SetUserAction): AppState { const lastName = user.lastName || ''; const userName = `${firstName} ${lastName}`; const initials = [firstName[0], lastName[0]].join(''); - const isAdmin = user.capabilities ? user.capabilities.isAdmin : true; + + const capabilities = (user).capabilities; + const isAdmin = capabilities ? capabilities.isAdmin : true; newState.user = { firstName, diff --git a/src/app/testing/app-testing.module.ts b/src/app/testing/app-testing.module.ts index 09d14c24da..0ad4590642 100644 --- a/src/app/testing/app-testing.module.ts +++ b/src/app/testing/app-testing.module.ts @@ -42,7 +42,8 @@ import { ContentService, ThumbnailService, UploadService, - PeopleContentService + PeopleContentService, + AlfrescoApiMock } from '@alfresco/adf-core'; import { HttpClientModule } from '@angular/common/http'; import { TranslateServiceMock } from './translation.service'; @@ -60,6 +61,7 @@ import { ContentManagementService } from '../common/services/content-management. import { NodeActionsService } from '../common/services/node-actions.service'; import { NodePermissionService } from '../common/services/node-permission.service'; import { BrowsingFilesService } from '../common/services/browsing-files.service'; +import { ContentApiService } from '../services/content-api.service'; @NgModule({ imports: [ @@ -76,6 +78,7 @@ import { BrowsingFilesService } from '../common/services/browsing-files.service' declarations: [TranslatePipeMock], exports: [TranslatePipeMock, RouterTestingModule, MaterialModule], providers: [ + { provide: AlfrescoApiService, useClass: AlfrescoApiMock }, { provide: TranslationService, useClass: TranslationMock }, { provide: TranslateService, useClass: TranslateServiceMock }, { provide: TranslatePipe, useClass: TranslatePipeMock }, @@ -108,7 +111,8 @@ import { BrowsingFilesService } from '../common/services/browsing-files.service' ContentManagementService, NodeActionsService, NodePermissionService, - BrowsingFilesService + BrowsingFilesService, + ContentApiService ] }) export class AppTestingModule {} From ce5f7f579a595db88d5231b5f326c0bc1144174d Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 25 Jun 2018 11:58:19 +0300 Subject: [PATCH 139/179] search sorting options (#456) --- src/app.config.json | 14 ++++++++++++++ src/assets/i18n/en.json | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/app.config.json b/src/app.config.json index 56759d2488..6af1d00f22 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -194,6 +194,20 @@ "field": "cm:modified", "ascending": true }, + { + "key": "modified", + "label": "SEARCH.SORT.MODIFIER", + "type": "FIELD", + "field": "cm:modifier", + "ascending": true + }, + { + "key": "modified", + "label": "SEARCH.SORT.CREATE_DATE", + "type": "FIELD", + "field": "cm:created", + "ascending": true + }, { "key": "content.sizeInBytes", "label": "SEARCH.SORT.SIZE", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index c9f2ee408e..7715a62e98 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -260,7 +260,9 @@ "TITLE": "Title", "MODIFIED_DATE": "Modified Date", "SIZE": "Size", - "TYPE": "Type" + "TYPE": "Type", + "MODIFIER": "Modifier", + "CREATE_DATE": "Created date" }, "FACET_FIELDS": { "FILE_TYPE": "File Type", From bdf7f566463145600372f27bb89a1cd4940565b1 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 25 Jun 2018 13:05:27 +0100 Subject: [PATCH 140/179] update to latest ADF rc (#457) --- package-lock.json | 36 ++++++++++++++++++------------------ package.json | 6 +++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f93b9d75e..3b4b0c45c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,11 @@ "requires": true, "dependencies": { "@alfresco/adf-content-services": { - "version": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", - "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4.tgz", - "integrity": "sha512-u7aDRhCLD8BxXgsPXcmPj6i1wTQ5jInpPHci1iTTapF7kWATjWWu9MsbV9WBmtmxlllcMwrDb/hg4DJj28bslw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0.tgz", + "integrity": "sha512-WHQFo1bokmc9hYi3C3zlQImvuajOJuycfjSmkyQ27sEQhsjzH7+lPXV7Loa8p5kGFIP6KBL61BxReCfJqIJDCA==", "requires": { - "@alfresco/adf-core": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", + "@alfresco/adf-core": "2.4.0", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -24,7 +24,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", + "alfresco-js-api": "2.4.0", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -41,9 +41,9 @@ }, "dependencies": { "alfresco-js-api": { - "version": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b.tgz", - "integrity": "sha512-aRwa7PE1ZvMqW4FquRCJbCCtt7FNE9RVGjH2wjr80duX3PUkH/2GXEGtImLGQFRRgkX47ZfnB3D/3gDY9u4Vmw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0.tgz", + "integrity": "sha512-XVf/B3fE0Rl632SU3w0/m6EX/HEwOebIHjP0tluJoD174VONiTsoBzUuicliZvsfuHAeLC5YqthCV4PaKnehCg==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", @@ -71,9 +71,9 @@ } }, "@alfresco/adf-core": { - "version": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", - "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4.tgz", - "integrity": "sha512-sI18hpQaGhsWm0KHiFHJAh2hUWSMrQFCqNcSwoivZntJqkzAUV9YpdAgzHB5Usl9b/L0kcbJJlgRTWytT5nVbg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0.tgz", + "integrity": "sha512-sK0C3Q9yDjqpXV3l5DQXqyRRSiZ+RaUKU81BHEY7Bq1szbBhJq9bJ3rF6PfABzGwB9DKhy+nU+fftCneLJQcnA==", "requires": { "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", @@ -89,7 +89,7 @@ "@angular/platform-browser-dynamic": "5.1.1", "@angular/router": "5.1.1", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", + "alfresco-js-api": "2.4.0", "chart.js": "2.5.0", "core-js": "2.4.1", "hammerjs": "2.0.8", @@ -106,9 +106,9 @@ }, "dependencies": { "alfresco-js-api": { - "version": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b.tgz", - "integrity": "sha512-aRwa7PE1ZvMqW4FquRCJbCCtt7FNE9RVGjH2wjr80duX3PUkH/2GXEGtImLGQFRRgkX47ZfnB3D/3gDY9u4Vmw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0.tgz", + "integrity": "sha512-XVf/B3fE0Rl632SU3w0/m6EX/HEwOebIHjP0tluJoD174VONiTsoBzUuicliZvsfuHAeLC5YqthCV4PaKnehCg==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", @@ -668,9 +668,9 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "alfresco-js-api": { - "version": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b.tgz", - "integrity": "sha512-aRwa7PE1ZvMqW4FquRCJbCCtt7FNE9RVGjH2wjr80duX3PUkH/2GXEGtImLGQFRRgkX47ZfnB3D/3gDY9u4Vmw==", + "version": "2.4.0-beta15", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-beta15.tgz", + "integrity": "sha512-w8gJr2pOqtTopmexiJbknsMqs/bgWLM76U6MAL5qUAttMv1JtU33GlEhj8OISpZ3Oro89lGWM7gz3jejN6tfLw==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", diff --git a/package.json b/package.json index 3bdac297f8..82279b7d70 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ }, "private": true, "dependencies": { - "@alfresco/adf-content-services": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", - "@alfresco/adf-core": "2.4.0-8f7383d9d04ecebe0d438c02457881d3b53278e4", + "@alfresco/adf-content-services": "2.4.0", + "@alfresco/adf-core": "2.4.0", "@angular/animations": "5.1.1", "@angular/cdk": "5.0.1", "@angular/common": "5.1.1", @@ -47,7 +47,7 @@ "@ngrx/store": "^5.2.0", "@ngrx/store-devtools": "^5.2.0", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-92eae7db59edeb63e2e0dc1e4c2e6b182ff46f2b", + "alfresco-js-api": "2.4.0-beta15", "core-js": "2.5.3", "cspell": "^2.1.12", "hammerjs": "2.0.8", From 00032ac9790ca5a4e5b7b01ac033b2522074d65b Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 25 Jun 2018 15:07:21 +0100 Subject: [PATCH 141/179] update readme --- README.md | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fa4065e229..e3544b6cb9 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ## Introduction The Alfresco Content Application is an example application built using -[Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.6.6. +[Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli). ### Who is this example application for @@ -40,16 +40,33 @@ The app will automatically reload if you change any of the source files. ## Build -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. -Use the `--prod` flag for a production build. +Run `npm run build` to build the project in the production mode. The build artifacts will be stored in the `dist/` directory. ## Running unit tests -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). +Run `npm test` to execute the unit tests via [Karma](https://karma-runner.github.io). ## Running end-to-end tests -Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). +Run the local instance of the application packaged into the docker image together with the ACS images: + +```sh +npm run build +npm run start:docker +``` + +The ACA runs on port 4000 inside the docker container. +Run `npm run e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). + +```sh +npm run e2e +``` + +When testing is over you can stop all corresponding containers: + +```sh +npm run stop:docker +``` ## Further help From 5461408595ae5fd9a21cc8a5c3aa7f6ca0ccea34 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 25 Jun 2018 16:10:12 +0100 Subject: [PATCH 142/179] upgrade to ADF 2.4.0 final --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3b4b0c45c5..1908ac6df5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -668,9 +668,9 @@ "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" }, "alfresco-js-api": { - "version": "2.4.0-beta15", - "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-beta15.tgz", - "integrity": "sha512-w8gJr2pOqtTopmexiJbknsMqs/bgWLM76U6MAL5qUAttMv1JtU33GlEhj8OISpZ3Oro89lGWM7gz3jejN6tfLw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0.tgz", + "integrity": "sha512-XVf/B3fE0Rl632SU3w0/m6EX/HEwOebIHjP0tluJoD174VONiTsoBzUuicliZvsfuHAeLC5YqthCV4PaKnehCg==", "requires": { "event-emitter": "0.3.4", "jsrsasign": "^8.0.12", diff --git a/package.json b/package.json index 82279b7d70..57f7d69654 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@ngrx/store": "^5.2.0", "@ngrx/store-devtools": "^5.2.0", "@ngx-translate/core": "9.1.1", - "alfresco-js-api": "2.4.0-beta15", + "alfresco-js-api": "2.4.0", "core-js": "2.5.3", "cspell": "^2.1.12", "hammerjs": "2.0.8", From dd08d1b3a861a0a6c3c6dccb83624d1a7f8cb2e9 Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Tue, 26 Jun 2018 09:08:37 +0300 Subject: [PATCH 143/179] [ACA-1485] use SearchTriggerDirective only when liveSearchEnabled (#458) --- .../search-input-control.component.html | 15 ++++++++++++--- .../search-input.component.theme.scss | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/app/components/search-input-control/search-input-control.component.html b/src/app/components/search-input-control/search-input-control.component.html index 4ef43ef9c6..13db9bdf2b 100644 --- a/src/app/components/search-input-control/search-input-control.component.html +++ b/src/app/components/search-input-control/search-input-control.component.html @@ -10,6 +10,7 @@ +
@@ -65,14 +74,14 @@

-

{{item?.entry.createdByUser.displayName}}

+

{{item?.entry?.createdByUser?.displayName}}

+ *ngIf="isNoSearchTemplatePresent(); else defaultNoResult">

{{ 'SEARCH.RESULTS.NONE' | translate:{searchTerm: searchTerm} }}

diff --git a/src/app/components/search-input/search-input.component.theme.scss b/src/app/components/search-input/search-input.component.theme.scss index ead9a266d1..8be93e791c 100644 --- a/src/app/components/search-input/search-input.component.theme.scss +++ b/src/app/components/search-input/search-input.component.theme.scss @@ -19,7 +19,7 @@ .adf-search-button { left: -15px; - margin-left: 13px; + margin-left: 15px; align-items: flex-start; font: 400 11px system-ui; color: mat-color($background, card); From e600d437e3c5aa230b16e123900eab8d345af153 Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Tue, 26 Jun 2018 15:11:33 +0300 Subject: [PATCH 144/179] [ACA-1489] Handling cleared searches and searches with no results (#460) * skip search action when no searchTerm * hide search filters when no results --- src/app/components/search-input/search-input.component.ts | 8 ++++++-- src/app/components/search/search.component.html | 4 +++- src/app/components/search/search.component.scss | 4 ++++ src/app/components/search/search.component.ts | 3 ++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/app/components/search-input/search-input.component.ts b/src/app/components/search-input/search-input.component.ts index ad8455fcca..2285cf376f 100644 --- a/src/app/components/search-input/search-input.component.ts +++ b/src/app/components/search-input/search-input.component.ts @@ -112,7 +112,9 @@ export class SearchInputComponent implements OnInit { */ onSearchSubmit(event: KeyboardEvent) { const searchTerm = (event.target as HTMLInputElement).value; - this.store.dispatch(new SearchByTermAction(searchTerm)); + if (searchTerm) { + this.store.dispatch(new SearchByTermAction(searchTerm)); + } } onSearchChange(searchTerm: string) { @@ -130,7 +132,9 @@ export class SearchInputComponent implements OnInit { } this.navigationTimer = setTimeout(() => { - this.store.dispatch(new SearchByTermAction(searchTerm)); + if (searchTerm) { + this.store.dispatch(new SearchByTermAction(searchTerm)); + } this.hasOneChange = false; }, 1000); } diff --git a/src/app/components/search/search.component.html b/src/app/components/search/search.component.html index dca4e21e75..e6a1898382 100644 --- a/src/app/components/search/search.component.html +++ b/src/app/components/search/search.component.html @@ -66,7 +66,9 @@
- +
diff --git a/src/app/components/search/search.component.scss b/src/app/components/search/search.component.scss index 2ba9bb18c8..6a201a3b10 100644 --- a/src/app/components/search/search.component.scss +++ b/src/app/components/search/search.component.scss @@ -34,6 +34,10 @@ padding: 5px; height: 100%; overflow: scroll; + + &--hidden { + display: none; + } } .text--bold { diff --git a/src/app/components/search/search.component.ts b/src/app/components/search/search.component.ts index c438a24548..895885ff96 100644 --- a/src/app/components/search/search.component.ts +++ b/src/app/components/search/search.component.ts @@ -87,7 +87,8 @@ export class SearchComponent extends PageComponent implements OnInit { this.queryBuilder.userQuery = query; this.queryBuilder.update(); } else { - this.onSearchResultLoaded( {list: { pagination: { totalItems: 0 }, entries: []}} ); + this.queryBuilder.userQuery = null; + this.queryBuilder.executed.next( {list: { pagination: { totalItems: 0 }, entries: []}} ); } }); } From 5a05aba2806958956a1b3a4b7f291fc8e92aff73 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 26 Jun 2018 15:53:36 +0100 Subject: [PATCH 145/179] improve docs readability (#459) * merge several pages together * docs cleanup * merge "Home" and "Features" together * fix broken links * update json example * fix link --- README.md | 2 +- docs/README.md | 367 ++++++++++++++++++++++++-- docs/build.md | 56 ---- docs/configuration.md | 141 ---------- docs/cors.md | 21 -- docs/doc-list.md | 143 ----------- docs/docker.md | 158 ------------ docs/faq.md | 33 --- docs/features.md | 19 -- docs/file-viewer.md | 43 ---- docs/getting-started.md | 556 ++++++++++++++++++++++++++++++++++++++++ docs/header.md | 25 -- docs/help.md | 29 ++- docs/i18n.md | 131 ---------- docs/index.html | 72 +----- docs/info-drawer.md | 23 -- docs/navigation.md | 163 ------------ docs/side-nav.md | 27 -- docs/version-manager.md | 33 --- 19 files changed, 934 insertions(+), 1108 deletions(-) delete mode 100644 docs/build.md delete mode 100644 docs/configuration.md delete mode 100644 docs/cors.md delete mode 100644 docs/doc-list.md delete mode 100644 docs/docker.md delete mode 100644 docs/faq.md delete mode 100644 docs/features.md delete mode 100644 docs/file-viewer.md create mode 100644 docs/getting-started.md delete mode 100644 docs/header.md delete mode 100644 docs/i18n.md delete mode 100644 docs/info-drawer.md delete mode 100644 docs/navigation.md delete mode 100644 docs/side-nav.md delete mode 100644 docs/version-manager.md diff --git a/README.md b/README.md index e3544b6cb9..a3a56594aa 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,6 @@ npm run stop:docker To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). -[contributing]: ttps://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md +[contributing]: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md [github]: https://github.com/Alfresco/alfresco-content-app/issues [jira]: https://issues.alfresco.com/jira/projects/ACA diff --git a/docs/README.md b/docs/README.md index 472b78e364..aadb637d16 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,35 +17,370 @@ with a simple and easy to use interface for working with files stored in the Alf This application uses the latest releases from Alfresco: -- [Alfresco ADF version 2.3](https://community.alfresco.com/community/application-development-framework/pages/get-started) -- [Alfresco Content Services version 5.2.3](https://www.alfresco.com/platform/content-services-ecm) -- [Alfresco Community Edition 201802 EA](https://www.alfresco.com/products/community/download) +- [Alfresco ADF (2.4.0)](https://community.alfresco.com/community/application-development-framework/pages/get-started) +- [Alfresco Content Services (5.2.3)](https://www.alfresco.com/platform/content-services-ecm) + or [Alfresco Community Edition (201802 EA)](https://www.alfresco.com/products/community/download)

-You also need node.js (8.9.1 or later) installed to build it locally from source code. +You also need node.js (LTS) installed to build it locally from source code.

The latest version of the Alfresco Content platform is required due to the application using the latest [REST APIs](https://docs.alfresco.com/5.2/pra/1/topics/pra-welcome.html) developments. -## Contribution Policy +## Features -### How to contribute +The concept of this example is a simple user interface which makes accessing files in the Alfresco Content Services repository easy. -Fork our repository and submit a pull request when your code is ready for review. -To be considered the Travis build must be green and all our automation tests must run without regressions. +Often Content Management systems provide more capabilities out of the box than most users need; +providing too many capabilities to these users prevents them from working efficiently, +so they may end up using unsanctioned file management solutions which presents a proliferation of content storage +and collaboration solutions as well as compliance issues for organizations. -### Contribute to the existing code base +This application demonstrates how the complexity of Content Management can be simplified +using the Alfresco Application Development Framework to easily and quickly create custom solutions for specific user cases. -What are we reviewing for? +### User Interface - layout -- **License**: Every file should contain the Alfresco LICENSE header, LGPL Licence. -- **Tests**: Add unit cases to cover the new behavior, and make sure all the existing tests are still green. -- **JS Documentation**: Every class needs to have its own inline jsdoc, this documentation should explain the general purpose of the class and of each method. -- **Documentation**: Update the documentation explaining how to use the new functionality, may not be necessary in the cases where change impacts only the CSS style. -- **Clean Coding**: Some good rules are enforced by the tslint, but we want also our code to be easy to read. Please avoid comments inside the code or leaving pieces of code commented out. -- **Localization**: Your contribution needs to support localization, with all new strings externalized, all translations are inside the i18n. The minimum requirement is English. +There are three main areas of the application controlled by the [Layout component](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/layout): + +- [(1) Application Header](#header) +- [(2) Side Navigation](#side-navigation) +- [(3) Document List](#document-list-layout) + +![](images/features-01.png) + +### Header + +The application [header](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/header) has three main elements. + +1. [Logo and Color](#logo-and-color) +2. [Search](#search) +3. [Current User](#current-user) + +![](images/header.png) + +#### Logo and Color + +Logo & app primary color - logo and color are configurable by updating the +[app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json) file in the root folder of the project. +Please refer to the [Application Configuration](https://github.com/Alfresco/alfresco-content-app/blob/master/docs/configuration.md#application-logo) documentation for more information on how to change the logo and color. + +#### Search + +The application [Search](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/search) - +uses the [ADF Search Component](https://github.com/Alfresco/alfresco-ng2-components/tree/master/lib/content-services/search) +the app provides a 'live' search feature, where users can open files and folders directly from the Search API results. + +![](images/search.png) + +#### Current User + +[Current User](https://github.com/Alfresco/alfresco-content-app/tree/development/src/app/components/current-user) - +displays the user's name, and a menu where users can logout. +Optionally through updating the [app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json) +a language switching menu can be displayed. + +![](images/current-user.png) + +### Side Navigation + +The application [side navigation](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/sidenav) has two features: +a button menu and navigation links. + +![](images/side-nav.png) + +#### New button + +The New button displays a menu which provides three actions: + +- Create a new folder - provides a dialog which allows the creation of a new folder, the folder name is mandatory and the description is optional. +- Upload a file - invokes the operating system file browser and allows a user to select file(s) to upload into their current location in the content repository. +- Upload a folder - invokes the operating system folder browser and allows a user to select a folder to upload to their current location in the content repository. + +When an upload starts the [upload component](https://github.com/Alfresco/alfresco-ng2-components/tree/master/lib/content-services/upload) +is displayed which shows the user the progress of the uploads they have started. +The upload dialog persists on the screen and can be minimized; users are able to continue using the application whilst uploads are in progress +and uploads can be canceled which will stop uploads in progress or permanently delete already completed uploads. + +![](images/uploader.png) + +#### Navigation + +The navigation links are configurable via the [app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json). +Default configuration creates two sections. +See [Navigation](#navigation) for more information about configuring the side navigation. + +### Document List Layout + +The main area of the application is composed of several individual ADF components: + +- (1) [Breadcrumb](https://alfresco.github.io/adf-component-catalog/components/BreadcrumbComponent.html) +- (2) [Toolbar](https://alfresco.github.io/adf-component-catalog/components/ToolbarComponent.html) +- (3) [Document List](https://alfresco.github.io/adf-component-catalog/components/DocumentListComponent.html) +- (4) [Pagination](https://alfresco.github.io/adf-component-catalog/components/PaginationComponent.html) + +![](images/doclist.png) + +The application has six different Document List views which share commonalities between each view and subtle differences depending on the content being loaded which are explained below. + +#### Personal Files + +Personal Files retrieves all content from the logged in user's home area (`/User Homes//`) in the repository; +if the user is ‘admin’ who does not have a home folder then the repository root folder is shown. + +Personal Files is the [Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/files) component, +using the [Nodes API](https://api-explorer.alfresco.com/api-explorer/#/nodes). + +#### File Libraries + +File Libraries retrieves all the sites that the user is a member of including what type of site it is: public, moderated or private. +File Libraries is the [Libraries](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/libraries) component, +using the [Sites API](https://api-explorer.alfresco.com/api-explorer/#/sites). + +When a user opens one of their sites then the content for the site's document library is shown. +To display the files and folders from a site (`/Sites//Document Library/`) the [Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/files) component, +using the [Nodes API](https://api-explorer.alfresco.com/api-explorer/#/nodes) is used. + +#### Shared Files + +The Shared Files view aggregates all files that have been shared using the QuickShare feature in the content repository. +The [Shared Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/shared-files) component uses the [shared-links API](https://api-explorer.alfresco.com/api-explorer/#/shared-links) +and includes extra columns to display where the file is +[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link) +in the content repository and who created the shared link. + +A feature for creating and removing Shared Links will be added in the future. + +#### Recent Files + +The Recent Files view shows all the files that have been created or modified within the last 30 days by the current user. +The [Recent Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/current-user) +component uses the Search API to query SOLR for changes made by the user and includes an extra column to display where the file is +[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link) +in the content repository. + +#### Favorites + +The Favorites view shows all files and folders from the content repository that have been marked as a favorite by the current user. +The [Favorites](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/favorites) component uses the +[favorites](https://api-explorer.alfresco.com/api-explorer/#/favorites) API to retrieve all the favorite nodes for the user +and includes an extra column to display where the file is +[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link) +in the content repository. + +#### Trash + +The Trash view shows all the items that a user has deleted, admin will see items deleted by all users. +The actions available in this view are Restore and Permanently Delete. +The [Trashcan](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/trashcan) component uses the +[trashcan](https://api-explorer.alfresco.com/api-explorer/#/trashcan) API to retrieve the deleted items +and perform the actions requested by the user and includes an extra column to display where the item was +[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link) +in the content repository before it was deleted. + +#### Actions and the Actions Toolbar + +All the views incorporate the [toolbar](https://alfresco.github.io/adf-component-catalog/components/ToolbarComponent.html) +component from the Alfresco Application Development Framework; +apart from the Trash view they all display the following actions when the current user has the necessary permissions, +actions are automatically hidden when the user does not have permission. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionFileFolder
View + Opens the selected file using the Preview component, + where the file cannot be displayed natively in a browser a PDF rendition is obtained from the repository. + Not applicable
DownloadDownloads single files to the user's computer, when multiple files are selected they are compressed into a ZIP and then downloaded.Folders are automatically compressed into a ZIP and then downloaded to the user's computer.
EditNot applicableThe folder name and description can be edited in a dialog.
Favorite + Toggle the favorite mark on or off for files and folders, when multiple items are selected + and one or more are not favorites then the mark will be toggled on. +
Copy + Files and folders can be copied to another location in the content repository using the + content-node-selector component; + once the copy action has completed the user is notified and can undo the action (which permanently deletes the created copies). +
Move + Files and folders can be moved to another location in the content repository using the + content-node-selector component; + once the move action has completed the user is notified and can undo the action (which moves the items back to the original location). +
Delete + Files and folders can be deleted from their location in the content repository; + once the delete action has completed the user is notified and can undo the action (which restores the items from the trash). +
Manage Versions + Versions of files can be viewed, uploaded, restored, downloaded and deleted by using the version manager dialog; + once each action has completed the list of versions is updated according to the change. + Not applicable
+ +Besides the actions available in the toolbar users can single click an item to select it, +or double click on a file to view it, and a folder to open it. + +### File Viewer + +The File Viewer has been created using the [ViewerComponent](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html) from the ADF. The Viewer has four main areas: + +![](images/File-Viewer.png) + +1. [Header & Toolbar](#header-and-toolbar) +2. [Content](#content) +3. [Thumbnails side pane](#thumbnails-side-pane) +4. [Viewer Controls](#viewer-controls) + +#### Header and Toolbar + +The Header & Toolbar section of the viewer contains a number of features that relate to the file currently being displayed: + +- Close 'X' will return the user to the folder that contains the file. +- The name and file type icon is shown in the middle. +- Next and previous buttons will be displayed either side of the file name so that users can navigate to other files in the folder without navigating away from the viewer. +- Finally, on the right hand side an actions toolbar provides users with the ability to download, favorite, move, copy, delete, manage versions and view info panel. + +#### Content + +The File Viewer consists of four separate views that handle displaying the content based on four types of content, covering various [file/mime](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html#supported-file-formats) types: + +- Document View: PDFs are displayed in the application File Viewer, for other document types (DOCX etc) then a PDF rendition is automatically retrieved. +- Image View: JPEG, PNG, GIF, BMP and SVG images are natively displayed in the application File Viewer. +- Media View: MP4, MP3, WAV, OGG and WEBM files are played natively application File Viewer. The File Viewer will download, by default, 50MB of the content at a time to ensure a smooth playback of the content. +- Text View: TXT, XML, JS, HTML, JSON and TS files are natively displayed as text in the application File Viewer. + +#### Thumbnails side pane + +The Document View includes a thumbnails pane which can be activated by a button in the Viewer Actions toolbar. Clicking on a thumbnail will take a user directly to the selected page and as users scroll through a document the current page is highlighted in the pane. + +#### Viewer Controls + +At the bottom of the content the Viewer Controls allow users to interact with the content in various ways; the actions available are dependant on the type of content being displayed. + +- Document View: + - Activate/Deactivate thumbnails pane + - Previous/Next page + - Jump to page number + - Zoom in/out + - Fit to page +- Image View: + - Zoom in/out + - Rotate left/right (does not alter content in the repository) + - Reset image +- Media View: + - Play/pause + - Timeline position + - Audio mute/unmute + - Audio volume + - Full screen + +### Info Drawer + +The Info Drawer displays node information in the right sidebar panel. It is created by using the [InfoDrawerComponent](https://alfresco.github.io/adf-component-catalog/components/InfoDrawerComponent.html). This info is available for both folder and file nodes. + +Currently, there are 2 tabs available: Properties and Versions. + +#### Properties tab + +The Properties tab displays the node's metadata info by using the [ContentMetadataCardComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataCardComponent.html). + +![](images/content-metadata.png) + +For more information, please check also the ADF's [ContentMetadataComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataComponent.html). + +#### Versions tab + +The Versions tab displays info about the node's versions and allows users to [manage versions](#version-manager), according to their permissions. Only the file nodes have version data available. + +![](images/version-manager-tab.png) + +It uses the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html) from ADF framework. + +Managing versions of a file can be possible also by accessing the 'Manage Versions' option from the 'More actions' menu. For more info on manage versions, please check the [version manager](#version-manager) page. + +### Version Manager + +The versions of a file can be viewed & managed by using the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html). + +There are 2 ways users can access the Version Manager: + +1. From the 'Manage Versions' option of the 'More actions' menu (check [Actions and the Actions Toolbar](#actions-and-the-actions-toolbar)): + +![](images/version-manager-action.png) +![](images/version-manager-dialog.png) + +2. From the [Info Drawer](/info-drawer) (the Details right panel): + +![](images/version-manager-tab.png) + +#### Upload new version + +A new version for the selected file can be added by using this button. There is a restriction currently to only upload files of the same extension as the old version. The new version file will be automatically renamed to have the same name as the old version has. Please also check the [UploadVersionButtonComponent](https://alfresco.github.io/adf-component-catalog/components/UploadVersionButtonComponent.html). + +#### Actions Menu + +Each item in the version list has a couple of actions available: Restore, Download and Delete. These are displayed if user has permission to do that specific action. The 'Download' and 'Delete' can be also disabled from the app.config. + +In the app.config.json file, these are the current settings for the ACA version manager: + +```json +{ + "adf-version-manager": { + "allowComments": true, + "allowDownload": true + } +} +``` + +Set the allowComments to false if the version comments should not be displayed on the version list. + +Clicking to delete a version of a file triggers a confirmation dialog. Please see the [ConfirmDialogComponent](https://alfresco.github.io/adf-component-catalog/components/ConfirmDialogComponent.html) for more info. + +## How to contribute + +Want to file a bug, contribute some code, or improve documentation? Excellent! +Read up on our guidelines for [contributing][contributing] +and then check out one of our issues in the [Jira][jira] or [GitHub][github] ### How long will it take for my contribution to be reviewed The time necessary for a code review will vary, smaller changes may be reviewed within days, while larger changes may take longer. + +[contributing]: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md +[github]: https://github.com/Alfresco/alfresco-content-app/issues +[jira]: https://issues.alfresco.com/jira/projects/ACA diff --git a/docs/build.md b/docs/build.md deleted file mode 100644 index 0d486c4790..0000000000 --- a/docs/build.md +++ /dev/null @@ -1,56 +0,0 @@ -# Building from source code - -The Content App is based on [Angular CLI](https://cli.angular.io), and you can use all the commands, generators and blueprints supported by the CLI. - -## Prerequisites - -- [Node.js](https://nodejs.org/en/) 8.9.1 or later LTS version -- [Angular CLI](https://cli.angular.io/) - -## Cloning and running - -Use the following commands to clone the project, install dependencies and run it. - -```sh -git clone https://github.com/Alfresco/alfresco-content-app.git -cd alfresco-content-app -npm install -npm start -``` - -The application runs at port 4200 by default, and should automatically open in the default browser once project compilation finishes. - -## Proxy settings - -The Content App provides a proxy configuration for local development server -that allows you to address specific scenarios with CORS and native authentication dialog. - -You can find settings in the "proxy.conf.js" file in the project root directory. - -

-The proxy settings get automatically applied every time you run the application with "npm start" script. -You must restart the application every time you change the settings values. -

- -## Running documentation locally - -For development purposes, you can run and test documentation locally. -This is useful when working in different branches instead of a `master` one. - -Run the following command to install the lightweight development server [wsrv](https://denysvuika.gitlab.io/wsrv/#/): - -```sh -npm install -g wsrv -``` - -Now you can use the next command to serve the documentation folder in the browser: - -```sh -wsrv docs/ -s -l -o -``` - -The browser page is going to automatically reload upon changes. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). diff --git a/docs/configuration.md b/docs/configuration.md deleted file mode 100644 index 258ddb4884..0000000000 --- a/docs/configuration.md +++ /dev/null @@ -1,141 +0,0 @@ -# Application Configuration - -The Content Application provides support for a global settings file `app.config.json` that you can use to customize the behavior of ACA and ADF components. - -## Server settings - -Once the Content Application starts, it needs to know where the Alfresco Content Services (either Community or Enterprise) server is. -The "ecmHost" property allows you to set the address of the server using the dynamic or static format. - -### Dynamic address - -The example below demonstrates the most common dynamic format for development environment: - -```json -{ - "ecmHost": "http://{hostname}{:port}", - ... -} -``` - -The configuration above assumes you are running ACS and Content App on the same server and port -and allows deploying to different servers having the same unified configuration file. - -For example, a proxy server at `localhost:4200` hosting the Content App as the root application, -and `localhost:4200/alfresco` for the ACS repository. - -At runtime, the application is going to automatically substitute the "{hostname}" value with the original hostname. -Optionally it can also use the value of the original port if present, for example, "4200" at local machines, or skip the value for port 80. - -### Static address - -Alternatively, you can provide a static address for the ACS server if necessary: - -```json -{ - "ecmHost": "http://localhost:4200", - ... -} -``` - -## Application settings - -There are many settings you can change to alter the default behavior of the application. - -### Application Name - -The following block allows you to change the name of the application. - -```json -{ - ..., - "application": { - "name": "Alfresco Example Content Application" - } -} -``` - -The value of the `application.name` key gets appended to every browser tab title at runtime -with the format `[page title] - [application name]`, -for example: "Personal Files - Alfresco Example Content Application". - -### Application Logo - -The default logo displayed in the top left corner of the Alfresco Content Application can be easily changed: - -1. Place your custom logo image file in the [app-name]/src/assets/images folder. The displayed image will resize automatically, an image with extreme width/height might not retain its dimensions. - -2. In the app.config.json file, set the value of the application.logo to contain the name of the custom logo image: "logo": "/assets/images/[image-name].[extension]" - - -```json -{ - ..., - "application": { - "logo": "/assets/images/alfresco-logo-white.svg" - } -} -``` - -### Header Background color - -You can change the header background color by specifying color code for the "headerColor" key: - -```json -{ - ..., - "headerColor": "#2196F3" -} -``` - - -### 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. - -By default, the application ships with the following rules already predefined: - -```json -{ - ..., - "files": { - "excluded": [ - ".DS_Store", - "desktop.ini", - "thumbs.db", - ".git" - ] - }, - ... -} -``` - -

-You can get more details on the supported rules in the following article: Upload Service. -

- -### Pagination settings - -You can change the default settings of the pagination that gets applied to all the document lists in the application. - -```json -{ - ..., - "pagination": { - "supportedPageSizes": [ - 25, - 50, - 100 - ] - }, - ... -} -``` - -## Your custom settings - -You can store any information in the application configuration file, and access it at runtime by using the `AppConfigService` service provided by ADF. - -

-Please refer to the AppConfigService documentation to get more details on Application Configuration features and API available. -

diff --git a/docs/cors.md b/docs/cors.md deleted file mode 100644 index 6ea79e47ad..0000000000 --- a/docs/cors.md +++ /dev/null @@ -1,21 +0,0 @@ -# Cross Origin Resource Sharing (CORS) - -## Chrome Workaround - -For the Chrome browser, you can use the following plugin that allows you to toggle CORS: -[Allow-Control-Allow-Origin](https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi) - -## Firefox Workaround - -Firefox users can try the following plugin: [CORS Everywhere](https://addons.mozilla.org/en-Gb/firefox/addon/cors-everywhere/) - -## Safari Workaround - -If you are developing or testing with Safari then you can use the "Develop" menu to toggle the CORS mode. -Please note that the page must be reloaded every time you change CORS settings. - -![](images/safari-develop-menu.png) - -## See also - -- [Using CORS](https://www.html5rocks.com/en/tutorials/cors/) diff --git a/docs/doc-list.md b/docs/doc-list.md deleted file mode 100644 index e3e2433473..0000000000 --- a/docs/doc-list.md +++ /dev/null @@ -1,143 +0,0 @@ -### Document List Layout - -The main area of the application is composed of several individual ADF components: - -- (1) [Breadcrumb](https://alfresco.github.io/adf-component-catalog/components/BreadcrumbComponent.html) -- (2) [Toolbar](https://alfresco.github.io/adf-component-catalog/components/ToolbarComponent.html) -- (3) [Document List](https://alfresco.github.io/adf-component-catalog/components/DocumentListComponent.html) -- (4) [Pagination](https://alfresco.github.io/adf-component-catalog/components/PaginationComponent.html) - -![](images/doclist.png) - -The application has six different Document List views which share commonalities between each view and subtle differences depending on the content being loaded which are explained below. - -#### Personal Files - -Personal Files retrieves all content from the logged in user's home area (`/User Homes//`) in the repository; -if the user is ‘admin’ who does not have a home folder then the repository root folder is shown. - -Personal Files is the [Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/files) component, -using the [Nodes API](https://api-explorer.alfresco.com/api-explorer/#/nodes). - -#### File Libraries - -File Libraries retrieves all the sites that the user is a member of including what type of site it is: public, moderated or private. -File Libraries is the [Libraries](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/libraries) component, -using the [Sites API](https://api-explorer.alfresco.com/api-explorer/#/sites). - -When a user opens one of their sites then the content for the site's document library is shown. -To display the files and folders from a site (`/Sites//Document Library/`) the [Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/files) component, -using the [Nodes API](https://api-explorer.alfresco.com/api-explorer/#/nodes) is used. - -#### Shared Files - -The Shared Files view aggregates all files that have been shared using the QuickShare feature in the content repository. -The [Shared Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/shared-files) component uses the [shared-links API](https://api-explorer.alfresco.com/api-explorer/#/shared-links) -and includes extra columns to display where the file is -[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link) -in the content repository and who created the shared link. - -A feature for creating and removing Shared Links will be added in the future. - -#### Recent Files - -The Recent Files view shows all the files that have been created or modified within the last 30 days by the current user. -The [Recent Files](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/current-user) -component uses the Search API to query SOLR for changes made by the user and includes an extra column to display where the file is -[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link) -in the content repository. - -#### Favorites - -The Favorites view shows all files and folders from the content repository that have been marked as a favorite by the current user. -The [Favorites](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/favorites) component uses the -[favorites](https://api-explorer.alfresco.com/api-explorer/#/favorites) API to retrieve all the favorite nodes for the user -and includes an extra column to display where the file is -[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link) -in the content repository. - -#### Trash - -The Trash view shows all the items that a user has deleted, admin will see items deleted by all users. -The actions available in this view are Restore and Permanently Delete. -The [Trashcan](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/trashcan) component uses the -[trashcan](https://api-explorer.alfresco.com/api-explorer/#/trashcan) API to retrieve the deleted items -and perform the actions requested by the user and includes an extra column to display where the item was -[located](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/location-link) -in the content repository before it was deleted. - -#### Actions and the Actions Toolbar - -All the views incorporate the [toolbar](https://alfresco.github.io/adf-component-catalog/components/ToolbarComponent.html) -component from the Alfresco Application Development Framework; -apart from the Trash view they all display the following actions when the current user has the necessary permissions, -actions are automatically hidden when the user does not have permission. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ActionFileFolder
View - Opens the selected file using the Preview component, - where the file cannot be displayed natively in a browser a PDF rendition is obtained from the repository. - Not applicable
DownloadDownloads single files to the user's computer, when multiple files are selected they are compressed into a ZIP and then downloaded.Folders are automatically compressed into a ZIP and then downloaded to the user's computer.
EditNot applicableThe folder name and description can be edited in a dialog.
Favorite - Toggle the favorite mark on or off for files and folders, when multiple items are selected - and one or more are not favorites then the mark will be toggled on. -
Copy - Files and folders can be copied to another location in the content repository using the - content-node-selector component; - once the copy action has completed the user is notified and can undo the action (which permanently deletes the created copies). -
Move - Files and folders can be moved to another location in the content repository using the - content-node-selector component; - once the move action has completed the user is notified and can undo the action (which moves the items back to the original location). -
Delete - Files and folders can be deleted from their location in the content repository; - once the delete action has completed the user is notified and can undo the action (which restores the items from the trash). -
Manage Versions - Versions of files can be viewed, uploaded, restored, downloaded and deleted by using the version manager dialog; - once each action has completed the list of versions is updated according to the change. - Not applicable
- -Besides the actions available in the toolbar users can single click an item to select it, -or double click on a file to view it, and a folder to open it. diff --git a/docs/docker.md b/docs/docker.md deleted file mode 100644 index 86d5ce13db..0000000000 --- a/docs/docker.md +++ /dev/null @@ -1,158 +0,0 @@ -# Using with Docker - -

-This article assumes you are familiar with Docker and know how to create images and containers. -

- -You can create a Docker image to run Alfresco Content App in the container. - -## Using public Docker images - -You can find all latest images for ACA in the [alfresco-content-app]( https://hub.docker.com/r/alfresco/alfresco-content-app/) DockerHub repository. - -### Tags - -- `latest`: latest stable release (`master` branch), available with 1.1 release or later -- `development`: most recent code (`development` branch) - -In addition, there are images for feature branches, pull requests and Travis CI builds. - -### Example - -You can run latest `development` build locally with the following command: - -```sh -docker run -p 3000:80 alfresco/alfresco-content-app:development -``` - -The default image expects an ACS 5.2.2 or later running at port `8080`. -You may also need CORS settings to be applied for your ACS installation or image. - -## Building from source code - -You need to run the following commands to build the project from the source code: - -```sh -npm install -npm run build -``` - -That produces a build in the "dist" folder that you can use with a Docker image. - -

-Also, you may need to update the `dist/app.config.json` file with the settings relevant to your scenario. -

- -## Creating an image - -The Content Application provides a "Dockerfile" file in the repository root. -You can build the image with the following command: - -```sh -docker image build -t content-app . -``` - -## Running image in a container - -To run the image locally, you can use the following command: - -```sh -docker container run -p 8888:80 --rm content-app -``` - -Navigate to "http://localhost:8888" to access the running application. - -## Docker Compose file - -You can also use the "docker-compose" file for local development and testing. -To build and run a container run the following command in the root project folder: - -```sh -docker-compose up -``` - -To perform a cleanup operation, use the next command: - -```sh -docker-compose down --rmi all -``` - -Navigate to "http://localhost:4200" to access the running application. - -

-Please keep in mind that you should manually build the project every time you want to publish the image or run it locally with the container. -

- -## Using with local ACS setup - -If you run ACS at port 8080 as a Docker container (typical development configuration), you can use the following command to build the project before creating an image: - -```sh -npm run build:dev -``` - -The command above updates the "dist/app.config.json" file to point the Content App to "http://localhost:8080" upon startup. -Alternatively, you can change the configuration file manually before generating an image. - -So, the development workflow, in this case, is going to be: - -```sh -npm run build:dev -docker-compose up -``` - -Navigate to "http://localhost:4200" to access the running application. - -To perform a cleanup operation, use the next command: - -```sh -docker-compose down --rmi all -``` - -## Publishing to Docker Hub - -First of all, if you do not have a Docker Hub account, you can register here: https://hub.docker.com/, the registration is absolutely free. - -Next, it is recommended that you get a clean build of the application: - -```sh -npm install -npm run build:dev -``` - -The commands above are going to produce a fresh build that is stored in the `dist` folder. -At this point, you can make modifications to the final code in the `dist` folder if needed. -For example you may want to change the `app.config.json` file content. - -Now you can build your first version of the image: - -```sh -docker image build -t myaccount/content-app:1.0 . -``` - -Where `myaccount` is usually your Docker Hub account name. - -

-Please note the ending "." symbol at the end of the command. It instructs the Docker to take current folder where the `Dockerfile` is located. -

- -To publish the newly created image use the next command: - -```sh -docker push myaccount/content-app:1.0 -``` - -## Running from Docker Hub - -To quickly test the published image, or run it on another machine, use the following command: - -```sh -docker container run -p 80:80 --rm myaccount/content-app:1.0 -``` - -The `--rm` switch means the Docker will cleanup the container and image data once you stop the process. - -

-You may also want to remove your local image before trying out the Docker Hub:
-`docker image rm myaccount/content-app:1.0` -

diff --git a/docs/faq.md b/docs/faq.md deleted file mode 100644 index 68d192eb76..0000000000 --- a/docs/faq.md +++ /dev/null @@ -1,33 +0,0 @@ -# Frequently asked questions - -## How do I log an issue (bug, enhancement, feature)? - -Log any issues in the ['ACA' JIRA project](https://issues.alfresco.com/jira/projects/ACA), -please include a clear description, steps to reproduce and screenshots where appropriate. -All issues will be reviewed; bugs will be categorized if reproducible and enhancement/feature suggestions -will be considered against existing priorities if the use case serves a general-purpose need. - -## Does Alfresco provide customer support for the example content application? - -Alfresco does not provide Customer Support, it is an example application for developers; [Developer Support Services](https://www.alfresco.com/alfresco-developer-support-services) are available from Alfresco. - -## Does this/Will this application replace Alfresco Share? - -This example application is designed to demonstrate how to construct a content application using the Alfresco Application Development Framework, -it is not intended to be a replacement for Alfresco Share. - -## Where can I get help building an application? - -See [Where to get help](/?id=where-to-get-help) section. - -## How do I contribute to the project? - -See [Contribution Policy](/?id=contribution-policy) section. - -## What would you like me to contribute? - -Please refer to the ['ACA' JIRA project](https://issues.alfresco.com/jira/projects/ACA) for tickets in the project backlog. - -## How often will this project be updated? - -This project will continue to evolve as the Alfresco ADF evolves, with Alfresco and community developers contributing to its progress. diff --git a/docs/features.md b/docs/features.md deleted file mode 100644 index 39de383ac9..0000000000 --- a/docs/features.md +++ /dev/null @@ -1,19 +0,0 @@ -# Features -## Introduction -The concept of this example is a simple user interface which makes accessing files in the Alfresco Content Services repository easy. - -Often Content Management systems provide more capabilities out of the box than most users need; -providing too many capabilities to these users prevents them from working efficiently, -so they may end up using unsanctioned file management solutions which presents a proliferation of content storage -and collaboration solutions as well as compliance issues for organizations. - -This application demonstrates how the complexity of Content Management can be simplified -using the Alfresco Application Development Framework to easily and quickly create custom solutions for specific user cases. - -## User Interface - layout -There are three main areas of the application controlled by the [Layout component](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/layout): -- [(1) Application Header](/header) -- [(2) Side Navigation](/side-nav) -- [(3) Document List](/doc-list) - -![](images/features-01.png) diff --git a/docs/file-viewer.md b/docs/file-viewer.md deleted file mode 100644 index 9ce7d51073..0000000000 --- a/docs/file-viewer.md +++ /dev/null @@ -1,43 +0,0 @@ -### File Viewer - -The File Viewer has been created using the [ViewerComponent](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html) from the ADF. The Viewer has four main areas: - -![](images/File-Viewer.png) - -#### Header & Toolbar (1) -The Header & Toolbar section of the viewer contains a number of features that relate to the file currently being displayed: -- Close 'X' will return the user to the folder that contains the file. -- The name and file type icon is shown in the middle. -- Next and previous buttons will be displayed either side of the file name so that users can navigate to other files in the folder without navigating away from the viewer. -- Finally, on the right hand side an actions toolbar provides users with the ability to download, favorite, move, copy, delete, manage versions and view info panel. - -#### Content (2) -The File Viewer consists of four separate views that handle displaying the content based on four types of content, covering various [file/mime](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html#supported-file-formats) types: - -- Document View: PDFs are displayed in the application File Viewer, for other document types (DOCX etc) then a PDF rendition is automatically retrieved. -- Image View: JPEG, PNG, GIF, BMP and SVG images are natively displayed in the application File Viewer. -- Media View: MP4, MP3, WAV, OGG and WEBM files are played natively application File Viewer. The File Viewer will download, by default, 50MB of the content at a time to ensure a smooth playback of the content. -- Text View: TXT, XML, JS, HTML, JSON and TS files are natively displayed as text in the application File Viewer. - -#### Thumbnails side pane (3) -The Document View includes a thumbnails pane which can be activated by a button in the Viewer Actions toolbar. Clicking on a thumbnail will take a user directly to the selected page and as users scroll through a document the current page is highlighted in the pane. - -#### Viewer Controls (4) -At the bottom of the content the Viewer Controls allow users to interact with the content in various ways; the actions available are dependant on the type of content being displayed. - -- Document View: - - Activate/Deactivate thumbnails pane - - Previous/Next page - - Jump to page number - - Zoom in/out - - Fit to page -- Image View: - - Zoom in/out - - Rotate left/right (does not alter content in the repository) - - Reset image -- Media View: - - Play/pause - - Timeline position - - Audio mute/unmute - - Audio volume - - Full screen diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000000..e31a9c8287 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,556 @@ +# Getting Started + +## Prerequisites + +This application uses the latest releases from Alfresco: + +- [Alfresco ADF (2.4.0)](https://community.alfresco.com/community/application-development-framework/pages/get-started) +- [Alfresco Content Services (5.2.3)](https://www.alfresco.com/platform/content-services-ecm) + or [Alfresco Community Edition (201802 EA)](https://www.alfresco.com/products/community/download) + +

+You also need node.js (LTS) installed to build it locally from source code. +

+ +The latest version of the Alfresco Content platform is required +due to the application using the latest [REST APIs](https://docs.alfresco.com/5.2/pra/1/topics/pra-welcome.html) developments. + +## Building from source + +The Content App is based on [Angular CLI](https://cli.angular.io), and you can use all the commands, generators and blueprints supported by the CLI. + +### Prerequisites for building + +- [Node.js](https://nodejs.org/en/) LTS +- [Angular CLI](https://cli.angular.io/) 1.7.3 + +### Cloning and running + +Use the following commands to clone the project, install dependencies and run it. + +```sh +git clone https://github.com/Alfresco/alfresco-content-app.git +cd alfresco-content-app +npm install +npm start +``` + +The application runs at port `4200` by default, and should automatically open in the default browser once project compilation finishes. + +### Proxy settings + +The Content App provides a proxy configuration for local development server +that allows you to address specific scenarios with CORS and native authentication dialog. + +You can find settings in the "proxy.conf.js" file in the project root directory. + +

+The proxy settings get automatically applied every time you run the application with "npm start" script. +You must restart the application every time you change the settings values. +

+ +### Running unit tests + +Run `npm test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Internationalization (i18n) + +The Content Application provides support for the following languages: + +- German (`de`) +- English (`en`) +- Spanish (`es`) +- French (`fr`) +- Italian (`it`) +- Japanese (`ja`) +- Norwegian (`nb`) +- Dutch (`nl`) +- Brazilian Portuguese (`pt-BR`) +- Russian (`ru`) +- Simplified Chinese (`zh-CN`) + +The fallback locale is the English one, however current browser language is taken as the default one automatically when the application starts. + +### User-defined language + +You can allow users to set custom language that gets saved to user preferences. +The main application menu already has the [ADF Language Menu](https://github.com/Alfresco/alfresco-ng2-components/blob/development/docs/language-menu.component.md) component integrated and pre-filled with the supported items. + +To change the default language set edit the `app.config.json` file and add or remove items: + +```json +{ + ..., + "languages": [ + { + "key": "de", + "label": "German" + }, + { + "key": "en", + "label": "English" + }, + { + "key": "es", + "label": "Spanish" + }, + ... + ] +} +``` + +The file is located at the following path: `/src/app.config.json`. + +### Custom languages + +To add a custom language, add a new "JSON" file to the "/src/assets/i18n" folder +with the name of the target locale, for instance, a "de.json" for the "German". + +Translate the resource strings based on the default "en.json" file. +You can copy the content over to your newly created file and replace English values with translated text. + +```json +{ + "APP": { + "SIGN_IN": "Anmelden", + "SIGN_OUT": "Abmelden", + "NEW_MENU": { + "LABEL": "Neu", + "MENU_ITEMS": { + "CREATE_FOLDER": "Ordner erstellen", + "UPLOAD_FILE": "Datei hochladen", + "UPLOAD_FOLDER": "Ordner hochladen" + }, + ... + } + }, + ... +} +``` + +The Content Application automatically bundles your file upon project build. +You can test your locale by changing the browser language settings and reloading the page. + +Optionally, you can extend the [ADF Language Menu](https://github.com/Alfresco/alfresco-ng2-components/blob/development/docs/language-menu.component.md) component with the newly added language by updating the `app.config.json` file. + +### Customizing ADF translations + +In addition to creating a custom language file for the Content Application, +you can also provide translations for the ADF resources. + +Your `/src/assets/i18n/.json` file can reflect the structure of one of the ADF language files: + +- ADF Core ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/core/i18n/en.json)) +- ADF Content Services ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/content-services/i18n/en.json)) +- ADF Process Services ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/process-services/i18n/en.json)) +- ADF Insights ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/insights/i18n/en.json)) + +At runtime, the application-level strings have the highest priority. +That means you can replace the value of any ADF resource string if needed. + +For example, let's change the title of the "Create Folder" dialog shipped with the ADF. +Modify the `/src/assets/i18n/en.json` file and append the "CORE" section like in the example below: + +```json +{ + "APP": { + ... + }, + "CORE": { + "FOLDER_DIALOG": { + "CREATE_FOLDER_TITLE": "Custom title" + } + } +} +``` + +Now, if you run the application and click the "New → Create Folder" menu, +the title of the dialog should look like the following: + +![](images/aca-i18n-01.png) + +### Language picker + +You can enable internal language picker in the `app.config.json` file: + +```json +{ + ..., + + "languagePicker": true, + + ... +} +``` + +![](images/aca-i18n-02.png) + +## CORS + +The ACA already comes with the proxy configuration for Angular CLI to address CORS-related issues for development. +Also, the docker images contain Nginx settings needed for CORS when developing and debugging application locally. + +### Chrome Workaround + +For the Chrome browser, you can use the following plugin that allows you to toggle CORS: +[Allow-Control-Allow-Origin](https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi) + +### Firefox Workaround + +Firefox users can try the following plugin: [CORS Everywhere](https://addons.mozilla.org/en-Gb/firefox/addon/cors-everywhere/) + +### Safari Workaround + +If you are developing or testing with Safari then you can use the "Develop" menu to toggle the CORS mode. +Please note that the page must be reloaded every time you change CORS settings. + +![](images/safari-develop-menu.png) + +### See also + +- [Using CORS](https://www.html5rocks.com/en/tutorials/cors/) + +## Configuration + +The Content Application provides support for a global settings file `app.config.json` that you can use to customize the behavior of ACA and ADF components. + +### Server settings + +Once the Content Application starts, it needs to know where the Alfresco Content Services (either Community or Enterprise) server is. +The "ecmHost" property allows you to set the address of the server using the dynamic or static format. + +#### Dynamic address + +The example below demonstrates the most common dynamic format for development environment: + +```json +{ + "ecmHost": "http://{hostname}{:port}", + ... +} +``` + +The configuration above assumes you are running ACS and Content App on the same server and port +and allows deploying to different servers having the same unified configuration file. + +For example, a proxy server at `localhost:4200` hosting the Content App as the root application, +and `localhost:4200/alfresco` for the ACS repository. + +At runtime, the application is going to automatically substitute the "{hostname}" value with the original hostname. +Optionally it can also use the value of the original port if present, for example, "4200" at local machines, or skip the value for port 80. + +#### Static address + +Alternatively, you can provide a static address for the ACS server if necessary: + +```json +{ + "ecmHost": "http://localhost:4200", + ... +} +``` + +### Application settings + +There are many settings you can change to alter the default behavior of the application. + +#### Application Name + +The following block allows you to change the name of the application. + +```json +{ + ..., + "application": { + "name": "Alfresco Example Content Application" + } +} +``` + +The value of the `application.name` key gets appended to every browser tab title at runtime +with the format `[page title] - [application name]`, +for example: "Personal Files - Alfresco Example Content Application". + +#### Application Logo + +The default logo displayed in the top left corner of the Alfresco Content Application can be easily changed: + +1. Place your custom logo image file in the [app-name]/src/assets/images folder. The displayed image will resize automatically, an image with extreme width/height might not retain its dimensions. + +2. In the app.config.json file, set the value of the application.logo to contain the name of the custom logo image: "logo": "/assets/images/[image-name].[extension]" + + +```json +{ + ..., + "application": { + "logo": "/assets/images/alfresco-logo-white.svg" + } +} +``` + +#### Header Background color + +You can change the header background color by specifying color code for the "headerColor" key: + +```json +{ + ..., + "headerColor": "#2196F3" +} +``` + +#### 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. + +By default, the application ships with the following rules already predefined: + +```json +{ + ..., + "files": { + "excluded": [ + ".DS_Store", + "desktop.ini", + "thumbs.db", + ".git" + ] + }, + ... +} +``` + +

+You can get more details on the supported rules in the following article: Upload Service. +

+ +#### Pagination settings + +You can change the default settings of the pagination that gets applied to all the document lists in the application. + +```json +{ + ..., + "pagination": { + "supportedPageSizes": [ + 25, + 50, + 100 + ] + }, + ... +} +``` + +### Your custom settings + +You can store any information in the application configuration file, and access it at runtime by using the `AppConfigService` service provided by ADF. + +

+Please refer to the AppConfigService documentation to get more details on Application Configuration features and API available. +

+ +## Navigation + +The Alfresco Content Application provides the following navigation links: + +- Personal Files +- File Libraries +- Shared +- Recent Files +- Favorites +- Trash + +The side navigation provides support to customize the appearance of the links by editing the `app.config.json`. + +### Customization + +Navigation configuration supports array and object like schema. Defining an object helps navigation to render visual delimiters between different groups of links. + +```json +{ + "navigation": { + "main": [ + ... + ], + "secondary": [ + ... + ] + } +} +``` + +![](images/navigation-01.png) + +```json +{ + "navigation": [ + { ... }, + { ... }, + ... + ] +} +``` + +![](images/navigation-02.png) + +#### Customize icons and text + +`icon` - supported value can be anything from [Material Design](https://material.io/icons) icons library. If not defined, the link will render just the label value. + +`title` - instructs the link to render a native browser tooltip with the given value. It can be a string or a i18n defined reference. If not defined, the link will not show a tooltip. + +`label` - represents the visual name of the link. It can be a string or a i18n defined reference. + +

+ Changing ` "route": { "url": "/..." } ` value will affect the navigation since these are mapped to application routing system. +

+ +#### Custom text (i18n) + +To change the `title` and `label` of navigation links edit the values under `BROWSE` entry found at `/src/assets/i18n/en.json` + +```json +"APP" : { + ... + "BROWSE": { + "PERSONAL": { + "TITLE": "Personal Files", + "SIDENAV_LINK": { + "LABEL": "Personal Files", + "TOOLTIP": "View your Personal Files" + } + }, + ... + } +} +``` + +For more information about internationalization see [Internationalization (i18n)](/i18n) section. + +### User-defined navigation + +To add custom navigation link for the application, first we need to create a component. + +`src/app/components/custom-page/custom-page.component.ts` + +```js +import { Component } from '@angular/core'; + +@Component({ +template: ` +

{{ title }}

+ ` +}) +export class CustomPage { + title = 'My Custom Page' +} +``` + +Register the component in ```app.module.ts``` + +```javascript + + ... + import { CustomPage } from './components/custom-page/custom-page.component'; + + @NgModule({ + ... + declarations: [ + ..., + CustomPage + ], + ... +}) + +``` + +In the `app.config.json` define a link entry which will point to the custom page + +```json +{ + ..., + "navigation": [ + "main": [ ... ], + "secondary": [ ... ], + "custom": [ + { + "icon": "work", + "label": "Link", + "title": "My custome link", + "route": { + "url": "/custom-route" + } + } + ] + ] +} + +``` + +Map the `/custom-route` in `app.routes.ts` as a child of `LayoutComponent` definition. + +```js + + import { CustomPage } from './components/custom-page/custom-page.component.ts'; + + ... + { + path: '', + component: LayoutComponent, + children: [ + ..., + { + path: 'custom-route', + component: CustomPage + } + ] + } + ..., + +``` + +![](images/navigation-03.png) + +For more information about the content of a custom page see [Document List Layout](/doc-list) section. + +## Docker + +The ACA comes with the ACS 6.0 Community Edition preconfigured. +The application runs in to modes: + +- Development (runs latest source code, requires building application) +- Preview (runs with latest published containers, master branch) + +### Development Mode + +Run the local instance of the application packaged into the docker image together with the ACS images: + +```sh +npm run build +npm run start:docker +``` + +The ACA runs on port `4000` when served from within container. + +Use the following command to stop all the containers: + +```sh +npm run stop:docker +``` + +### Preview Mode + +

+With this mode, you do not need building application from source code or installing dependencies. +

+ +To run the latest published container go to the `docker-compose` folder and start docker compose from there: + +```sh +cd docker-compose +docker-compose up +``` + +The application is available at the `http://localhost:3000` address. diff --git a/docs/header.md b/docs/header.md deleted file mode 100644 index cf77f6c998..0000000000 --- a/docs/header.md +++ /dev/null @@ -1,25 +0,0 @@ -## Header - -The application [header](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/header) has three main elements. - -![](images/header.png) - -### (1) Logo and Color -Logo & app primary color - logo and color are configurable by updating the -[app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json) file in the root folder of the project. -Please refer to the [Application Configuration](https://github.com/Alfresco/alfresco-content-app/blob/master/docs/configuration.md#application-logo) documentation for more information on how to change the logo and color. - -### (2) Search -The application [Search](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/search) - -uses the [ADF Search Component](https://github.com/Alfresco/alfresco-ng2-components/tree/master/lib/content-services/search) -the app provides a 'live' search feature, where users can open files and folders directly from the Search API results. - -![](images/search.png) - -### (3) Current User -[Current User](https://github.com/Alfresco/alfresco-content-app/tree/development/src/app/components/current-user) - -displays the user's name, and a menu where users can logout. -Optionally through updating the [app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json) -a language switching menu can be displayed. - -![](images/current-user.png) diff --git a/docs/help.md b/docs/help.md index f547b977e9..54652ee0fc 100644 --- a/docs/help.md +++ b/docs/help.md @@ -32,11 +32,30 @@ The most cost-effective way to take advantage of this valuable training is throu Visit the Alfresco University section on the Alfresco website for more information: https://www.alfresco.com/alfresco-university -# Building and running locally +## Frequently asked questions -Please refer to the [developer docs](/build) to get more details on building and running application on your local machine. +### How do I log an issue (bug, enhancement, feature)? -# Using with Docker +Log any issues in the [Jira][jira], +please include a clear description, steps to reproduce and screenshots where appropriate. +All issues will be reviewed; bugs will be categorized if reproducible and enhancement/feature suggestions +will be considered against existing priorities if the use case serves a general-purpose need. -The Content App provides a "Dockerfile" and "docker-compose" files to aid in running application in a container. -Please refer to the "[Using with Docker](/docker)" article for more details. +### Does this/Will this application replace Alfresco Share? + +This example application is designed to demonstrate how to construct a content application using the Alfresco Application Development Framework, +it is not intended to be a replacement for Alfresco Share. + +### How do I contribute to the project? + +Want to file a bug, contribute some code, or improve documentation? Excellent! +Read up on our guidelines for [contributing][contributing] +and then check out one of our issues in the [Jira][jira] or [GitHub][github] + +### How often will this project be updated? + +This project will continue to evolve as the Alfresco ADF evolves, with Alfresco and community developers contributing to its progress. + +[contributing]: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md +[github]: https://github.com/Alfresco/alfresco-content-app/issues +[jira]: https://issues.alfresco.com/jira/projects/ACA diff --git a/docs/i18n.md b/docs/i18n.md deleted file mode 100644 index 52d700fefc..0000000000 --- a/docs/i18n.md +++ /dev/null @@ -1,131 +0,0 @@ -# Internationalization (i18n) - -The Content Application provides support for the following languages: - -- German (`de`) -- English (`en`) -- Spanish (`es`) -- French (`fr`) -- Italian (`it`) -- Japanese (`ja`) -- Norwegian (`nb`) -- Dutch (`nl`) -- Brazilian Portuguese (`pt-BR`) -- Russian (`ru`) -- Simplified Chinese (`zh-CN`) - -The fallback locale is the English one, however current browser language is taken as the default one automatically when the application starts. - -## User-defined language - -You can allow users to set custom language that gets saved to user preferences. -The main application menu already has the [ADF Language Menu](https://github.com/Alfresco/alfresco-ng2-components/blob/development/docs/language-menu.component.md) component integrated and pre-filled with the supported items. - -To change the default language set edit the `app.config.json` file and add or remove items: - -```json -{ - ..., - "languages": [ - { - "key": "de", - "label": "German" - }, - { - "key": "en", - "label": "English" - }, - { - "key": "es", - "label": "Spanish" - }, - ... - ] -} -``` - -The file is located at the following path: `/src/app.config.json`. - -## Custom languages - -To add a custom language, add a new "JSON" file to the "/src/assets/i18n" folder -with the name of the target locale, for instance, a "de.json" for the "German". - -Translate the resource strings based on the default "en.json" file. -You can copy the content over to your newly created file and replace English values with translated text. - -```json -{ - "APP": { - "SIGN_IN": "Anmelden", - "SIGN_OUT": "Abmelden", - "NEW_MENU": { - "LABEL": "Neu", - "MENU_ITEMS": { - "CREATE_FOLDER": "Ordner erstellen", - "UPLOAD_FILE": "Datei hochladen", - "UPLOAD_FOLDER": "Ordner hochladen" - }, - ... - } - }, - ... -} -``` - -The Content Application automatically bundles your file upon project build. -You can test your locale by changing the browser language settings and reloading the page. - -Optionally, you can extend the [ADF Language Menu](https://github.com/Alfresco/alfresco-ng2-components/blob/development/docs/language-menu.component.md) component with the newly added language by updating the `app.config.json` file. - -## Customizing ADF translations - -In addition to creating a custom language file for the Content Application, -you can also provide translations for the ADF resources. - -Your `/src/assets/i18n/.json` file can reflect the structure of one of the ADF language files: - -- ADF Core ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/core/i18n/en.json)) -- ADF Content Services ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/content-services/i18n/en.json)) -- ADF Process Services ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/process-services/i18n/en.json)) -- ADF Insights ([en.json](https://github.com/Alfresco/alfresco-ng2-components/blob/master/lib/insights/i18n/en.json)) - -At runtime, the application-level strings have the highest priority. -That means you can replace the value of any ADF resource string if needed. - -For example, let's change the title of the "Create Folder" dialog shipped with the ADF. -Modify the `/src/assets/i18n/en.json` file and append the "CORE" section like in the example below: - -```json -{ - "APP": { - ... - }, - "CORE": { - "FOLDER_DIALOG": { - "CREATE_FOLDER_TITLE": "Custom title" - } - } -} -``` - -Now, if you run the application and click the "New → Create Folder" menu, -the title of the dialog should look like the following: - -![](images/aca-i18n-01.png) - -## Language picker - -You can enable internal language picker in the `app.config.json` file: - -```json -{ - ..., - - "languagePicker": true, - - ... -} -``` - -![](images/aca-i18n-02.png) diff --git a/docs/index.html b/docs/index.html index d9acb344ec..1ea7e81e39 100644 --- a/docs/index.html +++ b/docs/index.html @@ -19,76 +19,8 @@ path: '/' }, { - title: 'Features', - type: 'dropdown', - items: [ - { - title: 'Introduction', - path: 'features' - }, - { - title: 'Application Header', - path: 'header' - }, - { - title: 'Side Navigation', - path: 'side-nav' - }, - { - title: 'Document List', - path: 'doc-list' - }, - { - title: 'File Viewer', - path: 'file-viewer' - }, - { - title: 'Info Drawer', - path: 'info-drawer' - }, - { - title: 'Version Manager', - path: 'version-manager' - } - ] - }, - { - title: 'Building', - path: 'build' - }, - { - title: 'Docker', - path: 'docker' - }, - { - title: 'FAQ', - path: 'faq' - }, - { - title: 'Guides', - type: 'dropdown', - items: [ - { - title: 'Building', - path: 'build' - }, - { - title: 'Internationalization (i18n)', - path: 'i18n' - }, - { - title: 'CORS', - path: 'cors' - }, - { - title: 'Configuration', - path: 'configuration' - }, - { - title: 'Navigation', - path: 'navigation' - } - ] + title: 'Getting Started', + path: 'getting-started' }, { title: 'Get Help', diff --git a/docs/info-drawer.md b/docs/info-drawer.md deleted file mode 100644 index 6d22172cc0..0000000000 --- a/docs/info-drawer.md +++ /dev/null @@ -1,23 +0,0 @@ -### Info Drawer - -The Info Drawer displays node information in the right sidebar panel. It is created by using the [InfoDrawerComponent](https://alfresco.github.io/adf-component-catalog/components/InfoDrawerComponent.html). This info is available for both folder and file nodes. - -Currently, there are 2 tabs available: Properties and Versions. - -#### Properties tab - -The Properties tab displays the node's metadata info by using the [ContentMetadataCardComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataCardComponent.html). - -![](images/content-metadata.png) - -For more information, please check also the ADF's [ContentMetadataComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataComponent.html). - -#### Versions tab - -The Versions tab displays info about the node's versions and allows users to [manage versions](/version-manager), according to their permissions. Only the file nodes have version data available. - -![](images/version-manager-tab.png) - -It uses the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html) from ADF framework. - -Managing versions of a file can be possible also by accessing the 'Manage Versions' option from the 'More actions' menu. For more info on manage versions, please check the [version manager](/version-manager) page. diff --git a/docs/navigation.md b/docs/navigation.md deleted file mode 100644 index 4a283a2725..0000000000 --- a/docs/navigation.md +++ /dev/null @@ -1,163 +0,0 @@ -# Navigation - -The Alfresco Content Application provides the following navigation links: - -- Personal Files -- File Libraries -- Shared -- Recent Files -- Favorites -- Trash - -The side navigation provides support to customize the appearance of the links by editing the `app.config.json`. - -## Customization - -Navigation configuration supports array and object like schema. Defining an object helps navigation to render visual delimiters between different groups of links. - -```json -{ - "navigation": { - "main": [ - ... - ], - "secondary": [ - ... - ] - } -} -``` - -![](images/navigation-01.png) - -```json -{ - "navigation": [ - { ... }, - { ... }, - ... - ] -} -``` - -![](images/navigation-02.png) - -### Customize icons and text - -`icon` - supported value can be anything from [Material Design](https://material.io/icons) icons library. If not defined, the link will render just the label value. - -`title` - instructs the link to render a native browser tooltip with the given value. It can be a string or a i18n defined reference. If not defined, the link will not show a tooltip. - -`label` - represents the visual name of the link. It can be a string or a i18n defined reference. - -

- Changing ` "route": { "url": "/..." } ` value will affect the navigation since these are mapped to application routing system. -

- -### Custom text (i18n) - -To change the `title` and `label` of navigation links edit the values under `BROWSE` entry found at `/src/assets/i18n/en.json` - -```json -"APP" : { - ... - "BROWSE": { - "PERSONAL": { - "TITLE": "Personal Files", - "SIDENAV_LINK": { - "LABEL": "Personal Files", - "TOOLTIP": "View your Personal Files" - } - }, - ... - } -} -``` - -For more information about internationalization see [Internationalization (i18n)](/i18n) section. - -## User-defined navigation - -To add custom navigation link for the application, first we need to create a component. - -`src/app/components/custom-page/custom-page.component.ts` - -```js -import { Component } from '@angular/core'; - -@Component({ -template: ` -

{{ title }}

- ` -}) -export class CustomPage { - title = 'My Custom Page' -} -``` - -Register the component in ```app.module.ts``` - -```javascript - - ... - import { CustomPage } from './components/custom-page/custom-page.component'; - - @NgModule({ - ... - declarations: [ - ..., - CustomPage - ], - ... -}) - -``` - -In the `app.config.json` define a link entry which will point to the custom page - -```json -{ - ..., - "navigation": [ - "main": [ ... ], - "secondary": [ ... ], - "custom": [ - { - "icon": "work", - "label": "Link", - "title": "My custome link", - "route": { - "url": "/custom-route" - } - } - ] - ] -} - -``` - -Map the `/custom-route` in `app.routes.ts` as a child of `LayoutComponent` definition. - -```js - - import { CustomPage } from './components/custom-page/custom-page.component.ts'; - - ... - { - path: '', - component: LayoutComponent, - children: [ - ..., - { - path: 'custom-route', - component: CustomPage - } - ] - } - ..., - -``` - -![](images/navigation-03.png) - -For more information about the content of a custom page see [Document List Layout](/doc-list) section. diff --git a/docs/side-nav.md b/docs/side-nav.md deleted file mode 100644 index 98ac4258d3..0000000000 --- a/docs/side-nav.md +++ /dev/null @@ -1,27 +0,0 @@ -### Side Nav - -The application [side navigation](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/sidenav) has two features: -a button menu and navigation links. - -![](images/side-nav.png) - -#### New button - -The New button displays a menu which provides three actions: - -- Create a new folder - provides a dialog which allows the creation of a new folder, the folder name is mandatory and the description is optional. -- Upload a file - invokes the operating system file browser and allows a user to select file(s) to upload into their current location in the content repository. -- Upload a folder - invokes the operating system folder browser and allows a user to select a folder to upload to their current location in the content repository. - -When an upload starts the [upload component](https://github.com/Alfresco/alfresco-ng2-components/tree/master/lib/content-services/upload) -is displayed which shows the user the progress of the uploads they have started. -The upload dialog persists on the screen and can be minimized; users are able to continue using the application whilst uploads are in progress -and uploads can be canceled which will stop uploads in progress or permanently delete already completed uploads. - -![](images/uploader.png) - -#### Navigation - -The navigation links are configurable via the [app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json). -Default configuration creates two sections. -See [Navigation](/navigation) for more information about configuring the side navigation. diff --git a/docs/version-manager.md b/docs/version-manager.md deleted file mode 100644 index c291c84a89..0000000000 --- a/docs/version-manager.md +++ /dev/null @@ -1,33 +0,0 @@ -## Version Manager - -The versions of a file can be viewed & managed by using the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html). - -There are 2 ways users can access the Version Manager: - -1. From the 'Manage Versions' option of the 'More actions' menu (check [Actions and the Actions Toolbar](/doc-list?id=actions-and-the-actions-toolbar)): -![](images/version-manager-action.png) -![](images/version-manager-dialog.png) - -2. From the [Info Drawer](/info-drawer) (the Details right panel): -![](images/version-manager-tab.png) - -### Upload new version - -A new version for the selected file can be added by using this button. There is a restriction currently to only upload files of the same extension as the old version. The new version file will be automatically renamed to have the same name as the old version has. Please also check the [UploadVersionButtonComponent](https://alfresco.github.io/adf-component-catalog/components/UploadVersionButtonComponent.html). - -### Actions Menu - -Each item in the version list has a couple of actions available: Restore, Download and Delete. These are displayed if user has permission to do that specific action. The 'Download' and 'Delete' can be also disabled from the app.config. - -In the app.config.json file, these are the current settings for the ACA version manager: -``` - "adf-version-manager": { - "allowComments": true, - "allowDownload": true, - "allowDelete": true - }, - ... -``` -Set the allowComments to false if the version comments should not be displayed on the version list. - -Clicking to delete a version of a file triggers a confirmation dialog. Please see the [ConfirmDialogComponent](https://alfresco.github.io/adf-component-catalog/components/ConfirmDialogComponent.html) for more info. From a0f89555d3a660c31a3421620fb9a9ff7bffb487 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Tue, 26 Jun 2018 19:55:28 +0300 Subject: [PATCH 146/179] Thumbs over thumbs (#461) --- src/app.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.config.json b/src/app.config.json index 6af1d00f22..01436f1bfa 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -18,7 +18,7 @@ "supportedPageSizes": [25, 50, 100] }, "files": { - "excluded": [".DS_Store", "desktop.ini", "thumbs.db", ".git"] + "excluded": [".DS_Store", "desktop.ini", "Thumbs.db", ".git"] }, "adf-version-manager": { "allowComments": true, From 9188213845c876722613db9fc266c6213840605f Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 27 Jun 2018 10:34:23 +0100 Subject: [PATCH 147/179] docs on Search Result page (#462) --- docs/README.md | 70 ++++++++++++++++++----------- docs/images/aca-search-results.png | Bin 0 -> 398894 bytes 2 files changed, 45 insertions(+), 25 deletions(-) create mode 100644 docs/images/aca-search-results.png diff --git a/docs/README.md b/docs/README.md index aadb637d16..a05ced97aa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -48,7 +48,7 @@ There are three main areas of the application controlled by the [Layout componen - [(2) Side Navigation](#side-navigation) - [(3) Document List](#document-list-layout) -![](images/features-01.png) +![Features](images/features-01.png) ### Header @@ -58,7 +58,7 @@ The application [header](https://github.com/Alfresco/alfresco-content-app/tree/m 2. [Search](#search) 3. [Current User](#current-user) -![](images/header.png) +![Header](images/header.png) #### Logo and Color @@ -72,7 +72,10 @@ The application [Search](https://github.com/Alfresco/alfresco-content-app/tree/m uses the [ADF Search Component](https://github.com/Alfresco/alfresco-ng2-components/tree/master/lib/content-services/search) the app provides a 'live' search feature, where users can open files and folders directly from the Search API results. -![](images/search.png) +![Search Input](images/search.png) + +If you type `Enter` in the text input area, you are going to see [Search Results](#search-results) page +with advanced filtering and faceted search. #### Current User @@ -81,14 +84,14 @@ displays the user's name, and a menu where users can logout. Optionally through updating the [app.config.json](https://github.com/Alfresco/alfresco-content-app/blob/master/src/app.config.json) a language switching menu can be displayed. -![](images/current-user.png) +![Current User](images/current-user.png) ### Side Navigation The application [side navigation](https://github.com/Alfresco/alfresco-content-app/tree/master/src/app/components/sidenav) has two features: a button menu and navigation links. -![](images/side-nav.png) +![Side Navigation](images/side-nav.png) #### New button @@ -103,7 +106,7 @@ is displayed which shows the user the progress of the uploads they have started. The upload dialog persists on the screen and can be minimized; users are able to continue using the application whilst uploads are in progress and uploads can be canceled which will stop uploads in progress or permanently delete already completed uploads. -![](images/uploader.png) +![Uploader](images/uploader.png) #### Navigation @@ -259,7 +262,7 @@ or double click on a file to view it, and a folder to open it. The File Viewer has been created using the [ViewerComponent](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html) from the ADF. The Viewer has four main areas: -![](images/File-Viewer.png) +![File Viewer](images/File-Viewer.png) 1. [Header & Toolbar](#header-and-toolbar) 2. [Content](#content) @@ -293,21 +296,21 @@ The Document View includes a thumbnails pane which can be activated by a button At the bottom of the content the Viewer Controls allow users to interact with the content in various ways; the actions available are dependant on the type of content being displayed. - Document View: - - Activate/Deactivate thumbnails pane - - Previous/Next page - - Jump to page number - - Zoom in/out - - Fit to page + - Activate/Deactivate thumbnails pane + - Previous/Next page + - Jump to page number + - Zoom in/out + - Fit to page - Image View: - - Zoom in/out - - Rotate left/right (does not alter content in the repository) - - Reset image + - Zoom in/out + - Rotate left/right (does not alter content in the repository) + - Reset image - Media View: - - Play/pause - - Timeline position - - Audio mute/unmute - - Audio volume - - Full screen + - Play/pause + - Timeline position + - Audio mute/unmute + - Audio volume + - Full screen ### Info Drawer @@ -327,7 +330,7 @@ For more information, please check also the ADF's [ContentMetadataComponent](htt The Versions tab displays info about the node's versions and allows users to [manage versions](#version-manager), according to their permissions. Only the file nodes have version data available. -![](images/version-manager-tab.png) +![Version Manager Tab](images/version-manager-tab.png) It uses the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html) from ADF framework. @@ -341,16 +344,16 @@ There are 2 ways users can access the Version Manager: 1. From the 'Manage Versions' option of the 'More actions' menu (check [Actions and the Actions Toolbar](#actions-and-the-actions-toolbar)): -![](images/version-manager-action.png) -![](images/version-manager-dialog.png) +![Version Manager Menu](images/version-manager-action.png) +![Version Manager Dialog](images/version-manager-dialog.png) 2. From the [Info Drawer](/info-drawer) (the Details right panel): -![](images/version-manager-tab.png) +![Version Manager Inline](images/version-manager-tab.png) #### Upload new version -A new version for the selected file can be added by using this button. There is a restriction currently to only upload files of the same extension as the old version. The new version file will be automatically renamed to have the same name as the old version has. Please also check the [UploadVersionButtonComponent](https://alfresco.github.io/adf-component-catalog/components/UploadVersionButtonComponent.html). +A new version for the selected file can be added by using this button. There is a restriction currently to only upload files of the same extension as the old version. The new version file will be automatically renamed to have the same name as the old version has. Please also check the [UploadVersionButtonComponent](https://alfresco.github.io/adf-component-catalog/components/UploadVersionButtonComponent.html). #### Actions Menu @@ -371,6 +374,23 @@ Set the allowComments to false if the version comments should not be displayed o Clicking to delete a version of a file triggers a confirmation dialog. Please see the [ConfirmDialogComponent](https://alfresco.github.io/adf-component-catalog/components/ConfirmDialogComponent.html) for more info. +### Search Results + +Once you type the text in the Search Input component and press `Enter` you are going to see the Search Results page + +![Search Results](images/aca-search-results.png) + +This page consists of the following ADF components: + +- [Search Filter](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/content-services/search-filter.component.md) +- [Search Chip List](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/content-services/search-chip-list.component.md) +- [Search Sorting Picker](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/content-services/search-sorting-picker.component.md) +- [Document List](https://github.com/Alfresco/alfresco-ng2-components/blob/master/docs/content-services/document-list.component.md) with custom layout template +- [Info Drawer](#info-drawer) with Metadata and [Version Management](#version-manager) +- [Toolbar with basic actions](#actions-and-the-actions-toolbar) like `Preview`, `Download`, `Favorite`, `Copy`, etc. + +And also the Info Drawer, Toolbar and Node Selector dialogs for copy and move operations. + ## How to contribute Want to file a bug, contribute some code, or improve documentation? Excellent! diff --git a/docs/images/aca-search-results.png b/docs/images/aca-search-results.png new file mode 100644 index 0000000000000000000000000000000000000000..0a0e0260334b4a486eda0a4e35053ebc683f3959 GIT binary patch literal 398894 zcmeFYbyOT%vpzf!oFEASg1ZDwaCd@Ba0~7-xH|+0B)A0#lHfA9y96Da;Fbg#WUv7S zhu`F!YioV$p8Mwg`(rJ-o9^Db_pV*L>ZzxSXmwRN94t~S004laATOf<0ANc10H_NX zXox#3vMK}sz+*-`X=!x@X=!S8H)m@*M=Jn8J~}lWT~BkEC#=X%2v$l=$DG_Bz3GAbUgYVE@GBGf4E2tqM2V4GljNuq3vq?ok zft2@n{o%!tv$P>IKh&}_=-d&}0DyWbL9^wlD&Hm@;728Sq5v^K3h#T?_$Z+y zV=r@P(Q`D6Mdg8AEU$FevM{<$KG#>F37P=)ueFQ6JOEmjuCGo7b|>Q%Ni6+obgAF1 zU@S)U*|^i-Nl<2Ii$1C?BeX34eso*#&}XyvUX4#U@Eu{xkn9V2>L*q;Hg~yOm+MK{ z3=}zi&-hqO$cgB{`Z`UcBtN-|q&lgUV?TyfAYB!Our{T;5}S|`iCaD-(qX>iee@Wh z&XP{?3|F73Hu@zim%02=G9!kWWMqTf21-kXK)+rJYt9qyO{y`7LYPHV27B5BL*0u+ z>wz1*tCdkmO=KY7v*V4YgsxvfzG3g=hgcG*6uB(=q8yEhjvvuQIenXcu0ML5VL`1z z{xrY3XS9}~&(|y`0EyM@J)PT?t65CV0uQbsWftz{;~YzkZ!VvWjMb}YIV%#FK2pU{ zu@Y~geS5rkgl{E_w`dXDUZI|`hT`^tp3}?6(V4@@F($y3dL%YZ^IN2Yb@iYet9iGR z1PTU<88wt) zifkM8D)O;a`gNdJGwRu182XR3N%6B-ZWmG0DB-@0TUQf-ChYG)ROKG@8_o^nFxf_? zd`qWVs>QuQ3@t}3qu1?2Ea!pj&s+=Rv{+pVAcG>vUFB57Ykk4>-_lH@YEBnkKxyaR z&mu8;JuM%sG##`OspZQVo*y`NdwU{x|{D+OKm!X zOQda@Uc&f<)pg%$=Ab2}pv7x$iUW!t94yN>goa?@$N)9D=jolhZkd2%=FpKdXCc0o z@HkH-iQoqnn`7Buc2@@o8N;TqM*6-Z>=MAZ~fw3}`kb#&667cRI)XrLcNK7e^eCLdJ4 z9{6Y@{$+oX#e>t} zLyi<@e$%Aa8R1eCk}`>f>A)w7?Ko8PH+o!Yka7?CO z9-pI^d(KHC2RFz?&~u~Gf07-q`mhI~b%l!e_@7jvkV@v7Djm~TVW@jWtH*-))Ib^spOz>Z#5`MD!~IhH z8vQb^DbGLbaq`HM5|Q?h8pYDa9*`FE3hg{!O`(*BOcGCdPfkn=^G0W;WwMPu9@7{L z%w*5(Fd#J;H^4NwGDtNTY*-?B-WS$mZuu&W8}}8ETg-vX_Qv6~KHdIkzO(X9(k3M? z7gw!V1`;yPo;}g3ylT3tyqenT*&2W5B1+Z~?ZzRA=P_e&lOUVM@YegUURi=mfi+@mjzoP2t#m)`?7E$CkwIC)I(Flc_* zoftK*w8$}olkSs6ktoGBku*KO$kNOFmh~)?{H3p@;ww*n74ElAOO8tp)|Pxdj&b_2 zi-GR7Ep3A90iY}2Q#_(HqG+NI?0am+dV6}cY}jlLY*YqQ6#*c(in0oz0Rdz@YZfoR4N7qn~RE6ah!~ zYpgAj2P?__gP^+p#5Zg=6mUFp9`XUU}9Z<-J1QNc_2S`)3c^np!W*zYW^yCh0_OL1X*O;pT{o%=5aoH zF0y%*o}R5+G*4MYyumhjGH~#G{-@KgG5Ff{>S5oR!pY*^%%KAm39y z;){6F+uNrTxoSpIEl^>vbL7)>;y##*SsXbS>5LIfYDPd4XZtBc^|`p&?7OJM?Zn=p zR%ZPE7z4s{<|Qs6rtA3VZ_!f(tV~}00^dfX1*w$cvnkt{;DJUGE3jtt6P=Uk%Wag| zcP}t!F{z%0KLrykGsR}}cu#N9chE~}1aiF)r17YAY;vIW-ymtJXd zs?KDk@g7`y%&g09{gIu7iYuSX+X~m3!J1-7XGC>ajPX0ZHP*!F z%g>48`6`yIEJO_upY4j_UBajj-ir9cS_*-cjJHFbv<*r3w1G*GWZjGlSL@!M{D-%^LFZjA5Dvwj^og6!2x%oabK?a;KN4Wq4w{-W2Y(*;;|zm{8rNosgd5% z2wm(0Y%unNaY}Q^m!Ujc$v1MDWs&r=hT&XL~MTsMI zDP1Q8H^p^?<8JSGztsdiy^!5O|FAXS6zdn(&zNP_K;1(QT~1EsBRyU-?F0Mmy`4t-S+PT>(e#0*FyKc1mNW)a5RCK;QXQS4WKE}hM{j58_qjmG@ zLJu$m6bABciU5{_YD>x%R9AAEIvnJB<4(I;9&|c1oo#loly%gi(bMmQr4ZRu*AOyEZiO6({0P~Q5I6M zm&)4P%);kR_LugP_m<;g#phOj%(|S#zY2!h^8hPEDm??PFh`=l5`;5htHKfX%1^a0 zch5Fw?e@o6!3_U|vdD}Z-z_x4od%+sdm$bS3%iII_>e;!|JJQb%X{(M?SL?yRj#Vl zNObAfl7|1-fk9xooP+dob0figU{!AG6OWA*mANr+6RmT@YFt;~#dwPFfp?3y$qKmj zVmoN?+MFh?A)c8o=N;yRLa#e4R^XV%Q-DOJ6t9^U`2g5?}~dy;!a6 z%61(PS7RaKLnt*LMd1h!}qVA}MIl9|HhLxprE59(pRu zLKeU3n-w)L2M@aclPuU zrKSD-q5t~%dz@B2cK`h)p!VZ2!V-V ziE#dx@WrskQ6PJW^&q#CQPV=4k$*1^;siw;nEyT_u91(6Wd)Hd0RRbrf{dh=4-#}0 z`?Ka&_QQ#Zb<$`cidkAYb67+V%Ve49n+j%~81EE9$0qG2RJ5x(t|M4iuYN1_F%Lfv3cdsY=}!;T`zTW9QM3+jPeR69-TT7+oj$s0 zBmhfDz0!aB?cbvvGDbq4T=WO(ksxDGhXDTYAb^4)AuQqZ{!iQe{?a0=1VG4t0*6)l z&!q-HiUJ_nqGRAa`FBL_kBT8-bJSvH^>56W`UgHW-~jNG<_{(HmuxMo07yGfQT~d@ zf2=168IdES3kH6OSI9B`zay?%-4K8WJcmpt^54-;T*S7(#iykGH^e0Y$HEU8Uvuvp`TsZb zzqUR9{ms1d0?9k)J^wlbWyjdOc%ost63po7l|^F)(c|cMy;I^nE_#_~HH+53M?KX% z`%b}jD0w&FjBSBGw;O(MCF;gCcDxi4rKS$)$B^uJ~d$7CRmbb#!- z;09Ov5G~Vb?KTLS=X*cfvcXzuV!rR`DTE z2A+@B0RPy4gjPH`-v02I#ZBRhAz1t(blU+}$x~V{lLvowo)l@P(`!JF^N-EAgbwC2 zeEzl!p6XIziyO+3 z%t24hO!RPXZd5Tc0rj5nX4yYC`_!^Xng@$ofqb*M?q4!kCW}bxOR=&KVgVkFxioW8 ze{2>Lw2`keeJM4Pm{1QZ40O_oH=KzUO{kJg)1nYF_rB8N{^Kq~B!Zu~K%yVd9@jC6 z^T#*8V6Ih@o*erE6&3q;VTlA0=BJT~J}~UtyFB-n4E!@=O-vyr=}DA4_p8~#n)6JF z3|-4@+a_g-!!*qBQ`+EBb3W~;f-*jOPN-vA!*wy=q=S;B`5$VVyfn31-$b9{>9?%> z)ZFZ6NCaV(*b2I_iijVWz%tirWIb0`Utj+eW2uGXO$#hfEJnH2tgzf zSnrP8F+|t?miEIM_K^9VG``TFF$y{EpXjHAD(0u-)5#=}7cP+RW}ZGT@2wL94KRh4 zr4W-B7V-3upyox=JiodpiEzu&2?~;XH1WZBb(J*0E6y}*(!CfrkyDM7ycA2++3FFE zEz{HZKeLiUPeb!R7`bVM7UkWT3ID$s zu}D*mP@w`Nl`i9jF(Pa5_KNE!+Hdh~)>{*54IvDne;KDtPN0gl*YMD~+)8`i8HM%9 zQS+n5tZ2^zIB`(C8+(4D0BQEN@Q+{5Ny1|Eh^H(*DC%xbx ze=^GxhqkSA_NZmC#U3I}%!RK}4?8AGWN&I~#gsd~ z+oTGv+>8~ItNM%qKA+$n*;YH}!Xo|G$7~sk7;}XnAsb5QN33V9vXQCq)9DG^sSZz? z6DvtkUF69)f<9>!C~|5zY?HVyW|LWs`KkT=UE3_Y*zjmRs9h~AHi+b9wM?h~n5E#| zw-~P*L*dAJ#(<5`@M$egPGFTG-~9!{^w~7U)0NuZy{9c>WUiS$4CMM z?I&HuME*4dg9xP9L#u-3=&0u3ZO*>!QKeY;gyhTBG)*UNbd;`+_l%VRuv$9vO%=nk zA*A%`w?c?q>357$niwSq>94&dOQO7-UOKFK5&}$*V!Em8e$SO&(fL&dPGz4E92k%V zo!Og+&cu8*54~(Yf1zufV{~6gu<36i`l5Dy-w?M+%%+Rr47~upaYy?_PZrYVoJpJh z@$v&oP;gy`!+zj|;D!ACC3y3iS4_W+8=K>c?OPJ>e;J()ee9lBg$;R6FeijWLVHZ3_)#8I!ZKvot6QX!8SfZZ!Q<1 zLD!JDM3Xz|!pk7fOpE#j>7$BV#nt!jR&auIKSJ4~Af#wejQ_ukG(6sRXEW8_)|v~J zN*&oM@uN85iD%v6*~%aN+QO-=s`Pi~L&=Nf!wFq^`dr~0Qo!_GE3|T&WwK)tL*k-H z%-sgmJB+A2*b-Uy`SBF=<%gn%waar z+aFJd3q!UIc&<#vFX;bDIqN{R*DDC zJ@dBa41Sh!A%|xRWPN-4MK*Reu!0Juo6_ zf-7&@zs_)AA^J1>T+_Gw7z)J1s=85BFrxO=^pxlDp*84P%IwNt)?fOo)Op5%hUDHjEFzjaMQ4cp^c*m&e|-76Zv>P*$+ZRxxl6g1+tf>AQooy930x zzRq2bPhZ7dUZIV96^+-m@twR9y2%`*K+RJ*UPQ@LDaUz#d&%DQDX(Ex86)%m;3*_3 zF?{MnR#s=QErEr_no;$?ILF)u%f&E{9qP~SB8i8}>R?ub;~^`pVg@I2DI$))| z2>Y`m&Xu+rh|G9z3EnKj=cYQc1MLjru6cUhT=F}lk1fF$WTg*GUHO1B&T-C^ zjQsrBT*xk&8uCQ8s0H+&BbkH)o3q8>>}-ZS@W{R*PI2t22HaPsg;nRqRR{}R+sAY*_g^lN>INIMTFpyDSAiP zGpoYkcj!KrTWs+ujAR;BAKQT~CSLUZo#;(RRd`C$niCIH5daUo9Lu6TGGs=;-BhK$ zZy=aP(EU~-qcS)W=RIL!)j6tFw%EnB^<5n=sUPmHb`LL=4nqZUwmsnbr*kfYiOYjz zrg1ABL&+hAMEb57u$}Lk!Tn&|`YM?7#(-+x7VbO!^?TnOLJM^#*waQNeG~U42!gY( zn_v8##QbMAAe8ON%hX(|wi0Hu%d6}_NnZ=^moSCW?HP@51F?f|SUA7-j;4w}4yBh~ z?}Emy;jd65GyOWN3*BD?Zl44q>=!KUrFPkeATOuvl~&Q&wX?s-5(J53gRzv^)YLa& zO>svH5FMiXFyW@uLRr;Sq`%#@V3{5Eab?ZhD%yy$)Qc?5W`6Es;o{e_a_TA)$H~57 z)gymou7}herq>?lc}2=EQcx|%m{d!2rPYD{18OC0u|_T=M427bWqHw4*A)Ri-W2Q&QI#p?gJ3;W{JS;yTjG$@2YsdeNgk3z!buv(OV|QGaZ267qlwQk0@0*D)K=863H}ggBOh( zs1PD>IMcUwE|R@U9^w(ZLl)LDONUO7hUQw9`{oSy>y)i%{^6Vcg~fwI|EpRbVCctM z5Z&bSr0_Kn68rTcV%kvyik-uL4}ngi{Iu0;VR}t_{7bbJjMiDF^>=!3CjlZ$y|p@q zPFz6k{by{=EbXm=V$gvCRMNNfwP8=&A<)a1LWt7useRG|q9 zQmHTFnjk-jdzUvR&xr37HdTsndZo-$=>NE8)aj_IGo~XO*O>Ki_|JhyCMv(jOuWn4c;oX9u`rfjx)DJ~ ztxQ*w&a*)ia?4(C{tCMkUGMX?i-8q9i8iYPek`kx?9(2mO(sPm$t^zwk#^!9rdC~m ziKFxQ*YY6OjA04SLGGpl*Pcz}7PBxzM%ynFWlmxl_vZEyyvuPZqK2?DC2)z`*inCQ z^zI3&>i4~$c;wCzko+0v^@5&TnABBzBK*M2_rCCT%TY3=iTTPqGxqy-rH9~rD%+WS zcAH0&bNnfkvyL{kMxC|A*?otaYWk^hx?P6s7a|>+_F_wPUnByDvINgij;oTlT8Zu)2oK6CeL$jj1eYHwYb0 zExj9B>%FcsY91s@{Y2tP*YL#ttJRB-CTq~^pYnx4$o*jiv&w_)lTB3R#=w-Q4F`uJ z!4Hv>&foF%46Ne%81sdDy%^#4Em^2&tX2d3LlZ1#uP2GuCgO({7+j z!}_eme9c1SbjD%wrA|q$dyFkUPJ@DS%N(n2-p+6314KWEG67cEi)#<^TCQV32Z``8 z_W94yMB!q>`p8dXZ&3C~3(O`$Q*d`KH_(RbE$z%WH{<7>LDp!B$R>Da8jr9s)L zz@tfR(#*!eA`t5;zjo9ndSi7%hK0MQI_n#VLdHFyc#di=UQRyX+`mu<%onJ9b!+(r z`ov&rDS$0>_P&DZE&<5>(^(VKf6t}ETw$FjOI*jWY9qr!@79=lm$afY8koKBaHRM2 zAlEia-+AlD0-n_??%kS{cRJc59O zd_OJ10CQ>0n%yA*q!5&DeKdGS6#5etcGyq(!rAw-cM0tz*MN-}_dW2~!KVNgt@nj_ z<*x{#R*w4bAWm@ddD^|+OffvD}@7%uVtwkWxUf)s{gE?q@q)I4nFkW3P0p9Xk+Lx0{>#PCeJvwebEwI zS*JD$z6@`EVlTeN)HCq?K0J#JC7T(rntELKy{(_ytfO7yoZEM6BUg6rrazH?_@hPV zi}4?BD?Rn6-6+;7sWvmp3qFnadEeHQ1-#BzcJOSJ6MS2BLJvy>A5AivX4_{KJF9nj zmgy>M@A31RI#L>rIc9N>)1}A92j)a_r#PJps!4;lFxPxCx?!|9Y*`7;PUsn~1Xx`T z24=mk6}ZSplgd&xG7OvRsI zPa}&x$87;7EKARrEY2;^8Pw!?kc8^sO{cGhdh2N?vkc z#tFmkpAut+Yb2bGqWt|&7}m$X`;vxm0C6P5TPlo!M;fxbUPX#OOWUfL6U))$>ePfA zdF=5!ofuz4nAMhnr(`(*iOa_D2B6w`TnMjs3+@!PNKwG~mxKM`mgnh32n-~uFuTBB?& zf&#-w*Ap%Y)-M0FGljjuW=M*aLdR_sfDG_Q{mWmE}d}4sWz7|=oVEHru z%d^2ib4n9YAvKnjngm-FX?f$Bqm3ru`$&nS?_$J4*Oz2rum!T%TGO^b?bgZ{5pEAY zfd@N=fMBP((SV{Y(Pfva3ZZ4t>3c`N2_{|V$qNEv-z~PcN-a*nE)#B9GIRH)xXPQV z**m(yvLkWeOheb=bwNvh?y+k|T=8N)Opjguq+DV4XC7N{9~0hDbnB`(4XH#G^Mpe~ zc`2rX3fRXw&c?(p0hRPatl?>8fIim@T{8Lre7Qiojnk)a>u#L7i7n@6YU!i1t2y3x zTist0L~a@lwupyX(~kXTy#jOVW$T^W!z;OGS{7E*qd?ZBT2)+ z408T>zx^OGFJAB}Cz_=@xJHj(laY8N3{xnoQ_de&^IE^KDi>XCZeGnHV!N9BL47bn z1azX&LSgVLiB=8jnK~jya&XE|3KU}!TOk+t&Q>?K@Idu5iE8Xck^&s1zO(btcsp5_ zyY0SLX#Z>=Q`)$DMP^$nrAYFh#s@XI;bD zjy;ASbP9Mi#-2=vv{O1r1dgv1dqotK^Mi2y1YRWr0^9q`v5L3J-6`M7<|d-wUl^UB zZuBi_Mg?k*Klh4KHqe^)TE}gym~p8qy>&pYvAJ#J;CSwEV2`Je72+W$>0kp`A}MQJ zI}>CTF+9~5$FI%tj!g7+V6Z3H1Wnam6`7wD?d7p`=vBFplHUwEZ}S9>x)*g}o@YX; zruM)(pO&=@`9iI1F#L+pvVvWM>g^jAFCOen1>S5~)){jjc4fbrBz}>3P#(KptN`gwsl9pxT(%&HZDf)6YhjpwP(C(>b>GBG{MI0M=CT1~bsM(sL zNHBhR)TVcNU}n^Lpc=g(-~Z&V`1^k~*%D>QRmR$E`8;{%4P?0&!>3e@C@K}Pc569e zv?i2oB_*C!PUzCG!u9^(R)_uM6$R#(!G2%JyVjYo8wbP#A)``P#}v72yZtONC#=7o z{1xk${j^akYm%PSA!3AJS>bXfj1l`ANHx*;?tDROF`42NXwst;p}965G?`&bjb|8d z)Pq0{!7*E9G&L8m=iqb8+X;^LlTc-PTMDWWV>gvj<=BGvylkLo6M{U|m0sAA-xySx zIiYUpV5Y=uTQ86EP!E?^VQXV*MQtmER{yTW_PBXlUERL^cxy%>vJ z(lUx{4z^&ub>{U|67j2Vnpj&%QM+)ESj&C(!oE;Y{9&*qhsfgF<+@XdBkInf_}kG0 zY-GB6t=oMQ_C!=xuMu~$@?}wa&5lLyo%hCP%O~1caK*{4b#->}HopMNIAKnTRnj1@ zUGKhjg{csyHUj>(Z?geq&4YJFa9+nm*`r_(!qG#;>wN+Wu+G|3uM?k=2BRbFXY~ea6r4y3&($bNDQlA1!RVel1%b z_(mRO$5`Pgwd63%qR$OE7PooUs6+a4FmOA+=G1nZZGPkB+PmE37qt}s6d=m0{J87l zOf)wI=~u`@>&^epq>`!JCVd)803Svssj4xT^nFt0Dex%}T)IQ0L-9-n*J zR0;r%Ib%yG8C?qV)tZ#6I8RDc?yMwx9_ob%{6(K3vwm|}H<@?)fR>k^EAcZ;d!6|i zd*tf$S4v@?eXTD@E0}PW;nun0^0!C%APZ9I8D-R6ruj^)NqD#4nc!)Y z{weN(;j3;2^!lVz)T1qMo4cs%Pg?@mTAl;*JnyHNsc~!MNpC*C%^p_{&`Jel+^Z({ ziaxe1(^jWkLek3-M@CG$kCHY%&PMpcp16G5k%%P4*Uz|uWl{62oy|#*6W;J??>o9j z-zTm_Mcy$>;n(rQtMEx~L0Mr7-_2-WO2MVI{8!8n5vRMXI`Kr#4-lduW`8|lJCmEB zRqrkZx)0hYd2M)~5}&wW>Cr4?5j!V(KaiTdSzMg=BQJ4CNT^Z>yAOFMH5@)r9N<;L zc0H(RrK#Pa{G8;DMyC0TLD&%|q3acc5tMDoc?`d8jOx~En2d|*sn7k)+C!rF!By_N zpEeHhRG&K)h&m|}B1rL78x~nHyq}%%5+sh^Ro4nyb9=Fj1&wD9W{=#TN&aI^%8uTTM|bo~U+2_6T+z?@Eo!E> zho}wG#Sm?{4i7k3AngPStr2?|{YOr?h2FF`igWx!U{Wt4R34p&4#f49Zqa_Gu^rPI z5maiu4{WBhV0B0`B+To8ZO0myz9$a|U|w{r)!m83lUr^OAx+`1#Z=6q2C5(4s#rKM zSk9b=?aI16M8g%oowy^S4RkO5;S?M5FOxEOD?q!{w+pYFu9 z4tU!5|6(yVOw9+C9=1#Mov_cwcn3@}bI` zw!D?d%-~0x0p2lVRG~$<{2=Z+tzpY^h&2dEH6|7ue)&RiSaa`A+h z4sSfr4p}Ssxs6@nQpa1ew&wDtW<`v4PpeLxIyuMwg|Xd5jdn<5*0(VmGH$nd%gA3? zv`dfrPX;Gj%L7$cpA!!?3gN))&uyF?&LQXf`Mwqi$p*E83cr9fB*()sL%E8andvcmT5a#`kW;Gw8E!=a;c{2< zA@Iey8b81ZwR`LbJf{CZ#Tt2rQNqE%zh_YyEl(w4gFDDDy}GQ<6L-w7VzQis!kJ)%1}Rfr4-|%O{9tS(^D{^J|sw^4ARN4L+)+NvtYRU_=h2Q^oJ9IIbsT` zRHuAC?^YuTK7lS1B$OLFJb1d^KxwZuT10C=k|z+-t-&bn_esChQSvn3eI-NAcv>A+ zVB)_MxY#Lvl{&?E82~991Xm*&>vvuFUd`mB7c`dM#f;{X2uMYyJWkn&&tw@)3lyu} zd=yKiC_8lm8|;V&(>)Z=3ws`8>dF!F*lqoQcfDU^4|2IK8p2Z<#Z%L;+vm9y)_Bxi z^c#$Y)VP1Xv3d5ox6a!CZ{0ZPv4r?3|F}eWr7s)f#=OqjnvGG}2ik?XE7NREUB8;c z##$2S!P9w$g?~@?jGfGDpkHnDrL`QrXnd8 zWYcb-S$sp0)Ih}xPCAfu@L6_p%b!zyQ6aeNXNVrXYB$l)0U5<`o$&s(Qd~E_5Yy)6 ztmT`tIS5H;<1qcyT zoYZP|+7OS-^X)m5+`nqLu^h8%G;k`JGUv&21yyI3xK-;pm;bqNV~P0FCI3~exvEhN zA|cL@TXCu6*X3MmEeH{465(Qn->}x*-LCTvnc%`5hq?{${!_v5IZdr(DxeCtb%6(o zI`4L;4!60=Rgp6jnws==?&DSB(j*#vZ6Z5Yee znyhe^W?%3ya=d2$0=lbwVcJu-&xb( z{VwoAkbv>-cq80xVn%qG{2iva8VOaxQF~A_RK%@%>@=EBpl_nw`(A2orAb}cbGy*+ zFl{U+ZS%2ETWTjG+x5+xk7vI!ikb=_2( z+-f_7+-kADWjvN>x;PrVZUUC^d&BqOrPqlsG!4smmLF}x_olt1+&%BFSFh!q`E}6? z`GzktpBTJd*2_p!9a<67{dzO^%K4t>872qQUh)Xv%}L=6sk~Ld_5aQSBf!R;ez%Oi zjeP1gfRI%7g>qA_GsVtuz;ScN*00onfi8y9Z+;-Z)V;6-M zVYuaW8E?8!A7)tbJHwzKQ>qRMGTVT+uqX zQ>HTLP)gAJ-m_@(^G_Sit*fi-a!V;$6?(wk-8ugb;lk0-b3@M^=gxo@;0=Amlq`5Z zYO|nA@H->Q+XNGqhubS+t8=*dtI*B3Ozo?sJ)5xhU7pj3pn^z$74FnTPM@z|#tua( zLV$H4s=#XWyfOSD4S194`D$DoCM@ZL;@;r@PB z>6z2q@}hN>TlVm|rl5ptcRTD>-bjF8z1DER4pp<@ z*{rW>OONWc+itl6J(CfIes7y9ZeD-+_%Yy^`-tVjuSW@nj%!k>XL@YSdQTV3QnU1_JrrLibLRR0UcVW(uev>U71pEqWXj z{_%*?ZvsP;1UF}D4#3^(S;h{oWnxUptRRFxP;jOMp#;Jb=v<$hkozW&3T$V&ZRh{4 z?i>_nZn?IMUn$hZvnpfAE=bQkl5g|u=i6RX6io1@a(U#5WsA%vR zxQdSv8?QmNkK#WP#XFLrpD`uySQ5M;egz`t#8fiC_|wJ@ikkyZrhb&H6X|4gb;zgX zEF_J7e|f}Cy8SlQH197wZpqq1B3>mbzyJ8BfwX6#+H{^1mYF$su1gg_c|pB&f~;>-6Q}3V+lY?=-$|EWM}7%hyGG6mK_^@+*#gi_n~GK6mB5 zp+AjWcrL^@bR>t^V!JT!2vPf0gu?Y8P~MxY_l1^z4!N25L1hZF&m=v zI;5TY&E1tF)C$FBY#nF{gii;o)+uHzmT0pT+C-%~%&3o`**-G^oEp6uPy(TEJh>`( z{IFIyY^ z<-_NKlp9TfE3W(D^%qpdNSnLB#p+?s({)>aHd;!3Z;Q~6AC;da-B8*m*v5=eh7c{D zN#+|>k0;(K+KpY+-e%HfIL=O-IlK%^OC>gkl3Rt;B+#hR9WH$n5Cx<~En79d#w2^6Dk>T2(J7XN z0zN^K-V~nf<9_D_SJ>pIQ5@!m;?7?0@-&3z+=*i$?L7W05IKYsYN&QT0xI^|ny-SU zIZRN}%y+tk1{i71{OrM*vmduWpOa+~TxJzF6lO#e8$+^bcF_4(UX*)P)Oo4+875Gr z3`^q;7sPzns;#*gS;`)ByUVnt7TQ&1S6e8*2j270*QN7%)GPHuK$FeB(@iht zYnn*5njOn1HRbiNa}Q9+s-aU{(AhUc%3;BPWJxP5r>pi&1%K09OxCPwPknHzZ19{b z$bxThDV2Y$2&)-kd-&Ammlj_JSOV^){*lF!XL(sY$q+xvk}`qgL>8vnsu{+le7Okn zEy!ETtUi-ILZOXFdg@_C@Hf+daaJ9Y`eauzEk7##v#C%MnlrXxSQ9PTnq7jR^B!6J zv*q4$#m!!rEk>Pn6PkW*bR;Jv*MtrG^>W$FwKS}EJWtC`uhu+)i0XTHLu!AlYAT`# z;6D<(*|+vJX2CDrBv+yu3~+p#4aZ5d*GVymaF{0MTxzxP7bws8Bu^-Aq}?RAzoPP7P$$CpE;B^S-U z+WK+vw@)!&H~@miTl(D|Fl*eM<1Qi&Bn9)Fty$6jAA8>!*3`DO8xW*eP!W+Ls3?dC zh)6F9qM*{0DjlU0iZtl~L}4o>BE1HbA~j0yMFj)|LYErpy>~*$ow4kF&Uf~4<9C1E z=ehq-SZmES#+dIM;~iy9iL)&mPUvB02h%!H5!dy}>V3wzTb$|?g8R-(pOPA$kE{!b zdShX4GC|$Q<;rqmwqf>7y-c4r{W1Ml;+{FDuDp$dIP5>daMp<|^LbH)L7=y=}LF)X1R1rLOQ@^D*^k}@T42kLw*8z1kbVezb&FACA`&f|z8*bYo>l;Y$>&rv(I)AFF%2K% ztkzFw=RSU@M4kYWR*8|93(QR|Ag+b`6Wgt74WFpP1+A9cNXn0$A2|97-{i6d_%WIc@? zHdaZav>CYXgak=>sN6eILHEM6P^ghL4|WH!+N~6Prfn%eMB zHMLDc%p`FaXT8%(b4lS~#B@HKw_ST+A^CmZKNV0k6D!!H`*M zN|3HhV9~=x?knK_SK{MWBJ!s)ItG-q~r|I%XDxXy@dzd}(JB!mM_rTqp5zrMz|YW~imeW`#RJ>A;{L*oX_l-;iFO0ozu zrlFBV#MpLP4XFTg8p%)2n#j%d)`3GZEDBs^Gp`K*0OHEC?!rXD3i({{T*=#kT4#sM zXuskFdFNiTFa`emj`jiUZ>_Fj zQn<0bm!`5)Q>pnkZ%%DE8j1`%{Ob=!&+ zU6PGh;mz!}hWD*6>@CGr=r(&CC70k{qFM|hmylVR5vA+bas9+Z68}e|oV?ph+cHs= z)h8&e8Q9esG;w9GJuFwW_-nR5`nhnWnhT7Eyta9p{%Fg1dpf*o@-(_kteb00)C*Mf z^0K6);?a$k}&rEblrkq_>ue@~7)yUkx zDTRh{?6G5Y7f-O5k9f|sJ6hh%W#Bq0faYzCm3<0*Lss;<6+be*J$*VsJd+$2;m$bF zw=Fj1@=nyDJ&QAG%CQXFysB!*e&Q1^hr`Ob;2VC%Q*AO^YAG~Te0nhb6Q%IJ-BJgK z#!YEb3w4!!f4kZLc^Sx}4g6?CCQi=cVE+TUnhn0v{K^Md20rp+>HDaw-|Yn%G(6 zHFGuZ0u8tL!koMEbY^bJQ;g+bE!SzMG%5--n&;&&i`jYYJpH8ug)#TG)uNo3y=yI^ z3te|JdnO0EDe^AA1pLO+QC^DIo`bk^CyQ-Rqg^Ux52)!xn9i7`QvPTioz(Q!0j*P^ zUqatmGqf*1N-^=w&9o!ace6Ov!>1IlbD2j;#zHl%_R>wCB&NL6!{f(K2;K0%5M*AD znZHvfRQmOvNI!Q7#dVG~ifcLUZm##cZcC(wWZAn4pUYT3*W>v@d;DNfv*BZG8Vj77 znPJAxAz04;buGPA)0eN@`#cEm&x*Y6kd(bQIM8*jh4q9vP7&JK^Wlm^r0jTL0Gg-b zdu5!~tUzaQ+nm#NuBWV)vqQ@*C7)ss!JM2(p#!v*$L8}YK+h-!t%g_C%i4DFJ0LhT z>bbq6wKb$&*vO<7b8Nkk6hl}orZ*n)Wj!}1^cKTAvcHp^`GczOpho2lF6Fv-!tkdU zqgpJ)V(WHq}N+Bi&8F?b)lq?PQlTZB57wQITmq*mMMxo_SvhH@6Wc;p4DqfBi5qVbvg!m=$XAo8Ys+W z{Jh39^0^ed=y*@J7g6yU@vK&$&-~Z4a1S?(Qna*%CgXbt zgD0uFUSRA!g4hPLtumJUj<+hKO+sOpG8~$Oq zVhR`YB?8@W~6rM*1Wf*Zs}+_pC>6klxqeAubN zVOCb>NaWTP5+l1Y#_EH{d4Vm3wE#FM$H>piYA{~XSVfrF6@qw ze-;MymtpW#BppI8n-zZl+Ca0(`xd0Wa=&N_6`TNCoy3#zaZRfNP%<$k_sOmc>$KSqg&f@IZ1urkg- zD{;#@3$v5%p{+4bgAp+i8K)#0D;Y!dw1(M+%xW`Hf*BAtA5l~=4w3Uw*v~=*pJN_% z{{h7*Cw>+kK!8|OAX3D2-FJTsRj8egs%zizdTGl^rrXH{De ztvQpTWC&;04DT)xY_H2)pzvIL#t`#MYUDJgkepI#V{WBx`di<>oh)c#pO2LbBJ;kM z#V3+^HN37N^b@%$T?6zmlGOvWt2f zT-UoL@X7LhJ$sU6bncaR9{tUOLPLE30koY^n=_(O5?yQ?v2=0#ca!hWV9j#YzHnVm zU0J9jdrVM3cB;Bqqoa;2zSXh_&U{^9vj*fl<#3 znf&Pb6+QMg=knC3jwoZu#8Ftn2AO>8EhTsEMjjsa?{I5t=xe+MoDUazS?gTf7gCq` z4)=F;?W6)tSK#@+<5#}qz0DiPJg9;43p?DF9h4%<}cLtVdM(LFQVsrU%YL(Mdz3FktyS&+d7|6<1HWFu#E1{be{G*Vaz68)isg~ zVsCkd?se5Z-cc@g8K!obdVS`>;fX~dzp)IC8O{V#dy!?) zXwtk^8WXY~H8&E8OUcQj;_l11B!-Jj$VodKr>JI3+a_3dFPk;Oz&dL!3wtVntTWC& zY57a$l6aQEJacY3`*BSa6{7vuX&XDG)8>@hSzediWAu-W4Khsp@xA(90hoC~+|e!{ zSU1^ifp)dK{RqAW2a`zW+lk^2ueqCCe)#5=NtXF-)5znvl2KXv=SD9jNVtEtxE%Mp znb-#kRyxSf=0~VZ#%%#No8PA450TTC=O@Ko=573qZSW?VtJU2fS>>5;3zAH7Qxw+k zvw`-Hzo|R;ChYmkO#^fqsYi%!L?QDIbZeKD{^n(70=eCFmvUy6F2on7!6FJ{qp9NM zG2=DWC9Btic&3zt$Wk(nD~V|j6n=fw!x9R~k3CJGH{(02a_-sB-9G>Zua&rYFr4xp zJaRI*MrdV(zcEfnCVt0AF;V^@*-L$w*LP3MPLIAgH7jWQe1A3)sqe1q7@|`q$WIV5 zYx|_5#;fir=%)lJ@u4SC+R*o&VRsqTSK>7T{q$-M@s-mJ!f&n*nPz;z3@_O=nR>ES zVz-`%=h)inP;Nhw61ei_@>XYeL=fI7O2;-$r?R%2TP-$A!0y*H9w6d8RH|4Wv+wi^ zwVcV2A#yg8F<`bBZrsJNlQNIvj^5XoQa6@vDE7^uR*Nf_8XD~Tl`UqDygAU2X*zNs z6BO)M>4JLUnXtR-t|;KVv|mA4ey*DA1Pyux^q^Z_8cay@rma6x%w_O2fd=OUH`vna zv6~z#@)5W{9>XqqUVjTOzm-(YJGhe&z;KTXB(m$)>?MV>cT}UGyQw)Dk4ksGA`4~L zo9v&C<_%HA>9Qe_T+kaPr=0u_a;1fW>~sBc)*KS`@QC2Ak37)DTzRBu?YPak0NB_B z!nQ=@CNUfY&6i+_=Q$o5pMD`lLhHeDH=KjT?GIs}k&Vto`L&4wExbs7BLz@ygc79P zw6ZF5WMKKL%hQ)={igLUoA5&v@!=k>Zl5Y;gC=Zj@}cFaGC9RH0G zF$wfw?B2#%NfkCsAZSkyzMt$eAS{h#awYZ~Y2Nt|264c;&AkOVhRwk!ay#Q>*$iiOCHN2a-D37&7ZV_*0M{@Pjlm*1|I5J#av z$uB{?t!Yo{%)Y#WPNM*g*iVv65)0v=+G-z(nI4idiIcc}qnuuGSfg7e3vNkI8@J;0 zLp%;?kHpVRN=YHo`o(RZ&Z1e_H_#h$9x9edg-$8FS^5{l`ClXdza|)A>r`M+T!sDn z=SMz;!YWKqvY}(Q5KvySQwN`c=`^=4i!HZYgNUl2AJ$HFlN##<*YR?Ox9*!BO|!y= zbNlHj)*FHZInnrDE-;?a*HcI9Gv|zQN#D)@*#9r@{IAda&rt6q2`Q%R@R3he-e(Kt ze8bllE@E)g@7un_N-)ThVv6xLL9b_kxjo)(VR(AQK2KYa)%`Al(CYc=C?Wm{*JU-7 zDf5bgh{qRf{kW2}-GF`I6BO<3cSnid+AoRKfBmiZApJ?z(U;4QcNrc_exDpf1&z_z zM>07`5UTz$ImvydgOuB4;br++%-HMb!qs%Y=&sk9;@iv&>dKtJGrF-rZq!-}8%4k= z_A-LY=z3LpZB%geNiyP6Pn(hjdA{K>4SKpy3gR74d%1N27^w2s`C^gW`|O^%pW;jI z2wpmGeTXb!MA+F2W4HJ`nKo;paW~h^u-z*#*Ne^`mx{{GaJN0Rw9S#VX_^GSHv3 z99E^XX9fSMeh>B2`ZI}#x$0?^g8UL<@+Vi~dtZ>{Uf!|P6DJNMf}S}M^q=AJqd$BT4)kjlmnrf# zU@zrhpP+K{mUA5q$P&1ztbcDP)i*1NQ6c#DTZ`OVo+q+5_LL zP>AfgMD|UA$uh|kj}QA^PiOkjhUstug_U&D5K*DsfrrQcUJKvzRDZ9$@(W+|_?msU1)e67=vBTZdO8&42_>q#b({7J3?3+3xG;#{3FC{*tr+FLU z1o}}MIlQKRU;TC(2_Fp~W6nOcR=BZoZAAb+*~9BmGMo$A+wxSN)cr43YILtEBvmaj z|Exory00MJtJ2&k>J~?>sUB5#>$ZlL;x0O?l1nT8DpsgzV`)a(PH^%)&91Got#0>(;uh7h6F* z17>A*c;%+eTJDm4Xl-aViAh^zru3}=fFQ>P8PIROTKDYl?dn&8gB=EwTbsQ@KArg= z`+G0{#OQ;u!W$9%O}78!C;iRBUhD%-q5ao$c9g$b-``wFG|*Lg5>gC)Ox`~Be{u1s z7r=66;b+XGdp~^t6bJqW2tzzY+L<~27Z;112BVZI6wmto^CtWAfj?gm3}8I{|JD3o z?BPG81^({;tNHJw^56gO|ApPWNa!i07cNcT*8573KSp_srOjgT))BrmnL5+=`Gr&# z3JKvbkIy&wHqD08tw^&1wG59R3cj6*{HPAsg5HMly}FhFYqL0CDEU(T>SMu<2R>S- z@}?L6VE8mM?`X0f<1LF2{b}X;0Uk#uSmNC~9te_z)=O&c^XSSM%$8B!rQr zi0>?ZAjM?m4YS40@Oo}Fw#9M8IkZu_J!JZ~*ZTF1ydd7K2Pk34!MEpKk9b)>GZwt{ zuQK_Ei>s38k9fte%3T%N4~DmhbX8yYOPv33DUf{@4?w@^1+O#B`ViMY?nEE`9r*=h zctKW+mIak2NHI;h;U?GqhcdB$I4^%-#JLEBMuQ-`BT~ni58H zbL84x5beLYkNS5b`t{`ouRsLBal4{Ao(nQyaKNPKHy-TGP6rg!_Vm<@ITZ|<|7Q1h zL`^1h_B2G|SpJDJSx5;v{Xi(yuNV4n!VI|sgSZ~!X)t1b30XDLp))-D8^)R!4|df| z*47^;mmm^n1%-Z3$?t%YPx=VLoq&={a>l_yy=U7ty9AV6tA(aw%7UyuX?452=PQAl zVNyW3UiY00z&*UJbp8V?ekDC&J5o}NY;#E>>KtSM(`dT*J4#MD3X~k3%#3{oHYFN8 z_&a(c^JNE0zM2|t0|uTh+mJwh=fStmfNMF!?=RC_gSalEgOC0WnrRWmMW^m^a2&wE z{y$27XCogunGclwhD!T2pd7mHndYAR4eOGB1Qb+XaV^BiofH#dbmpMX-VNk5W*8`n zdw2iI=~eOszl+JIe#b(poB<3VQ>|&&xFG}A{mn1_j%|r6ZL!eA#_mCkHSW5q}BGTlVI%-N34XiHaBHJ zFszX*!4p5DUzb%l$moRiaO(FY;0-@&l*UByo7S4A#+@*Yb5u{ln|uM=;67cG_nx4} zo9+BVtj9);g3y3!L*`sx;lfRcg4I}A@!_LONgNWK2*QRZR8e^73ETGUGiOk)@panD z2_c*^?+));yhEsMNBT=6wVC};n=ggkhgC)v`Et(&xi~150;O@{<^wr(vHqOU9X~VN zf@i=NeJ-D#6BH8!W9DclbHc9nq(B#8z+Kl1CVEITZ{sm4x z3Ke=EzP^|YafmDYn26_FgEzjOgG#nmwtnWQtv1y^;TPX=wDplHVJ5$s*;Tj~eCRc0 z5TW_e2Rhq5jG00Q`c&e(H9gyLy6|<{eRwDAMZzhTsWq!-kk#>~m=SI4c2{r#x5R=- zi;H5}&KNK1g(-4OIz|M7UqKPXD|Xk=b| zj3*xLyfeZI4Uaw4-W|@Z{a~yiY-}lo5Z>F@*I4&@U~62ck^#HBUMM%d5C0`_bp)z> zdXrPh<+eC}O39`K8-V{x0sSMlWggc`W8*QSJ+g-O#G9E9DD43eE_;)9>$zFY_U6M$ zWicC*p&KHEofVwo)uDLEYL&m}8UcSd&x4TOu-{77w0gp+CNUL%>thE)ShugM!&|Z5 z3S4mfX@?Wfd90I}@F#z#MqX`O|XKbq^k z*{R0yKy2wFEgLx_lLx#OvWiBmWfbi!H_Aax9=u(<)mhe#{p7m4f`Z;_PbopnWEIw) zkI+$$Z=Zk?wr&#GSTeZrwIc`gH{ZW4(JrvmESplWc^;xDYJP7+p{v$yefHUTx$scG zjb^8c+;RF6RZda71su+Wzlb#epQHIl;4)~VD%&Vu2&7uY; zx51V8FNHSxP39?Q6F8Ynn8dupfseo8X>C}?#OJZSdedfF1{=){iA$G6**A*>U&GW` z)dnyuedLhjLu`Ivl>r}_TT(WMs*Nkq1*=fz(-kZohM_fc*|RIQr>_{#M^kvHoS)a4 zS^Oj`d8J~rhPT#`WhHXCJg|iS9z+yhxKZ5V!6UioO%s~pJmASJJz}{r3TMW=6d4d1~KO&IR!>>ehg`#+H*O)G;`d4X{eO3-gpMzW-8e zZ@M)*)p=X;{|4Roqb5O>A%0Bu{lmGLJ313X0u z&JDX4fXhPxi50ZcDx1+=NG~dJU7LPBlE@6KKC$ zo!iANAlGKP>jul+xKd)Mv$MgGpl^$LE_2wI8+ZW_&8)A>4+$JmCE1-V5M*peDj*;9 z!)qh1r3O~0QQQ`?8DyTDn+uf8vSskhS94q&QjHU_+V`}Mf~g}~06sjOf#wlldPC~) z4q08RV%c{A=R=-Q2~fF?3A
-
+
License
diff --git a/src/app/components/about/about.component.ts b/src/app/components/about/about.component.ts index 3f4c0ae236..3b5cb988f8 100644 --- a/src/app/components/about/about.component.ts +++ b/src/app/components/about/about.component.ts @@ -70,15 +70,18 @@ export class AboutComponent implements OnInit { {type: 'text', key: 'isThumbnailGenerationEnabled', title: 'Thumbnail Generation', sortable: true} ]); - this.license = new ObjectDataTableAdapter([repository.license], [ - {type: 'date', key: 'issuedAt', title: 'Issued At', sortable: true}, - {type: 'date', key: 'expiresAt', title: 'Expires At', sortable: true}, - {type: 'text', key: 'remainingDays', title: 'Remaining Days', sortable: true}, - {type: 'text', key: 'holder', title: 'Holder', sortable: true}, - {type: 'text', key: 'mode', title: 'Type', sortable: true}, - {type: 'text', key: 'isClusterEnabled', title: 'Cluster Enabled', sortable: true}, - {type: 'text', key: 'isCryptodocEnabled', title: 'Cryptodoc Enable', sortable: true} - ]); + + if (repository.license) { + this.license = new ObjectDataTableAdapter([repository.license], [ + {type: 'date', key: 'issuedAt', title: 'Issued At', sortable: true}, + {type: 'date', key: 'expiresAt', title: 'Expires At', sortable: true}, + {type: 'text', key: 'remainingDays', title: 'Remaining Days', sortable: true}, + {type: 'text', key: 'holder', title: 'Holder', sortable: true}, + {type: 'text', key: 'mode', title: 'Type', sortable: true}, + {type: 'text', key: 'isClusterEnabled', title: 'Cluster Enabled', sortable: true}, + {type: 'text', key: 'isCryptodocEnabled', title: 'Cryptodoc Enable', sortable: true} + ]); + } }); this.http.get('/versions.json') From 66783e1f9cb1520e357c45f906a48addeb70f696 Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Tue, 3 Jul 2018 16:19:26 +0300 Subject: [PATCH 168/179] [ACA-1518] search results - file size settings (#479) * [ACA-1518] search results - file size settings * [ACA-1518][ACA-118] set file size intervals limits --- src/app.config.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app.config.json b/src/app.config.json index 67007ecce5..0673d08960 100644 --- a/src/app.config.json +++ b/src/app.config.json @@ -269,10 +269,10 @@ "selector": "check-list", "settings": { "options": [ - { "name": "Small", "value": "content.size:[0 TO 1048576]" }, - { "name": "Medium", "value": "content.size:[1048576 TO 5242880]" }, - { "name": "Large", "value": "content.size:[5242880 TO 52428800]" }, - { "name": "Huge", "value": "content.size:[52428800 TO MAX]" } + { "name": "Small", "value": "content.size:[0 TO 1048576>" }, + { "name": "Medium", "value": "content.size:[1048576 TO 52428800]" }, + { "name": "Large", "value": "content.size:<52428800 TO 524288000]" }, + { "name": "Huge", "value": "content.size:<524288000 TO MAX]" } ] } } From aead0d19fc13fbbb08035a1d0658558af6948d00 Mon Sep 17 00:00:00 2001 From: john-knowles <18680913+john-knowles@users.noreply.github.com> Date: Wed, 4 Jul 2018 11:08:57 +0100 Subject: [PATCH 169/179] Add files via upload (#483) Replacing logo image. --- alfresco.png | Bin 8205 -> 9661 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/alfresco.png b/alfresco.png index 7f6326b0b376141cc757e4bc128590a6cf48508b..fc2bcdeccb3c2620219a0f2c727212fa64f3b727 100644 GIT binary patch literal 9661 zcmX|nbyU;u`~GMorKP*O9Ni^2x>E&2K)Qv|(%lWxN(s`f(hVcWMkBoeO4oPq&pE%} z^T)Pxc3#ixJl9>2{yBF8;UgJ%P_HVOWnb6VoOU1PK^z_KZu@kJ0**Vk_IEJ!3=%PIC!_`=6 zULVKNmsT@{qq8gvg_|l!&8-U92Zn@%6m-D4{M;6B!Q0kpA_u<$~~N}iiy2Gu%3J0E1RiHV7mp9FO^TTC=%>oa(a1;l+W zzIAtMs|qV~i|;EWFa7@gdwcI)pJ}(|SKcs>i@1WXT5;FYSF5Jqzhu-^EO0SNPwFHu z<`Nvtrt#jjvCH$~3Nf^+LYn6uggO4(JmNFB-ak|S3hnZqkR5iphL=TU%m$N}-Plet zAll9%!#{O~F7-?1RZ<|1JOcd7<6NN+bmOM}CBvI%eerHKcm|qqf@QMa)u9=x5RGr% zXgtnG9`EZm^MKj9dIli`r}g?gE;dQyzsq8G81~Wp@7>6j(<3tUAHuvs%R(Yv1#UqzU3meKfd{-C=#=C#`E3>~9z^Y}i) zHdvD(Mdc6Jx3Oq2ZLJIEuUG&yPimK`9}#FD!om-L|Lp%Aw@g?zmc5F|?X;8L-gEnt z7v|En)KG|@Db17dfgzOy|*sUps9C+MuR#`|A&28xtw){A(2o`XMON>4`c1t zghTIc9kNYazjL1Vn;-dK2$aP&=$=fQQ8wS^>f>lg{jsudp8T044^OpCA4v6k zA!twi-fD_XV~^wDX@SZfcQ0rB4DVq=xRY zT`Jx~aSxZkGyrQoP5SH|8d(_`86uuEvu;-M0`T8*`=H)RiL;`Gg~XR9Fuk#_#1lLJ zT=_dTmoF37Om-=%f1M<@Qn?CZD2&U>Ty`8fe|<1jKQSdy$!N&N`p>K*&rQyFD$D_8 z9Kmgg#91$mlM<`z;yVH$e+pr;XE+Fk`Pe^`ES5wU7s8nW3NE0!``KF6`@aiDdeT>D zx)<=U{50a3|4g{SlsXt_<2+?#&VL&aMA{8^j?4TwmPTKey{q&vWhTqOL&M$z@6nzKqD2HAsW++dR z4fXNgt}G8#Ppz)t8@r%F?SuM^+s~Db^5rj=clIkEm}XYNH(zY2bzW{RuLFSXf^MFC zWqODCu2A~W@h~|BtrA@S(Z&SHKyml~La-013(P`=OK& zx$oruFWML3$WL$jtqD;cy`92TlnbRe6@+JX?*JpSQi*!6jghx56_{X}LW{~WCnwS| z8gE0iZ~n61yuHrJmW)ey;sBi$GRr$Kh2Mb?N(nz3+(nQyu|LTO`eE2;zv+hAn~PqF z=;-L-pCB0%WdVh^W~Pd*ZbfQUFzVlPv-LzC{5TO&h6=)~frfjpC3r{mqTu4jMHhMAuY0@0C(2!ne{Tvfu5J=3AT zcM6rLH!-Wo3|c&!X)(gizHrYU9&IC@($V4^V}(@yN0`oC205eA0L>6&?U$u)PX0LN%kM1S~tvo zO6+rZ5ENWbqFdb7jQyfimv5Y3Q4oWyemQ8h>Kj@r`uNZvOrm>_O#gvBV!?dWfREn# zI1D)*QD^wAB`u@sE^9wt;+?GSo;TFs=-%BtDJ}@CEVINczQo|?#C4QAb<{PB=BW>J z$*eAH`CxVeXu8@jPrNC-3&ani=F92Rl9($D(u+#0NZ4Y+-H zPE|pLTbHr&?(_6Wk>J~R#`WBGdr2Z=<2)<9JsHSsm-iF-`1>;NNS|_g3!+27m^wx4 zh0VtV&G*J21`XG7zCSM<`p3S`3kFg(VO(SX*`&>hUKA$t3{OE&?dFrI9HCNTA4P9) zbeKG@dzt=WeNP8SVI;(}#}yj5`dh+TF!}2ARARvK%~|IOg9CZy z5@uB2BP;$ALTQ10s-mv0{w=I){d}{HHm9yw`|tbU`lo6AZxq#~};l7-NrrDidl;z1!*d zgwsy6PjrvBoS)GU(L1IMbYYyK{t)qcO0^$vSR{?jn$dED#iP{dz&z{aUY;>z<=-W8vU8*`MVVbN& zhC3BYW;Kd!on${BjPKGhAV-pPIwmLh!yyla4f&VxB&*}86H&UtBaHOp%iwJv2qL*% zrV~Rv$^Ks0={}nI@xWSvm(BJas}SR;vVhi0U3jw&hAUbWVD{&jKD?O|gSg_{8ynsX z3Hv#stS!w#1|`~1e^Y5o&6_?Nld`MM(M^_;kk6!xRSS^A>hY^Lj%b zVT}pN`m$Bg!;frpTVTo$XW87mv@()P&YAJwsuQS%;@`uE=nI5Av27CQCgi7)Q!##7 z1{Mvv((m>#9PAxV4@Q2B@INL&lYN?BqBS#c^H?eTB`k#&k9PaG0ZwP*8p(J5UAB!P zZUrmm0U(I}zIsRgPlakp74OQQbQ_!lc-1+7uhMUJM-BRuCzCVfl!8Y+-U(MP3Dg^+8(2#Ix?Y#CnvB7 zx)T@{c_cYfssGhO+fJzWNq81?r@Y}iEE4?sdouAThcGUVjBTSO@FX?KzMHb~Yq%o*kLJ3BvO zvFR+`u&GJ(`s4g_s0m-G?-2cmI`D@ceJ??P?ixeL(rRwcA-CqY9TFFxiB={?$;iy@LtCR{cfqW_OyAAo-MA3;9%1M{`>J0ZcWbg|Kt}@T`1TW2*I*#}H5m4@Dd3JWj@>;Dx&+A6ClB4EcAm zP+n?W6^wyp8Lok+M9)7Jt(o;J!J7q>yhaQ{^r&{x zA*M%!i8sW0+jMA;2)n@ic4 z>M2%k@%Od@$(U372M1MtFOy+Gl0^~GGoKI1S*fXM8|*c$p5H{{YjB!vCpxS~C&{Rk zsx%6Q| zEAv-}E1-#PJf=vO7|$DmKws7nhCFD~`Wl3nS1P%wYa--czr zx_FHT-8_2!v{wdNkP-4CbnwlV(E8MGq9qi+k(*3PcP|#U=0>_N&O9|ui+S4}b0`M*)L|@Um%DE+Qo)t;QIEfTZ;Rylf7f?`D%!@2dc9oqb0sntg_`_bJ5(kB=Ce z7t=0D_T}>o(>*%OpNo@TCqzq0r)KI1GKC1*8zGd?@dHgU)`!~xD1PE zt8Eb{M(EwerVLt`8e3)m)1oT1jelP-C!XDV@?&J2AT2xhJ~ubB<)R!X2+xe>@8r-Z zA1r4Xt47ywp4`CPDpGSUzwM`o)0LBCW^_PQ7ThNiuQa^niO=wng6o?y z!y@n1-Msm;A+YR*;WPDNTkP+I9%KZHpLBxIEEBo9mV6)#e@xYWVIFJ58v{>1{`%R+ zjjF2ik!L|snCKXYb|zTD2kM#me+|GCf@B#JZO!z#pK;Cyg7YBh3s<8v`-Kx;Gwy<; zmYqO)p)0){mQHu04nFd%4jgV>yO5rX zc<#@BBcqKcu5zxi6=$j|t;~7E>U#@57vyct{Zmyr3&&i!%-%`_@)ELj>*p?#ht-d7_QmMq-Bb@__@P;ariWE@I?5Bh z_U5yFh4(JxRr~(V14mL-()WDM`7(*-+iNB%AP_6SsMB#8AfS4GI;r21bA|19o{K)u zvgE~|c4dWcI^wW{jM1vZ6QUpYm)tU?&mE9vLS&+<@wK4v3@FfdV0;|Lv~>_8zDmaJ z<3~5{&-yb(`mpkW!JRbi=tLsxEQSj z>lTOan`FW&oY_z5Pn?%T0>qs($AYo@41@k)ddEWU`fo{k_N{Kmp1M6Rjp=)jsae zs1Wpe2uxo#FACb4IOR>6s`*mi%9(uyj!YbspJVCauW1cYbpea_9R$$YxR{UKPu8T3 zY5wJgIxNgG|43p3`;LqsW2QYzsh!*s*XShgSGi&=PPpkeF8_AK2X7|!; z*AzT|RsuY%1bdL}G8{Z2o^|p5ol>e@UmFqeCKu8Kp0vam-EyBwo+>9ilBRCwt`9V- zK)AP%SbuPvSu4-cz7ABzV|}papT} zz^ZvltntlqNn$TA(XPspkQ`+!-W@G)Y+zDvKTfA(L*fK^>^re7^*&MwEPoL21f&7% zbxuX1z9Q>S2w@fNu2A@M`KQ=^VvV&+jF`K_U^^D%F+(3f&v!ia&DpBP>0gZvR(SKe zPi7UdUQRJ<@$XM;E~kzgC?cxky<3D^t8OeBq6%|u>pcI&8h2$iQ1VIgu+v6)jvDFL z!2QQ*c2e~TGgmkGbNfF5bh&v@AlJEM$XF(sK5UrTb(~Pcce)CpLwsd@qQVi)!{Ul4 zC~^^LaLz9r%9@MvNC?&0{)+#}{oS7V57DX7(W zfZJJ*vsH@d zO;M$z2gn0hO?gw>DtkcwNBJ@Al7TKi!GHW=q%`vH_HjC1*8?QUzSf<0yWT5Ai5jaA zR-E$L=FnV|SlzHe^%noCR$4y?%*^YVnLa#S;t!wiF7}29D9&Lj7e|{Rc8s=6ht}aP z$ivDW!rbq@sF+EMnND_vK4Cw8$@e|le@%dbP?h``m7&NxR|)!K{5?m3s1T31XWZsq zS)3koFA=e~&zq;IU}KkwS{3gLkn&Exk25s$P!kTq(LAj$8)G9}@S2_6Uw z3ly`9eyygJ8e1iq7G4c=?t;JtamMQ|Y{ETq$+icgSNVwj3?`vE^8S4DUgbw~K>bGa7`{-<$S+@&Xa_|ik z*gP)t{$X*qR^Ut&ykd(PM0B4Rbd&^0cg z?gQwv^y4ogYWb9oT~d|GYYp%JHpa-*KO@-&t2M`0<6Sd3t@;k!;!^{bFie_p1s;8&P0TU89-_?*2Zy zagD(fiibj&qD098@w2E9vai>v8*cTs)LuT2U>ei%{L6fVq`c1+b$qQrR#$ye)s;xu zF55=Wi}eG)6lCf!G!@0ZJU90u}RKz+zpYt%{rc z6+Pyf(I20hx5gfCU}C#-8JVs#oSJP0@d5W#IZ~TE5r^*(M<0@0&f6bw{8NdBz&s_G)5%@z;0O<#S)TVc|Q; zzKU7NKl1$Vi%2_m{C_njxLsa6Ln*xRHIZoE5ZC1E&kaf(eDXr(z!N1Jo@n&Tsb2|v z`7j9SdU#A9u?oVq*6w;a^VKi7M&_;&DsX(gnr&~+1e6hXN1cv+B&jF*7?#x2oOIFq zhpLSF7dbJ%S#2b;gpISUSxwO0P|XagFX&1i(ICgIR}898gOD)W7*?*7gkb-ZO!cHOh`md*97xTZ5 zV4i;2yvo4`&Z9~=ir)bEV)x$YM7ly-A~Wv@?}Ori=ZfB7_iX>KrCMfgMCWMc1!KZV z-j|<<{HG?f!So(R_l52Yv>GM+9`!ccXRlTG4zc=+Nwi>lV@`%@h3H>QRfS2kx*~E! zQ!7Ha7=&{q7JF@}MSUQTFP<%b&f}g`;QNCeX99F7KH`WO?1;p8&m>Tz!Q1{k0JflQ zve==*Wesm`z#2m_W!wZ*J0vxC&y~9c8hE|o*6G;h!)L4Y&j(dPiAhKDuw`oVFR5Y# z?@5-%dZtr{jN1+>>CZE#*M2v46DKTy?vQ$B%0S3zFF3STszE(NC?@1abb#<&yPNFz z5yv^txH_ZLQzO~fV7Op)0qA!j02PmRtkJ(?_?+Q7{09r=uf&VT=7a0+9}>qp2Y62x z*wIR|xV6;MDMvPDe-!OaQTN%dT=G9l#^9=(<*NOcT5PS8e4j4aHEe^%@geWhGEKRG zqnmFHqK@pwx+gPxw5ra(Luub5XB0&H5JyY?Q_-A()iZF6p%cCa7E$kcY7sp8* zMBlw3^-9KZOU%Vuu$YkPn7-`xCBUgOytzufLlb+yQg*#D0Si?fh$j|6t4iU9oJ=)g z=`2&vM3`Z(m-jzl+@m^`5N1gj71@H@Aid7?%!BunO|e>nJ-yHXAzd$W>{=zeDv^qX zH_3)fpad1%c<^Qi7R}z|E|+vyC@t)+Q`(j@5Bml!uM&h)-|PFP>vlNWcROO2tXi{F z0?k~!#z7&N@TBRyy?eck+=%>3NG+#PC$n)jrm0P3PVfv3zP`B+Sw zF{VVt_{Du|^5=D`9JOQZH?t^V%!keI)xdz2QY24U9y8?{_K~JTd0e@+VK{|RF52`Pk1A27 zuNNvaI_dmfpiPahZ6tFicje-0z=S*z7&JRCYpTHS>G|^)wjuYHD^JhDAL(3gHaIk$ zX=rH86bJk7o$BTPn62Gi}Br{K| z7vI-gE+LJHre#U(%!E}S&5^x4ew0MHXX&WwnfKv|tqGfj62BjPSOmLs)eT3P?IlL+4w1ly`jN5G7$1@do%U3aieq`?LwBJWm&D~oSdS}#!ufGqc zEm4iOyjJd2fETh=3_Y_eY^8csBu*|L7>}96ST<`cYNhu1H(9e;?rTK1+L?!Tvp~0A znMby2G}~oAiD<63m9~DZsIBw(@~Bl!Q^Y9i1W#ALF6YOsq;*aRS*Cb?2h!x}%`a8t z-}CQhGTuX6YQ=JCXTPoAZK)bi2SCZ@7m(%MpE&!&?KGFz=i;1xl_k)kB%+{S_CGLS z8MVa`e$VAe``zKqE>?M;hX+6r0h#VZ$OsgX>*{URwYxUABHcG&K4+Nn!U+0O6-@W+ zweQ3J*${-T@uM@eST5rsc`YwwE{EcG%DN6qa})CSvp1UHb^auLl4Hbm7`@CMxBMASBC zdAkM>xcul!&&-NvOk7yq6LCAy42GVGvm1T3^qUa1tK8*qp*c1;$Zi*Go1M|?t&&kU zJ+Rbicl#OqyOE$G|I$c9p`5VkA5D3F>$3@>o0mRc_a*Voh%SAIiz6@xm1H8X>%uk4 zueUI>e6iCo6FCJR$%2-y5$= zzU15{4$e6h$E6ynriioRD^tr8Ta%V#O2>DvvW<{$X0wt_o7sa`dZnifKT%qK=4(K+ zer9GCILaF%$VJ$$1U%_OVC25?Fi6%`tX(hC0KCK2-Q|eIdH&?Q^W;x7SKs(jX^I>e zQ`a(axr={s8$yssR8j|NmwI#xT#m!s(c+pgxK+N!Pfm%r}YK zFfOmcz>jveU)oZ|zL|>N;ttpg;hpiDYq;CfrXe77K&r(Gf>94pi%wJYFdA!7&09(Z z?N3e~`K~vd-`)Q@Jo5tQci?YsedG6@I3V?t53Qqk2@TI6;b5JM?x3&4XHB^m~mPxpV;9`M>Nwc~D6*ybt^ z(BrCVYzYK2S9Ia)o%YC79C=hfhiol~o%CsPOSMYGF}@7RG1R#GBb)nue=zbcl5aV2 zQ0v;hiucq}XW-YY(u}=>(l2SZg;6Pk!9!3sWix$-@;|- zY3i&b^QM%y;W69#j=E%Hp8hXJU5?{S`|48SzOroG?ax78h>)M62vh@$-pQ)N3~Gy*Tk;4O0;a6f6U%W!Uy#g1S3ej31zqB1aHgi}>8`xQ&!2Tm2=c-nrn+JtOezg)ls$1R#!q3)*l+QCpG zzIcO*KT8|szF);NrOH5}k=v7yFuJ)9xJJT)46tp!XV+`fuCcTc?=Y4Ib#-`}6^ zADe*(RRvDImm*_+s9^B+S9%KC{S-)ha;Hv&T%8jQ_gt}W(4=3!{6?<Q>m|n2lZ&eh4m=|+VZhH9NRXrssk2MIghEv2faxh5oz{o1i-@4oNcIln=fwy*q zi=&+Cdbd*^jxFzOa#nK1_mAwh)4^e^rTXq(WdER85*>eA2oS#b{i1o5vbpXK|C?b* zD3AXHf;?g-IInke0vYbmAMm3-H{tsJsC5^xGQTVb8&k>=O4%)Vygs_tq$;Vbj|28~ zrBAZQ2W%CXblg%YkNR5Vw2a5lmkW#>OlCe5Z|qDh0ib1KL9aXhyJ2Ql#B=$8Suw9$ zzOD0P3`&|s6+Bg$#-3s5qO81q%=$Fe^b6~?nMj<%m_EA@@cVDK8>79WXSbp`ZNXAL zJ{DX&HtH^5ii5C^=OX{9blZ;Ua0<51`^F&1mVE8xZ(G6BCK{PbAh+MmlGuqXlNGnP zi0sV0j(Q7iS|Ez%6B>T(yNp=YKj&Zn7z9kp7~-n9{`9bV|NTb!*6+p8Xko+81}tS+ zGv#9?n$>Qid(Ockl*^#z2-rcv-EozUtf|nD4E>(eDxpwvq5X)i#2423EtwRmHe#>p zON$r+IJcL=rBi}yjWj9@Iw~Cl@Aw4&2WylpxSj%#SIMvDbcv>`3E#iMf~B4`uoUPyd<0-MUKs z@S9vckempGbBx>x8Q z!jt%e&oD5DuP-HFRtTObdb&=;3vk#&E4zx!Kse9W+1GAdfFo5%$q0NpdmKKLBckfbV`Uw$I{&mOR97?F4FByO8NKq zHJ)eAnK;*6Z|2O*i#Zdcp{77YKuv&wfkC9CD655mfr~z>P3t8rswFHNIjtHbY+GbMc4)Y^sCc$( znf4Kw^^w|+0PRP?ZsS1Laj^e9k>5Nx2=)GD=n8J=5njYKN%%2o{3T7sH3wo@C}u?} zd6fmR#r*Y7AQml=j^-|TltP|Lm7R!|UJD~1M9Qy)%AX{V7h=de@v=*?vOlo2CF9&R z<&rghbCUi&W!8O#&t*Lx$AbtYo68XcICgU>d+PqM>fsp9@X1ktp{FRyI!4# zLCrgXO^1P9I{{sXetmm^eMi21=dr6;@eAb1i@=mQ%7`C=F>}o6lN_1jV(D|NUl&C4 zm-q@6B|-;H@)qTyQBDackJM4W;wAa&HJ$R=pvE=3wsp@ov~vgA`ym(ixcu315#?C} z)?Fdy??SSR)@KJu*4;{x-(|cf~J(8CJF-3a6DG{eIo(c?bJ z*_PDZF6+&*V-a~X z5k(VG$l2J+`SkkL%-&yN5q+ERzMY8v#Nck^=@0n7Ir)E59RJ=r z{#zCdPc1d=zyE&=hV~5}%fBY$yDA!ZU|)6$Y&?C;-K{Y+ z%+`whe@)he!YgI6vrmxAKLqrUxy49Ikg|t)b3j5D=#_KS$sN#MB5H==vD|5(( zpwQmf+Lv})y3We=oc4|T2p;>ro?W3$kBMyYo6`|P-Sr;t!)+9bKB&8*Rex=9q{25Y z?rO!Uethvou<1}|+KrABT)`nqICyIWc7d0q_rhWb^t6+*(nJIb{%icGBFCXefW{sO zU14{;x=)9{XMq!5u#i^pPt@fhZ7C{7>!5(6CfxbIuk}MTq@vShZY^+REiZ*& zz6~~$f04mKllvRB6;HK7w9lLl=7a)HyzK7putGbB04dzDS$t*4US(Lc z`+0YWekiY+?A;OjTiWxNUT!t+(Mc%hZke9=c9Dx7fPi}%=ShKLafxoAwHTh%B)_c9fK zjo-H2C;8i<4! zcDSj@f3BcNg*Gfpjv1?yX)*F#k1=>t%TW3kJPnNaI`rNAJK#mQx2N|CS3TeO0v=E7yu1*|Ggy(fNNyuotw?3QMBXvZJSdcF_e|x4sFrKY(k4?7RTlMz z_V+Fy0krE`g_FaOSuQD2jh5F7>V-G5OeT4Z)^KA)@-|MXBE_o2OmS%PbF3Aka6owj zA?&lsjSD?-@@wc*vh0cU<5K;QcF5foU&z7x?%+`KX)d5W6;v0O9!D6;{@QD=4QxdZ z@C=Gg15ZqTRbV{kB4jR*d&eQ8oR zOz(n9$lkaITcqe{z+rF`;{MIwry+(t6>(_=^yoKkRv<{X!&~8E6I9&l;}B{7K)IB4 z2p*u^HL`g~!4AbZX3@@J4KoaVxTy{F-rVTEzn1d3-2`@oU}!5aa(XdYdEL9l)9({> z1s^TYxOaLTy^iINL)>42d(PL8no{H99cQj#zioLV>EK1@mt&ii?{^7`Zb&@>ei6wC z#LXk;z^Ci7Dg^TM{d;DVF$kEX7|+2}Sn`)O)ev4lF!Q2+ZSThm>@1hA;74T&br-gT z^U9FAeo4eo7dP^NNd@hT9>EoYRrKciJ%U^xL2(3x|S!F&G;nsanFbn2s;KG~dR)ve{ zXL_d(M^DMKgBNfS#HC)_WKerw1o_plKqx42&CZyTEW7Q3HRilWCA7o3466N2&dPy+ zmL!sFBPn#!MkqWOUm2WhWN6qyx%e5|A)OJ`T)2f|gB7zsuErQpeBs%lF{itW_qgJWFQe-@w~LqlqdFQZ#4LKLA3RU zcZ+Gr$a9rHUQvlro%=6he&Emt(3`;WrUY=^; zuu9})7B%$H9LXMOIjYfRXLm@&4z&W5hF}YcodLM~f4InPZZojRM9a@poR0N3DFV?{ z-0!%IA%DMpElF{B`S|Se=Qn$s*wQ}l20*hn<=^Swji9a&lZYVvtT3a;(ShH@C6f|rOVs0A;Qb*LsNPr6D zgdgvF3lpG%1x3Q~P68lFH)S`PYjmX@tVli_^Sxnug{W zK^Y0vJBnceYp$&GHGUrWLOjZXD*Qb+L+%>@=b-;9cFHUJEFG@F8H9I@N=FEh<>}~?c(y7DwrSm%281Br^+l9D?&puoo40zleNR&CtKRpr^k?m z67fzum3<=d+@t@dx|gLm;C%4&p}>uG{ce8@WY&=yLBSsRgheDh%+(wDWHC|{G*m6k zJL2LK_|x<>lMEHDZ!D`(H9wBWXVG~Ez2K%AD$YHe076K&0;^4H^CYi4o>LvY`;7wj zhJ5@&3{^$i*XV5{lBF*0wI~(KhklGlx)9pAl%YgB)?5@z_dZ<+6-mU7pw4%p?81`9c91iw#GMMo!T`v^oP zem`708?}7Q0j=se5A-@c0i&iL^05B+{2o!4Asi8H_q&;uiAM{FMN`;AiuE}ubVt?# zbkIeb@n<9@%JdER-l~;$Nd5L2AO2p_Yt7jbJ z=_SK&v8PXrx}a9{YQe*M0<)fo7>F@f?aHF-dbigGp++AV=QDFZ`TI@F$!6gcG_i2s zn}|b!Qu_|nAjr@xV<>wo49|}A3qFy(ov~*xb6b2#Uf@Al%nw;GaKuL(AqG%*;Wp6( zv_C4lY8mkBLg+_`CflEL$bfEcTdMT$C=_O*ZKFpxMnq#)rss43Nye3`B!Pv_;Yl8H z1X)RE6ks)O*r}$Rj?s!%PzQ$qc}t=_#-0s7ssG^3b-nu8)v+2c`rXv!Uq5B31Z}{5koby4CoE3AmRV_526QB^la;(D^ z+EM=v0zzlstuc#`w@{?N%C3Z&Ik|lO$+k?lCZG(@uXrXHC?X%lVw6<{nAI-$KBZE` z6#rjDd+!LeOOHd2N@~Q$QDq;!`V=!-X4nH`Q3WGdF&}{V8`NvFt zDS9xP`jmfO!NT`BOLSec*jteRyQdz8+xIv!>#@OgxFU{B*&qRjetutLMY6t(8YUGo zNWesDi8W6DMZuhKqwmXcgS2lU<=n>jkZ0AIEE4q5@2Jq@u^$T4Z|y3yb<8WhoNOqN z@SZOAeZT_)#le$pK{Zx^AZm)te3Nih%U(Hk;X_trTEYDTezbM?E-{LX*;k!OjX`#8 zH2I71Qubb7G^<;<(jAoexv~r_)!&#-XIL}NpB>H$V|Durpn5?_&!He#m^vd|EXeRY z+Eq(sc~UuC-jSqW$dxUx&Ud2UYUwt3lNB!~m)#!zWEkV7SfRw_pn7cw*JC`*HQW7~ zr?wu=T8kR*Ibf(dm$mT{42hK__;X4e=WdX+ zchrXl{TGSb{R_@Fcld=D9wqVTsF|7BPPQLpBWyn9_OH~Ioru&_#K4RLEY1Id@zXwzH5)ixZ++)v2vcs8%%O(33 z=iWtu^)90RlOU=v_NlzoyZ_qW5fii6Gbx%=3Sdpp`Q;%HqCCmL1pGWzL{;K0_6E-B zvrvXL*ae2F{6|TCk>*kCUui*QvHVC3fA=GX;&0a07&XLKsH1N#NyBW~xkiJGulgL% zzL0x4l*T#%)RC)(2p}pqc{%HpJKM;=X_PYQ^gL5-?!ZGH!04HFQ-O-3-Ja7jBT9=? zR_&=D37cn})j()kj?S`^O-P%UTB6m<3Oo)PrlHGLvO3^Q!Fk-2DKCIpFs{I`t01Ni*F z;ZWltk@I4Ru-j;|zboqXuc5(%m>=(`%zw~KN`D;F9b^tC2UQ#upbDYm;yUgOnWE5I zA+q||O5_XL9F6G^&tqVtE5e>BaNJf20nNR|p-r}EijK-K4u8Jk${AI|Uvu!^a+EB7R5hZ>B-qtX>`^w9v{*B?w>p zj9oDELc`TgM7Ul3LU)a2Hn|0IH3|aFVA=~fjx456jbj0Xz~)<#b4)OL==e8Gyw~c7 z3YiLGSv?SEdowKiNFh3y!`L$V#H6_Yib>^CPG$$hQ+K&Wxd2S8!&=Eq`DXL_n;1 zkF5cmvi*JAnvRiYF*fdunGeNK*ACe~F!%bHL3fJkE#k(p;r6Ap)3{v4#^eZs<wG)YdVad7wE7$ zRF}!}K?fGg|6|0eK@&1!9n{Vsn`L2W-g}kEU=SFxZ7Ep=k!3ea&rHG?O1D8Io17^( zy2gT1PqU}!?yh()961^Xx3BkK(pP zN}AO;P?r)TrF`2)_Qs^N50PMwAY13QfvqFrEeVd3jCl?7O4>+WLVM2eWEFU-K;pw4 zvMGIjVqO;)^7m6`CQsg{OuN{5nfDU~B#Mnjk<9fOOnqMwe2lN+&X?FcO?fyg{ z1J9MJfEE6dI3R^GV`e#Eqo=SVzg^=&qU+|dsCxFgxQ!4W6r%Lze$>AO;8N3#;OJO0 z!M|DgGQ64NxeKpj0M`|ZLd!Rzs5SR@@54dIY`tWm2H$%}E1SSjVbYGMsE3OlhB?VB zvq%`67B~{jz%9Gv5N5x&-=;+a$q_pFDO%a}?k$MGL9BJ4{SJh_BdU1AAWTcGI3u7= zSy6}G5G2i>Sw2?wDxV4mYCHn0vhtp4eq1TJ0i3kw@a3lftXnNOrJugPMws4}$kGnT z@>-xof&wjNNg%s*xLwiM-l`q{xc2b>aqHim{1t72bItED`-C;n(XY?<`;u%^ycPQ* z;o*6c=q=vgb#D?Bv!kZ2bo~N<(vMv#}l2u;` z-HuZ>G>^rhLGqX;TLwXP&mk{YG|byehemdugccyp*eMB`hgk$@1?qQxpg)E_&I$of z*KDBJdc*B6`b`m2`yBkm2+os@mc=hD!s84S$Vt;xLHwgA))|#kM_0Czj)5gd@(j6s zqgsG`F@jI{^93#n8ZO8?E%|9$wXJbnIgtQnf}5IhbB?`ep5V9?8aBCp6ASry-DIM1 zECLm<;USV%*NmAFgG<_1xRPrY!yV|}Q^_O{7BY4a1sL7S#;hL)4-H917hAW#*?DPV zU(O4-UP+$ubEuQ6p_>DxkvK8L=n+cjl_E5LFu}f;iRE29%s|Pcc%qcsU8Ni5U0@{K z5=zS*c))-vsG*B%sVuEd6Ty#>p*M`3fQizdQ0*v9q2Gmpqb1}9i`x9M64EbxAsbh% zCEarShuoim7U0+(K?G)$C(wQ0Xt{ZVh5O!yv6ma+S!~;_}ljr{RPHN{JjS8~kn5 zv9Ab!C_{E)7VR1Y#W^t8zsk_JVqBeZ%nbHm1tK?cvj;ZPL+4^3> zweS(u&+Zf#1R!XBZy!A99IAVzz?D0wvu7L-GqtE2iLdpUK4Gc@9WBU_T(Gc=K7YgR z{7p60DHPrYNa{YrvEl>Y0Vz(zEWj%{pjjb=;uI-fkk+8)j->A0xQ5^=4bTUbbTSKr zGZ2laPGhQaL+|s!qQEVgWV%d@UUWKs{*s?D+$wzlNE7O9cMU2C0i||R#!Yn$KnZh= zdbOAMU%thhoX@qecqYf6<`9+buqpvB{ILcW4s^mjP60SeIGo8}!*_wr@HX2M(ZjO; zbOvLAe&lWz&V<%yph#W{P!=%GFKXJBadvs zuoMgsv0-^t9;p2aFx`*)q@4p~QgLS5*#h*E+rMR{2naPCD1)svO$J1QI_(DA&CjTO zW&_}Io>14hBcMxSGaVfi+%K%@+=iM!f`O(M1l5g&$v6Xkr1-J%twH*@2^Rr(_T@{@P<*+bHn&%Fqln ziqKB892MssN!^rAT&fNCCyL{9Coz3x_j^vaZ^$pcsHcKf^NEa>si|auj#5j(o;1iH zlW63*gghk~Fk1mgZqJtUSX_gZNX-dNo2JZ0u^EaP%f|ED!I5=PearaEL~tQ62VL~0 zDjXsghDyw={#t)Z7VKpkgQY-tm3DM-r4Lc7vfvwStDOLE8PEcW#KXirDshQR(z83< z$wWy!k9i~KuOfpMtg`d@z?#ga*KI*nEHFSpWdsi z@*2H*Yr-(tE>c3-X{(t^oQDI`*cxtuV@Di`mOkw-$KW09xOJ!uYdaYGkY`DO%-Jvf zN6EJ+;dVU^w;VCp0i4FYO*!Z58?j@)RVaM From 052d126d0579ce0e0b4f21b53b4cecd4154c1d02 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 4 Jul 2018 13:13:42 +0300 Subject: [PATCH 170/179] workaround isFile for Shared (#482) --- src/app/common/directives/node-versions.directive.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/common/directives/node-versions.directive.ts b/src/app/common/directives/node-versions.directive.ts index cb8ff2c22c..55c862ef23 100644 --- a/src/app/common/directives/node-versions.directive.ts +++ b/src/app/common/directives/node-versions.directive.ts @@ -68,7 +68,8 @@ export class NodeVersionsDirective { } openVersionManagerDialog(node: MinimalNodeEntryEntity) { - if (node.isFile) { + // workaround Shared + if (node.isFile || node.nodeId) { this.dialog.open(NodeVersionsDialogComponent, { data: { node }, panelClass: 'adf-version-manager-dialog-panel', From 2d7a0b9a7d7c756dd34e75caa9c6a103172e1b4b Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 4 Jul 2018 14:22:33 +0300 Subject: [PATCH 171/179] [ACA-1519] Action menu - ripple effect renders outside constrains --- src/app/components/sidenav/sidenav.component.html | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/components/sidenav/sidenav.component.html b/src/app/components/sidenav/sidenav.component.html index 00648da12e..65dbccf6e3 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -20,7 +20,6 @@ Date: Wed, 4 Jul 2018 14:53:35 +0100 Subject: [PATCH 173/179] Update README.md (#487) --- README.md | 55 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a3a56594aa..44911403c7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Alfresco Example Content Application

- Alfresco + Alfresco - make business flow

## Introduction @@ -9,29 +9,50 @@ The Alfresco Content Application is an example application built using [Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli). +The Alfresco Content Application is an example application built using [Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli). + ### Who is this example application for -This example application demonstrates to Angular software engineers -how to construct a content application using the Alfresco ADF. +This example application demonstrates how to construct an application for Alfresco Content Services using the Alfresco ADF and represents a meaningful composition of ADF components that provide end users with a simple easy to use interface for working with files in the content repository. -This example application represents a meaningful composition of ADF components that provide end users -with a simple and easy to use interface for working with files stored in the Alfresco Content Services repository. +### Where to get help +There are a number of resources available to help get you started with the Content App and the ADF: +* [Content App Documentation](https://alfresco.github.io/alfresco-content-app/) +* [Alfresco ADF Documentation](https://alfresco.github.io/adf-component-catalog/) +* [Alfresco Community](https://community.alfresco.com/) +* [ADF Gitter Channel](https://gitter.im/Alfresco/alfresco-ng2-components) -[Public documentation](https://alfresco.github.io/alfresco-content-app/) +To get help on Angular CLI use ng help or read the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). ### Raising issues and feature requests +Isuses can be raised in GitHub or in the Alfresco JIRA project. +Please include a clear description, steps to reproduce and screenshots where appropriate.All issues will be reviewed; bugs will be categorized if reproducible and enhancement/feature suggestions will be considered against existing priorities if the use case serves a general-purpose need. + +#### High level features planned for Q3 2018 (July - September) +* Library Management - create, find, join and manage file libraries. +* Commenting - View and add comments to files and folders +* Sharing Files - activate and deactivate shared file both manually and automatically. +* Permissions - update file and folder permissions. +* Application Extensibility - Extension framework to provide simple ways to extend the application. + +### Want to help? +Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our guidelines for [contributing](https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md) and then check out one of our issues in the [Jira](https://issues.alfresco.com/jira/projects/ACA) or [GitHub](https://github.com/Alfresco/alfresco-content-app/issues) + +## Available Features +| Feature | Description | +|------------------|----------------------------------------------------------------| +| Document List | Folder/File browsing of Personal Files, and File Libraries | +| Shared Files | Lists all files that have shared. | +| Recent Files | List files created and/or modified by the logged users within the last 30 days| +| Favorites | Lists all favorited files for the user. | +| Trash | Lists all deleted items stored in the trash can, users can restore or permanently remove. Admin user will see items deleted by all users.| +| Upload | Files and folders can be uploaded through the New button or by dragging and dropping into the browser.| +| Search | Quick search with live results, and full faceted search results page.| +| Actions | A number of actions can be performed on files and/or folders, either individually or multiples at a time| +| Viewer | Viewing files in natively in the browser, unsupported formats are transformed by the repository | +| Metadata | The information drawer can be configured in the app.config.json to display metadata information, by default file the Properties Aspect is shown and images will also include EXIF information.| +| Versioning | The version manager provides access and management of previous file versions, and the ability to upload new versions.| -Log any issues in the ['ACA' JIRA project](https://issues.alfresco.com/jira/projects/ACA), -please include a clear description, steps to reproduce and screenshots where appropriate. - -All issues will be reviewed; bugs will be categorized if reproducible and enhancement/feature suggestions -will be considered against existing priorities if the use case serves a general-purpose need. - -## Want to help? - -Want to file a bug, contribute some code, or improve documentation? Excellent! -Read up on our guidelines for [contributing][contributing] -and then check out one of our issues in the [Jira][jira] or [GitHub][github] ## Development server From dd318335c71a14a5f1a7482cd2e256387919834e Mon Sep 17 00:00:00 2001 From: john-knowles <18680913+john-knowles@users.noreply.github.com> Date: Wed, 4 Jul 2018 15:47:57 +0100 Subject: [PATCH 174/179] Update README.md (#488) --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 44911403c7..3e40b7360b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,7 @@ +

Alfresco - make business flow

+ # Alfresco Example Content Application -

- Alfresco - make business flow -

- ## Introduction The Alfresco Content Application is an example application built using From c3b4a352be7e56b4e1d08e1489959b034c5d49f2 Mon Sep 17 00:00:00 2001 From: john-knowles <18680913+john-knowles@users.noreply.github.com> Date: Wed, 4 Jul 2018 16:24:16 +0100 Subject: [PATCH 175/179] Update README.md (#489) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e40b7360b..eb3b307c56 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

Alfresco - make business flow

+

Alfresco - make business flow

# Alfresco Example Content Application @@ -7,7 +7,7 @@ The Alfresco Content Application is an example application built using [Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli). -The Alfresco Content Application is an example application built using [Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli). +This project is an example application built using [Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli). ### Who is this example application for From 7c66750edc7d634b5f5202a95125fcb2f343d6b8 Mon Sep 17 00:00:00 2001 From: john-knowles <18680913+john-knowles@users.noreply.github.com> Date: Wed, 4 Jul 2018 16:28:28 +0100 Subject: [PATCH 176/179] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index eb3b307c56..35743a0f9b 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,9 @@ The Alfresco Content Application is an example application built using [Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli). -This project is an example application built using [Alfresco Application Development Framework (ADF)](https://github.com/Alfresco/alfresco-ng2-components) components and was generated with [Angular CLI](https://github.com/angular/angular-cli). - ### Who is this example application for -This example application demonstrates how to construct an application for Alfresco Content Services using the Alfresco ADF and represents a meaningful composition of ADF components that provide end users with a simple easy to use interface for working with files in the content repository. +This project demonstrates how to construct an application for Alfresco Content Services using the Alfresco ADF and it represents a meaningful composition of ADF components that provide end users with a simple easy to use interface for working with files in the content repository. ### Where to get help There are a number of resources available to help get you started with the Content App and the ADF: From cdfcccff3c59fce976d63a14dc38930f74e35c8b Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Wed, 4 Jul 2018 18:49:32 +0300 Subject: [PATCH 177/179] [ACA-1523] Shared - file version manager (#486) * workaround shared isFile * revert commented --- src/app/components/shared-files/shared-files.component.html | 4 ++-- src/app/store/reducers/app.reducer.ts | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/app/components/shared-files/shared-files.component.html b/src/app/components/shared-files/shared-files.component.html index 29c92d2e18..8e74cdcf2c 100644 --- a/src/app/components/shared-files/shared-files.component.html +++ b/src/app/components/shared-files/shared-files.component.html @@ -80,8 +80,8 @@ diff --git a/src/app/store/reducers/app.reducer.ts b/src/app/store/reducers/app.reducer.ts index 30c8f83ba1..38d559e253 100644 --- a/src/app/store/reducers/app.reducer.ts +++ b/src/app/store/reducers/app.reducer.ts @@ -152,7 +152,10 @@ function updateSelectedNodes( last = nodes[nodes.length - 1]; if (nodes.length === 1) { - file = nodes.find(entity => entity.entry.isFile); + file = nodes.find(entity => { + // workaround Shared + return entity.entry.isFile || entity.entry.nodeId; + }); folder = nodes.find(entity => entity.entry.isFolder); } } From 29f4b64ccc8618810c62edc115197f044a95e1d3 Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Wed, 4 Jul 2018 19:00:03 +0300 Subject: [PATCH 178/179] [ACA-1521] set upload version tooltip text (#485) --- src/assets/i18n/de.json | 7 +++++++ src/assets/i18n/en.json | 7 +++++++ src/assets/i18n/es.json | 7 +++++++ src/assets/i18n/fr.json | 7 +++++++ src/assets/i18n/it.json | 14 +++++++++++++- src/assets/i18n/ja.json | 7 +++++++ src/assets/i18n/nb.json | 7 +++++++ src/assets/i18n/nl.json | 7 +++++++ src/assets/i18n/pt-BR.json | 7 +++++++ src/assets/i18n/ru.json | 7 +++++++ src/assets/i18n/zh-CN.json | 7 +++++++ 11 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 7cccedc505..35f234fdeb 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "Details anzeigen" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "Neue Version hochladen" + } + } } } diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 248a75c117..189470c163 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "View details" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "Upload new version" + } + } } } diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json index 3d959998da..1552320c61 100644 --- a/src/assets/i18n/es.json +++ b/src/assets/i18n/es.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "Ver los detalles" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "Cargar nueva versión" + } + } } } diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index cf2244d19f..17a776dac7 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "Afficher les détails" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "Importer une nouvelle version" + } + } } } diff --git a/src/assets/i18n/it.json b/src/assets/i18n/it.json index fcf26c05fd..c77b64fd0e 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -283,5 +283,17 @@ "CANCEL": "Ignora modifiche" } } + }, + "ADF_VIEWER": { + "ACTIONS": { + "INFO": "Visualizza dettagli" + } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "Utilizza nuova versione" + } + } } -} \ No newline at end of file +} diff --git a/src/assets/i18n/ja.json b/src/assets/i18n/ja.json index 7dafcaa1f3..fff2ce9516 100644 --- a/src/assets/i18n/ja.json +++ b/src/assets/i18n/ja.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "詳細の表示" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "新しいバージョンのアップロード" + } + } } } diff --git a/src/assets/i18n/nb.json b/src/assets/i18n/nb.json index 70d5772e15..a212ebcb4b 100644 --- a/src/assets/i18n/nb.json +++ b/src/assets/i18n/nb.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "Visningsdetaljer" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "Last opp ny versjon" + } + } } } diff --git a/src/assets/i18n/nl.json b/src/assets/i18n/nl.json index 19127db2f8..2cee0f8941 100644 --- a/src/assets/i18n/nl.json +++ b/src/assets/i18n/nl.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "Details weergeven" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "Nieuwe versie uploaden" + } + } } } diff --git a/src/assets/i18n/pt-BR.json b/src/assets/i18n/pt-BR.json index 408b93c083..1b760c7637 100644 --- a/src/assets/i18n/pt-BR.json +++ b/src/assets/i18n/pt-BR.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "Exibir detalhes" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "Carregar nova versão" + } + } } } diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index 675d0198e8..3da7094e1b 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "Подробно" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "Отправить новую версию" + } + } } } diff --git a/src/assets/i18n/zh-CN.json b/src/assets/i18n/zh-CN.json index 7e4e88fb41..4645a3e43d 100644 --- a/src/assets/i18n/zh-CN.json +++ b/src/assets/i18n/zh-CN.json @@ -288,5 +288,12 @@ "ACTIONS": { "INFO": "查看详细信息" } + }, + "ADF_VERSION_LIST": { + "ACTIONS": { + "UPLOAD": { + "TOOLTIP": "上传新版本" + } + } } } From eb40e523a853d226de57c4465bfa99cbddc109af Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 4 Jul 2018 17:22:09 +0100 Subject: [PATCH 179/179] add safety checks for folders --- src/app/components/info-drawer/info-drawer.component.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/app/components/info-drawer/info-drawer.component.ts b/src/app/components/info-drawer/info-drawer.component.ts index c6df10aa01..d3ff5cfe58 100644 --- a/src/app/components/info-drawer/info-drawer.component.ts +++ b/src/app/components/info-drawer/info-drawer.component.ts @@ -84,12 +84,15 @@ export class InfoDrawerComponent implements OnChanges { } } - private hasAspectNames(entry: MinimalNodeEntryEntity) { + private hasAspectNames(entry: MinimalNodeEntryEntity): boolean { return entry.aspectNames && entry.aspectNames.includes('exif:exif'); } - private isTypeImage(entry) { - return entry.content.mimeType.includes('image/'); + private isTypeImage(entry: MinimalNodeEntryEntity): boolean { + if (entry && entry.content && entry.content.mimeType) { + return entry.content.mimeType.includes('image/'); + } + return false; } private loadNodeInfo(nodeId: string) {