Merge pull request #45 from Alfresco/development

Sync with latest development branch
This commit is contained in:
Cilibiu Bogdan
2017-11-10 12:15:32 +02:00
committed by GitHub
41 changed files with 603 additions and 1251 deletions
+7
View File
@@ -0,0 +1,7 @@
FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf
WORKDIR /usr/share/nginx/html
COPY dist/ .
+8
View File
@@ -0,0 +1,8 @@
version: '3.1'
services:
app:
image: 'alfresco/content-app'
build: '.'
ports:
- 3000:80
+1 -1
View File
@@ -19,7 +19,7 @@ import { by, ElementFinder, promise } from 'protractor';
import { Component } from '../component';
export class LoginComponent extends Component {
static selector = 'alfresco-login';
static selector = 'adf-login';
private locators = {
usernameInput: by.css('input#username'),
+4 -1
View File
@@ -40,7 +40,10 @@ export class LoginPage extends Page {
const { submitButton } = this.login;
const hasSumbitButton = EC.presenceOf(submitButton);
return browser.wait(hasSumbitButton, BROWSER_WAIT_TIMEOUT);
return browser.wait(hasSumbitButton, BROWSER_WAIT_TIMEOUT)
.then(() => browser.executeScript('window.localStorage.clear();'))
.then(() => browser.executeScript('window.sessionStorage.clear();'))
.then(() => browser.driver.manage().deleteAllCookies());
});
}
+1 -1
View File
@@ -22,7 +22,7 @@ import { APP_ROUTES } from '../configs';
export class LogoutPage extends Page {
/** @override */
constructor() {
super(APP_ROUTES.LOGOUT);
super(APP_ROUTES.LOGIN);
}
/** @override */
+1 -1
View File
@@ -18,7 +18,7 @@
import { browser, element, by, ElementFinder, promise } from 'protractor';
export abstract class Page {
private static USE_HASH_STRATEGY = true;
private static USE_HASH_STRATEGY = false;
private locators = {
app: by.css('app-root'),
+161 -134
View File
@@ -17,21 +17,24 @@
import { protractor, browser, by, ElementFinder } from 'protractor';
import { APP_ROUTES, BROWSER_WAIT_TIMEOUT } from '../../configs';
import { APP_ROUTES, BROWSER_WAIT_TIMEOUT, SITE_VISIBILITY, SITE_ROLES } from '../../configs';
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-folder-dialog';
import { LocalStorageUtility } from '../../utilities/local-storage';
import { Utils } from '../../utilities/utils';
import { RepoClient, NodeContentTree } from '../../utilities/repo-client/repo-client';
describe('Create folder', () => {
const username = 'jane.doe';
const password = 'jane.doe';
const parent = 'parent-folder';
const folderName1 = 'my-folder1';
const folderName2 = 'my-folder2';
const folderDescription = 'description of my folder';
const duplicateFolderName = 'duplicate-folder-name';
const nameWithSpaces = ' folder name ';
const nameWithSpaces = ' folder-name ';
const siteName = 'site-private';
const apis = {
admin: new RepoClient(),
@@ -55,7 +58,10 @@ describe('Create folder', () => {
beforeAll(done => {
apis.admin.people.createUser(username, password)
.then(() => apis.user.nodes.createFolders([ duplicateFolderName ]))
.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.load())
.then(() => loginPage.loginWith(username, password))
.then(done);
@@ -74,80 +80,84 @@ describe('Create folder', () => {
afterAll(done => {
Promise
.all([
apis.user.nodes.deleteNodes([
folderName1,
folderName2,
duplicateFolderName,
nameWithSpaces.trim()
]),
apis.user.nodes.deleteNodes([ parent ]),
logoutPage.load()
.then(() => LocalStorageUtility.clear())
.then(() => Utils.clearLocalStorage())
])
.then(done);
});
it('option is enabled when having enough permissions', () => {
personalFilesPage.sidenav.openNewMenu()
.then((menu) => {
const isEnabled = menu.getItemByLabel('Create folder').getWebElement().isEnabled();
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => personalFilesPage.sidenav.openNewMenu()
.then((menu) => {
const isEnabled = menu.getItemByLabel('Create folder').getWebElement().isEnabled();
expect(isEnabled).toBe(true, 'Create folder is not enabled');
});
expect(isEnabled).toBe(true, 'Create folder is not enabled');
})
);
});
it('creates new folder with name', () => {
openCreateDialog()
.then(() => createDialog.enterName(folderName1).clickCreate())
.then(() => createDialog.waitForDialogToClose())
.then(() => dataTable.waitForHeader())
.then(() => {
const isPresent = dataTable.getRowByContainingText(folderName1).isPresent();
expect(isPresent).toBe(true, 'Folder not displayed in list view');
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog()
.then(() => createDialog.enterName(folderName1).clickCreate())
.then(() => createDialog.waitForDialogToClose())
.then(() => dataTable.waitForHeader())
.then(() => {
const isPresent = dataTable.getRowByContainingText(folderName1).isPresent();
expect(isPresent).toBe(true, 'Folder not displayed in list view');
})
);
});
it('creates new folder with name and description', () => {
openCreateDialog()
.then(() => {
createDialog
.enterName(folderName2)
.enterDescription(folderDescription)
.clickCreate();
})
.then(() => createDialog.waitForDialogToClose())
.then(() => dataTable.waitForHeader())
.then(() => {
const isPresent = dataTable.getRowByContainingText(folderName2).isPresent();
expect(isPresent).toBe(true, 'Folder not displayed in list view');
})
.then(() => {
apis.user.nodes.getNodeDescription(folderName2)
.then((description) => {
expect(description).toEqual(folderDescription, 'Description is not correct');
});
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog()
.then(() => {
createDialog
.enterName(folderName2)
.enterDescription(folderDescription)
.clickCreate();
})
.then(() => createDialog.waitForDialogToClose())
.then(() => dataTable.waitForHeader())
.then(() => {
const isPresent = dataTable.getRowByContainingText(folderName2).isPresent();
expect(isPresent).toBe(true, 'Folder not displayed in list view');
})
.then(() => {
apis.user.nodes.getNodeDescription(folderName2)
.then((description) => {
expect(description).toEqual(folderDescription, 'Description is not correct');
});
})
);
});
it('enabled option tooltip', () => {
personalFilesPage.sidenav.openNewMenu()
.then(menu => {
const action = browser.actions().mouseMove(menu.getItemByLabel('Create folder'));
action.perform();
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => personalFilesPage.sidenav.openNewMenu()
.then(menu => {
const action = browser.actions().mouseMove(menu.getItemByLabel('Create folder'));
action.perform();
return menu;
})
.then((menu) => {
const tooltip = menu.getItemTooltip('Create folder');
expect(tooltip).toContain('Create new folder');
});
return menu;
})
.then((menu) => {
const tooltip = menu.getItemTooltip('Create folder');
expect(tooltip).toContain('Create new folder');
})
);
});
it('option is disabled when not enough permissions', () => {
// refactor after implementing Breadcrumb automation component
const breadcrumbRoot: ElementFinder = protractor.element(by.css('.adf-breadcrumb-item[title="User Homes"]'));
const fileLibrariesPage = new BrowsingPage(APP_ROUTES.FILE_LIBRARIES);
browser.actions().mouseMove(breadcrumbRoot).click().perform()
.then(() => personalFilesPage.sidenav.openNewMenu())
fileLibrariesPage.sidenav.navigateToLinkByLabel('File Libraries')
.then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(siteName))
.then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(folderName1))
.then(() => fileLibrariesPage.sidenav.openNewMenu())
.then(menu => {
const isEnabled = menu.getItemByLabel('Create folder').getWebElement().isEnabled();
expect(isEnabled).toBe(false, 'Create folder is not disabled');
@@ -155,11 +165,12 @@ describe('Create folder', () => {
});
it('disabled option tooltip', () => {
// refactor after implementing Breadcrumb automation component
const breadcrumbRoot: ElementFinder = protractor.element(by.css('.adf-breadcrumb-item[title="User Homes"]'));
const fileLibrariesPage = new BrowsingPage(APP_ROUTES.FILE_LIBRARIES);
browser.actions().mouseMove(breadcrumbRoot).click().perform()
.then(() => personalFilesPage.sidenav.openNewMenu())
fileLibrariesPage.sidenav.navigateToLinkByLabel('File Libraries')
.then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(siteName))
.then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(folderName1))
.then(() => fileLibrariesPage.sidenav.openNewMenu())
.then(menu => {
const action = browser.actions().mouseMove(menu.getItemByLabel('Create folder'));
action.perform()
@@ -171,107 +182,123 @@ describe('Create folder', () => {
});
it('dialog UI elements', () => {
openCreateDialog().then(() => {
const dialogTitle = createDialog.getTitle();
const isFolderNameDisplayed = createDialog.nameInput.getWebElement().isDisplayed();
const isDescriptionDisplayed = createDialog.descriptionTextArea.getWebElement().isDisplayed();
const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled();
const isCancelEnabled = createDialog.cancelButton.getWebElement().isEnabled();
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog().then(() => {
const dialogTitle = createDialog.getTitle();
const isFolderNameDisplayed = createDialog.nameInput.getWebElement().isDisplayed();
const isDescriptionDisplayed = createDialog.descriptionTextArea.getWebElement().isDisplayed();
const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled();
const isCancelEnabled = createDialog.cancelButton.getWebElement().isEnabled();
expect(dialogTitle).toBe('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');
});
expect(dialogTitle).toBe('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', () => {
openCreateDialog()
.then(() => {
createDialog.deleteNameWithBackspace();
})
.then(() => {
const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled();
const validationMessage = createDialog.getValidationMessage();
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog()
.then(() => {
createDialog.deleteNameWithBackspace();
})
.then(() => {
const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled();
const validationMessage = createDialog.getValidationMessage();
expect(isCreateEnabled).toBe(false, 'Create button is enabled');
expect(validationMessage).toMatch('Folder name is required');
});
expect(isCreateEnabled).toBe(false, 'Create button is enabled');
expect(validationMessage).toMatch('Folder name is required');
})
);
});
it('with folder name ending with a dot "."', () => {
openCreateDialog()
.then(() => createDialog.enterName('folder-name.'))
.then((dialog) => {
const isCreateEnabled = dialog.createButton.getWebElement().isEnabled();
const validationMessage = dialog.getValidationMessage();
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog()
.then(() => createDialog.enterName('folder-name.'))
.then((dialog) => {
const isCreateEnabled = dialog.createButton.getWebElement().isEnabled();
const validationMessage = dialog.getValidationMessage();
expect(isCreateEnabled).toBe(false, 'Create button is not disabled');
expect(validationMessage).toMatch(`Folder name can't end with a period .`);
});
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', 'a<a', 'a>a', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a' ];
openCreateDialog()
.then(() => {
namesWithSpecialChars.forEach(name => {
createDialog.enterName(name);
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog()
.then(() => {
namesWithSpecialChars.forEach(name => {
createDialog.enterName(name);
const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled();
const validationMessage = createDialog.getValidationMessage();
const isCreateEnabled = createDialog.createButton.getWebElement().isEnabled();
const validationMessage = createDialog.getValidationMessage();
expect(isCreateEnabled).toBe(false, 'Create button is not disabled');
expect(validationMessage).toContain(`Folder name can't contain these characters`);
});
});
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', () => {
openCreateDialog()
.then(() => createDialog.enterName(' '))
.then((dialog) => {
const isCreateEnabled = dialog.createButton.getWebElement().isEnabled();
const validationMessage = dialog.getValidationMessage();
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog()
.then(() => createDialog.enterName(' '))
.then((dialog) => {
const isCreateEnabled = dialog.createButton.getWebElement().isEnabled();
const validationMessage = dialog.getValidationMessage();
expect(isCreateEnabled).toBe(false, 'Create button is not disabled');
expect(validationMessage).toMatch(`Folder name can't contain only spaces`);
});
expect(isCreateEnabled).toBe(false, 'Create button is not disabled');
expect(validationMessage).toMatch(`Folder name can't contain only spaces`);
})
);
});
it('cancel folder creation', () => {
openCreateDialog()
.then(() => {
createDialog
.enterName('test')
.enterDescription('test description')
.clickCancel();
})
.then(() => expect(createDialog.component.isPresent()).not.toBe(true, 'dialog is not closed'));
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog()
.then(() => {
createDialog
.enterName('test')
.enterDescription('test description')
.clickCancel();
})
.then(() => expect(createDialog.component.isPresent()).not.toBe(true, 'dialog is not closed'))
);
});
it('duplicate folder name', () => {
openCreateDialog()
.then(() => createDialog.enterName(duplicateFolderName).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');
});
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog()
.then(() => createDialog.enterName(duplicateFolderName).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', () => {
openCreateDialog()
.then(() => createDialog.enterName(nameWithSpaces).clickCreate())
.then(() => createDialog.waitForDialogToClose())
.then(() => dataTable.waitForHeader())
.then(() => {
const isPresent = dataTable.getRowByContainingText(nameWithSpaces.trim()).isPresent();
expect(isPresent).toBe(true, 'Folder not displayed in list view');
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => openCreateDialog()
.then(() => createDialog.enterName(nameWithSpaces).clickCreate())
.then(() => createDialog.waitForDialogToClose())
.then(() => dataTable.waitForHeader())
.then(() => {
const isPresent = dataTable.getRowByContainingText(nameWithSpaces.trim()).isPresent();
expect(isPresent).toBe(true, 'Folder not displayed in list view');
})
);
});
});
+112 -91
View File
@@ -20,12 +20,13 @@ import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
import { APP_ROUTES, SITE_VISIBILITY, SITE_ROLES } from '../../configs';
import { RepoClient } from '../../utilities/repo-client/repo-client';
import { CreateOrEditFolderDialog } from '../../components/dialog/create-edit-folder-dialog';
import { LocalStorageUtility } from '../../utilities/local-storage';
import { Utils } from '../../utilities/utils';
describe('Edit folder', () => {
const username = 'jane.doe';
const password = 'jane.doe';
const username = 'john.doe';
const password = 'john.doe';
const parent = 'parent-folder';
const folderName = 'my-folder';
const folderDescription = 'my folder description';
@@ -44,7 +45,7 @@ describe('Edit folder', () => {
const loginPage = new LoginPage();
const logoutPage = new LogoutPage();
const personalFilesPage = new BrowsingPage();
const personalFilesPage = new BrowsingPage(APP_ROUTES.PERSONAL_FILES);
const editDialog = new CreateOrEditFolderDialog();
const dataTable = personalFilesPage.dataTable;
const editButton = personalFilesPage.toolbar.actions.getButtonByTitleAttribute('Edit');
@@ -58,11 +59,11 @@ describe('Edit folder', () => {
])
.then(() => apis.admin.sites.addSiteMember(siteName, username, SITE_ROLES.SITE_CONSUMER))
.then(() => Promise.all([
apis.user.nodes.createNodeWithProperties( folderName, '', folderDescription ),
apis.user.nodes.createFolders([ folderNameToEdit, duplicateFolderName ]),
apis.user.nodes.createNodeWithProperties( folderName, '', folderDescription, parent ),
apis.user.nodes.createFolders([ folderNameToEdit, duplicateFolderName ], parent),
loginPage.load()
]))
.then(() => { loginPage.loginWith(username, password); })
.then(() => loginPage.loginWith(username, password))
.then(done);
});
@@ -80,57 +81,63 @@ describe('Edit folder', () => {
Promise
.all([
apis.admin.sites.deleteSite(siteName, true),
apis.user.nodes.deleteNodes([ folderName, folderNameEdited, duplicateFolderName ]),
apis.user.nodes.deleteNodes([ parent ]),
logoutPage.load()
.then(() => LocalStorageUtility.clear())
.then(() => Utils.clearLocalStorage())
])
.then(done);
});
it('button is enabled when having permissions', () => {
dataTable.clickOnRowByContainingText(folderName)
.then(() => {
expect(editButton.isEnabled()).toBe(true);
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => dataTable.clickOnRowByContainingText(folderName)
.then(() => {
expect(editButton.isEnabled()).toBe(true);
})
);
});
it('dialog UI defaults', () => {
dataTable.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => {
expect(editDialog.getTitle()).toBe('Edit folder');
expect(editDialog.nameInput.getWebElement().getAttribute('value')).toBe(folderName);
expect(editDialog.descriptionTextArea.getWebElement().getAttribute('value')).toBe(folderDescription);
expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(true, 'upload button is not enabled');
expect(editDialog.cancelButton.getWebElement().isEnabled()).toBe(true, 'cancel button is not enabled');
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => dataTable.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => {
expect(editDialog.getTitle()).toBe('Edit folder');
expect(editDialog.nameInput.getWebElement().getAttribute('value')).toBe(folderName);
expect(editDialog.descriptionTextArea.getWebElement().getAttribute('value')).toBe(folderDescription);
expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(true, 'upload button is not enabled');
expect(editDialog.cancelButton.getWebElement().isEnabled()).toBe(true, 'cancel button is not enabled');
})
);
});
it('folder properties are modified when pressing OK', () => {
dataTable.clickOnRowByContainingText(folderNameToEdit)
.then(() => editButton.click())
.then(() => {
editDialog
.enterName(folderNameEdited)
.enterDescription(folderDescriptionEdited)
.clickUpdate();
})
.then(() => editDialog.waitForDialogToClose())
.then(() => dataTable.waitForHeader())
.then(() => {
const isPresent = dataTable.getRowByContainingText(folderNameEdited).isPresent();
expect(isPresent).toBe(true, 'Folder not displayed in list view');
})
.then(() => {
apis.user.nodes.getNodeDescription(folderNameEdited)
.then((description) => {
expect(description).toEqual(folderDescriptionEdited);
});
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => dataTable.clickOnRowByContainingText(folderNameToEdit)
.then(() => editButton.click())
.then(() => {
editDialog
.enterName(folderNameEdited)
.enterDescription(folderDescriptionEdited)
.clickUpdate();
})
.then(() => editDialog.waitForDialogToClose())
.then(() => dataTable.waitForHeader())
.then(() => {
const isPresent = dataTable.getRowByContainingText(folderNameEdited).isPresent();
expect(isPresent).toBe(true, 'Folder not displayed in list view');
})
.then(() => {
apis.user.nodes.getNodeDescription(folderNameEdited)
.then((description) => {
expect(description).toEqual(folderDescriptionEdited);
});
})
);
});
it('button is not displayed when not enough permissions', () => {
const fileLibrariesPage = new BrowsingPage();
const fileLibrariesPage = new BrowsingPage(APP_ROUTES.FILE_LIBRARIES);
fileLibrariesPage.sidenav.navigateToLinkByLabel('File Libraries')
.then(() => fileLibrariesPage.dataTable.doubleClickOnRowByContainingText(siteName))
@@ -141,71 +148,85 @@ describe('Edit folder', () => {
});
it('with empty folder name', () => {
dataTable.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => {
editDialog.deleteNameWithBackspace();
})
.then(() => {
expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not enabled');
expect(editDialog.getValidationMessage()).toMatch('Folder name is required');
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => dataTable.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => {
editDialog.deleteNameWithBackspace();
})
.then(() => {
expect(editDialog.updateButton.getWebElement().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', 'a<a', 'a>a', `a\\a`, 'a/a', 'a?a', 'a:a', 'a|a' ];
dataTable.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => {
namesWithSpecialChars.forEach(name => {
editDialog.enterName(name);
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => dataTable.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => {
namesWithSpecialChars.forEach(name => {
editDialog.enterName(name);
expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not disabled');
expect(editDialog.getValidationMessage()).toContain(`Folder name can't contain these characters`);
});
});
expect(editDialog.updateButton.getWebElement().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.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => editDialog.nameInput.sendKeys('.'))
.then(() => {
expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not enabled');
expect(editDialog.getValidationMessage()).toMatch(`Folder name can't end with a period .`);
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => dataTable.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => editDialog.nameInput.sendKeys('.'))
.then(() => {
expect(editDialog.updateButton.getWebElement().isEnabled()).toBe(false, 'upload button is not enabled');
expect(editDialog.getValidationMessage()).toMatch(`Folder name can't end with a period .`);
})
);
});
it('Cancel button', () => {
dataTable.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => editDialog.clickCancel())
.then(() => { expect(editDialog.component.isPresent()).not.toBe(true, 'dialog is not closed'); });
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => dataTable.clickOnRowByContainingText(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.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => editDialog.enterName(duplicateFolderName).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');
});
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => dataTable.clickOnRowByContainingText(folderName)
.then(() => editButton.click())
.then(() => editDialog.enterName(duplicateFolderName).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.clickOnRowByContainingText(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.getRowByContainingText(folderName).isPresent()).toBe(true, 'Folder not displayed in list view');
});
personalFilesPage.dataTable.doubleClickOnRowByContainingText(parent)
.then(() => dataTable.clickOnRowByContainingText(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.getRowByContainingText(folderName).isPresent()).toBe(true, 'Folder not displayed in list view');
})
);
});
});
+2 -2
View File
@@ -19,7 +19,7 @@ import { browser } from 'protractor';
import { SIDEBAR_LABELS } from '../../configs';
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
import { LocalStorageUtility } from '../../utilities/local-storage';
import { Utils } from '../../utilities/utils';
describe('Page titles', () => {
const loginPage = new LoginPage();
@@ -65,7 +65,7 @@ describe('Page titles', () => {
afterAll(done => {
logoutPage.load()
.then(() => LocalStorageUtility.clear())
.then(() => Utils.clearLocalStorage())
.then(done);
});
+2 -2
View File
@@ -19,7 +19,7 @@ import { browser } from 'protractor';
import { APP_ROUTES } from '../../configs';
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
import { LocalStorageUtility } from '../../utilities/local-storage';
import { Utils } from '../../utilities/utils';
import { RepoClient } from '../../utilities/repo-client/repo-client';
describe('Login', () => {
@@ -63,7 +63,7 @@ describe('Login', () => {
afterEach(done => {
logoutPage.load()
.then(() => LocalStorageUtility.clear())
.then(() => Utils.clearLocalStorage())
.then(done);
});
+2 -2
View File
@@ -19,7 +19,7 @@ import { browser } from 'protractor';
import { APP_ROUTES, BROWSER_WAIT_TIMEOUT } from '../../configs';
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
import { LocalStorageUtility } from '../../utilities/local-storage';
import { Utils } from '../../utilities/utils';
import { RepoClient } from '../../utilities/repo-client/repo-client';
describe('Logout', () => {
@@ -48,7 +48,7 @@ describe('Logout', () => {
afterEach((done) => {
logoutPage.load()
.then(() => LocalStorageUtility.clear())
.then(() => Utils.clearLocalStorage())
.then(done);
});
+3 -3
View File
@@ -19,7 +19,7 @@ import { browser } from 'protractor';
import { APP_ROUTES } from '../../configs';
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
import { LocalStorageUtility } from '../../utilities/local-storage';
import { Utils } from '../../utilities/utils';
import { RepoClient, NodeContentTree } from '../../utilities/repo-client/repo-client';
describe('Personal Files', () => {
@@ -81,7 +81,7 @@ describe('Personal Files', () => {
afterAll(done => {
logoutPage.load()
.then(() => LocalStorageUtility.clear())
.then(() => Utils.clearLocalStorage())
.then(done);
});
@@ -109,7 +109,7 @@ describe('Personal Files', () => {
afterAll(done => {
logoutPage.load()
.then(() => LocalStorageUtility.clear())
.then(() => Utils.clearLocalStorage())
.then(done);
});
@@ -19,7 +19,7 @@ import { browser } from 'protractor';
import { APP_ROUTES, SIDEBAR_LABELS } from '../../configs';
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
import { LocalStorageUtility } from '../../utilities/local-storage';
import { Utils } from '../../utilities/utils';
describe('Side navigation', () => {
const loginPage = new LoginPage();
@@ -38,7 +38,7 @@ describe('Side navigation', () => {
afterAll(done => {
logoutPage.load()
.then(() => LocalStorageUtility.clear())
.then(() => Utils.clearLocalStorage())
.then(done);
});
+2 -2
View File
@@ -19,7 +19,7 @@ import { browser } from 'protractor';
import { APP_ROUTES } from '../../configs';
import { LoginPage, LogoutPage, BrowsingPage } from '../../pages/pages';
import { LocalStorageUtility } from '../../utilities/local-storage';
import { Utils } from '../../utilities/utils';
import { RepoClient, NodeContentTree } from '../../utilities/repo-client/repo-client';
describe('Pagination', () => {
@@ -75,7 +75,7 @@ describe('Pagination', () => {
afterAll(done => {
logoutPage
.load()
.then(() => LocalStorageUtility.clear())
.then(() => Utils.clearLocalStorage())
.then(() => nodesApi.deleteNodes([ content.name ]))
.then(done);
});
@@ -0,0 +1,60 @@
/*!
* @license
* Copyright 2017 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 { promise } from 'protractor';
import { RepoApi } from '../repo-api';
import { NodesApi } from '../nodes/nodes-api';
import { RepoClient } from './../../repo-client';
export class FavoritesApi extends RepoApi {
addFavorite(api: RepoClient, nodeType: string, name: string): Promise<any> {
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);
}
getFavorite(api: RepoClient, name: string): Promise<any> {
return api.nodes.getNodeByPath(name)
.then((response) => {
const { id } = response.data.entry;
return this.get(`/people/-me-/favorites/${id}`);
})
.catch((response) => Promise.resolve(response));
}
removeFavorite(api: RepoClient, nodeType: string, name: string): Promise<any> {
return api.nodes.getNodeByPath(name)
.then((response) => {
const { id } = response.data.entry;
return this.delete(`/people/-me-/favorites/${id}`);
})
.catch(this.handleError);
}
}
+2 -1
View File
@@ -20,12 +20,13 @@ 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';
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 favorites: FavoritesApi = new FavoritesApi(this.auth, this.config);
// public shared: SharedLinksApi = new SharedLinksApi(this.auth, this.config);
constructor(
@@ -17,18 +17,14 @@
import { browser, promise } from 'protractor';
declare var window;
export class LocalStorageUtility {
static clear(): promise.Promise<any> {
return browser.executeScript(() => {
return window.localStorage.clear();
});
export class Utils {
// generate a random value
static random(): string {
return Math.random().toString(36).substring(3, 10);
}
static getTicket(): promise.Promise<any> {
return browser.executeScript(() => {
return window.localStorage.getItem('ticket-ECM');
});
// local storage
static clearLocalStorage(): promise.Promise<any> {
return browser.executeScript('window.localStorage.clear();');
}
}
+25
View File
@@ -0,0 +1,25 @@
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
include /etc/nginx/mime.types;
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
location / {
try_files $uri $uri/ /index.html;
}
}
}
+18 -16
View File
@@ -6,6 +6,8 @@
"ng": "ng",
"start": "ng serve --open",
"build": "ng build",
"build:prod": "ng build --prod",
"build:dev": "ng build && node postbuild-dev.js",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
@@ -24,17 +26,17 @@
"@angular/platform-browser": "4.4.5",
"@angular/platform-browser-dynamic": "4.4.5",
"@angular/router": "4.4.5",
"@ngx-translate/core": "7.0.0",
"alfresco-js-api": "1.10.0-beta5",
"@ngx-translate/core": "8.0.0",
"alfresco-js-api": "1.10.0-beta6",
"core-js": "^2.4.1",
"hammerjs": "2.0.8",
"ng2-alfresco-core": "1.10.0-beta5",
"ng2-alfresco-datatable": "1.10.0-beta5",
"ng2-alfresco-documentlist": "1.10.0-beta5",
"ng2-alfresco-login": "1.10.0-beta5",
"ng2-alfresco-search": "1.10.0-beta5",
"ng2-alfresco-upload": "1.10.0-beta5",
"ng2-alfresco-viewer": "1.10.0-beta5",
"ng2-alfresco-core": "1.10.0-beta6",
"ng2-alfresco-datatable": "1.10.0-beta6",
"ng2-alfresco-documentlist": "1.10.0-beta6",
"ng2-alfresco-login": "1.10.0-beta6",
"ng2-alfresco-search": "1.10.0-beta6",
"ng2-alfresco-upload": "1.10.0-beta6",
"ng2-alfresco-viewer": "1.10.0-beta6",
"pdfjs-dist": "1.8.557",
"rxjs": "5.1.0",
"wsrv": "0.2.2",
@@ -44,14 +46,14 @@
"@angular/cli": "1.4.7",
"@angular/compiler-cli": "4.4.5",
"@angular/language-service": "4.4.5",
"@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2",
"@types/jasmine": "^2.5.53",
"@types/jasminewd2": "^2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "~3.2.0",
"jasmine-core": "~2.6.2",
"jasmine-reporters": "2.2.1",
"jasmine-spec-reporter": "~4.1.0",
"jasmine2-protractor-utils": "1.3.0",
"jasmine-core": "^2.6.2",
"jasmine-reporters": "^2.2.1",
"jasmine-spec-reporter": "^4.1.0",
"jasmine2-protractor-utils": "^1.3.0",
"karma": "~1.7.0",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
@@ -59,7 +61,7 @@
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"node-rest-client": "^3.1.0",
"protractor": "~5.1.2",
"protractor": "^5.1.2",
"ts-node": "~3.2.0",
"tslint": "~5.7.0",
"typescript": "~2.3.3"
+26
View File
@@ -0,0 +1,26 @@
/*!
* @license
* Copyright 2017 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.
*/
var fs = require('fs');
var config = require('./dist/app.config.json');
config.ecmHost = 'http://localhost:8080';
fs.writeFileSync(
'./dist/app.config.json',
JSON.stringify(config, null, 4)
);
+48 -43
View File
@@ -8,49 +8,54 @@ const jasmineReporters = require('jasmine-reporters');
const projectRoot = path.resolve(__dirname);
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.test.ts'
],
capabilities: {
'browserName': 'chrome',
chromeOptions: {
prefs: {
'credentials_enable_service': false
allScriptsTimeout: 11000,
specs: [
'./e2e/suites/authentication/*.test.ts',
'./e2e/suites/list-views/*.test.ts',
'./e2e/suites/application/page-titles.test.ts',
'./e2e/suites/navigation/side-navigation.test.ts',
'./e2e/suites/pagination/pagination.test.ts',
'./e2e/suites/actions/*.test.ts'
],
capabilities: {
'browserName': 'chrome',
chromeOptions: {
prefs: {
'credentials_enable_service': false
}
}
}
},
directConnect: true,
baseUrl: 'http://localhost:3000',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
plugins: [{
package: 'jasmine2-protractor-utils',
disableHTMLReport: false,
disableScreenshot: false,
screenshotOnExpectFailure: true,
screenshotOnSpecFailure: false,
clearFoldersBeforeTest: true,
htmlReportDir: `${projectRoot}/e2e-output/html-report/`,
screenshotPath: `${projectRoot}/e2e-output/screenshots/`
}],
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
},
directConnect: true,
baseUrl: 'http://localhost:3000',
framework: 'jasmine2',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
plugins: [{
package: 'jasmine2-protractor-utils',
disableHTMLReport: false,
disableScreenshot: false,
screenshotOnExpectFailure: true,
screenshotOnSpecFailure: false,
clearFoldersBeforeTest: true,
htmlReportDir: `${projectRoot}/e2e-output/html-report/`,
screenshotPath: `${projectRoot}/e2e-output/screenshots/`
}],
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
savePath: `${projectRoot}/e2e-output/junit-report`,
filePrefix: 'results.xml',
useDotNotation: false,
useFullTestName: false,
reportFailedUrl: true
}));
}
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
savePath: `${projectRoot}/e2e-output/junit-report`,
filePrefix: 'results.xml',
useDotNotation: false,
useFullTestName: false,
reportFailedUrl: true
}));
}
};
-1
View File
@@ -46,7 +46,6 @@ import { SidenavComponent } from './components/sidenav/sidenav.component';
imports: [
BrowserModule,
RouterModule.forRoot(APP_ROUTES, {
useHash: true,
enableTracing: false // enable for debug only
}),
AdfModule,
+1 -11
View File
@@ -23,10 +23,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AdfModule } from '../adf.module';
import { MaterialModule } from './material.module';
import { FolderDialogComponent } from './dialogs/folder-dialog.component';
import { FolderCreateDirective } from './directives/folder-create.directive';
import { FolderEditDirective } from './directives/folder-edit.directive';
import { NodeCopyDirective } from './directives/node-copy.directive';
import { NodeDeleteDirective } from './directives/node-delete.directive';
import { NodeMoveDirective } from './directives/node-move.directive';
@@ -51,10 +47,6 @@ export function modules() {
export function declarations() {
return [
FolderDialogComponent,
FolderCreateDirective,
FolderEditDirective,
NodeCopyDirective,
NodeDeleteDirective,
NodeMoveDirective,
@@ -77,9 +69,7 @@ export function providers() {
@NgModule({
imports: modules(),
declarations: declarations(),
entryComponents: [
FolderDialogComponent
],
entryComponents: [],
providers: providers(),
exports: [
...modules(),
@@ -1,62 +0,0 @@
<h2 mat-dialog-title>
{{
(editing
? 'APP.FOLDER_DIALOG.EDIT_FOLDER_TITLE'
: 'APP.FOLDER_DIALOG.CREATE_FOLDER_TITLE'
) | translate
}}
</h2>
<mat-dialog-content>
<form [formGroup]="form" (submit)="submit()">
<mat-form-field style="width: 100%">
<input
placeholder="{{ 'APP.FOLDER_DIALOG.FOLDER_NAME.LABEL' | translate }}"
matInput
required
[formControl]="form.controls['name']"
/>
<mat-hint *ngIf="form.controls['name'].dirty">
<span *ngIf="form.controls['name'].errors?.required">
{{ 'APP.FOLDER_DIALOG.FOLDER_NAME.ERRORS.REQUIRED' | translate }}
</span>
<span *ngIf="!form.controls['name'].errors?.required && form.controls['name'].errors?.message">
{{ form.controls['name'].errors?.message | translate }}
</span>
</mat-hint>
</mat-form-field>
<br />
<br />
<mat-form-field style="width: 100%">
<textarea
matInput
placeholder="{{ 'APP.FOLDER_DIALOG.FOLDER_DESCRIPTION.LABEL' | translate }}"
rows="4"
[formControl]="form.controls['description']"></textarea>
</mat-form-field>
</form>
</mat-dialog-content>
<mat-dialog-actions>
<button
mat-raised-button
(click)="submit()"
[disabled]="!form.valid">
{{
(editing
? 'APP.FOLDER_DIALOG.UPDATE_BUTTON.LABEL'
: 'APP.FOLDER_DIALOG.CREATE_BUTTON.LABEL'
) | translate
}}
</button>
<button
mat-button
mat-dialog-close>
{{ 'APP.FOLDER_DIALOG.CANCEL_BUTTON.LABEL' | translate }}
</button>
</mat-dialog-actions>
@@ -1,260 +0,0 @@
/*!
* @license
* Copyright 2017 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 { TestBed, async } from '@angular/core/testing';
import { Observable } from 'rxjs/Rx';
import { MatDialogModule, MatDialogRef } from '@angular/material';
import { CoreModule, NodesApiService, TranslationService, NotificationService } from 'ng2-alfresco-core';
import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing';
import { FolderDialogComponent } from './folder-dialog.component';
import { ComponentFixture } from '@angular/core/testing';
describe('FolderDialogComponent', () => {
let fixture: ComponentFixture<FolderDialogComponent>;
let component: FolderDialogComponent;
let translationService: TranslationService;
let nodesApi: NodesApiService;
let notificationService: NotificationService;
let dialogRef;
beforeEach(async(() => {
dialogRef = {
close: jasmine.createSpy('close')
};
TestBed.configureTestingModule({
imports: [
CoreModule,
MatDialogModule
],
declarations: [
FolderDialogComponent
],
providers: [
{ provide: MatDialogRef, useValue: dialogRef }
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FolderDialogComponent);
component = fixture.componentInstance;
nodesApi = TestBed.get(NodesApiService);
notificationService = TestBed.get(NotificationService);
translationService = TestBed.get(TranslationService);
spyOn(translationService, 'get').and.returnValue(Observable.of('message'));
});
describe('Edit', () => {
beforeEach(() => {
component.data = {
folder: {
id: 'node-id',
name: 'folder-name',
properties: {
['cm:description']: 'folder-description'
}
}
};
component.ngOnInit();
});
it('should init form with folder name and description', () => {
expect(component.name).toBe('folder-name');
expect(component.description).toBe('folder-description');
});
it('should update form input', () => {
component.form.controls['name'].setValue('folder-name-update');
component.form.controls['description'].setValue('folder-description-update');
expect(component.name).toBe('folder-name-update');
expect(component.description).toBe('folder-description-update');
});
it('should submit updated values if form is valid', () => {
spyOn(nodesApi, 'updateNode').and.returnValue(Observable.of({}));
component.form.controls['name'].setValue('folder-name-update');
component.form.controls['description'].setValue('folder-description-update');
component.submit();
expect(nodesApi.updateNode).toHaveBeenCalledWith(
'node-id',
{
name: 'folder-name-update',
properties: {
'cm:title': 'folder-name-update',
'cm:description': 'folder-description-update'
}
}
);
});
it('should call dialog to close with form data when submit is succesfluly', () => {
const folder = {
data: 'folder-data'
};
spyOn(nodesApi, 'updateNode').and.returnValue(Observable.of(folder));
component.submit();
expect(dialogRef.close).toHaveBeenCalledWith(folder);
});
it('should not submit if form is invalid', () => {
spyOn(nodesApi, 'updateNode');
component.form.controls['name'].setValue('');
component.form.controls['description'].setValue('');
component.submit();
expect(component.form.valid).toBe(false);
expect(nodesApi.updateNode).not.toHaveBeenCalled();
});
it('should not call dialog to close if submit fails', () => {
spyOn(nodesApi, 'updateNode').and.returnValue(Observable.throw('error'));
spyOn(component, 'handleError').and.callFake(val => val);
component.submit();
expect(component.handleError).toHaveBeenCalled();
expect(dialogRef.close).not.toHaveBeenCalled();
});
});
describe('Create', () => {
beforeEach(() => {
component.data = {
parentNodeId: 'parentNodeId',
folder: null
};
component.ngOnInit();
});
it('should init form with empty inputs', () => {
expect(component.name).toBe('');
expect(component.description).toBe('');
});
it('should update form input', () => {
component.form.controls['name'].setValue('folder-name-update');
component.form.controls['description'].setValue('folder-description-update');
expect(component.name).toBe('folder-name-update');
expect(component.description).toBe('folder-description-update');
});
it('should submit updated values if form is valid', () => {
spyOn(nodesApi, 'createFolder').and.returnValue(Observable.of({}));
component.form.controls['name'].setValue('folder-name-update');
component.form.controls['description'].setValue('folder-description-update');
component.submit();
expect(nodesApi.createFolder).toHaveBeenCalledWith(
'parentNodeId',
{
name: 'folder-name-update',
properties: {
'cm:title': 'folder-name-update',
'cm:description': 'folder-description-update'
}
}
);
});
it('should call dialog to close with form data when submit is succesfluly', () => {
const folder = {
data: 'folder-data'
};
component.form.controls['name'].setValue('name');
component.form.controls['description'].setValue('description');
spyOn(nodesApi, 'createFolder').and.returnValue(Observable.of(folder));
component.submit();
expect(dialogRef.close).toHaveBeenCalledWith(folder);
});
it('should not submit if form is invalid', () => {
spyOn(nodesApi, 'createFolder');
component.form.controls['name'].setValue('');
component.form.controls['description'].setValue('');
component.submit();
expect(component.form.valid).toBe(false);
expect(nodesApi.createFolder).not.toHaveBeenCalled();
});
it('should not call dialog to close if submit fails', () => {
spyOn(nodesApi, 'createFolder').and.returnValue(Observable.throw('error'));
spyOn(component, 'handleError').and.callFake(val => val);
component.form.controls['name'].setValue('name');
component.form.controls['description'].setValue('description');
component.submit();
expect(component.handleError).toHaveBeenCalled();
expect(dialogRef.close).not.toHaveBeenCalled();
});
});
describe('handleError()', () => {
it('should raise error for 409', () => {
spyOn(notificationService, 'openSnackMessage').and.stub();
const error = {
message: '{ "error": { "statusCode" : 409 } }'
};
component.handleError(error);
expect(notificationService.openSnackMessage).toHaveBeenCalled();
expect(translationService.get).toHaveBeenCalledWith('APP.MESSAGES.ERRORS.EXISTENT_FOLDER');
});
it('should raise generic error', () => {
spyOn(notificationService, 'openSnackMessage').and.stub();
const error = {
message: '{ "error": { "statusCode" : 123 } }'
};
component.handleError(error);
expect(notificationService.openSnackMessage).toHaveBeenCalled();
expect(translationService.get).toHaveBeenCalledWith('APP.MESSAGES.ERRORS.GENERIC');
});
});
});
@@ -1,138 +0,0 @@
/*!
* @license
* Copyright 2017 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 { Observable } from 'rxjs/Rx';
import { Component, Inject, Optional, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { TranslationService, NodesApiService, NotificationService } from 'ng2-alfresco-core';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { forbidSpecialCharacters, forbidEndingDot, forbidOnlySpaces } from './folder-name.validators';
@Component({
selector: 'app-folder-dialog',
templateUrl: './folder-dialog.component.html'
})
export class FolderDialogComponent implements OnInit {
form: FormGroup;
folder: MinimalNodeEntryEntity = null;
constructor(
private formBuilder: FormBuilder,
private dialog: MatDialogRef<FolderDialogComponent>,
private nodesApi: NodesApiService,
private translation: TranslationService,
private notification: NotificationService,
@Optional()
@Inject(MAT_DIALOG_DATA)
public data: any
) {}
get editing(): boolean {
return !!this.data.folder;
}
ngOnInit() {
const { folder } = this.data;
let name = '', description = '';
if (folder) {
const { properties } = folder;
name = folder.name || '';
description = properties ? properties['cm:description'] : '';
}
const validators = {
name: [
Validators.required,
forbidSpecialCharacters,
forbidEndingDot,
forbidOnlySpaces
]
};
this.form = this.formBuilder.group({
name: [ name, validators.name ],
description: [ description ]
});
}
get name(): string {
const { name } = this.form.value;
return (name || '').trim();
}
get description(): string {
const { description } = this.form.value;
return (description || '').trim();
}
private get properties(): any {
const { name: title, description } = this;
return {
'cm:title': title,
'cm:description': description
};
}
private create(): Observable<MinimalNodeEntryEntity> {
const { name, properties, nodesApi, data: { parentNodeId} } = this;
return nodesApi.createFolder(parentNodeId, { name, properties });
}
private edit(): Observable<MinimalNodeEntryEntity> {
const { name, properties, nodesApi, data: { folder: { id: nodeId }} } = this;
return nodesApi.updateNode(nodeId, { name, properties });
}
submit() {
const { form, dialog, editing } = this;
if (!form.valid) { return; }
(editing ? this.edit() : this.create())
.subscribe(
(folder: MinimalNodeEntryEntity) => dialog.close(folder),
(error) => this.handleError(error)
);
}
handleError(error: any): any {
let i18nMessageString = 'APP.MESSAGES.ERRORS.GENERIC';
try {
const { error: { statusCode } } = JSON.parse(error.message);
if (statusCode === 409) {
i18nMessageString = 'APP.MESSAGES.ERRORS.EXISTENT_FOLDER';
}
} catch (err) { /* Do nothing, keep the original message */ }
this.translation.get(i18nMessageString).subscribe(message => {
this.notification.openSnackMessage(message, 3000);
});
return error;
}
}
@@ -1,45 +0,0 @@
/*!
* @license
* Copyright 2017 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 { FormControl } from '@angular/forms';
const I18N_ERRORS_PATH = 'APP.FOLDER_DIALOG.FOLDER_NAME.ERRORS';
export function forbidSpecialCharacters({ value }: FormControl) {
const specialCharacters: RegExp = /([\*\"\<\>\\\/\?\:\|])/;
const isValid: boolean = !specialCharacters.test(value);
return (isValid) ? null : {
message: `${I18N_ERRORS_PATH}.SPECIAL_CHARACTERS`
};
}
export function forbidEndingDot({ value }: FormControl) {
const isValid: boolean = ((value || '').split('').pop() !== '.');
return isValid ? null : {
message: `${I18N_ERRORS_PATH}.ENDING_DOT`
};
}
export function forbidOnlySpaces({ value }: FormControl) {
const isValid: boolean = !!((value || '')).trim();
return isValid ? null : {
message: `${I18N_ERRORS_PATH}.ONLY_SPACES`
};
}
@@ -1,96 +0,0 @@
/*!
* @license
* Copyright 2017 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 { TestBed, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { MatDialogModule, MatDialog } from '@angular/material';
import { FolderCreateDirective } from './folder-create.directive';
import { ContentManagementService } from '../services/content-management.service';
@Component({
template: '<div [app-create-folder]="parentNode"></div>'
})
class TestComponent {
parentNode = '';
}
describe('FolderCreateDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let element;
let node: any;
let dialog: MatDialog;
let contentService: ContentManagementService;
let dialogRefMock;
const event: any = {
type: 'click',
preventDefault: () => null
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ MatDialogModule ],
declarations: [
TestComponent,
FolderCreateDirective
]
,
providers: [
ContentManagementService
]
});
fixture = TestBed.createComponent(TestComponent);
element = fixture.debugElement.query(By.directive(FolderCreateDirective));
dialog = TestBed.get(MatDialog);
contentService = TestBed.get(ContentManagementService);
});
beforeEach(() => {
node = { entry: { id: 'nodeId' } };
dialogRefMock = {
afterClosed: val => Observable.of(val)
};
spyOn(dialog, 'open').and.returnValue(dialogRefMock);
});
it('emits createFolder event when input value is not undefined', () => {
spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(node));
contentService.createFolder.subscribe((val) => {
expect(val).toBe(node);
});
element.triggerEventHandler('click', event);
fixture.detectChanges();
});
it('does not emits createFolder event when input value is undefined', () => {
spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(null));
spyOn(contentService.createFolder, 'next');
element.triggerEventHandler('click', event);
fixture.detectChanges();
expect(contentService.createFolder.next).not.toHaveBeenCalled();
});
});
@@ -1,66 +0,0 @@
/*!
* @license
* Copyright 2017 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, HostListener, Input } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { FolderDialogComponent } from '../dialogs/folder-dialog.component';
import { ContentManagementService } from '../services/content-management.service';
@Directive({
selector: '[app-create-folder]'
})
export class FolderCreateDirective {
static DIALOG_WIDTH: number = 400;
@Input('app-create-folder')
parentNodeId: string;
@HostListener('click', [ '$event' ])
onClick(event) {
event.preventDefault();
this.openDialog();
}
constructor(
public dialogRef: MatDialog,
public content: ContentManagementService
) {}
private get dialogConfig(): MatDialogConfig {
const { DIALOG_WIDTH: width } = FolderCreateDirective;
const { parentNodeId } = this;
return {
data: { parentNodeId },
width: `${width}px`
};
}
private openDialog(): void {
const { dialogRef, dialogConfig, content } = this;
const dialogInstance = dialogRef.open(FolderDialogComponent, dialogConfig);
dialogInstance.afterClosed().subscribe((node: MinimalNodeEntryEntity) => {
if (node) {
content.createFolder.next(node);
}
});
}
}
@@ -1,96 +0,0 @@
/*!
* @license
* Copyright 2017 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 { TestBed, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { MatDialogModule, MatDialog } from '@angular/material';
import { FolderEditDirective } from './folder-edit.directive';
import { ContentManagementService } from '../services/content-management.service';
@Component({
template: '<div [app-edit-folder]="folder"></div>'
})
class TestComponent {
folder = {};
}
describe('FolderEditDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let element;
let node: any;
let dialog: MatDialog;
let contentService: ContentManagementService;
let dialogRefMock;
const event = {
type: 'click',
preventDefault: () => null
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ MatDialogModule ],
declarations: [
TestComponent,
FolderEditDirective
]
,
providers: [
ContentManagementService
]
});
fixture = TestBed.createComponent(TestComponent);
element = fixture.debugElement.query(By.directive(FolderEditDirective));
dialog = TestBed.get(MatDialog);
contentService = TestBed.get(ContentManagementService);
});
beforeEach(() => {
node = { entry: { id: 'folderId' } };
dialogRefMock = {
afterClosed: val => Observable.of(val)
};
spyOn(dialog, 'open').and.returnValue(dialogRefMock);
});
it('emits editFolder event when input value is not undefined', () => {
spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(node));
contentService.createFolder.subscribe((val) => {
expect(val).toBe(node);
});
element.triggerEventHandler('click', event);
fixture.detectChanges();
});
it('does not emits FolderEditDirective event when input value is undefined', () => {
spyOn(dialogRefMock, 'afterClosed').and.returnValue(Observable.of(null));
spyOn(contentService.createFolder, 'next');
element.triggerEventHandler('click', event);
fixture.detectChanges();
expect(contentService.createFolder.next).not.toHaveBeenCalled();
});
});
@@ -1,67 +0,0 @@
/*!
* @license
* Copyright 2017 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, HostListener, ElementRef, Input } from '@angular/core';
import { MatDialog, MatDialogConfig } from '@angular/material';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { FolderDialogComponent } from '../dialogs/folder-dialog.component';
import { ContentManagementService } from '../services/content-management.service';
@Directive({
selector: '[app-edit-folder]'
})
export class FolderEditDirective {
static DIALOG_WIDTH = 400;
@Input('app-edit-folder')
folder: MinimalNodeEntryEntity;
@HostListener('click', [ '$event' ])
onClick(event) {
event.preventDefault();
this.openDialog();
}
constructor(
public dialogRef: MatDialog,
public elementRef: ElementRef,
public content: ContentManagementService
) {}
private get dialogConfig(): MatDialogConfig {
const { DIALOG_WIDTH: width } = FolderEditDirective;
const { folder } = this;
return {
data: { folder },
width: `${width}px`
};
}
private openDialog(): void {
const { dialogRef, dialogConfig, content } = this;
const dialogInstance = dialogRef.open(FolderDialogComponent, dialogConfig);
dialogInstance.afterClosed().subscribe((node: MinimalNodeEntryEntity) => {
if (node) {
content.editFolder.next(node);
}
});
}
}
@@ -18,12 +18,8 @@
import { Subject } from 'rxjs/Rx';
import { Injectable } from '@angular/core';
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
@Injectable()
export class ContentManagementService {
createFolder = new Subject<MinimalNodeEntryEntity>();
editFolder = new Subject<MinimalNodeEntryEntity>();
deleteNode = new Subject<string>();
moveNode = new Subject<string>();
restoreNode = new Subject<string>();
@@ -25,7 +25,7 @@
mat-icon-button
*ngIf="canEditFolder(documentList.selection)"
title="{{ 'APP.ACTIONS.EDIT' | translate }}"
[app-edit-folder]="documentList.selection[0]?.entry">
[adf-edit-folder]="documentList.selection[0]?.entry">
<mat-icon>create</mat-icon>
</button>
@@ -20,7 +20,7 @@ import { RouterTestingModule } from '@angular/router/testing';
import { TestBed, async } from '@angular/core/testing';
import { Observable } from 'rxjs/Rx';
import { CoreModule, NodesApiService, AlfrescoApiService } from 'ng2-alfresco-core';
import { CoreModule, NodesApiService, AlfrescoApiService, AlfrescoContentService } from 'ng2-alfresco-core';
import { CommonModule } from '../../common/common.module';
import { ContentManagementService } from '../../common/services/content-management.service';
@@ -32,6 +32,7 @@ describe('Favorites Routed Component', () => {
let component: FavoritesComponent;
let nodesApi: NodesApiService;
let alfrescoApi: AlfrescoApiService;
let alfrescoContentService: AlfrescoContentService;
let contentService: ContentManagementService;
let router: Router;
let page;
@@ -80,6 +81,7 @@ describe('Favorites Routed Component', () => {
nodesApi = TestBed.get(NodesApiService);
alfrescoApi = TestBed.get(AlfrescoApiService);
alfrescoContentService = TestBed.get(AlfrescoContentService);
contentService = TestBed.get(ContentManagementService);
router = TestBed.get(Router);
});
@@ -94,7 +96,7 @@ describe('Favorites Routed Component', () => {
spyOn(component, 'refresh');
fixture.detectChanges();
contentService.editFolder.next(null);
alfrescoContentService.folderEdit.next(null);
expect(component.refresh).toHaveBeenCalled();
});
@@ -20,7 +20,7 @@ import { Router } from '@angular/router';
import { Subscription } from 'rxjs/Rx';
import { MinimalNodeEntryEntity, PathElementEntity, PathInfo } from 'alfresco-js-api';
import { NodesApiService } from 'ng2-alfresco-core';
import { AlfrescoContentService, NodesApiService } from 'ng2-alfresco-core';
import { DocumentListComponent } from 'ng2-alfresco-documentlist';
import { ContentManagementService } from '../../common/services/content-management.service';
@@ -41,12 +41,13 @@ export class FavoritesComponent extends PageComponent implements OnInit, OnDestr
constructor(
private router: Router,
private nodesApi: NodesApiService,
private contentService: AlfrescoContentService,
private content: ContentManagementService) {
super();
}
ngOnInit() {
this.onEditFolder = this.content.editFolder.subscribe(() => this.refresh());
this.onEditFolder = this.contentService.folderEdit.subscribe(() => this.refresh());
this.onMoveNode = this.content.moveNode.subscribe(() => this.refresh());
this.onToggleFavorite = this.content.toggleFavorite
.debounceTime(300).subscribe(() => this.refresh());
@@ -27,7 +27,7 @@
mat-icon-button
*ngIf="canEditFolder(documentList.selection)"
title="{{ 'APP.ACTIONS.EDIT' | translate }}"
[app-edit-folder]="documentList.selection[0]?.entry">
[adf-edit-folder]="documentList.selection[0]?.entry">
<mat-icon>create</mat-icon>
</button>
@@ -170,13 +170,13 @@ describe('FilesComponent', () => {
});
it('calls refresh onCreateFolder event', () => {
contentManagementService.createFolder.next();
alfrescoContentService.folderCreate.next();
expect(component.load).toHaveBeenCalled();
});
it('calls refresh editFolder event', () => {
contentManagementService.editFolder.next();
alfrescoContentService.folderEdit.next();
expect(component.load).toHaveBeenCalled();
});
+4 -4
View File
@@ -16,7 +16,7 @@
*/
import { Observable, Subscription } from 'rxjs/Rx';
import { Component, ViewChild, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { MinimalNodeEntity, MinimalNodeEntryEntity, PathElementEntity, NodePaging, PathElement } from 'alfresco-js-api';
import { UploadService, FileUploadEvent, NodesApiService, AlfrescoContentService, AlfrescoApiService } from 'ng2-alfresco-core';
@@ -60,7 +60,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
}
ngOnInit() {
const { route, contentManagementService, nodeActionsService, uploadService } = this;
const { route, contentManagementService, contentService, nodeActionsService, uploadService } = this;
const { data } = route.snapshot;
this.routeData = data;
@@ -87,8 +87,8 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
this.onCopyNode = nodeActionsService.contentCopied
.subscribe((nodes) => this.onContentCopied(nodes));
this.onCreateFolder = contentManagementService.createFolder.subscribe(() => this.load());
this.onEditFolder = contentManagementService.editFolder.subscribe(() => this.load());
this.onCreateFolder = contentService.folderCreate.subscribe(() => this.load());
this.onEditFolder = contentService.folderEdit.subscribe(() => this.load());
this.onDeleteNode = contentManagementService.deleteNode.subscribe(() => this.load());
this.onMoveNode = contentManagementService.moveNode.subscribe(() => this.load());
this.onRestoreNode = contentManagementService.restoreNode.subscribe(() => this.load());
@@ -8,8 +8,8 @@
<mat-menu #menu="matMenu" [overlapTrigger]="false">
<button
mat-menu-item
[app-create-folder]="node?.id"
[disabled]="!canCreateContent(node)"
[adf-create-folder]="node?.id"
title="{{
( canCreateContent(node)
? 'APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER'
+1 -1
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title>Alfresco Content App</title>
<base href="./">
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96">
+91 -78
View File
@@ -3,8 +3,8 @@
"@angular-devkit/build-optimizer@~0.0.23":
version "0.0.31"
resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.0.31.tgz#511bc00e18c787a6cd4efe37b8cdb9f1bc6d4472"
version "0.0.32"
resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.0.32.tgz#1bf32332d8a7c84043059e3d265a52f9d11726fd"
dependencies:
loader-utils "^1.1.0"
source-map "^0.5.6"
@@ -18,13 +18,13 @@
source-map "^0.5.6"
"@angular-devkit/schematics@~0.0.25":
version "0.0.34"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-0.0.34.tgz#c3ef61b0e49e585d9982f2828e9a67b3879a6b1b"
version "0.0.35"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-0.0.35.tgz#23dbe2c8dd430114a903a7995d6eefcf1f0f648d"
dependencies:
"@angular-devkit/core" "0.0.20"
"@ngtools/json-schema" "^1.1.0"
minimist "^1.2.0"
rxjs "^5.4.2"
rxjs "^5.5.2"
"@angular/animations@4.4.5":
version "4.4.5"
@@ -189,9 +189,9 @@
magic-string "^0.22.3"
source-map "^0.5.6"
"@ngx-translate/core@7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-7.0.0.tgz#5b6f63bd4042164d44cd85f68703af96e9392e7d"
"@ngx-translate/core@8.0.0":
version "8.0.0"
resolved "https://registry.yarnpkg.com/@ngx-translate/core/-/core-8.0.0.tgz#751fd6b512d80f3a748d2de8dfc96dfefa29afe0"
"@schematics/angular@~0.0.38":
version "0.0.49"
@@ -303,9 +303,9 @@ ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5:
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.3.0"
alfresco-js-api@1.10.0-beta5:
version "1.10.0-beta5"
resolved "https://registry.yarnpkg.com/alfresco-js-api/-/alfresco-js-api-1.10.0-beta5.tgz#6b3b111b1774b6b81a51f0ad0e5f7c24e5e234da"
alfresco-js-api@1.10.0-beta6:
version "1.10.0-beta6"
resolved "https://registry.yarnpkg.com/alfresco-js-api/-/alfresco-js-api-1.10.0-beta6.tgz#c988a46f81ce17c70edd053d03b95d61ce5447f5"
dependencies:
event-emitter "0.3.4"
superagent "3.7.0"
@@ -887,8 +887,8 @@ caniuse-api@^1.5.2:
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000756"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000756.tgz#e938a6b991630f30d2263dd3458beb65d362268b"
version "1.0.30000758"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000758.tgz#a235627b1922e878b63164942c991b84de92c810"
caseless@~0.12.0:
version "0.12.0"
@@ -925,7 +925,7 @@ chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0:
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba"
dependencies:
@@ -1292,8 +1292,8 @@ cryptiles@3.x.x, cryptiles@^3.1.2:
boom "5.x.x"
crypto-browserify@^3.11.0:
version "3.11.1"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f"
version "3.12.0"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
dependencies:
browserify-cipher "^1.0.0"
browserify-sign "^4.0.0"
@@ -1305,6 +1305,7 @@ crypto-browserify@^3.11.0:
pbkdf2 "^3.0.3"
public-encrypt "^4.0.0"
randombytes "^2.0.0"
randomfill "^1.0.3"
css-color-names@0.0.4:
version "0.0.4"
@@ -1542,6 +1543,10 @@ detect-indent@^4.0.0:
dependencies:
repeating "^2.0.0"
detect-libc@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.2.tgz#71ad5d204bf17a6a6ca8f450c61454066ef461e1"
detect-node@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127"
@@ -3669,9 +3674,9 @@ negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
ng2-alfresco-core@1.10.0-beta5:
version "1.10.0-beta5"
resolved "https://registry.yarnpkg.com/ng2-alfresco-core/-/ng2-alfresco-core-1.10.0-beta5.tgz#d641754b9440014a5b747811b82520c449f2694e"
ng2-alfresco-core@1.10.0-beta6:
version "1.10.0-beta6"
resolved "https://registry.yarnpkg.com/ng2-alfresco-core/-/ng2-alfresco-core-1.10.0-beta6.tgz#d1ed5028f3bb4e9c063e338290dfba9a9cb44992"
dependencies:
"@angular/animations" "4.4.5"
"@angular/cdk" "2.0.0-beta.12"
@@ -3685,8 +3690,8 @@ ng2-alfresco-core@1.10.0-beta5:
"@angular/platform-browser" "4.4.5"
"@angular/platform-browser-dynamic" "4.4.5"
"@angular/router" "4.4.5"
"@ngx-translate/core" "7.0.0"
alfresco-js-api "1.10.0-beta5"
"@ngx-translate/core" "8.0.0"
alfresco-js-api "1.10.0-beta6"
core-js "2.4.1"
hammerjs "2.0.8"
moment "2.15.2"
@@ -3695,9 +3700,9 @@ ng2-alfresco-core@1.10.0-beta5:
systemjs "0.19.27"
zone.js "0.8.12"
ng2-alfresco-datatable@1.10.0-beta5:
version "1.10.0-beta5"
resolved "https://registry.yarnpkg.com/ng2-alfresco-datatable/-/ng2-alfresco-datatable-1.10.0-beta5.tgz#a63feac548ee5aac5ec677a923c84fbaecb3ba3c"
ng2-alfresco-datatable@1.10.0-beta6:
version "1.10.0-beta6"
resolved "https://registry.yarnpkg.com/ng2-alfresco-datatable/-/ng2-alfresco-datatable-1.10.0-beta6.tgz#37312c3be022b7eb893e4fa278c0177c77b9130f"
dependencies:
"@angular/animations" "4.4.5"
"@angular/cdk" "2.0.0-beta.12"
@@ -3710,19 +3715,19 @@ ng2-alfresco-datatable@1.10.0-beta5:
"@angular/platform-browser" "4.4.5"
"@angular/platform-browser-dynamic" "4.4.5"
"@angular/router" "4.4.5"
"@ngx-translate/core" "7.0.0"
alfresco-js-api "1.10.0-beta5"
"@ngx-translate/core" "8.0.0"
alfresco-js-api "1.10.0-beta6"
core-js "2.4.1"
hammerjs "2.0.8"
ng2-alfresco-core "1.10.0-beta5"
ng2-alfresco-core "1.10.0-beta6"
reflect-metadata "0.1.10"
rxjs "5.1.0"
systemjs "0.19.27"
zone.js "0.8.12"
ng2-alfresco-documentlist@1.10.0-beta5:
version "1.10.0-beta5"
resolved "https://registry.yarnpkg.com/ng2-alfresco-documentlist/-/ng2-alfresco-documentlist-1.10.0-beta5.tgz#c63d5cb769c4ed5995179b883acf460c7bfb13a5"
ng2-alfresco-documentlist@1.10.0-beta6:
version "1.10.0-beta6"
resolved "https://registry.yarnpkg.com/ng2-alfresco-documentlist/-/ng2-alfresco-documentlist-1.10.0-beta6.tgz#512dd75fbef9df43949fa74665ccb831c3346b23"
dependencies:
"@angular/animations" "4.4.5"
"@angular/cdk" "2.0.0-beta.12"
@@ -3736,21 +3741,21 @@ ng2-alfresco-documentlist@1.10.0-beta5:
"@angular/platform-browser" "4.4.5"
"@angular/platform-browser-dynamic" "4.4.5"
"@angular/router" "4.4.5"
"@ngx-translate/core" "7.0.0"
alfresco-js-api "1.10.0-beta5"
"@ngx-translate/core" "8.0.0"
alfresco-js-api "1.10.0-beta6"
core-js "2.4.1"
hammerjs "2.0.8"
ng2-alfresco-core "1.10.0-beta5"
ng2-alfresco-datatable "1.10.0-beta5"
ng2-alfresco-upload "1.10.0-beta5"
ng2-alfresco-core "1.10.0-beta6"
ng2-alfresco-datatable "1.10.0-beta6"
ng2-alfresco-upload "1.10.0-beta6"
reflect-metadata "0.1.10"
rxjs "5.1.0"
systemjs "0.19.27"
zone.js "0.8.12"
ng2-alfresco-login@1.10.0-beta5:
version "1.10.0-beta5"
resolved "https://registry.yarnpkg.com/ng2-alfresco-login/-/ng2-alfresco-login-1.10.0-beta5.tgz#fc54c6e6eb32774bb47e29654432209413993fe0"
ng2-alfresco-login@1.10.0-beta6:
version "1.10.0-beta6"
resolved "https://registry.yarnpkg.com/ng2-alfresco-login/-/ng2-alfresco-login-1.10.0-beta6.tgz#db18061d219362cf8533a49099b8aafa17c648d8"
dependencies:
"@angular/animations" "4.4.5"
"@angular/cdk" "2.0.0-beta.12"
@@ -3763,18 +3768,18 @@ ng2-alfresco-login@1.10.0-beta5:
"@angular/platform-browser" "4.4.5"
"@angular/platform-browser-dynamic" "4.4.5"
"@angular/router" "4.4.5"
"@ngx-translate/core" "7.0.0"
alfresco-js-api "1.10.0-beta5"
"@ngx-translate/core" "8.0.0"
alfresco-js-api "1.10.0-beta6"
hammerjs "2.0.8"
ng2-alfresco-core "1.10.0-beta5"
ng2-alfresco-core "1.10.0-beta6"
reflect-metadata "0.1.10"
rxjs "5.1.0"
systemjs "0.19.27"
zone.js "0.8.12"
ng2-alfresco-search@1.10.0-beta5:
version "1.10.0-beta5"
resolved "https://registry.yarnpkg.com/ng2-alfresco-search/-/ng2-alfresco-search-1.10.0-beta5.tgz#6a2c83c0bc9b3696908a53c3bf042cd1c7736127"
ng2-alfresco-search@1.10.0-beta6:
version "1.10.0-beta6"
resolved "https://registry.yarnpkg.com/ng2-alfresco-search/-/ng2-alfresco-search-1.10.0-beta6.tgz#6257100b8f52e5d812d4b8dae065b84124b636bb"
dependencies:
"@angular/animations" "4.4.5"
"@angular/cdk" "2.0.0-beta.12"
@@ -3787,21 +3792,21 @@ ng2-alfresco-search@1.10.0-beta5:
"@angular/platform-browser" "4.4.5"
"@angular/platform-browser-dynamic" "4.4.5"
"@angular/router" "4.4.5"
"@ngx-translate/core" "7.0.0"
alfresco-js-api "1.10.0-beta5"
"@ngx-translate/core" "8.0.0"
alfresco-js-api "1.10.0-beta6"
core-js "2.4.1"
hammerjs "2.0.8"
ng2-alfresco-core "1.10.0-beta5"
ng2-alfresco-datatable "1.10.0-beta5"
ng2-alfresco-documentlist "1.10.0-beta5"
ng2-alfresco-core "1.10.0-beta6"
ng2-alfresco-datatable "1.10.0-beta6"
ng2-alfresco-documentlist "1.10.0-beta6"
reflect-metadata "0.1.10"
rxjs "5.1.0"
systemjs "0.19.27"
zone.js "0.8.12"
ng2-alfresco-upload@1.10.0-beta5:
version "1.10.0-beta5"
resolved "https://registry.yarnpkg.com/ng2-alfresco-upload/-/ng2-alfresco-upload-1.10.0-beta5.tgz#6d61b0777c6dd7703993ae04921dd44b78eb5bab"
ng2-alfresco-upload@1.10.0-beta6:
version "1.10.0-beta6"
resolved "https://registry.yarnpkg.com/ng2-alfresco-upload/-/ng2-alfresco-upload-1.10.0-beta6.tgz#7da94739cee61125dae4a4aa9c23573a414aa23e"
dependencies:
"@angular/animations" "4.4.5"
"@angular/cdk" "2.0.0-beta.12"
@@ -3814,20 +3819,20 @@ ng2-alfresco-upload@1.10.0-beta5:
"@angular/platform-browser" "4.4.5"
"@angular/platform-browser-dynamic" "4.4.5"
"@angular/router" "4.4.5"
"@ngx-translate/core" "7.0.0"
alfresco-js-api "1.10.0-beta5"
"@ngx-translate/core" "8.0.0"
alfresco-js-api "1.10.0-beta6"
core-js "2.4.1"
hammerjs "2.0.8"
minimatch "3.0.4"
ng2-alfresco-core "1.10.0-beta5"
ng2-alfresco-core "1.10.0-beta6"
reflect-metadata "0.1.10"
rxjs "5.1.0"
systemjs "0.19.27"
zone.js "0.8.12"
ng2-alfresco-viewer@1.10.0-beta5:
version "1.10.0-beta5"
resolved "https://registry.yarnpkg.com/ng2-alfresco-viewer/-/ng2-alfresco-viewer-1.10.0-beta5.tgz#b52a7afc89c6816ebe8def703aa8d879a38d3eb6"
ng2-alfresco-viewer@1.10.0-beta6:
version "1.10.0-beta6"
resolved "https://registry.yarnpkg.com/ng2-alfresco-viewer/-/ng2-alfresco-viewer-1.10.0-beta6.tgz#04f9c400869e9e603acc47fc88b3ab3f5db2657b"
dependencies:
"@angular/animations" "4.4.5"
"@angular/cdk" "2.0.0-beta.12"
@@ -3840,11 +3845,11 @@ ng2-alfresco-viewer@1.10.0-beta5:
"@angular/platform-browser" "4.4.5"
"@angular/platform-browser-dynamic" "4.4.5"
"@angular/router" "4.4.5"
"@ngx-translate/core" "7.0.0"
alfresco-js-api "1.10.0-beta5"
"@ngx-translate/core" "8.0.0"
alfresco-js-api "1.10.0-beta6"
core-js "2.4.1"
hammerjs "2.0.8"
ng2-alfresco-core "1.10.0-beta5"
ng2-alfresco-core "1.10.0-beta6"
pdfjs-dist "1.5.404"
reflect-metadata "0.1.10"
rxjs "5.1.0"
@@ -3929,9 +3934,10 @@ node-modules-path@^1.0.0:
resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8"
node-pre-gyp@^0.6.36:
version "0.6.38"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.38.tgz#e92a20f83416415bb4086f6d1fb78b3da73d113d"
version "0.6.39"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649"
dependencies:
detect-libc "^1.0.2"
hawk "3.1.3"
mkdirp "^0.5.1"
nopt "^4.0.1"
@@ -4524,8 +4530,8 @@ postcss-minify-selectors@^2.0.4:
postcss-selector-parser "^2.0.0"
postcss-modules-extract-imports@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85"
version "1.1.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz#b614c9720be6816eaee35fb3a5faa1dba6a05ddb"
dependencies:
postcss "^6.0.1"
@@ -4652,10 +4658,10 @@ postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.
supports-color "^3.2.3"
postcss@^6.0.1:
version "6.0.13"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.13.tgz#b9ecab4ee00c89db3ec931145bd9590bbf3f125f"
version "6.0.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.14.tgz#5534c72114739e75d0afcf017db853099f562885"
dependencies:
chalk "^2.1.0"
chalk "^2.3.0"
source-map "^0.6.1"
supports-color "^4.4.0"
@@ -4806,12 +4812,19 @@ randomatic@^1.1.3:
is-number "^3.0.0"
kind-of "^4.0.0"
randombytes@^2.0.0, randombytes@^2.0.1:
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
dependencies:
safe-buffer "^5.1.0"
randomfill@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.3.tgz#b96b7df587f01dd91726c418f30553b1418e3d62"
dependencies:
randombytes "^2.0.5"
safe-buffer "^5.1.0"
range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
@@ -5064,7 +5077,7 @@ require-main-filename@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
requires-port@1.0.x, requires-port@1.x.x:
requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
@@ -5099,7 +5112,7 @@ rxjs@5.1.0:
dependencies:
symbol-observable "^1.0.1"
rxjs@^5.4.2:
rxjs@^5.4.2, rxjs@^5.5.2:
version "5.5.2"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.2.tgz#28d403f0071121967f18ad665563255d54236ac3"
dependencies:
@@ -5863,8 +5876,8 @@ tslint@~5.7.0:
tsutils "^2.8.1"
tsutils@^2.8.1:
version "2.12.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.12.1.tgz#f4d95ce3391c8971e46e54c4cf0edb0a21dd5b24"
version "2.12.2"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.12.2.tgz#ad58a4865d17ec3ddb6631b6ca53be14a5656ff3"
dependencies:
tslib "^1.7.1"
@@ -5987,11 +6000,11 @@ url-parse@1.0.x:
requires-port "1.0.x"
url-parse@^1.1.8:
version "1.1.9"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19"
version "1.2.0"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986"
dependencies:
querystringify "~1.0.0"
requires-port "1.0.x"
requires-port "~1.0.0"
url@^0.11.0:
version "0.11.0"
@@ -6169,8 +6182,8 @@ webpack-dev-server@~2.7.1:
yargs "^6.0.0"
webpack-merge@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.0.tgz#6ad72223b3e0b837e531e4597c199f909361511e"
version "4.1.1"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.1.tgz#f1197a0a973e69c6fbeeb6d658219aa8c0c13555"
dependencies:
lodash "^4.17.4"