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 11e39bebb..f97f4facd 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 000000000..134287c0c --- /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 000000000..604be941d --- /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 000000000..1bf8de816 --- /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 000000000..696746e63 --- /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 000000000..ef151d54d --- /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 000000000..b5e840080 --- /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 000000000..5b6a306a8 --- /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 000000000..ba6796a8c --- /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 000000000..47a07dd85 --- /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 000000000..53d4baf84 --- /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 000000000..6847a306d --- /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 000000000..7b939d120 --- /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 000000000..7bfbcfba0 --- /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 000000000..3ac50a40d --- /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 000000000..d5eab3de1 --- /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 000000000..87fcf6981 --- /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 000000000..b78cb0443 --- /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 000000000..b2dce1d52 --- /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 000000000..196228230 --- /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 000000000..d3b4024d8 --- /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 000000000..c401680ae --- /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 000000000..137dcfe3f --- /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 000000000..f6f79cf09 --- /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 000000000..1025feefd --- /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 000000000..c6f379407 --- /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 000000000..56c67ac1d --- /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 000000000..61e20a22c --- /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 000000000..2409444d4 --- /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 000000000..7789d4366 --- /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 000000000..07197ca50 --- /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 000000000..3ab8cdfab --- /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 000000000..dfb79669a --- /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 000000000..dd9ea40cd --- /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 000000000..3cd8ae546 --- /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 000000000..3f6567ddd --- /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 000000000..9b637babb --- /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 000000000..88bdd95de --- /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 000000000..0902c7c70 --- /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 000000000..b8168d3c0 --- /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 000000000..43e12985b --- /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 000000000..8af8827bf --- /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 000000000..419950ed3 --- /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 000000000..531fc36d2 --- /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 000000000..2244be6e8 --- /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 000000000..beb580638 --- /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 000000000..bf3baa066 --- /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 000000000..ae0b47511 --- /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 000000000..35452d2c3 --- /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 000000000..3e92d7838 --- /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 000000000..d82201ab2 --- /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 000000000..65915d480 --- /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 000000000..bde0a2a11 --- /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 000000000..93be7980c --- /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 000000000..2ede55982 --- /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 000000000..ee61ce6df --- /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 000000000..bb09fabd4 --- /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 000000000..6140dcd74 --- /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 000000000..598aad900 --- /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 000000000..a824893ba --- /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 000000000..0f94d5ee6 --- /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 000000000..a352eb882 --- /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 000000000..e3ffc0107 --- /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 000000000..756bfb4a8 --- /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 000000000..2f92e394a --- /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 000000000..6b5098d40 --- /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 000000000..49b724a9b --- /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 000000000..901d8f5a4 --- /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 f998d1fae..3696d78d4 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 331c14da8..770480b5e 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 9a1a1b39c..3971e2d2c --- 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 | 1421 ++++++++------------------------------------- 1 file changed, 254 insertions(+), 1167 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3696d78d4..c804b491a 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,91 +3971,25 @@ "optional": true, "requires": { "delegates": "1.0.0", - "readable-stream": "2.2.9" + "readable-stream": "2.3.6" } }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "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", + "brace-expansion": { + "version": "1.1.11", "bundled": true, "dev": true, - "optional": true + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } }, - "co": { - "version": "4.6.0", + "chownr": { + "version": "1.0.1", "bundled": true, "dev": true, "optional": true @@ -4351,14 +3999,6 @@ "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, @@ -4372,35 +4012,11 @@ "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 - } - } + "optional": true }, "debug": { - "version": "2.6.8", + "version": "2.6.9", "bundled": true, "dev": true, "optional": true, @@ -4414,11 +4030,6 @@ "dev": true, "optional": true }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "delegates": { "version": "1.0.0", "bundled": true, @@ -4426,74 +4037,25 @@ "optional": true }, "detect-libc": { - "version": "1.0.2", + "version": "1.0.3", "bundled": true, "dev": true, "optional": true }, - "ecc-jsbn": { - "version": "0.1.1", + "fs-minipass": { + "version": "1.2.5", "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", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "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", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", + "iconv-lite": { + "version": "0.4.21", "bundled": true, "dev": true, "optional": true, "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" + "safer-buffer": "2.1.2" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "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,104 +4140,18 @@ "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", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "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", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, "minimatch": { "version": "3.0.4", "bundled": true, "dev": true, "requires": { - "brace-expansion": "1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -4728,6 +4159,24 @@ "bundled": true, "dev": true }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.1.1", + "yallist": "3.0.2" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "2.2.4" + } + }, "mkdirp": { "version": "0.5.1", "bundled": true, @@ -4742,23 +4191,33 @@ "dev": true, "optional": true }, - "node-pre-gyp": { - "version": "0.6.39", + "needle": { + "version": "2.2.0", "bundled": true, "dev": true, "optional": true, "requires": { - "detect-libc": "1.0.2", - "hawk": "3.1.3", + "debug": "2.6.9", + "iconv-lite": "0.4.21", + "sax": "1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.9.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "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", - "bundled": true, - "dev": 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", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", + "version": "2.3.6", "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" + "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" } }, "rimraf": { - "version": "2.6.1", + "version": "2.6.2", "bundled": true, "dev": true, + "optional": true, "requires": { "glob": "7.1.2" } }, "safe-buffer": { - "version": "5.0.1", + "version": "5.1.1", "bundled": true, "dev": true }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": 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", + "version": "4.4.1", "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" + "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" } }, - "tough-cookie": { - "version": "2.3.2", - "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" - } - }, - "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 c804b491a..ec86141a3 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 770480b5e..f42ee6cc8 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 e5c288aca..7fb3f30b5 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 8b54addb1..19c57a87a 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 27c2380e7..0fd10629e 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 d3f9b478e..8d0e088ed 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 | 138 ++++++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/src/app.config.json b/src/app.config.json index 6db201ac8..111986f78 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,20 +212,28 @@ } }, { - "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": "contentSizeRange", + "name": "Content Size (range)", + "enabled": true, + "component": { + "selector": "number-range", + "settings": { + "field": "cm:content.size" } } }, @@ -238,34 +241,29 @@ "id": "queryType", "name": "Type", "enabled": true, - "expanded": false, "component": { - "selector": "adf-search-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": "queryLocations", - "name": "Locations", - "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 ec86141a3..b5c4353bb 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 f42ee6cc8..5b57b0b4a 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 61e20a22c..0cea2b68b 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 c0235eaab..48d0b390f 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 c0235eaab..8d75501a2 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 0cea2b68b..0ae7ad4f7 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 0e3fb2b06..144b4545c 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 bef30d031..077b30a37 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 012911596..40bf2a131 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 000000000..e9319ec4a --- /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 000000000..3a53f3e3f --- /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 b2dce1d52..570b40c00 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 c401680ae..bb0bf1564 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 2409444d4..a780644bc 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 b8168d3c0..b81fc56a9 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 3e92d7838..e2de4f8c4 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 901d8f5a4..92da973bf 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 e32cd3c9a..0d26ead0c 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 91c61268e..4256ebc5f 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 05cce99df..16ad941af 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 dc76f3ab8..758eb24e9 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 d2a6f4275..b905e6675 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 c063e2e80..5b9784615 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 754b1a7df..0ecd2ea1e 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 e69699849..cb2ac5b15 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 812e687ec..d3fab7451 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 f08ffd5d8..e5246daaa 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 68b6cab5f..8a3958b7a 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 8d16d8a67..2b83ad19c 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 abd6f2b71..75f4af345 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 f822e1b82..169e114c1 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 19c57a87a..8bce8ff2d 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 0fd10629e..54dca3a63 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 585cec05b..236345b5f 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 18aa9a7db..77255f50a 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 a6705935f..87bcbd565 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 8c4371f8f..6a1030df8 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 109c57a0f..2e32e80c0 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 b6e591b2b..34eed5a45 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 7f29dd9c0..5ccd54108 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 | 172 +++++++----------- 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, 114 insertions(+), 297 deletions(-) diff --git a/src/app/components/favorites/favorites.component.html b/src/app/components/favorites/favorites.component.html index 8bce8ff2d..3378d3ed6 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 04c960c0b..edefece61 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,10 +138,36 @@ describe('FilesComponent', () => { pagination: {} } }; + + spyOn(component.documentList, 'loadFolder').and.callFake(() => {}); + }); + + 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.throw(null)); + + component.ngOnInit(); + fixture.detectChanges(); + tick(); + + expect(component.isValidPath).toBe(false); + })); + + 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.isValidPath).toBe(true); + })); }); describe('OnInit', () => { - it('set current node', () => { + it('should set current node', () => { spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page)); @@ -150,13 +176,13 @@ describe('FilesComponent', () => { expect(component.node).toBe(node); }); - it('get current node children', () => { + 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.paging).toBe(page); + expect(component.fetchNodes).toHaveBeenCalled(); }); it('emits onChangeParent event', () => { @@ -170,25 +196,6 @@ describe('FilesComponent', () => { .toHaveBeenCalledWith(node); }); - it('raise error when fetchNode() fails', () => { - spyOn(component, 'fetchNode').and.returnValue(Observable.throw(null)); - spyOn(component, 'onFetchError'); - - fixture.detectChanges(); - - expect(component.onFetchError).toHaveBeenCalled(); - }); - - it('raise error when fetchNodes() fails', () => { - spyOn(component, 'fetchNode').and.returnValue(Observable.of(node)); - spyOn(component, 'fetchNodes').and.returnValue(Observable.throw(null)); - spyOn(component, 'onFetchError'); - - fixture.detectChanges(); - - expect(component.onFetchError).toHaveBeenCalled(); - }); - it('if should navigate to parent if node is not a folder', () => { node.isFolder = false; node.parentId = 'parent-id'; @@ -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 8eab1d700..86018017b 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 aed07e6e6..60c279828 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 0b1f78e95..7b1539f02 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 2c66c376b..2cc52f67e 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 77255f50a..1d993701b 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 43846d3a4..94f837fa8 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 | 175 ++++++++++-------- .../components/search/search.component.html | 10 +- src/app/components/search/search.component.ts | 2 +- 6 files changed, 107 insertions(+), 118 deletions(-) diff --git a/e2e/suites/actions/toolbar-single-selection.test.ts b/e2e/suites/actions/toolbar-single-selection.test.ts index 0ae7ad4f7..5c9dc25ae 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 b5c4353bb..951991325 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 5b57b0b4a..337b83f09 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 111986f78..0378eb081 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" - } - } - }, - { - "id": "contentSize", - "name": "Content Size", - "enabled": true, - "component": { - "selector": "slider", - "settings": { - "field": "cm:content.size", - "min": 0, - "max": 18, - "step": 1, - "thumbLabel": true - } - } - }, - { - "id": "contentSizeRange", - "name": "Content Size (range)", - "enabled": true, - "component": { - "selector": "number-range", - "settings": { - "field": "cm:content.size" - } - } - }, - { - "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'" - } - ] - } + "categories": [ + { + "id": "queryName", + "name": "Name", + "enabled": true, + "expanded": true, + "component": { + "selector": "text", + "settings": { + "pattern": "cm:name:'(.*?)'", + "field": "cm:name", + "placeholder": "Enter the name" } } - ] - } + }, + { + "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": "contentSize", + "name": "Content Size", + "enabled": true, + "component": { + "selector": "slider", + "settings": { + "field": "cm:content.size", + "min": 0, + "max": 18, + "step": 1, + "thumbLabel": true + } + } + }, + { + "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 18aa4ac04..a132eba67 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 645668776..87ce6f898 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 8c17e443a..f28690446 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 b905e6675..000000000 --- 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 f36f78535..7e85ca804 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 0378eb081..26f08d7ae 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 b23521bf6..d6aa3fc8c 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 18f006a8a..fe4f9a2df 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 c0e24091e..76aa0f722 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 951991325..5f3b0873b 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 337b83f09..0097673c1 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 26f08d7ae..f12cd56e8 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 b5d8072e6..89f484547 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 b8e549685..000000000 --- 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 010468714..000000000 --- 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 96302e8aa..9deea7cda 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 53d4baf84..3c14615b6 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 7fb3f30b5..2dc6c0af3 100644 --- a/src/app/components/sidenav/sidenav.component.html +++ b/src/app/components/sidenav/sidenav.component.html @@ -1,64 +1,53 @@
-
- - {{ 'APP.NEW_MENU.LABEL' | translate }} - arrow_drop_down - + + - - - - - - - - - - - + + +
+
diff --git a/src/app/components/sidenav/sidenav.component.scss b/src/app/components/sidenav/sidenav.component.scss index 724a6ee3f..48df44e8f 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 8941378c3..9ec93afae 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 89f484547..c179506b5 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 000000000..35dc19ae3 --- /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 e3dbbfd00..896211be3 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 3378d3ed6..8ef804c29 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 60c279828..160cebc8e 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 1d993701b..32b0db5f2 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 7e85ca804..fe10ad64a 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 2f36d7f77..c762a0afa 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 19c6925b4..073bec5bd 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 7b1539f02..5d0c6dfa3 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 2cc52f67e..48e102130 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 9d88c729c..980803be4 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 62f681d2c..deab9387f 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 a62b3e4f2..2d2dfe455 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 fe10ad64a..063e55b3c 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 980803be4..06f5c8529 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 144b4545c..035ee9939 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 1bf8de816..2939adebe 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 5f3b0873b..0f7b89dfc 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 0097673c1..f6e62794b 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 f12cd56e8..7fe0ce871 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 439960187..c08f4cb1e 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 f28690446..6738d4bff 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 46470d69a..000000000 --- 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 43ecf6bf8..000000000 --- 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 2da90ab1c..000000000 --- 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 32e4d5571..000000000 --- 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 4e137d1de..000000000 --- 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 c09577a5d..37679d231 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 13f571a1d..0dd725591 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 195bcf44f..8107da7fd 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 edefece61..063e0499e 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 160cebc8e..3a11a4767 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 a04008200..ec4a7d74b 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 d6aa3fc8c..e5a80250b 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 06f5c8529..e20c81d00 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 deab9387f..f8b1af991 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 063e55b3c..9bbf5a8de 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 6a1030df8..8bcc22091 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 c762a0afa..f475d16f1 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 df6b8a078..1e9dfa7bf 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 c179506b5..e4ac8ee9a 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 3d8305f0a..000000000 --- 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 94f837fa8..55e9d2293 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 0f7b89dfc..df7be44db 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 f6e62794b..7660f963a 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 48d0b390f..000000000 --- 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 423c40099..3ce9f8c7b 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 40bf2a131..720c0b1de 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 8d75501a2..000000000 --- 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 b6153d718..752b41053 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 e9319ec4a..000000000 --- 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 3a53f3e3f..000000000 --- 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 df7be44db..8dcd5cc65 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 7660f963a..a94d76c2d 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 c08f4cb1e..61548951c 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 6738d4bff..519b51d76 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 2dc6c0af3..174af8aa7 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 07e53b2fc..4d48dbca5 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 84fe64749..385c96df6 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 000000000..6c92d4cfb --- /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 000000000..da18d9352 --- /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 000000000..19ec8d487 --- /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 000000000..fd170fba6 --- /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 000000000..c1f5a772e --- /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 000000000..69c55b9d7 --- /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 8dcd5cc65..8ac296b96 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 a94d76c2d..e437da399 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 7fe0ce871..0fb00c0e6 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 958362bc2..090d002c0 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 166179c45..0424abf35 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 07f3fa06e..1800a8ddc 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 f97f4facd..7da6fc0ce 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 e437da399..be7e9ff6e 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 688fda628..faccdb503 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 c5d885dad..e2df279f2 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 be7e9ff6e..ef8c23ba5 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 519b51d76..f12f94d52 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 3a098acb5..eb6089c30 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 000000000..9aa53e017 --- /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 000000000..89c2e8cb7 --- /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 000000000..ad87b6492 --- /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 000000000..f0087bb06 --- /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 8d0e088ed..0316a4f36 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 077b30a37..8c32532fa 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 7da6fc0ce..f97f4facd 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 000000000..9e9b86be0 --- /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 f6f79cf09..cc861d022 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 5c9dc25ae..5404e4062 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 3ab8cdfab..e17028248 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 419950ed3..974c62df7 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 756bfb4a8..76d6683e5 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 2f92e394a..ad08110be 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 8ac296b96..f6cd03857 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 ef8c23ba5..a2d3de4e2 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 758eb24e9..291cced24 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 2b83ad19c..dfd480126 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 2942e578e..c3037f4a3 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 974c62df7..2f11df8d2 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 f6cd03857..719988861 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 a2d3de4e2..336b364e7 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 61548951c..e1f84dca9 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 eb6089c30..cc06445f2 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 86018017b..ba3774b40 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 6c92d4cfb..000000000 --- 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 719988861..3c1181338 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 336b364e7..59ba23688 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 0fb00c0e6..35f4f8723 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 a132eba67..6dd4e7397 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 a650b0c02..3367d7d1d 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 87ce6f898..7fca7073a 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 f12f94d52..4ff689b40 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 090d002c0..754195e4c 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 0424abf35..f89274906 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 1800a8ddc..4f1cf43bc 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 000000000..513073faa --- /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 e64871faf..ad9e7e81d 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 236345b5f..ef8420396 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 e4ac8ee9a..0d28f2cd2 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 9cd3784d1..d84615b8f 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 fc9a7cc62..000000000 --- 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 37679d231..d8369726a 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 8107da7fd..439f6ca0f 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 1e033fe0a..867174369 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 c32d91cfc..468d3f63d 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 e20c81d00..83102ad7f 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 9bbf5a8de..15c563421 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 174af8aa7..87708b9db 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 8c32532fa..309640f2d 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 | 31 ++++++----- .../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, 80 insertions(+), 92 deletions(-) diff --git a/src/app/common/directives/node-copy.directive.ts b/src/app/common/directives/node-copy.directive.ts index 4256ebc5f..29911cba4 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 291cced24..bce80a8c9 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 d3fab7451..d2d6a91a0 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 => { + { success: succeeded, failed: failures, partially: partiallySucceeded} + ); - this.notification.openSnackMessageAction( - messages[successMessage] - + beforePartialSuccessMessage + messages[partialSuccessMessage] - + beforeFailedMessage + messages[failedMessage], - undo, - NodeActionsService[`SNACK_MESSAGE_DURATION${withUndo}`] - ) - .onAction() - .subscribe(() => this.revertMoving(moveResponse, initialParentId)); - }); + // 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 e5246daaa..755f632b4 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 a9aa7f90a..501976ae1 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 8a3958b7a..9a7c55708 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 dfd480126..cb0ff38b3 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 169e114c1..93c209f35 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 da18d9352..000000000 --- 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 19ec8d487..000000000 --- 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 fd170fba6..000000000 --- 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 c1f5a772e..000000000 --- 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 69c55b9d7..000000000 --- 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 9e9b86be0..9789a3c84 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 4d46e20e3..944545eca 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 bba3d1050..2799ebc8f 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 e1f84dca9..f2846ea89 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 cef4d50fc..8776393e8 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 d17090b6c..c389a6072 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 22227f806..7b5e7bf88 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 67d8d1f92..83e302e6b 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 d7de9b902..5c50a342f 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 220c7e91c..bf9642628 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 7c7e57ca4..9973f0ef2 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 139ecda59..66347206e 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 000000000..99468992f --- /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 000000000..df3b064f8 --- /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 9031c518d..0083aefba 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 28ed0f3ce..fc2e0db7f 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 0d66e02ba..a34c0215d 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 2543ec889..fc38e6fce 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 edcd1b126..b2dfce3d2 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(); + } + + // 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; + } + } + + showPreview(node: MinimalNodeEntity) { + if (node && node.entry) { + if (node.entry.isFile) { + this.router.navigate(['./preview', node.entry.id], { relativeTo: this.route }); + } + } } getParentNodeId(): string { return this.node ? this.node.id : null; } - hasSelection(selection: Array): boolean { - return selection && selection.length > 0; - } - - isFileSelected(selection: Array): boolean { - if (selection && selection.length === 1) { - const entry = selection[0].entry; - - if (entry && entry.isFile) { - return true; - } - } - return false; - } - - isFolderSelected(selection: Array): boolean { - if (selection && selection.length === 1) { - const entry = selection[0].entry; - - if (entry && entry.isFolder) { - return true; - } - } - return false; - } - 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 ef8420396..666879f6e 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 635316fa9..3019f1b10 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 323a5b231..c89aa944b 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 c771a410c..f74895f80 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 15beb27c8..41c8c843e 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 730702330..ab1c3a15a 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 f6c7cc5a4..e23806878 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 4d48dbca5..73df9f2fb 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 12775a851..e792b078f 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 7ba36264a..d646e10e1 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 542a1dec0..37ccdbf5b 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 000000000..1e0646fd5 --- /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 48fa50df3..d12eae6ea 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 52e6a81f3..d49588766 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 75fcd165d..370e2c78e 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 34eed5a45..b43b9774e 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 0fb20094c..476d72c49 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 869777686..988f46999 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 5404e4062..3d163eb3b 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 720c0b1de..a05cc0891 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 bb0bf1564..f3a7b4c2f 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 ff5d8ffcd..1d5c6a9f2 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 3971e2d2c..6b6fbb0d4 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 6b8551dab..367eb31c4 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 76829abc0..ceb989c3e 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 1d5c6a9f2..5175f4685 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 5d7e66bea..990035274 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 990035274..6a50e9448 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 ba77cd66d..e4a41e09b 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 fc38e6fce..f46fe3966 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 b2dfce3d2..296c4a478 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 c964cc175..a868fd498 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 a717626db..4bd05d037 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 3d163eb3b..5404e4062 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 4bd05d037..56c39453b 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 cad70b4eb..2ed6862e9 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 7b5e7bf88..806666799 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 e2083f774..5754f7f65 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 e4a41e09b..126c867ff 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 bf9642628..9b05e2b0b 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 b1cd8e1ec..0e1b4e583 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 78a9afbbf..61efe7c6b 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 f8c7e150e..1bc2bd754 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 1a84f6b50..554a22f2c 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 c89aa944b..c74b89c87 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 32a5a1038..0e2670e89 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 ab1c3a15a..1ebf9755d 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 eb3ea2074..47f9af629 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 87708b9db..e42cb40be 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 0e1b4e583..bb25fe00c 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 61efe7c6b..4bcb4fd30 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 1bc2bd754..73f0fdc39 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 554a22f2c..e989fa993 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 c74b89c87..43e11c588 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 0e2670e89..9d8999f6e 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 1ebf9755d..e5de30198 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 47f9af629..efc889853 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 988f46999..2dcbe46ec 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 99468992f..f6f75fe03 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 d1ca1b18c..2d892668d 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 b0a14c365..e6893912e 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 45d8be7e5..938e1d8d0 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 2dcbe46ec..0a29509db 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 334a01080..bc9b56cc3 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 638f9230b..9ce4be5ac 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 77d6a8ddf..88f025232 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 6ef40663a..b91bd6ce1 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 806666799..c6529cf93 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 000000000..e061a03de --- /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 000000000..727f85e8b --- /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 000000000..09dbd495b --- /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 b0774cbd4..a4943d35f 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 000000000..c1a723c3a --- /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 938e1d8d0..4c6ab1665 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 4fe5b50a7..461c404ff 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 c1ce61c98..0a6b0020c 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 35dc19ae3..000000000 --- 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 896211be3..000000000 --- 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 000000000..b245c1b02 --- /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 9a8c46193..b2fa28225 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 000000000..8ee04c650 --- /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 4c6ab1665..4d2e0347a 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 38936fdac..9a127c429 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 570b40c00..f4d334342 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 f4d334342..570b40c00 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 | 195 ++++++++++++------ 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, 365 insertions(+), 77 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 a4943d35f..711a02d83 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 bb25fe00c..3bba704b3 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 4d2e0347a..de16027fb 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 9a127c429..fdb6c4b82 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 000000000..53a790404 --- /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 e76bd7bc5..4d7cb313a 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 859f4918c..5bedc85af 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 000000000..224c9afef --- /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 b5d761cda..08adb84cd 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 49c7ee484..e94d6c13a 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 de16027fb..3116bca57 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 53a790404..ea2d61dc7 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 acadd47de..831fd7c98 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 6e5d684cd..000000000 --- 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 000000000..71be08396 --- /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 8bcad5897..0c55d3f13 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 25054d318..02fdf15ec 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 461c404ff..e04d525ab 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 0a6b0020c..8e8ed6479 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 cdec99c34..000000000 --- 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 737b54ecd..000000000 --- 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 76d9a1382..000000000 --- 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 afafe9d43..000000000 --- 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 000000000..95691ef0b --- /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 000000000..47060f65b --- /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 000000000..06b2490e6 --- /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 000000000..1b232ee3e --- /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 000000000..ad5d4d35d --- /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 dc198a35d..a64d7c9ef 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 | 31 ++++++------- .../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, 123 insertions(+), 194 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 711a02d83..7cea82e7a 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 c6529cf93..9edb6f295 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 5754f7f65..7870c6984 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 126c867ff..41ebb77cd 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 9b05e2b0b..a39ad52bd 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 3bba704b3..beabc58fa 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(); - - } else if (node.isFile) { - this.router.navigate(['./preview', node.id], { relativeTo: this.route }); - } + if (isFolder) { + this.navigate(id); + return; } + 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 098ac4ceb..74cfc73df 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 f46fe3966..680eee69b 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 4bcb4fd30..9a4af15c6 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 e989fa993..1d140d3a0 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 a868fd498..70eb1765e 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 43e11c588..235ab5b29 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 9d8999f6e..cb5244acb 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 3116bca57..f4029e9a4 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 fdb6c4b82..c982e6cb7 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 974bbd3a0..7cce92bfd 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 e5de30198..db7fa5f2f 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 efc889853..b2cf92a82 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 5fa4648f6..a97d316c1 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 4d7cb313a..6503d085c 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 000000000..e5c70d6e6 --- /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 000000000..a74bc6f8c --- /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 2d892668d..f37d847a3 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 01065f775..de837ebb5 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 640ed4ac6..62d7101c9 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 e6893912e..31ed8d222 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 f4029e9a4..44f8bc4d5 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 c982e6cb7..0b5a415af 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 0b5a415af..7d798e290 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 476d72c49..3497e0e6f 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 7cea82e7a..b4d5658e0 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 000000000..7384e3a68 --- /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 000000000..39b45278b --- /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 000000000..6753b4a65 --- /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 a64d7c9ef..1cf93f11f 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 44f8bc4d5..614de260e 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 0a29509db..7e39669eb 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 7384e3a68..aeaeb0c4b 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 6753b4a65..0d18534d5 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 7e39669eb..32b256490 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 b4d5658e0..953f374b6 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 e94d6c13a..d3b4103b8 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 9a4af15c6..38cbc8f93 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 c1874f01d..000000000 --- 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 9be059419..000000000 --- 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 3a6e0e667..000000000 --- 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 000000000..4a0dc8e72 --- /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 000000000..ab3ec908b --- /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 000000000..4a96bccf6 --- /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 cbc694c2a..2ae594719 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 8e8ed6479..1f9535842 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 7cdfbeb92..7cf3146e6 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 7d798e290..ae3308bb3 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 3497e0e6f..b0828ea99 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 38cbc8f93..a81857959 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 32b256490..cec609fb1 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 e42cb40be..e68803396 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 b301ce7bc..000000000 --- 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 000000000..6a22fa665 --- /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 b91bd6ce1..996646cf5 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 41ebb77cd..e24f683c7 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 1525e9ba3..ac7157b63 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 a3b5b67f1..000000000 --- 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 000000000..bbf0735e9 --- /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 abfbf9a6d..dfae6b91e 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 c389a6072..2a4668d66 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 1ef205891..000000000 --- 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 000000000..8b56a4224 --- /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 2c121e61a..6ad498bb3 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 754195e4c..52c37d768 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 1cf93f11f..0277f76ce 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 1d140d3a0..cd603cd73 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 f37d847a3..95fd9b69d 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 513e16531..000000000 --- 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 000000000..ead9a266d --- /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 31ed8d222..71b90270d 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 ad87b6492..000000000 --- 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 000000000..11de98a19 --- /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 f0087bb06..27507dd1a 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 4a96bccf6..e99e07d38 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 ad9e7e81d..000000000 --- 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 02fdf15ec..000000000 --- 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 e04d525ab..70891f13f 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 1f9535842..f99eea249 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 000000000..bb38d0e07 --- /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 000000000..f83b1b64e --- /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 cec609fb1..c7b97ea31 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 b43b9774e..12d8eaf91 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 0277f76ce..b72c25fae 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 62d7101c9..82de63b77 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 71b90270d..860d87d5e 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 ce672a6a3..8773b5514 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 11e24413a..d3cec5741 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 457b28ef4..2e3faa760 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 000000000..5d3632bb6 --- /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 7000b3537..6c547ee28 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 463ac1680..c4f6826e8 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 566d65db5..e0f66c4b3 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 000000000..0d5dd150f --- /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 e061a03de..4768a150e 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 ab3ec908b..dbb69e9fc 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 891235405..a6c71fa4e 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 e24f683c7..446090a0d 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 680eee69b..ee65afb82 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 a81857959..3bb25af10 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,35 +65,24 @@ 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$.next(true); 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; - } - } - showPreview(node: MinimalNodeEntity) { if (node && node.entry) { const { id, nodeId, name, isFile, isFolder } = node.entry; @@ -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 666879f6e..8a19b3151 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 70eb1765e..18ce84406 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 614de260e..d1af64136 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 7cce92bfd..451525317 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 3e0c7d956..c6b1de7e3 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 daff5aeb9..19b1d3f3e 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 068e5ee26..5d7a7cc64 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 3de91e926..c10145d21 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 000000000..9db206192 --- /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 e68803396..97a6211a0 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 000000000..cb1dd538d --- /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 000000000..496cb1d5b --- /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 95fd9b69d..3b2ba7f96 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 860d87d5e..ad8455fcc 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 8773b5514..dca6a02c4 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 4aaf70d36..436e6b991 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 880fa9e42..19638586c 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 2d87d408c..c9e6c692e 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 f6f75fe03..985ebec34 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 8a19b3151..4807b59a9 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 4a0dc8e72..829ea13b1 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 d7536f5e4..0d3efbeef 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 000000000..1743d1a70 --- /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 436e6b991..c883e33a8 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 19638586c..50abdc70e 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 0d3efbeef..2a7127cb7 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 a6c71fa4e..9959a67e3 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 29ea2e326..3d4a7912d 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 446090a0d..56515fd14 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 beabc58fa..ea0cc7152 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 21021940c..c78715378 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 74cfc73df..19e5a2430 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 ee65afb82..d44f5a257 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 3bb25af10..765612193 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 cd603cd73..dd66d74e6 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 18ce84406..67f5fea8c 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 cb5244acb..f9581e608 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 d1af64136..4e46297d9 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 451525317..33a296a85 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 b2cf92a82..535f8948f 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 711dc36f5..6d081f8d6 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 4f817b463..b914eeab9 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 000000000..d0bcddae2 --- /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 000000000..94155d892 --- /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 8fe4709b7..000000000 --- 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 8af8827bf..df378e765 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 2a7127cb7..d3b59831a 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 595fe7654..0a4b610a0 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 000000000..ec169d83d --- /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 c2eeef62e..17d9c756d 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 88f025232..000000000 --- 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 996646cf5..014207cc5 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 6d081f8d6..b9a6700d1 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 b914eeab9..f754cf3f4 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 d3cec5741..cb5ff1eee 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 000000000..447bf6c39 --- /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 19b1d3f3e..03e736edc 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 5d7a7cc64..c5ce779e0 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 c10145d21..46848f894 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 000000000..2113d51c9 --- /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 d3b59831a..d7fe07e74 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 9aa53e017..000000000 --- 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 4e46297d9..2818a94b2 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 aeaeb0c4b..154a8f24b 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 e81f5cdb1..ac09ad06b 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 ea0cc7152..1f03ce723 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 c9e6c692e..01f23c221 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 d7fe07e74..a5cbd78fc 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 000000000..1370a7136 --- /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 d8bc2b3fe..c34e999e2 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 5404e4062..d97d7f65b 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 01f23c221..5aa7fd007 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 8773f583a..e5e4c1c74 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 e1c47d5f7..032b8231b 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 c78715378..133da22a2 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 fe9e624c5..583722211 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 19e5a2430..125b9c984 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 cb5ff1eee..013545cb3 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 000000000..d2fad4aef --- /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 6c547ee28..2fff5f17b 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 c4f6826e8..3c773fee2 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 000000000..71e07894b --- /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 0b15b0b78..51afdae0c 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 c34e999e2..c65451ac0 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 17d9c756d..46858be8c 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 014207cc5..2f10576f6 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[] = []; +export class CurrentUserComponent { + profile$: Observable; + languagePicker$: Observable; - user: ProfileState; - - constructor(private store: Store) {} - - ngOnInit() { - this.subscriptions = this.subscriptions.concat([ - this.store.select(selectUser).subscribe((user) => this.user = user) - ]); - } - - 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 7b800f8fd..c73a019f5 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 2fff5f17b..ecf31fd66 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 03e736edc..f8d234372 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 c5ce779e0..8fe15c58c 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 000000000..7309f63a5 --- /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 46848f894..e63212685 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 2818a94b2..dca4e21e7 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 5aa7fd007..56759d248 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 89c2e8cb7..c17358f9e 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 27507dd1a..e2ff08280 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 1370a7136..3546f8c50 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 51afdae0c..c9f2ee408 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 1f03ce723..4a961245d 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 c883e33a8..00a4513df 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 50abdc70e..5df9bc7ee 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 00a4513df..8bbe78c5d 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 5df9bc7ee..688d016f7 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 | 54 +++++++------------ src/app/material.module.ts | 14 ++++- src/app/testing/app-testing.module.ts | 3 +- 10 files changed, 45 insertions(+), 116 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8bbe78c5d..9f93b9d75 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 688d016f7..3bdac297f 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 c65451ac0..74d5e6aa4 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 a5cbd78fc..80542533f 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 97a6211a0..00648da12 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 84cfa138a..47725c12d 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 0df82e90a..b667661a7 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 b50695abc..441a3af0a 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); - - component.documentList = { - reload: jasmine.createSpy('reload'), - resetSelection: jasmine.createSpy('resetSelection') - }; }); - })); + + fixture = TestBed.createComponent(TrashcanComponent); + component = fixture.componentInstance; + + 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 1743d1a70..c0c3e2032 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 4768a150e..71be7cb26 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 | 47 ++++------- .../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 | 47 ++++------- .../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, 223 insertions(+), 543 deletions(-) diff --git a/src/app/common/directives/node-copy.directive.spec.ts b/src/app/common/directives/node-copy.directive.spec.ts index 0d26ead0c..0be679d6c 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 15de3820c..6a1c3f866 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 342abe7ed..32e3404af 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 2c7914f69..e95cca93c 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 db10f1329..66f6ad5d5 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)); - - dialog = TestBed.get(MatDialog); }); - })); - beforeEach(() => { + alfrescoApiService = TestBed.get(AlfrescoApiService); + alfrescoApiService.reset(); + actions$ = TestBed.get(Actions); + + 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 403e28254..d657ff883 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 9edb6f295..cdc54ccbc 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 a39ad52bd..226a17007 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 2728e3a54..f2a3f88ec 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 f89274906..8a6e3a351 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 583722211..d2e1dfa7a 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 3c5583b93..7db3e5a82 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); - location = TestBed.get(Location); - auth = TestBed.get(AuthenticationService); - userPreference = TestBed.get(UserPreferencesService); - })); - - beforeEach(() => { - spyOn(userPreference, 'setStoragePrefix'); spyOn(router, 'navigateByUrl'); - spyOn(auth, 'getRedirect').and.returnValue('/some-url'); + + location = TestBed.get(Location); spyOn(location, 'forward'); + + auth = TestBed.get(AuthenticationService); + spyOn(auth, 'getRedirect').and.returnValue('/some-url'); + + userPreference = TestBed.get(UserPreferencesService); + spyOn(userPreference, 'setStoragePrefix'); }); describe('OnInit()', () => { diff --git a/src/app/components/preview/preview.component.spec.ts b/src/app/components/preview/preview.component.spec.ts index 73f0fdc39..1d650a938 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 235ab5b29..1f7865044 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 db7fa5f2f..4cd743077 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 47725c12d..b237127e5 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 441a3af0a..111b3a632 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 71be7cb26..09d14c24d 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 09dbd495b..1d6b30312 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 | 33 ++- 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, 551 insertions(+), 392 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 80542533f..f5f07237d 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 0be679d6c..e9d115b15 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 308403c3b..461b79382 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 6a1c3f866..a9087766b 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 32e3404af..fc9cb7af5 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 e95cca93c..a9b60669b 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 66f6ad5d5..efde1230f 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 d657ff883..620c22ec9 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 e5e4c1c74..ddacb0b28 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 75f4af345..19fdedfa7 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 d3b4103b8..cb8ff2c22 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 032b8231b..0d9e7284a 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 c3037f4a3..9902a7ce3 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 68e52b0df..1d49bf082 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 ec169d83d..85508f005 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) { } +export class ProfileResolver implements Resolve { + constructor( + private store: Store, + private contentApi: ContentApiService + ) {} - 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)); + 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 ba1e413f5..dfb666c47 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 0c55d3f13..3f4c0ae23 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 cdc54ccbc..ae27594cd 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 3d4a7912d..98336e2e7 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 226a17007..88868b150 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 4a961245d..726c47567 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 bc9b56cc3..708e8a068 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 d2e1dfa7a..fe340e282 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 125b9c984..201bcec1f 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 b72c25fae..ed23e74de 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 1d650a938..e4c466510 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 dd66d74e6..81bbdfdb3 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 33a296a85..5d8fae5f7 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 535f8948f..01058f99b 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 000000000..a5ecff227 --- /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 447bf6c39..a128e1511 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 20bea20e0..72a6d1dbb 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 71e07894b..a8df0f9bb 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 b48f4ea63..c0adad2a3 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 f8d234372..30c8f83ba 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 09d14c24d..0ad459064 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 56759d248..6af1d00f2 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 c9f2ee408..7715a62e9 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 9f93b9d75..3b4b0c45c 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 3bdac297f..82279b7d7 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 fa4065e22..e3544b6cb 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 3b4b0c45c..1908ac6df 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 82279b7d7..57f7d6965 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 4ef43ef9c..13db9bdf2 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 ead9a266d..8be93e791 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 ad8455fcc..2285cf376 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 dca4e21e7..e6a189838 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 2ba9bb18c..6a201a3b1 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 c438a2454..895885ff9 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 e3544b6cb..a3a56594a 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 472b78e36..aadb637d1 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 0d486c479..000000000 --- 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 258ddb488..000000000 --- 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 6ea79e47a..000000000 --- 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 e3e243347..000000000 --- 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 86d5ce13d..000000000 --- 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 68d192eb7..000000000 --- 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 39de383ac..000000000 --- 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 9ce7d5107..000000000 --- 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 000000000..e31a9c828 --- /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 cf77f6c99..000000000 --- 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 f547b977e..54652ee0f 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 52d700fef..000000000 --- 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 d9acb344e..1ea7e81e3 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 6d22172cc..000000000 --- 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 4a283a272..000000000 --- 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 98ac4258d..000000000 --- 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 c291c84a8..000000000 --- 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 6af1d00f2..01436f1bf 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 aadb637d1..a05ced97a 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 3f4c0ae23..3b5cb988f 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 67007ecce..0673d0896 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 cb8ff2c22..55c862ef2 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 00648da12..65dbccf6e 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 | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a3a56594a..44911403c 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. -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. +#### 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. -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](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) -## Want to help? +## 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.| -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 44911403c..3e40b7360 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 3e40b7360..eb3b307c5 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 eb3b307c5..35743a0f9 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 29c92d2e1..8e74cdcf2 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 30c8f83ba..38d559e25 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 7cccedc50..35f234fde 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 248a75c11..189470c16 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 3d959998d..1552320c6 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 cf2244d19..17a776dac 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 fcf26c05f..c77b64fd0 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 7dafcaa1f..fff2ce951 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 70d5772e1..a212ebcb4 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 19127db2f..2cee0f894 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 408b93c08..1b760c763 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 675d0198e..3da7094e1 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 7e4e88fb4..4645a3e43 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 c6df10aa0..d3ff5cfe5 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) {