From: Daniel Kos Date: Tue, 12 Jun 2018 19:38:39 +0000 (+0200) Subject: refs #13535 Merge branch '13535-tree-component' into 13610-projects-hierarchy X-Git-Tag: 1.2.0~80^2~3 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/eeb82d50816250cc6287928e6d958affa73880ee?hp=22cfdad7a451f67b0b4c195b58815cdf2abcfda9 refs #13535 Merge branch '13535-tree-component' into 13610-projects-hierarchy # Conflicts: # package.json # src/components/tree/tree.tsx # src/index.tsx # src/models/project.ts # src/store/project-action.ts # src/store/project-reducer.ts # src/views/workbench/workbench.test.tsx # src/views/workbench/workbench.tsx # tslint.json # yarn.lock Arvados-DCO-1.1-Signed-off-by: Daniel Kos --- diff --git a/package.json b/package.json index e4ba28ac..399750a3 100644 --- a/package.json +++ b/package.json @@ -3,18 +3,20 @@ "version": "0.1.0", "private": true, "dependencies": { - "@material-ui/core": "1.0.0", + "@material-ui/core": "1.2.0", + "@material-ui/icons": "^1.1.0", "lodash": "4.17.10", - "react": "16.3.2", - "react-dom": "16.3.2", + "axios": "0.18.0", + "react": "16.4.0", + "react-dom": "16.4.0", "react-redux": "5.0.7", "react-router": "4.2.0", "react-router-dom": "4.2.2", "react-router-redux": "5.0.0-alpha.9", "react-scripts-ts": "2.16.0", "redux": "4.0.0", - "redux-devtools": "3.4.1", - "typesafe-actions": "2.0.3" + "redux-thunk": "2.3.0", + "unionize": "2.1.2" }, "scripts": { "start": "react-scripts-ts start", @@ -26,19 +28,20 @@ "devDependencies": { "@types/enzyme": "^3.1.10", "@types/enzyme-adapter-react-16": "^1.0.2", - "@types/jest": "22.2.3", - "@types/lodash": "4.14.109", - "@types/node": "10.1.2", - "@types/react": "16.3.14", + "@types/jest": "23.0.0", + "@types/node": "10.3.0", + "@types/react": "16.3.16", "@types/react-dom": "16.0.5", - "@types/react-redux": "6.0.0", - "@types/react-router": "4.0.25", - "@types/react-router-dom": "4.2.6", - "@types/react-router-redux": "5.0.14", + "@types/react-redux": "6.0.1", + "@types/react-router": "4.0.26", + "@types/react-router-dom": "4.2.7", + "@types/react-router-redux": "5.0.15", "@types/redux-devtools": "3.0.44", "enzyme": "^3.3.0", "enzyme-adapter-react-16": "^1.1.1", - "typescript": "2.8.3" + "jest-localstorage-mock": "2.2.0", + "redux-devtools": "3.4.1", + "typescript": "2.9.1" }, "moduleNameMapper": { "^~/(.*)$": "/src/$1" diff --git a/run-tests-build.sh b/run-tests-build.sh new file mode 100755 index 00000000..e55b1e0e --- /dev/null +++ b/run-tests-build.sh @@ -0,0 +1,69 @@ +#!/bin/bash -x +# Copyright (C) The Arvados Authors. All rights reserved. +# +# SPDX-License-Identifier: AGPL-3.0 +# The script uses the docker image composer-build:latest +# Usage docker run -ti -v /var/lib/jenkins/workspace/build-packages-workbench2/:/tmp/workbench2 composer-build:latest /tmp/workbench2/run-tests-build.sh --build_version 1.0.1 +format_last_commit_here() { + local format="$1"; shift + TZ=UTC git log -n1 --first-parent "--format=format:$format" . +} + +version_from_git() { + # Output the version being built, or if we're building a + # dev/prerelease, output a version number based on the git log for + # the current working directory. + if [[ -n "$ARVADOS_BUILDING_VERSION" ]]; then + echo "$ARVADOS_BUILDING_VERSION" + return + fi + + local git_ts git_hash prefix + if [[ -n "$1" ]] ; then + prefix="$1" + else + prefix="0.1" + fi + + declare $(format_last_commit_here "git_ts=%ct git_hash=%h") + ARVADOS_BUILDING_VERSION="$(git describe --abbrev=0).$(date -ud "@$git_ts" +%Y%m%d%H%M%S)" + echo "$ARVADOS_BUILDING_VERSION" +} + +nohash_version_from_git() { + version_from_git $1 | cut -d. -f1-3 +} + +timestamp_from_git() { + format_last_commit_here "%ct" +} + +WORKDIR="/tmp/workbench2" +cd $WORKDIR +if [[ -n "$2" ]]; then + build_version="$2" +else + build_version="$(version_from_git)" +fi +rm -Rf $WORKDIR/node_modules +rm -f $WORKDIR/*.deb; rm -f $WORKDIR/*.rpm +# run test and build dist +make test +#make build +yarn build + +# Build deb and rpm packages using fpm from dist passing the destination folder for the deploy to be /var/www/arvados-workbench2/ +fpm -s dir -t deb -n arvados-workbench2 -v "$build_version" "--maintainer=Ward Vandewege " --description "workbench2 Package" --deb-no-default-config-files $WORKDIR/build/=/var/www/arvados-workbench2/workbench2/ +fpm -s dir -t rpm -n arvados-workbench2 -v "$build_version" "--maintainer=Ward Vandewege " --description "workbench2 Package" $WORKDIR/build/=/var/www/arvados-workbench2/workbench2/ + +mkdir $WORKDIR/packages +mkdir $WORKDIR/packages/centos7 +mkdir $WORKDIR/packages/ubuntu1404 +mkdir $WORKDIR/packages/ubuntu1604 +mkdir $WORKDIR/packages/debian8 +mkdir $WORKDIR/packages/debian9 +cp $WORKDIR/*.rpm $WORKDIR/packages/centos7/ +cp $WORKDIR/*.deb $WORKDIR/packages/ubuntu1404/ +cp $WORKDIR/*.deb $WORKDIR/packages/ubuntu1604/ +cp $WORKDIR/*.deb $WORKDIR/packages/debian8 +cp $WORKDIR/*.deb $WORKDIR/packages/debian9 diff --git a/src/common/actions.ts b/src/common/actions.ts new file mode 100644 index 00000000..6a5f4107 --- /dev/null +++ b/src/common/actions.ts @@ -0,0 +1,3 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 diff --git a/src/common/api/filter-builder.ts b/src/common/api/filter-builder.ts new file mode 100644 index 00000000..c4c29b40 --- /dev/null +++ b/src/common/api/filter-builder.ts @@ -0,0 +1,34 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +export enum FilterField { + UUID = "uuid" +} + +export default class FilterBuilder { + private filters = ""; + + private addCondition(field: FilterField, cond: string, value?: string) { + if (value) { + this.filters += `["${field}","${cond}","${value}"]`; + } + return this; + } + + public addEqual(field: FilterField, value?: string) { + return this.addCondition(field, "=", value); + } + + public addLike(field: FilterField, value?: string) { + return this.addCondition(field, "like", value); + } + + public addILike(field: FilterField, value?: string) { + return this.addCondition(field, "ilike", value); + } + + public get() { + return "[" + this.filters + "]"; + } +} diff --git a/src/common/api/server-api.ts b/src/common/api/server-api.ts new file mode 100644 index 00000000..2e676dde --- /dev/null +++ b/src/common/api/server-api.ts @@ -0,0 +1,20 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import Axios, { AxiosInstance } from "axios"; + +export const API_HOST = 'https://qr1hi.arvadosapi.com'; + +export const serverApi: AxiosInstance = Axios.create({ + baseURL: API_HOST + '/arvados/v1' +}); + +export function setServerApiAuthorizationHeader(token: string) { + serverApi.defaults.headers.common = { + 'Authorization': `OAuth2 ${token}` + };} + +export function removeServerApiAuthorizationHeader() { + delete serverApi.defaults.headers.common.Authorization; +} diff --git a/src/common/api/url-builder.ts b/src/common/api/url-builder.ts new file mode 100644 index 00000000..e5786a23 --- /dev/null +++ b/src/common/api/url-builder.ts @@ -0,0 +1,26 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +export default class UrlBuilder { + private url: string = ""; + private query: string = ""; + + constructor(host: string) { + this.url = host; + } + + public addParam(param: string, value: string) { + if (this.query.length === 0) { + this.query += "?"; + } else { + this.query += "&"; + } + this.query += `${param}=${value}`; + return this; + } + + public get() { + return this.url + this.query; + } +} diff --git a/src/components/api-token/api-token.tsx b/src/components/api-token/api-token.tsx new file mode 100644 index 00000000..87da39b0 --- /dev/null +++ b/src/components/api-token/api-token.tsx @@ -0,0 +1,34 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { Redirect, RouteProps } from "react-router"; +import * as React from "react"; +import { connect, DispatchProp } from "react-redux"; +import authActions from "../../store/auth/auth-action"; +import { authService, projectService } from "../../services/services"; + +interface ApiTokenProps { +} + +class ApiToken extends React.Component, {}> { + static getUrlParameter(search: string, name: string) { + const safeName = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); + const regex = new RegExp('[\\?&]' + safeName + '=([^&#]*)'); + const results = regex.exec(search); + return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); + }; + + componentDidMount() { + const search = this.props.location ? this.props.location.search : ""; + const apiToken = ApiToken.getUrlParameter(search, 'api_token'); + this.props.dispatch(authActions.SAVE_API_TOKEN(apiToken)); + this.props.dispatch(authService.getUserDetails()); + this.props.dispatch(projectService.getProjectList()); + } + render() { + return + } +} + +export default connect()(ApiToken); diff --git a/src/index.tsx b/src/index.tsx index 9cc33feb..17329681 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -8,29 +8,16 @@ import { Provider } from "react-redux"; import Workbench from './views/workbench/workbench'; import ProjectList from './components/project-list/project-list'; import './index.css'; -import { Route, Router } from "react-router"; +import { Route } from "react-router"; import createBrowserHistory from "history/createBrowserHistory"; import configureStore from "./store/store"; import { ConnectedRouter } from "react-router-redux"; +import ApiToken from "./components/api-token/api-token"; +import authActions from "./store/auth/auth-action"; +import { projectService } from "./services/services"; import { TreeItem } from "./components/tree/tree"; import { Project } from "./models/project"; -const sampleProjects = [ - [ - 'Project 1', [ - ['Project 1.1', [['Project 1.1.1'], ['Project 1.1.2']]], - ['Project 1.2', [['Project 1.2.1'], ['Project 1.2.2'], ['Project 1.2.3']]] - ] - ], - [ - 'Project 2' - ], - [ - 'Project 3', [['Project 3.1'], ['Project 3.2']] - ] -]; - - function buildProjectTree(tree: any[], level = 0): Array> { const projects = tree.map((t, idx) => ({ id: `l${level}i${idx}${t[0]}`, @@ -45,28 +32,35 @@ function buildProjectTree(tree: any[], level = 0): Array> { })); return projects; } - - const history = createBrowserHistory(); const projects = buildProjectTree(sampleProjects); const store = configureStore({ - projects, + projects: [ + ], router: { location: null + }, + auth: { + user: undefined } }, history); +store.dispatch(authActions.INIT()); +store.dispatch(projectService.getProjectList()); + + const App = () =>
- + +
; ReactDOM.render( - , + , document.getElementById('root') as HTMLElement ); diff --git a/src/models/project.ts b/src/models/project.ts index d730bcdf..f4faf7d6 100644 --- a/src/models/project.ts +++ b/src/models/project.ts @@ -5,5 +5,9 @@ export interface Project { name: string; createdAt: string; + modifiedAt: string; + uuid: string; + ownerUuid: string; + href: string; icon?: any; } diff --git a/src/models/user.ts b/src/models/user.ts new file mode 100644 index 00000000..f1780d5d --- /dev/null +++ b/src/models/user.ts @@ -0,0 +1,9 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +export interface User { + email: string; + firstName: string; + lastName: string; +} diff --git a/src/services/auth-service/auth-service.ts b/src/services/auth-service/auth-service.ts new file mode 100644 index 00000000..da593c2d --- /dev/null +++ b/src/services/auth-service/auth-service.ts @@ -0,0 +1,77 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { API_HOST, serverApi } from "../../common/api/server-api"; +import { User } from "../../models/user"; +import { Dispatch } from "redux"; +import actions from "../../store/auth/auth-action"; + +export const API_TOKEN_KEY = 'apiToken'; +export const USER_EMAIL_KEY = 'userEmail'; +export const USER_FIRST_NAME_KEY = 'userFirstName'; +export const USER_LAST_NAME_KEY = 'userLastName'; + +export interface UserDetailsResponse { + email: string; + first_name: string; + last_name: string; + is_admin: boolean; +} + +export default class AuthService { + + public saveApiToken(token: string) { + localStorage.setItem(API_TOKEN_KEY, token); + } + + public removeApiToken() { + localStorage.removeItem(API_TOKEN_KEY); + } + + public getApiToken() { + return localStorage.getItem(API_TOKEN_KEY) || undefined; + } + + public getUser(): User | undefined { + const email = localStorage.getItem(USER_EMAIL_KEY); + const firstName = localStorage.getItem(USER_FIRST_NAME_KEY); + const lastName = localStorage.getItem(USER_LAST_NAME_KEY); + return email && firstName && lastName + ? { email, firstName, lastName } + : undefined; + } + + public saveUser(user: User) { + localStorage.setItem(USER_EMAIL_KEY, user.email); + localStorage.setItem(USER_FIRST_NAME_KEY, user.firstName); + localStorage.setItem(USER_LAST_NAME_KEY, user.lastName); + } + + public removeUser() { + localStorage.removeItem(USER_EMAIL_KEY); + localStorage.removeItem(USER_FIRST_NAME_KEY); + localStorage.removeItem(USER_LAST_NAME_KEY); + } + + public login() { + const currentUrl = `${window.location.protocol}//${window.location.host}/token`; + window.location.assign(`${API_HOST}/login?return_to=${currentUrl}`); + } + + public logout() { + const currentUrl = `${window.location.protocol}//${window.location.host}`; + window.location.assign(`${API_HOST}/logout?return_to=${currentUrl}`); + } + + public getUserDetails = () => (dispatch: Dispatch) => { + dispatch(actions.USER_DETAILS_REQUEST()); + serverApi + .get('/users/current') + .then(resp => { + dispatch(actions.USER_DETAILS_SUCCESS(resp.data)); + }) + // .catch(err => { + // }); + }; +} diff --git a/src/services/project-service/project-service.ts b/src/services/project-service/project-service.ts new file mode 100644 index 00000000..87272d42 --- /dev/null +++ b/src/services/project-service/project-service.ts @@ -0,0 +1,56 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { serverApi } from "../../common/api/server-api"; +import { Dispatch } from "redux"; +import actions from "../../store/project/project-action"; +import { Project } from "../../models/project"; +import UrlBuilder from "../../common/api/url-builder"; +import FilterBuilder, { FilterField } from "../../common/api/filter-builder"; + +interface GroupsResponse { + offset: number; + limit: number; + items: Array<{ + href: string; + kind: string; + etag: string; + uuid: string; + owner_uuid: string; + created_at: string; + modified_by_client_uuid: string; + modified_by_user_uuid: string; + modified_at: string; + name: string; + group_class: string; + description: string; + writable_by: string[]; + delete_at: string; + trash_at: string; + is_trashed: boolean; + }>; +} + +export default class ProjectService { + public getProjectList = (parentUuid?: string) => (dispatch: Dispatch) => { + dispatch(actions.PROJECTS_REQUEST()); + + const ub = new UrlBuilder('/groups'); + const fb = new FilterBuilder(); + fb.addEqual(FilterField.UUID, parentUuid); + const url = ub.addParam('filter', fb.get()).get(); + + serverApi.get(url).then(groups => { + const projects = groups.data.items.map(g => ({ + name: g.name, + createdAt: g.created_at, + modifiedAt: g.modified_at, + href: g.href, + uuid: g.uuid, + ownerUuid: g.owner_uuid + } as Project)); + dispatch(actions.PROJECTS_SUCCESS(projects)); + }); + }; +} diff --git a/src/services/services.ts b/src/services/services.ts new file mode 100644 index 00000000..ea72001a --- /dev/null +++ b/src/services/services.ts @@ -0,0 +1,9 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import AuthService from "./auth-service/auth-service"; +import ProjectService from "./project-service/project-service"; + +export const authService = new AuthService(); +export const projectService = new ProjectService(); diff --git a/src/store/auth/auth-action.ts b/src/store/auth/auth-action.ts new file mode 100644 index 00000000..e18c78b1 --- /dev/null +++ b/src/store/auth/auth-action.ts @@ -0,0 +1,21 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { ofType, default as unionize, UnionOf } from "unionize"; +import { UserDetailsResponse } from "../../services/auth-service/auth-service"; + +const actions = unionize({ + SAVE_API_TOKEN: ofType(), + LOGIN: {}, + LOGOUT: {}, + INIT: {}, + USER_DETAILS_REQUEST: {}, + USER_DETAILS_SUCCESS: ofType() +}, { + tag: 'type', + value: 'payload' +}); + +export type AuthAction = UnionOf; +export default actions; diff --git a/src/store/auth/auth-reducer.test.ts b/src/store/auth/auth-reducer.test.ts new file mode 100644 index 00000000..17bd4217 --- /dev/null +++ b/src/store/auth/auth-reducer.test.ts @@ -0,0 +1,102 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import authReducer from "./auth-reducer"; +import actions from "./auth-action"; +import { + API_TOKEN_KEY, + USER_EMAIL_KEY, + USER_FIRST_NAME_KEY, + USER_LAST_NAME_KEY +} from "../../services/auth-service/auth-service"; +import { API_HOST } from "../../common/api/server-api"; + +import 'jest-localstorage-mock'; + +describe('auth-reducer', () => { + beforeAll(() => { + localStorage.clear(); + }); + + it('should return default state on initialisation', () => { + const initialState = undefined; + const state = authReducer(initialState, actions.INIT()); + expect(state).toEqual({ + apiToken: undefined, + user: undefined + }); + }); + + it('should read user and api token from local storage on init if they are there', () => { + const initialState = undefined; + + localStorage.setItem(API_TOKEN_KEY, "token"); + localStorage.setItem(USER_EMAIL_KEY, "test@test.com"); + localStorage.setItem(USER_FIRST_NAME_KEY, "John"); + localStorage.setItem(USER_LAST_NAME_KEY, "Doe"); + + const state = authReducer(initialState, actions.INIT()); + expect(state).toEqual({ + apiToken: "token", + user: { + email: "test@test.com", + firstName: "John", + lastName: "Doe" + } + }); + }); + + it('should store token in local storage', () => { + const initialState = undefined; + + const state = authReducer(initialState, actions.SAVE_API_TOKEN("token")); + expect(state).toEqual({ + apiToken: "token", + user: undefined + }); + + expect(localStorage.getItem(API_TOKEN_KEY)).toBe("token"); + }); + + it('should set user details on success fetch', () => { + const initialState = undefined; + + const userDetails = { + email: "test@test.com", + first_name: "John", + last_name: "Doe", + is_admin: true + }; + + const state = authReducer(initialState, actions.USER_DETAILS_SUCCESS(userDetails)); + expect(state).toEqual({ + apiToken: undefined, + user: { + email: "test@test.com", + firstName: "John", + lastName: "Doe" + } + }); + + expect(localStorage.getItem(API_TOKEN_KEY)).toBe("token"); + }); + + it('should fire external url to login', () => { + const initialState = undefined; + window.location.assign = jest.fn(); + authReducer(initialState, actions.LOGIN()); + expect(window.location.assign).toBeCalledWith( + `${API_HOST}/login?return_to=${window.location.protocol}//${window.location.host}/token` + ); + }); + + it('should fire external url to logout', () => { + const initialState = undefined; + window.location.assign = jest.fn(); + authReducer(initialState, actions.LOGOUT()); + expect(window.location.assign).toBeCalledWith( + `${API_HOST}/logout?return_to=${location.protocol}//${location.host}` + ); + }); +}); diff --git a/src/store/auth/auth-reducer.ts b/src/store/auth/auth-reducer.ts new file mode 100644 index 00000000..57a17ae5 --- /dev/null +++ b/src/store/auth/auth-reducer.ts @@ -0,0 +1,55 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import actions, { AuthAction } from "./auth-action"; +import { User } from "../../models/user"; +import { authService } from "../../services/services"; +import { removeServerApiAuthorizationHeader, setServerApiAuthorizationHeader } from "../../common/api/server-api"; +import { UserDetailsResponse } from "../../services/auth-service/auth-service"; + +export interface AuthState { + user?: User; + apiToken?: string; +}; + +const authReducer = (state: AuthState = {}, action: AuthAction) => { + return actions.match(action, { + SAVE_API_TOKEN: (token: string) => { + authService.saveApiToken(token); + setServerApiAuthorizationHeader(token); + return {...state, apiToken: token}; + }, + INIT: () => { + const user = authService.getUser(); + const token = authService.getApiToken(); + if (token) { + setServerApiAuthorizationHeader(token); + } + return {user, apiToken: token}; + }, + LOGIN: () => { + authService.login(); + return state; + }, + LOGOUT: () => { + authService.removeApiToken(); + authService.removeUser(); + removeServerApiAuthorizationHeader(); + authService.logout(); + return {...state, apiToken: undefined}; + }, + USER_DETAILS_SUCCESS: (ud: UserDetailsResponse) => { + const user = { + email: ud.email, + firstName: ud.first_name, + lastName: ud.last_name + }; + authService.saveUser(user); + return {...state, user}; + }, + default: () => state + }); +}; + +export default authReducer; diff --git a/src/store/project/project-action.ts b/src/store/project/project-action.ts new file mode 100644 index 00000000..21016195 --- /dev/null +++ b/src/store/project/project-action.ts @@ -0,0 +1,20 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { Project } from "../../models/project"; +import { default as unionize, ofType, UnionOf } from "unionize"; + +const actions = unionize({ + CREATE_PROJECT: ofType(), + REMOVE_PROJECT: ofType(), + PROJECTS_REQUEST: {}, + PROJECTS_SUCCESS: ofType(), + TOGGLE_PROJECT_TREE_ITEM: ofType() +}, { + tag: 'type', + value: 'payload' +}); + +export type ProjectAction = UnionOf; +export default actions; diff --git a/src/store/project/project-reducer.test.ts b/src/store/project/project-reducer.test.ts new file mode 100644 index 00000000..0bcf9428 --- /dev/null +++ b/src/store/project/project-reducer.test.ts @@ -0,0 +1,39 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import projectsReducer from "./project-reducer"; +import actions from "./project-action"; + +describe('project-reducer', () => { + it('should add new project to the list', () => { + const initialState = undefined; + const project = { + name: 'test', + href: 'href', + createdAt: '2018-01-01', + modifiedAt: '2018-01-01', + ownerUuid: 'owner-test123', + uuid: 'test123' + }; + + const state = projectsReducer(initialState, actions.CREATE_PROJECT(project)); + expect(state).toEqual([project]); + }); + + it('should load projects', () => { + const initialState = undefined; + const project = { + name: 'test', + href: 'href', + createdAt: '2018-01-01', + modifiedAt: '2018-01-01', + ownerUuid: 'owner-test123', + uuid: 'test123' + }; + + const projects = [project, project]; + const state = projectsReducer(initialState, actions.PROJECTS_SUCCESS(projects)); + expect(state).toEqual(projects); + }); +}); diff --git a/src/store/project/project-reducer.ts b/src/store/project/project-reducer.ts new file mode 100644 index 00000000..458177c0 --- /dev/null +++ b/src/store/project/project-reducer.ts @@ -0,0 +1,57 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: AGPL-3.0 + +import { Project } from "../../models/project"; +import actions, { ProjectAction } from "./project-action"; +import { TreeItem } from "../../components/tree/tree"; +import * as _ from "lodash"; + +export type ProjectState = Array>; + +function findTreeItem(tree: Array>, itemId: string): TreeItem | undefined { + let item; + for (const t of tree) { + item = t.id === itemId + ? t + : findTreeItem(t.items ? t.items : [], itemId); + if (item) { + break; + } + } + return item; +} + +function resetTreeActivity(tree: Array>): boolean | undefined { + let item; + for (const leaf of tree) { + item = leaf.active === true + ? leaf.active = false + : resetTreeActivity(leaf.items ? leaf.items : []); + } + return item; +} + +const projectsReducer = (state: ProjectState = [], action: ProjectAction) => { + return actions.match(action, { + CREATE_PROJECT: project => [...state, project], + REMOVE_PROJECT: () => state, + PROJECTS_REQUEST: () => state, + PROJECTS_SUCCESS: projects => { + return projects; + }, + TOGGLE_PROJECT_TREE_ITEM: itemId => { + const tree = _.cloneDeep(state); + resetTreeActivity(tree); + const item = findTreeItem(tree, itemId); + if (item) { + item.open = !item.open; + item.active = true; + } + return tree; + }, + default: () => state + }); +}; + +export default projectsReducer; diff --git a/src/store/root-reducer.ts b/src/store/root-reducer.ts deleted file mode 100644 index f86eed0e..00000000 --- a/src/store/root-reducer.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -import { combineReducers } from "redux"; -import { StateType } from "typesafe-actions"; -import projectsReducer from "./project-reducer"; -import { routerReducer } from "react-router-redux"; - -const rootReducer = combineReducers({ - projects: projectsReducer, - router: routerReducer -}); - -export type RootState = StateType; - -export default rootReducer; diff --git a/src/store/store.ts b/src/store/store.ts index 975debe8..d541156e 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -2,19 +2,35 @@ // // SPDX-License-Identifier: AGPL-3.0 -import { createStore, applyMiddleware, compose, Middleware } from 'redux'; -import { default as rootReducer, RootState } from "./root-reducer"; -import { routerMiddleware } from "react-router-redux"; +import { createStore, applyMiddleware, compose, Middleware, combineReducers } from 'redux'; +import { routerMiddleware, routerReducer, RouterState } from "react-router-redux"; +import thunkMiddleware from 'redux-thunk'; import { History } from "history"; +import projectsReducer, { ProjectState } from "./project/project-reducer"; +import authReducer, { AuthState } from "./auth/auth-reducer"; const composeEnhancers = (process.env.NODE_ENV === 'development' && window && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose; +export interface RootState { + auth: AuthState, + projects: ProjectState, + router: RouterState +} + +const rootReducer = combineReducers({ + auth: authReducer, + projects: projectsReducer, + router: routerReducer +}); + + export default function configureStore(initialState: RootState, history: History) { const middlewares: Middleware[] = [ - routerMiddleware(history) + routerMiddleware(history), + thunkMiddleware ]; const enhancer = composeEnhancers(applyMiddleware(...middlewares)); return createStore(rootReducer, initialState!, enhancer); diff --git a/src/views/workbench/workbench.test.tsx b/src/views/workbench/workbench.test.tsx index b1657bc3..7b9b74d0 100644 --- a/src/views/workbench/workbench.test.tsx +++ b/src/views/workbench/workbench.test.tsx @@ -14,7 +14,7 @@ const history = createBrowserHistory(); it('renders without crashing', () => { const div = document.createElement('div'); - const store = configureStore({ projects: [], router: { location: null } }, createBrowserHistory()); + const store = configureStore({ projects: [], router: { location: null }, auth: {} }, createBrowserHistory()); ReactDOM.render( diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx index 6f39ac78..7cccfe30 100644 --- a/src/views/workbench/workbench.tsx +++ b/src/views/workbench/workbench.tsx @@ -9,11 +9,21 @@ import Drawer from '@material-ui/core/Drawer'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; import Typography from '@material-ui/core/Typography'; -import { connect } from "react-redux"; -import { RootState } from "../../store/root-reducer"; +import { connect, DispatchProp } from "react-redux"; +import Tree from "../../components/tree/tree"; +import { Project } from "../../models/project"; import ProjectList from "../../components/project-list/project-list"; import { Route, Switch } from "react-router"; import { Link } from "react-router-dom"; +import Button from "@material-ui/core/Button/Button"; +import authActions from "../../store/auth/auth-action"; +import IconButton from "@material-ui/core/IconButton/IconButton"; +import Menu from "@material-ui/core/Menu/Menu"; +import MenuItem from "@material-ui/core/MenuItem/MenuItem"; +import { AccountCircle } from "@material-ui/icons"; +import { User } from "../../models/user"; +import Grid from "@material-ui/core/Grid/Grid"; +import { RootState } from "../../store/store"; import { actions as projectActions } from "../../store/project-action"; import ProjectTree, { WorkbenchProps } from '../../components/project-tree/project-tree'; @@ -29,8 +39,8 @@ const styles: StyleRulesCallback = (theme: Theme) => ({ overflow: 'hidden', position: 'relative', display: 'flex', - width: '100%', - height: '100%' + width: '100vw', + height: '100vh' }, appBar: { zIndex: theme.zIndex.drawer + 1, @@ -44,40 +54,117 @@ const styles: StyleRulesCallback = (theme: Theme) => ({ flexGrow: 1, backgroundColor: theme.palette.background.default, padding: theme.spacing.unit * 3, + height: '100%', minWidth: 0, }, toolbar: theme.mixins.toolbar }); -class Workbench extends React.Component> { +interface WorkbenchDataProps { + projects: Project[]; + user?: User; +} + +interface WorkbenchActionProps { +} + +type WorkbenchProps = WorkbenchDataProps & WorkbenchActionProps & DispatchProp & WithStyles; + +interface WorkbenchState { + anchorEl: any; +} + +class Workbench extends React.Component { + constructor(props: WorkbenchProps) { + super(props); + this.state = { + anchorEl: null + } + } + + login = () => { + this.props.dispatch(authActions.LOGIN()); + }; + + logout = () => { + this.handleClose(); + this.props.dispatch(authActions.LOGOUT()); + }; + + handleOpenMenu = (event: React.MouseEvent) => { + this.setState({ + anchorEl: event.currentTarget + }); + }; + + handleClose = () => { + this.setState({ + anchorEl: null + }); + }; + render() { - const { classes } = this.props; + const {classes, user} = this.props; return (
- - Arvados
Workbench 2 + + Arvados
Workbench 2
+ {user ? + + + + {user.firstName} {user.lastName} + + + + + + + + + Logout + My account + + + : + + }
+ {user && -
- + - + toggleProjectTreeItem={this.props.toggleProjectTreeItem}/> + }
-
+
- - Hello new workbench! - - +
@@ -85,10 +172,11 @@ class Workbench extends React.Component> { } } -export default connect( +export default connect( (state: RootState) => ({ - projects: state.projects - }), { + projects: state.projects, + user: state.auth.user + }){ toggleProjectTreeItem: (id: string) => projectActions.toggleProjectTreeItem(id) } )( diff --git a/yarn.lock b/yarn.lock index eadc3467..f3950fae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,35 +3,37 @@ "@babel/code-frame@^7.0.0-beta.35": - version "7.0.0-beta.47" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.47.tgz#d18c2f4c4ba8d093a2bcfab5616593bfe2441a27" + version "7.0.0-beta.49" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.49.tgz#becd805482734440c9d137e46d77340e64d7f51b" dependencies: - "@babel/highlight" "7.0.0-beta.47" + "@babel/highlight" "7.0.0-beta.49" -"@babel/highlight@7.0.0-beta.47": - version "7.0.0-beta.47" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.47.tgz#8fbc83fb2a21f0bd2b95cdbeb238cf9689cad494" +"@babel/highlight@7.0.0-beta.49": + version "7.0.0-beta.49" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.49.tgz#96bdc6b43e13482012ba6691b1018492d39622cc" dependencies: chalk "^2.0.0" esutils "^2.0.2" js-tokens "^3.0.0" "@babel/runtime@^7.0.0-beta.42": - version "7.0.0-beta.47" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.47.tgz#273f5e71629e80f6cbcd7507503848615e59f7e0" + version "7.0.0-beta.49" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.49.tgz#03b3bf07eb982072c8e851dd2ddd5110282e61bf" dependencies: - core-js "^2.5.3" + core-js "^2.5.6" regenerator-runtime "^0.11.1" -"@material-ui/core@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-1.0.0.tgz#857b871038bb300f2d25594ce0cd250be944e71b" +"@material-ui/core@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-1.2.0.tgz#ec372fd44f949faa604c4ccd4b7ee0bc5e08ac8c" dependencies: "@babel/runtime" "^7.0.0-beta.42" "@types/jss" "^9.5.3" "@types/react-transition-group" "^2.0.8" brcast "^3.0.1" classnames "^2.2.5" + csstype "^2.5.2" + debounce "^1.1.0" deepmerge "^2.0.1" dom-helpers "^3.2.1" hoist-non-react-statics "^2.5.0" @@ -43,17 +45,21 @@ jss-props-sort "^6.0.0" jss-vendor-prefixer "^7.0.0" keycode "^2.1.9" - lodash "^4.2.0" normalize-scroll-left "^0.1.2" prop-types "^15.6.0" - react-event-listener "^0.5.1" + react-event-listener "^0.6.0" react-jss "^8.1.0" react-popper "^0.10.0" - react-scrollbar-size "^2.0.2" react-transition-group "^2.2.1" recompose "^0.26.0 || ^0.27.0" scroll "^2.0.3" - warning "^3.0.0" + warning "^4.0.1" + +"@material-ui/icons@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-1.1.0.tgz#4d025df7b0ba6ace8d6710079ed76013a4d26595" + dependencies: + recompose "^0.26.0 || ^0.27.0" "@types/cheerio@*": version "0.22.7" @@ -76,9 +82,9 @@ version "4.6.2" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.6.2.tgz#12cfaba693ba20f114ed5765467ff25fdf67ddb0" -"@types/jest@22.2.3": - version "22.2.3" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-22.2.3.tgz#0157c0316dc3722c43a7b71de3fdf3acbccef10d" +"@types/jest@23.0.0": + version "23.0.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.0.0.tgz#760cac74f00bb9c3075587716d2b3b4435663bc0" "@types/jss@^9.5.3": version "9.5.3" @@ -91,9 +97,9 @@ version "4.14.109" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.109.tgz#b1c4442239730bf35cabaf493c772b18c045886d" -"@types/node@*", "@types/node@10.1.2": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.1.2.tgz#1b928a0baa408fc8ae3ac012cc81375addc147c6" +"@types/node@*", "@types/node@10.3.0": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.3.0.tgz#078516315a84d56216b5d4fed8f75d59d3b16cac" "@types/react-dom@16.0.5": version "16.0.5" @@ -102,46 +108,46 @@ "@types/node" "*" "@types/react" "*" -"@types/react-redux@6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-6.0.0.tgz#31711592b13ed6d6d2fd4506e5447b00e1f0b484" +"@types/react-redux@6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-6.0.1.tgz#bb8f6cc19d00a999f9d932ab796212ad3921994b" dependencies: "@types/react" "*" redux "^4.0.0" -"@types/react-router-dom@4.2.6": - version "4.2.6" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.2.6.tgz#9f7eb3c0e6661a9607d878ff8675cc4ea95cd276" +"@types/react-router-dom@4.2.7": + version "4.2.7" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.2.7.tgz#9d36bfe175f916dd8d7b6b0237feed6cce376b4c" dependencies: "@types/history" "*" "@types/react" "*" "@types/react-router" "*" -"@types/react-router-redux@5.0.14": - version "5.0.14" - resolved "https://registry.yarnpkg.com/@types/react-router-redux/-/react-router-redux-5.0.14.tgz#4f140248f65c74217e296854b1abe8c55e99764c" +"@types/react-router-redux@5.0.15": + version "5.0.15" + resolved "https://registry.yarnpkg.com/@types/react-router-redux/-/react-router-redux-5.0.15.tgz#aebc593bd3426adb6ae2eba6ac8c919ee232ce7b" dependencies: "@types/history" "*" "@types/react" "*" "@types/react-router" "*" - redux "^3.7.2" + redux ">= 3.7.2" -"@types/react-router@*", "@types/react-router@4.0.25": - version "4.0.25" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-4.0.25.tgz#1e25490780b80e0d8f96bf649379cca8638c1e5a" +"@types/react-router@*", "@types/react-router@4.0.26": + version "4.0.26" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-4.0.26.tgz#4489c873642baa633014294a6d0a290001ba9860" dependencies: "@types/history" "*" "@types/react" "*" "@types/react-transition-group@^2.0.8": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-2.0.9.tgz#ed6a71fb711e524345844defec2a861c1a222a03" + version "2.0.11" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-2.0.11.tgz#feb274676a39383fffaa0dff710958d2251abefb" dependencies: "@types/react" "*" -"@types/react@*", "@types/react@16.3.14": - version "16.3.14" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.14.tgz#f90ac6834de172e13ecca430dcb6814744225d36" +"@types/react@*", "@types/react@16.3.16": + version "16.3.16" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.16.tgz#78fc44a90b45701f50c8a7008f733680ba51fc86" dependencies: csstype "^2.2.0" @@ -184,8 +190,8 @@ acorn@^4.0.3: resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" acorn@^5.0.0, acorn@^5.3.0: - version "5.5.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" + version "5.6.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.6.1.tgz#c9e50c3e3717cf897f1b071ceadbb543bbc0a8d4" address@1.0.3, address@^1.0.1: version "1.0.3" @@ -290,8 +296,8 @@ aproba@^1.0.3, aproba@^1.1.1: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -467,6 +473,13 @@ aws4@^1.6.0: version "1.7.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" +axios@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" + dependencies: + follow-redirects "^1.3.0" + is-buffer "^1.1.5" + babel-code-frame@6.26.0, babel-code-frame@^6.11.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -1307,8 +1320,8 @@ bser@^2.0.0: node-int64 "^0.4.0" buffer-from@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" buffer-indexof@^1.0.0: version "1.1.1" @@ -1414,12 +1427,12 @@ 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.30000844" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000844.tgz#bca5798cda2b6931d68100c2d69e55fb338cbb41" + version "1.0.30000848" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000848.tgz#e149c981c72aa20439e3bc12c7cf8b3f7e1237c6" caniuse-lite@^1.0.30000748, caniuse-lite@^1.0.30000792: - version "1.0.30000844" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000844.tgz#de7c84cde0582143cf4f5abdf1b98e5a0539ad4a" + version "1.0.30000848" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000848.tgz#ec9c0a72ec8f9ef812e4f4b8628625af9c85ade0" capture-exit@^1.2.0: version "1.2.0" @@ -1784,9 +1797,9 @@ core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" -core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.3: - version "2.5.6" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.6.tgz#0fe6d45bf3cac3ac364a9d72de7576f4eb221b9d" +core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.6: + version "2.5.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -1984,15 +1997,15 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": version "0.3.2" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" -"cssstyle@>= 0.2.37 < 0.3.0": - version "0.2.37" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" +"cssstyle@>= 0.3.1 < 0.4.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.3.1.tgz#6da9b4cff1bc5d716e6e5fe8e04fcb1b50a49adf" dependencies: cssom "0.3.x" -csstype@^2.0.0, csstype@^2.2.0: - version "2.5.2" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.5.2.tgz#4534308476ceede8fbe148b9b99f9baf1c80fa06" +csstype@^2.0.0, csstype@^2.2.0, csstype@^2.5.2: + version "2.5.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.5.3.tgz#2504152e6e1cc59b32098b7f5d6a63f16294c1f7" currently-unhandled@^0.4.1: version "0.4.1" @@ -2028,6 +2041,10 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" +debounce@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.1.0.tgz#6a1a4ee2a9dc4b7c24bb012558dbcdb05b37f408" + debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -2052,17 +2069,17 @@ deep-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" -deep-extend@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.5.1.tgz#b894a9dd90d3023fbf1c55a394fb858eb2066f1f" +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" deepmerge@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.0.tgz#511a54fff405fc346f0240bb270a3e9533a31102" + version "2.1.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.1.tgz#e862b4e45ea0555072bf51e7fd0d9845170ae768" default-require-extensions@^1.0.0: version "1.0.0" @@ -2327,8 +2344,8 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30: - version "1.3.47" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.47.tgz#764e887ca9104d01a0ac8eabee7dfc0e2ce14104" + version "1.3.48" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz#d3b0d8593814044e092ece2108fc3ac9aea4b900" elliptic@^6.0.0: version "6.4.0" @@ -2429,16 +2446,6 @@ error-ex@^1.2.0: is-arrayish "^0.2.1" es-abstract@^1.5.1, es-abstract@^1.7.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" - dependencies: - 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-abstract@^1.6.1: version "1.12.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" dependencies: @@ -2457,8 +2464,8 @@ es-to-primitive@^1.1.1: is-symbol "^1.0.1" es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.42" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.42.tgz#8c07dd33af04d5dcd1310b5cef13bea63a89ba8d" + version "0.10.45" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" @@ -2902,7 +2909,7 @@ flush-write-stream@^1.0.0: inherits "^2.0.1" readable-stream "^2.0.4" -follow-redirects@^1.0.0: +follow-redirects@^1.0.0, follow-redirects@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.0.tgz#234f49cf770b7f35b40e790f636ceba0c3a0ab77" dependencies: @@ -3020,7 +3027,7 @@ fsevents@^1.0.0, fsevents@^1.1.2, fsevents@^1.1.3, fsevents@^1.2.3: nan "^2.9.2" node-pre-gyp "^0.10.0" -function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: +function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -3269,10 +3276,10 @@ has-values@^1.0.0: kind-of "^4.0.0" has@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" dependencies: - function-bind "^1.0.2" + function-bind "^1.1.1" hash-base@^3.0.0: version "3.0.4" @@ -3420,8 +3427,8 @@ http-errors@~1.6.2: statuses ">= 1.4.0 < 2" http-parser-js@>=0.4.0: - version "0.4.12" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.12.tgz#b9cfbf4a2cf26f0fc34b10ca1489a27771e3474f" + version "0.4.13" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" http-proxy-middleware@~0.17.4: version "0.17.4" @@ -3985,8 +3992,8 @@ istanbul-lib-source-maps@^1.2.1: source-map "^0.5.3" istanbul-lib-source-maps@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.4.tgz#cc7ccad61629f4efff8e2f78adb8c522c9976ec7" + version "1.2.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz#ffe6be4e7ab86d3603e4290d54990b14506fc9b1" dependencies: debug "^3.1.0" istanbul-lib-coverage "^1.2.0" @@ -4129,6 +4136,10 @@ jest-leak-detector@^22.4.0: dependencies: pretty-format "^22.4.3" +jest-localstorage-mock@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jest-localstorage-mock/-/jest-localstorage-mock-2.2.0.tgz#ce9a9de01dfdde2ad8aa08adf73acc7e5cc394cf" + jest-matcher-utils@^22.4.0, jest-matcher-utils@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.4.3.tgz#4632fe428ebc73ebc194d3c7b65d37b161f710ff" @@ -4268,8 +4279,8 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" js-yaml@^3.4.3, js-yaml@^3.7.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -4286,21 +4297,21 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" jsdom@^11.5.1: - version "11.10.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.10.0.tgz#a42cd54e88895dc765f03f15b807a474962ac3b5" + version "11.11.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.11.0.tgz#df486efad41aee96c59ad7a190e2449c7eb1110e" dependencies: abab "^1.0.4" acorn "^5.3.0" acorn-globals "^4.1.0" array-equal "^1.0.0" cssom ">= 0.3.2 < 0.4.0" - cssstyle ">= 0.2.37 < 0.3.0" + cssstyle ">= 0.3.1 < 0.4.0" data-urls "^1.0.0" domexception "^1.0.0" escodegen "^1.9.0" html-encoding-sniffer "^1.0.2" left-pad "^1.2.0" - nwmatcher "^1.4.3" + nwsapi "^2.0.0" parse5 "4.0.0" pn "^1.1.0" request "^2.83.0" @@ -4312,7 +4323,7 @@ jsdom@^11.5.1: webidl-conversions "^4.0.2" whatwg-encoding "^1.0.3" whatwg-mimetype "^2.1.0" - whatwg-url "^6.4.0" + whatwg-url "^6.4.1" ws "^4.0.0" xml-name-validator "^3.0.0" @@ -4453,8 +4464,8 @@ jss-vendor-prefixer@^7.0.0: css-vendor "^0.3.8" jss@^9.3.3, jss@^9.7.0: - version "9.8.1" - resolved "https://registry.yarnpkg.com/jss/-/jss-9.8.1.tgz#e2ff250777ad657430e6edc47a63516541b888fa" + version "9.8.2" + resolved "https://registry.yarnpkg.com/jss/-/jss-9.8.2.tgz#09cabdfba831545bf094e399cfa45a1743daf4a6" dependencies: is-in-browser "^1.1.3" symbol-observable "^1.1.0" @@ -4673,10 +4684,6 @@ lru-cache@^4.0.1, lru-cache@^4.1.1: pseudomap "^1.0.2" yallist "^2.1.2" -macaddress@^0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" - make-dir@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" @@ -4811,7 +4818,11 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.33.0 < 2", mime-db@~1.33.0: +"mime-db@>= 1.33.0 < 2": + version "1.34.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.34.0.tgz#452d0ecff5c30346a6dc1e64b1eaee0d3719ff9a" + +mime-db@~1.33.0: version "1.33.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" @@ -4871,11 +4882,11 @@ minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" -minipass@^2.2.1, minipass@^2.2.4: - version "2.3.1" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.1.tgz#4e872b959131a672837ab3cb554962bc84b1537d" +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" dependencies: - safe-buffer "^5.1.1" + safe-buffer "^5.1.2" yallist "^3.0.0" minizlib@^1.1.0: @@ -5155,9 +5166,9 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -nwmatcher@^1.4.3: - version "1.4.4" - resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e" +nwsapi@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.1.tgz#a50d59a2dcb14b6931401171713ced2d0eb3468f" oauth-sign@~0.8.2: version "0.8.2" @@ -5604,11 +5615,10 @@ postcss-discard-unused@^2.2.1: uniqs "^2.0.0" postcss-filter-plugins@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" + version "2.0.3" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz#82245fdf82337041645e477114d8e593aa18b8ec" dependencies: postcss "^5.0.4" - uniqid "^4.0.0" postcss-flexbugs-fixes@3.2.0: version "3.2.0" @@ -5952,8 +5962,8 @@ punycode@^1.2.4, punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" punycode@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" q@^1.1.2: version "1.5.1" @@ -6044,10 +6054,10 @@ raw-body@2.3.2: unpipe "1.0.0" rc@^1.0.1, rc@^1.1.6, rc@^1.1.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.7.tgz#8a10ca30d588d00464360372b890d06dacd02297" + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" dependencies: - deep-extend "^0.5.1" + deep-extend "^0.6.0" ini "~1.3.0" minimist "^1.2.0" strip-json-comments "~2.0.1" @@ -6075,9 +6085,9 @@ react-dev-utils@^5.0.1: strip-ansi "3.0.1" text-table "0.2.0" -react-dom@16.3.2: - version "16.3.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.2.tgz#cb90f107e09536d683d84ed5d4888e9640e0e4df" +react-dom@16.4.0: + version "16.4.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -6088,12 +6098,11 @@ react-error-overlay@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4" -react-event-listener@^0.5.1: - version "0.5.6" - resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.5.6.tgz#f9349fda4b7735fc6886ca403bdcfd6057e89ceb" +react-event-listener@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.0.tgz#f8cf2821f5ca1844e0df1dac1c7b9a3ecb686fd7" dependencies: "@babel/runtime" "^7.0.0-beta.42" - fbjs "^0.8.16" prop-types "^15.6.0" warning "^3.0.0" @@ -6243,9 +6252,9 @@ react-transition-group@^2.2.1: loose-envify "^1.3.1" prop-types "^15.6.1" -react@16.3.2: - version "16.3.2" - resolved "https://registry.yarnpkg.com/react/-/react-16.3.2.tgz#fdc8420398533a1e58872f59091b272ce2f91ea9" +react@16.4.0: + version "16.4.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.4.0.tgz#402c2db83335336fba1962c08b98c6272617d585" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -6371,14 +6380,18 @@ redux-devtools@3.4.1: prop-types "^15.5.7" redux-devtools-instrument "^1.0.1" -redux@4.0.0, redux@^4.0.0: +redux-thunk@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" + +redux@4.0.0, "redux@>= 3.7.2", redux@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.0.tgz#aa698a92b729315d22b34a0553d7e6533555cc03" dependencies: loose-envify "^1.1.0" symbol-observable "^1.2.0" -redux@^3.6.0, redux@^3.7.2: +redux@^3.6.0: version "3.7.2" resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b" dependencies: @@ -7047,10 +7060,6 @@ stealthy-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" -stifle@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/stifle/-/stifle-1.0.4.tgz#8b3bcdf52419b0a9c79e35adadce50123c1d8e99" - stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -7066,8 +7075,8 @@ stream-each@^1.1.0: stream-shift "^1.0.0" stream-http@^2.7.2: - version "2.8.2" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.2.tgz#4126e8c6b107004465918aa2fc35549e77402c87" + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" @@ -7098,7 +7107,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -7245,12 +7254,12 @@ tapable@^0.2.7: resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" tar@^4: - version "4.4.2" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.2.tgz#60685211ba46b38847b1ae7ee1a24d744a2cd462" + version "4.4.4" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" dependencies: chownr "^1.0.1" fs-minipass "^1.2.5" - minipass "^2.2.4" + minipass "^2.3.3" minizlib "^1.1.0" mkdirp "^0.5.0" safe-buffer "^5.1.2" @@ -7423,8 +7432,8 @@ tsconfig-paths@^3.1.1: strip-json-comments "^2.0.1" tslib@^1.8.0, tslib@^1.8.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.1.tgz#a5d1f0532a49221c87755cfcc89ca37197242ba7" + version "1.9.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.2.tgz#8be0cc9a1f6dc7727c38deb16c2ebd1a2892988e" tslint-config-prettier@^1.10.0: version "1.13.0" @@ -7490,13 +7499,9 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typesafe-actions@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/typesafe-actions/-/typesafe-actions-2.0.3.tgz#5451a4f8bf0d1e79f7d12af7582cc5f12d490708" - -typescript@2.8.3: - version "2.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.3.tgz#5d817f9b6f31bb871835f4edf0089f21abe6c170" +typescript@2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.1.tgz#fdb19d2c67a15d11995fd15640e373e09ab09961" ua-parser-js@^0.7.9: version "0.7.18" @@ -7509,9 +7514,9 @@ uglify-es@^3.3.4: commander "~2.13.0" source-map "~0.6.1" -uglify-js@3.3.x, uglify-js@^3.0.13: - version "3.3.26" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.26.tgz#858b74e5e7262e876c834b907a5fa57d4fa0d525" +uglify-js@3.3.x: + version "3.3.28" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.28.tgz#0efb9a13850e11303361c1051f64d2ec68d9be06" dependencies: commander "~2.15.0" source-map "~0.6.1" @@ -7525,6 +7530,13 @@ uglify-js@^2.6, uglify-js@^2.8.29: optionalDependencies: uglify-to-browserify "~1.0.0" +uglify-js@^3.0.13: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.0.tgz#796762282b5b5f0eafe7d5c8c708d1d7bd5ba11d" + dependencies: + commander "~2.15.0" + source-map "~0.6.1" + uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" @@ -7563,16 +7575,14 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" +unionize@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/unionize/-/unionize-2.1.2.tgz#2513b148de515bec93f045d1685bd88eab62b608" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" -uniqid@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" - dependencies: - macaddress "^0.2.8" - uniqs@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" @@ -7638,8 +7648,8 @@ upper-case@^1.1.1: resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" uri-js@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.1.tgz#4595a80a51f356164e22970df64c7abd6ade9850" + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" dependencies: punycode "^2.1.0" @@ -7696,12 +7706,18 @@ util.promisify@^1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" -util@0.10.3, util@^0.10.3: +util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" dependencies: inherits "2.0.1" +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + dependencies: + inherits "2.0.3" + utila@~0.3: version "0.3.3" resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" @@ -7773,6 +7789,12 @@ warning@^3.0.0: dependencies: loose-envify "^1.0.0" +warning@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.1.tgz#66ce376b7fbfe8a887c22bdf0e7349d73d397745" + dependencies: + loose-envify "^1.0.0" + watch@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" @@ -7910,7 +7932,7 @@ whatwg-mimetype@^2.0.0, whatwg-mimetype@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz#f0f21d76cbba72362eb609dbed2a30cd17fcc7d4" -whatwg-url@^6.4.0: +whatwg-url@^6.4.0, whatwg-url@^6.4.1: version "6.4.1" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.1.tgz#fdb94b440fd4ad836202c16e9737d511f012fd67" dependencies: @@ -7931,16 +7953,16 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" dependencies: - string-width "^1.0.2" + string-width "^1.0.2 || 2" widest-line@^2.0.0: version "2.0.0"