"version": "0.1.0",
"private": true,
"dependencies": {
- "@material-ui/core": "1.2.0",
- "@material-ui/icons": "^1.1.0",
- "@types/lodash": "^4.14.109",
+ "@material-ui/core": "1.2.1",
+ "@material-ui/icons": "1.1.0",
+ "@types/lodash": "4.14.109",
"axios": "0.18.0",
"lodash": "4.17.10",
- "react": "16.4.0",
- "react-dom": "16.4.0",
+ "react": "16.4.1",
+ "react-dom": "16.4.1",
"react-redux": "5.0.7",
- "react-router": "4.2.0",
- "react-router-dom": "4.2.2",
+ "react-router": "4.3.1",
+ "react-router-dom": "4.3.1",
"react-router-redux": "5.0.0-alpha.9",
"react-scripts-ts": "2.16.0",
"redux": "4.0.0",
"lint": "tslint src/** -t verbose"
},
"devDependencies": {
- "@types/enzyme": "^3.1.10",
- "@types/enzyme-adapter-react-16": "^1.0.2",
- "@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.1",
+ "@types/enzyme": "3.1.10",
+ "@types/enzyme-adapter-react-16": "1.0.2",
+ "@types/jest": "23.1.0",
+ "@types/node": "10.3.3",
+ "@types/react": "16.3.18",
+ "@types/react-dom": "16.0.6",
+ "@types/react-redux": "6.0.2",
"@types/react-router": "4.0.26",
"@types/react-router-dom": "4.2.7",
"@types/react-router-redux": "5.0.15",
"enzyme-adapter-react-16": "^1.1.1",
"jest-localstorage-mock": "2.2.0",
"redux-devtools": "3.4.1",
- "typescript": "2.9.1"
+ "typescript": "2.9.2"
},
"moduleNameMapper": {
"^~/(.*)$": "<rootDir>/src/$1"
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export const formatDate = (isoDate: string) => {
+ const date = new Date(isoDate);
+ return date.toLocaleString();
+};
+
+export const formatFileSize = (size?: number) => {
+ if (typeof size === "number") {
+ for (const { base, unit } of fileSizes) {
+ if (size >= base) {
+ return `${(size / base).toFixed()} ${unit}`;
+ }
+ }
+ }
+ return "";
+};
+
+const fileSizes = [
+ {
+ base: 1000000000000,
+ unit: "TB"
+ },
+ {
+ base: 1000000000,
+ unit: "GB"
+ },
+ {
+ base: 1000000,
+ unit: "MB"
+ },
+ {
+ base: 1000,
+ unit: "KB"
+ },
+ {
+ base: 1,
+ unit: "B"
+ }
+];
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { DataTable, DataTableProps, DataColumn, ColumnSelector } from "../../components/data-table";
+import { Typography, Grid, ListItem, Divider, List, ListItemIcon, ListItemText, Paper, Toolbar } from '@material-ui/core';
+import IconButton, { IconButtonProps } from '@material-ui/core/IconButton';
+import MoreVertIcon from "@material-ui/icons/MoreVert";
+import Popover from '../popover/popover';
+import { formatFileSize, formatDate } from '../../common/formatters';
+import { DataItem } from './data-item';
+
+interface DataExplorerProps {
+ items: DataItem[];
+ onItemClick: (item: DataItem) => void;
+}
+
+type DataExplorerState = Pick<DataTableProps<DataItem>, "columns">;
+
+class DataExplorer extends React.Component<DataExplorerProps, DataExplorerState> {
+ state: DataExplorerState = {
+ columns: [
+ {
+ name: "Name",
+ selected: true,
+ render: item => this.renderName(item)
+ },
+ {
+ name: "Status",
+ selected: true,
+ render: item => renderStatus(item.status)
+ },
+ {
+ name: "Type",
+ selected: true,
+ render: item => renderType(item.type)
+ },
+ {
+ name: "Owner",
+ selected: true,
+ render: item => renderOwner(item.owner)
+ },
+ {
+ name: "File size",
+ selected: true,
+ render: (item) => renderFileSize(item.fileSize)
+ },
+ {
+ name: "Last modified",
+ selected: true,
+ render: item => renderDate(item.lastModified)
+ },
+ {
+ name: "Actions",
+ selected: true,
+ configurable: false,
+ renderHeader: () => null,
+ render: renderItemActions
+ }
+ ]
+ };
+
+ render() {
+ return <Paper>
+ <Toolbar>
+ <Grid container justify="flex-end">
+ <ColumnSelector
+ columns={this.state.columns}
+ onColumnToggle={this.toggleColumn} />
+ </Grid>
+ </Toolbar>
+ <DataTable
+ columns={this.state.columns}
+ items={this.props.items} />
+ <Toolbar />
+ </Paper>;
+ }
+
+ toggleColumn = (column: DataColumn<DataItem>) => {
+ const index = this.state.columns.indexOf(column);
+ const columns = this.state.columns.slice(0);
+ columns.splice(index, 1, { ...column, selected: !column.selected });
+ this.setState({ columns });
+ }
+
+ renderName = (item: DataItem) =>
+ <Grid
+ container
+ alignItems="center"
+ wrap="nowrap"
+ spacing={16}
+ onClick={() => this.props.onItemClick(item)}>
+ <Grid item>
+ {renderIcon(item)}
+ </Grid>
+ <Grid item>
+ <Typography color="primary">
+ {item.name}
+ </Typography>
+ </Grid>
+ </Grid>
+
+}
+
+const renderIcon = (dataItem: DataItem) => {
+ switch (dataItem.type) {
+ case "arvados#group":
+ return <i className="fas fa-folder fa-lg" />;
+ case "arvados#groupList":
+ return <i className="fas fa-th fa-lg" />;
+ default:
+ return <i />;
+ }
+};
+
+const renderDate = (date: string) =>
+ <Typography noWrap>
+ {formatDate(date)}
+ </Typography>;
+
+const renderFileSize = (fileSize?: number) =>
+ <Typography noWrap>
+ {formatFileSize(fileSize)}
+ </Typography>;
+
+const renderOwner = (owner: string) =>
+ <Typography noWrap color="primary">
+ {owner}
+ </Typography>;
+
+const renderType = (type: string) =>
+ <Typography noWrap>
+ {type}
+ </Typography>;
+
+const renderStatus = (status?: string) =>
+ <Typography noWrap align="center">
+ {status || "-"}
+ </Typography>;
+
+const renderItemActions = () =>
+ <Grid container justify="flex-end">
+ <Popover triggerComponent={ItemActionsTrigger}>
+ <List dense>
+ {[{
+ icon: "fas fa-users",
+ label: "Share"
+ },
+ {
+ icon: "fas fa-sign-out-alt",
+ label: "Move to"
+ },
+ {
+ icon: "fas fa-star",
+ label: "Add to favourite"
+ },
+ {
+ icon: "fas fa-edit",
+ label: "Rename"
+ },
+ {
+ icon: "fas fa-copy",
+ label: "Make a copy"
+ },
+ {
+ icon: "fas fa-download",
+ label: "Download"
+ }].map(renderAction)}
+ < Divider />
+ {renderAction({ icon: "fas fa-trash-alt", label: "Remove" })}
+ </List>
+ </Popover>
+ </Grid>;
+
+const renderAction = (action: { label: string, icon: string }, index?: number) =>
+ <ListItem button key={index}>
+ <ListItemIcon>
+ <i className={action.icon} />
+ </ListItemIcon>
+ <ListItemText>
+ {action.label}
+ </ListItemText>
+ </ListItem>;
+
+const ItemActionsTrigger: React.SFC<IconButtonProps> = (props) =>
+ <IconButton {...props}>
+ <MoreVertIcon />
+ </IconButton>;
+
+export default DataExplorer;
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export interface DataItem {
+ name: string;
+ type: string;
+ owner: string;
+ lastModified: string;
+ fileSize?: number;
+ status?: string;
+}
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export { default as DataExplorer } from "./data-explorer";
+export * from "./data-item";
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { mount, configure } from "enzyme";
+import * as Adapter from "enzyme-adapter-react-16";
+import ColumnSelector, { ColumnSelectorProps, ColumnSelectorTrigger } from "./column-selector";
+import { DataColumn } from "../data-column";
+import { ListItem, Checkbox } from "@material-ui/core";
+
+configure({ adapter: new Adapter() });
+
+describe("<ColumnSelector />", () => {
+ it("shows only configurable columns", () => {
+ const columns: Array<DataColumn<void>> = [
+ {
+ name: "Column 1",
+ render: () => <span />,
+ selected: true
+ },
+ {
+ name: "Column 2",
+ render: () => <span />,
+ selected: true,
+ configurable: true,
+ },
+ {
+ name: "Column 3",
+ render: () => <span />,
+ selected: true,
+ configurable: false
+ }
+ ];
+ const columnsConfigurator = mount(<ColumnSelector columns={columns} onColumnToggle={jest.fn()} />);
+ columnsConfigurator.find(ColumnSelectorTrigger).simulate("click");
+ expect(columnsConfigurator.find(ListItem)).toHaveLength(2);
+ });
+
+ it("renders checked checkboxes next to selected columns", () => {
+ const columns: Array<DataColumn<void>> = [
+ {
+ name: "Column 1",
+ render: () => <span />,
+ selected: true
+ },
+ {
+ name: "Column 2",
+ render: () => <span />,
+ selected: false
+ },
+ {
+ name: "Column 3",
+ render: () => <span />,
+ selected: true
+ }
+ ];
+ const columnsConfigurator = mount(<ColumnSelector columns={columns} onColumnToggle={jest.fn()} />);
+ columnsConfigurator.find(ColumnSelectorTrigger).simulate("click");
+ expect(columnsConfigurator.find(Checkbox).at(0).prop("checked")).toBe(true);
+ expect(columnsConfigurator.find(Checkbox).at(1).prop("checked")).toBe(false);
+ expect(columnsConfigurator.find(Checkbox).at(2).prop("checked")).toBe(true);
+ });
+
+ it("calls onColumnToggle with clicked column", () => {
+ const columns: Array<DataColumn<void>> = [
+ {
+ name: "Column 1",
+ render: () => <span />,
+ selected: true
+ }
+ ];
+ const onColumnToggle = jest.fn();
+ const columnsConfigurator = mount(<ColumnSelector columns={columns} onColumnToggle={onColumnToggle} />);
+ columnsConfigurator.find(ColumnSelectorTrigger).simulate("click");
+ columnsConfigurator.find(ListItem).simulate("click");
+ expect(onColumnToggle).toHaveBeenCalledWith(columns[0]);
+ });
+});
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { WithStyles, StyleRulesCallback, Theme, withStyles, IconButton, Paper, List, Checkbox, ListItemText, ListItem } from '@material-ui/core';
+import MenuIcon from "@material-ui/icons/Menu";
+import { DataColumn, isColumnConfigurable } from '../data-column';
+import Popover from "../../popover/popover";
+import { IconButtonProps } from '@material-ui/core/IconButton';
+
+export interface ColumnSelectorProps {
+ columns: Array<DataColumn<any>>;
+ onColumnToggle: (column: DataColumn<any>) => void;
+}
+
+const ColumnSelector: React.SFC<ColumnSelectorProps & WithStyles<CssRules>> = ({ columns, onColumnToggle, classes }) =>
+ <Popover triggerComponent={ColumnSelectorTrigger}>
+ <Paper>
+ <List dense>
+ {columns
+ .filter(isColumnConfigurable)
+ .map((column, index) => (
+ <ListItem
+ button
+ key={index}
+ onClick={() => onColumnToggle(column)}>
+ <Checkbox
+ disableRipple
+ color="primary"
+ checked={column.selected}
+ className={classes.checkbox} />
+ <ListItemText>
+ {column.name}
+ </ListItemText>
+ </ListItem>
+ ))}
+ </List>
+ </Paper>
+ </Popover>;
+
+export const ColumnSelectorTrigger: React.SFC<IconButtonProps> = (props) =>
+ <IconButton {...props}>
+ <MenuIcon />
+ </IconButton>;
+
+type CssRules = "checkbox";
+
+const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
+ checkbox: {
+ width: 24,
+ height: 24
+ }
+});
+
+export default withStyles(styles)(ColumnSelector);
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export interface DataColumn<T> {
+ name: string;
+ selected: boolean;
+ configurable?: boolean;
+ key?: React.Key;
+ render: (item: T) => React.ReactElement<void>;
+ renderHeader?: () => React.ReactElement<void> | null;
+}
+
+export const isColumnConfigurable = <T>(column: DataColumn<T>) => {
+ return column.configurable === undefined || column.configurable;
+};
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { mount, configure } from "enzyme";
+import * as Adapter from "enzyme-adapter-react-16";
+import DataTable from "./data-table";
+import { DataColumn } from "./data-column";
+import { TableHead, TableCell, Typography, TableBody, Button } from "@material-ui/core";
+
+configure({ adapter: new Adapter() });
+
+describe("<DataTable />", () => {
+ it("shows only selected columns", () => {
+ const columns: Array<DataColumn<string>> = [
+ {
+ name: "Column 1",
+ render: () => <span />,
+ selected: true
+ },
+ {
+ name: "Column 2",
+ render: () => <span />,
+ selected: true
+ },
+ {
+ name: "Column 3",
+ render: () => <span />,
+ selected: false
+ }
+ ];
+ const dataTable = mount(<DataTable columns={columns} items={["item 1"]}/>);
+ expect(dataTable.find(TableHead).find(TableCell)).toHaveLength(2);
+ });
+
+ it("renders column name", () => {
+ const columns: Array<DataColumn<string>> = [
+ {
+ name: "Column 1",
+ render: () => <span />,
+ selected: true
+ }
+ ];
+ const dataTable = mount(<DataTable columns={columns} items={["item 1"]}/>);
+ expect(dataTable.find(TableHead).find(TableCell).text()).toBe("Column 1");
+ });
+
+ it("uses renderHeader instead of name prop", () => {
+ const columns: Array<DataColumn<string>> = [
+ {
+ name: "Column 1",
+ renderHeader: () => <span>Column Header</span>,
+ render: () => <span />,
+ selected: true
+ }
+ ];
+ const dataTable = mount(<DataTable columns={columns} items={["item 1"]}/>);
+ expect(dataTable.find(TableHead).find(TableCell).text()).toBe("Column Header");
+ });
+
+ it("passes column key prop to corresponding cells", () => {
+ const columns: Array<DataColumn<string>> = [
+ {
+ name: "Column 1",
+ key: "column-1-key",
+ render: () => <span />,
+ selected: true
+ }
+ ];
+ const dataTable = mount(<DataTable columns={columns} items={["item 1"]}/>);
+ expect(dataTable.find(TableHead).find(TableCell).key()).toBe("column-1-key");
+ expect(dataTable.find(TableBody).find(TableCell).key()).toBe("column-1-key");
+ });
+
+ it("shows information that items array is empty", () => {
+ const columns: Array<DataColumn<string>> = [
+ {
+ name: "Column 1",
+ render: () => <span />,
+ selected: true
+ }
+ ];
+ const dataTable = mount(<DataTable columns={columns} items={[]}/>);
+ expect(dataTable.find(Typography).text()).toBe("No items");
+ });
+
+ it("renders items", () => {
+ const columns: Array<DataColumn<string>> = [
+ {
+ name: "Column 1",
+ render: (item) => <Typography>{item}</Typography>,
+ selected: true
+ },
+ {
+ name: "Column 2",
+ render: (item) => <Button>{item}</Button>,
+ selected: true
+ }
+ ];
+ const dataTable = mount(<DataTable columns={columns} items={["item 1"]}/>);
+ expect(dataTable.find(TableBody).find(Typography).text()).toBe("item 1");
+ expect(dataTable.find(TableBody).find(Button).text()).toBe("item 1");
+ });
+
+
+});
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { Table, TableBody, TableRow, TableCell, TableHead, StyleRulesCallback, Theme, WithStyles, withStyles, Typography } from '@material-ui/core';
+import { DataColumn } from './data-column';
+
+export interface DataTableProps<T> {
+ items: T[];
+ columns: Array<DataColumn<T>>;
+ onItemClick?: (item: T) => void;
+}
+
+class DataTable<T> extends React.Component<DataTableProps<T> & WithStyles<CssRules>> {
+ render() {
+ const { items, columns, classes, onItemClick } = this.props;
+ return <div className={classes.tableContainer}>
+ {items.length > 0 ?
+ <Table>
+ <TableHead>
+ <TableRow>
+ {columns
+ .filter(column => column.selected)
+ .map(({ name, renderHeader, key }, index) =>
+ <TableCell key={key || index}>
+ {renderHeader ? renderHeader() : name}
+ </TableCell>
+ )}
+ </TableRow>
+ </TableHead>
+ <TableBody className={classes.tableBody}>
+ {items
+ .map((item, index) =>
+ <TableRow
+ hover
+ key={index}
+ onClick={() => onItemClick && onItemClick(item)}>
+ {columns
+ .filter(column => column.selected)
+ .map((column, index) => (
+ <TableCell key={column.key || index}>
+ {column.render(item)}
+ </TableCell>
+ ))}
+ </TableRow>
+ )}
+ </TableBody>
+ </Table> : <Typography
+ className={classes.noItemsInfo}
+ variant="body2"
+ gutterBottom>
+ No items
+ </Typography>}
+ </div>;
+ }
+}
+
+type CssRules = "tableBody" | "tableContainer" | "noItemsInfo";
+
+const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
+ tableContainer: {
+ overflowX: 'auto'
+ },
+ tableBody: {
+ background: theme.palette.background.paper
+ },
+ noItemsInfo: {
+ textAlign: "center",
+ padding: theme.spacing.unit
+ }
+});
+
+export default withStyles(styles)(DataTable);
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+export * from "./data-column";
+export * from "./column-selector/column-selector";
+export { default as ColumnSelector } from "./column-selector/column-selector";
+export * from "./data-table";
+export { default as DataTable } from "./data-table";
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from "react";
+import { mount, configure } from "enzyme";
+import * as Adapter from "enzyme-adapter-react-16";
+
+import Popover, { DefaultTrigger } from "./popover";
+import Button, { ButtonProps } from "@material-ui/core/Button";
+
+configure({ adapter: new Adapter() });
+
+describe("<Popover />", () => {
+ it("opens on default trigger click", () => {
+ const popover = mount(<Popover />);
+ popover.find(DefaultTrigger).simulate("click");
+ expect(popover.state().anchorEl).toBeDefined();
+ });
+
+ it("renders custom trigger", () => {
+ const popover = mount(<Popover triggerComponent={CustomTrigger} />);
+ expect(popover.find(Button).text()).toBe("Open popover");
+ });
+
+ it("opens on custom trigger click", () => {
+ const popover = mount(<Popover triggerComponent={CustomTrigger} />);
+ popover.find(CustomTrigger).simulate("click");
+ expect(popover.state().anchorEl).toBeDefined();
+ });
+
+ it("renders children when opened", () => {
+ const popover = mount(
+ <Popover>
+ <CustomTrigger />
+ </Popover>
+ );
+ popover.find(DefaultTrigger).simulate("click");
+ expect(popover.find(CustomTrigger)).toHaveLength(1);
+ });
+
+ it("does not close if closeOnContentClick is not set", () => {
+ const popover = mount(
+ <Popover>
+ <CustomTrigger />
+ </Popover>
+ );
+ popover.find(DefaultTrigger).simulate("click");
+ popover.find(CustomTrigger).simulate("click");
+ expect(popover.state().anchorEl).toBeDefined();
+ });
+ it("closes on content click if closeOnContentClick is set", () => {
+ const popover = mount(
+ <Popover closeOnContentClick>
+ <CustomTrigger />
+ </Popover>
+ );
+ popover.find(DefaultTrigger).simulate("click");
+ popover.find(CustomTrigger).simulate("click");
+ expect(popover.state().anchorEl).toBeUndefined();
+ });
+
+});
+
+const CustomTrigger: React.SFC<ButtonProps> = (props) => (
+ <Button {...props}>
+ Open popover
+ </Button>
+);
\ No newline at end of file
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { Popover as MaterialPopover } from '@material-ui/core';
+
+import { PopoverOrigin } from '@material-ui/core/Popover';
+import IconButton, { IconButtonProps } from '@material-ui/core/IconButton';
+
+export interface PopoverProps {
+ triggerComponent?: React.ComponentType<{ onClick: (event: React.MouseEvent<any>) => void }>;
+ closeOnContentClick?: boolean;
+}
+
+
+class Popover extends React.Component<PopoverProps> {
+
+ state = {
+ anchorEl: undefined
+ };
+
+ transformOrigin: PopoverOrigin = {
+ vertical: "top",
+ horizontal: "right",
+ };
+
+ render() {
+ const Trigger = this.props.triggerComponent || DefaultTrigger;
+ return (
+ <>
+ <Trigger onClick={this.handleTriggerClick} />
+ <MaterialPopover
+ anchorEl={this.state.anchorEl}
+ open={Boolean(this.state.anchorEl)}
+ onClose={this.handleClose}
+ onClick={this.handleSelfClick}
+ transformOrigin={this.transformOrigin}
+ anchorOrigin={this.transformOrigin}
+ >
+ {this.props.children}
+ </MaterialPopover>
+ </>
+ );
+ }
+
+ handleClose = () => {
+ this.setState({ anchorEl: undefined });
+ }
+
+ handleTriggerClick = (event: React.MouseEvent<any>) => {
+ this.setState({ anchorEl: event.currentTarget });
+ }
+
+ handleSelfClick = () => {
+ if (this.props.closeOnContentClick) {
+ this.handleClose();
+ }
+ }
+
+}
+
+export const DefaultTrigger: React.SFC<IconButtonProps> = (props) => (
+ <IconButton {...props}>
+ <i className="fas" />
+ </IconButton>
+);
+
+export default Popover;
import * as Adapter from 'enzyme-adapter-react-16';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import { Collapse } from '@material-ui/core';
+import CircularProgress from '@material-ui/core/CircularProgress';
import ProjectTree from './project-tree';
import { TreeItem } from '../tree/tree';
describe("ProjectTree component", () => {
- it("checks is there ListItemIcon in the ProjectTree component", () => {
+ it("should render ListItemIcon", () => {
const project: TreeItem<Project> = {
data: {
name: "sample name",
},
id: "3",
open: true,
- active: true
+ active: true,
+ status: 1
};
const wrapper = mount(<ProjectTree projects={[project]} toggleProjectTreeItem={() => { }} />);
- expect(wrapper.find(ListItemIcon).length).toEqual(1);
+ expect(wrapper.find(ListItemIcon)).toHaveLength(1);
});
- it("checks are there two ListItemIcon's in the ProjectTree component", () => {
+ it("should render 2 ListItemIcons", () => {
const project: Array<TreeItem<Project>> = [
{
data: {
},
id: "3",
open: false,
- active: true
+ active: true,
+ status: 1
},
{
data: {
},
id: "3",
open: false,
- active: true
+ active: true,
+ status: 1
}
];
const wrapper = mount(<ProjectTree projects={project} toggleProjectTreeItem={() => { }} />);
- expect(wrapper.find(ListItemIcon).length).toEqual(2);
+ expect(wrapper.find(ListItemIcon)).toHaveLength(2);
});
- it("check ProjectTree, when open is changed", () => {
+ it("should render Collapse", () => {
+ const project: Array<TreeItem<Project>> = [
+ {
+ data: {
+ name: "sample name",
+ createdAt: "2018-06-12",
+ modifiedAt: "2018-06-13",
+ uuid: "uuid",
+ ownerUuid: "ownerUuid",
+ href: "href",
+ },
+ id: "3",
+ open: true,
+ active: true,
+ status: 2,
+ items: [
+ {
+ data: {
+ name: "sample name",
+ createdAt: "2018-06-12",
+ modifiedAt: "2018-06-13",
+ uuid: "uuid",
+ ownerUuid: "ownerUuid",
+ href: "href",
+ },
+ id: "3",
+ open: true,
+ active: true,
+ status: 1
+ }
+ ]
+ }
+ ];
+ const wrapper = mount(<ProjectTree projects={project} toggleProjectTreeItem={() => { }} />);
+
+ expect(wrapper.find(Collapse)).toHaveLength(1);
+ });
+
+ it("should render CircularProgress", () => {
const project: TreeItem<Project> = {
data: {
name: "sample name",
href: "href",
},
id: "3",
- open: true,
+ open: false,
active: true,
- items: [
- {
- data: {
- name: "sample name",
- createdAt: "2018-06-12",
- modifiedAt: "2018-06-13",
- uuid: "uuid",
- ownerUuid: "ownerUuid",
- href: "href",
- },
- id: "4",
- open: false,
- active: true
- }
- ]
+ status: 1
};
const wrapper = mount(<ProjectTree projects={[project]} toggleProjectTreeItem={() => { }} />);
- wrapper.setState({open: true });
- expect(wrapper.find(Collapse).length).toEqual(1);
+ expect(wrapper.find(CircularProgress)).toHaveLength(1);
});
});
import ListItemIcon from '@material-ui/core/ListItemIcon';
import Typography from '@material-ui/core/Typography';
-import Tree, { TreeItem } from '../tree/tree';
+import Tree, { TreeItem, TreeItemStatus } from '../tree/tree';
import { Project } from '../../models/project';
type CssRules = 'active' | 'listItemText' | 'row' | 'treeContainer';
marginLeft: '20px',
},
treeContainer: {
- position: 'absolute',
+ marginTop: '37px',
overflowX: 'visible',
- marginTop: '80px',
+ overflowY: 'auto',
minWidth: '240px',
whiteSpace: 'nowrap',
}
export interface ProjectTreeProps {
projects: Array<TreeItem<Project>>;
- toggleProjectTreeItem: (id: string) => void;
+ toggleProjectTreeItem: (id: string, status: TreeItemStatus) => void;
}
class ProjectTree<T> extends React.Component<ProjectTreeProps & WithStyles<CssRules>> {
// Copyright (C) The Arvados Authors. All rights reserved.
//
// SPDX-License-Identifier: AGPL-3.0
+import * as React from 'react';
+import { mount } from 'enzyme';
+import * as Enzyme from 'enzyme';
+import * as Adapter from 'enzyme-adapter-react-16';
+import { Collapse } from '@material-ui/core';
+import CircularProgress from '@material-ui/core/CircularProgress';
+import ListItem from "@material-ui/core/ListItem/ListItem";
-it("should render the tree", () => {
- expect(true).toBe(true);
-});
\ No newline at end of file
+import Tree, {TreeItem} from './tree';
+import { Project } from '../../models/project';
+Enzyme.configure({ adapter: new Adapter() });
+
+describe("Tree component", () => {
+
+ it("should render ListItem", () => {
+ const project: TreeItem<Project> = {
+ data: {
+ name: "sample name",
+ createdAt: "2018-06-12",
+ modifiedAt: "2018-06-13",
+ uuid: "uuid",
+ ownerUuid: "ownerUuid",
+ href: "href",
+ },
+ id: "3",
+ open: true,
+ active: true,
+ status: 1,
+ };
+ const wrapper = mount(<Tree render={project => <div/>} toggleItem={() => { }} items={[project]}/>)
+ expect(wrapper.find(ListItem)).toHaveLength(1);
+ });
+
+ it("should render arrow", () => {
+ const project: TreeItem<Project> = {
+ data: {
+ name: "sample name",
+ createdAt: "2018-06-12",
+ modifiedAt: "2018-06-13",
+ uuid: "uuid",
+ ownerUuid: "ownerUuid",
+ href: "href",
+ },
+ id: "3",
+ open: true,
+ active: true,
+ status: 1,
+ };
+ const wrapper = mount(<Tree render={project => <div/>} toggleItem={() => { }} items={[project]}/>)
+ expect(wrapper.find('i')).toHaveLength(1);
+ });
+});
import { StyleRulesCallback, Theme, withStyles, WithStyles } from '@material-ui/core/styles';
import { ReactElement } from "react";
import Collapse from "@material-ui/core/Collapse/Collapse";
+import CircularProgress from '@material-ui/core/CircularProgress';
+import { inherits } from 'util';
-type CssRules = 'list' | 'activeArrow' | 'arrow' | 'arrowRotate';
+type CssRules = 'list' | 'activeArrow' | 'inactiveArrow' | 'arrowRotate' | 'arrowTransition' | 'loader' | 'arrowVisibility';
const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
list: {
color: '#4285F6',
position: 'absolute',
},
- arrow: {
+ inactiveArrow: {
position: 'absolute',
},
+ arrowTransition: {
+ transition: 'all 0.1s ease',
+ },
arrowRotate: {
+ transition: 'all 0.1s ease',
transform: 'rotate(-90deg)',
+ },
+ arrowVisibility: {
+ opacity: 0,
+ },
+ loader: {
+ position: 'absolute',
+ transform: 'translate(0px)',
+ top: '3px'
}
});
+export enum TreeItemStatus {
+ Initial,
+ Pending,
+ Loaded
+}
+
export interface TreeItem<T> {
data: T;
id: string;
open: boolean;
active: boolean;
+ status: TreeItemStatus;
+ toggled?: boolean;
items?: Array<TreeItem<T>>;
}
interface TreeProps<T> {
items?: Array<TreeItem<T>>;
render: (item: TreeItem<T>, level?: number) => ReactElement<{}>;
- toggleItem: (id: string) => any;
+ toggleItem: (id: string, status: TreeItemStatus) => any;
level?: number;
}
class Tree<T> extends React.Component<TreeProps<T> & WithStyles<CssRules>, {}> {
- renderArrow (items: boolean, arrowClass: string, open: boolean){
- return <i className={`${arrowClass} ${open ? "fas fa-caret-down" : `fas fa-caret-down ${this.props.classes.arrowRotate}`}`} />;
+ renderArrow(status: TreeItemStatus, arrowClass: string, open: boolean, id: string) {
+ return <i
+ onClick={() => this.props.toggleItem(id, status)}
+ className={`
+ ${arrowClass}
+ ${status === TreeItemStatus.Pending ? this.props.classes.arrowVisibility : ''}
+ ${open ? `fas fa-caret-down ${this.props.classes.arrowTransition}` : `fas fa-caret-down ${this.props.classes.arrowRotate}`}`} />;
}
render(): ReactElement<any> {
const level = this.props.level ? this.props.level : 0;
- const {classes, render, toggleItem, items} = this.props;
- const {list, arrow, activeArrow} = classes;
+ const { classes, render, toggleItem, items } = this.props;
+ const { list, inactiveArrow, activeArrow, loader } = classes;
return <List component="div" className={list}>
{items && items.map((it: TreeItem<T>, idx: number) =>
- <div key={`item/${level}/${idx}`}>
- <ListItem button onClick={() => toggleItem(it.id)} className={list} style={{paddingLeft: (level + 1) * 20}}>
- {this.renderArrow(true, it.active ? activeArrow : arrow, it.open)}
- {render(it, level)}
- </ListItem>
- {it.items && it.items.length > 0 &&
- <Collapse in={it.open} timeout="auto" unmountOnExit>
- <StyledTree
- items={it.items}
- render={render}
- toggleItem={toggleItem}
- level={level + 1}/>
- </Collapse>}
- </div>)}
+ <div key={`item/${level}/${idx}`}>
+ <ListItem button className={list} style={{ paddingLeft: (level + 1) * 20 }}>
+ {it.status === TreeItemStatus.Pending ? <CircularProgress size={10} className={loader} /> : null}
+ {it.toggled && it.items && it.items.length === 0 ? null : this.renderArrow(it.status, it.active ? activeArrow : inactiveArrow, it.open, it.id)}
+ {render(it, level)}
+ </ListItem>
+ {it.items && it.items.length > 0 &&
+ <Collapse in={it.open} timeout="auto" unmountOnExit>
+ <StyledTree
+ items={it.items}
+ render={render}
+ toggleItem={toggleItem}
+ level={level + 1} />
+ </Collapse>}
+ </div>)}
</List>;
}
}
uuid: string;
ownerUuid: string;
href: string;
+ kind: string;
}
export default class ProjectService {
public getProjectList = (parentUuid?: string) => (dispatch: Dispatch): Promise<Project[]> => {
- dispatch(actions.PROJECTS_REQUEST());
+ dispatch(actions.PROJECTS_REQUEST(parentUuid));
if (parentUuid) {
const fb = new FilterBuilder();
fb.addLike(FilterField.OWNER_UUID, parentUuid);
modifiedAt: g.modified_at,
href: g.href,
uuid: g.uuid,
- ownerUuid: g.owner_uuid
+ ownerUuid: g.owner_uuid,
+ kind: g.kind
} as Project));
dispatch(actions.PROJECTS_SUCCESS({projects, parentItemId: parentUuid}));
return projects;
const actions = unionize({
CREATE_PROJECT: ofType<Project>(),
REMOVE_PROJECT: ofType<string>(),
- PROJECTS_REQUEST: {},
+ PROJECTS_REQUEST: ofType<any>(),
PROJECTS_SUCCESS: ofType<{ projects: Project[], parentItemId?: string }>(),
TOGGLE_PROJECT_TREE_ITEM: ofType<string>()
}, {
import projectsReducer, { findTreeBranch } from "./project-reducer";
import actions from "./project-action";
-import { TreeItem } from "../../components/tree/tree";
+import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
describe('project-reducer', () => {
it('should add new project to the list', () => {
createdAt: '2018-01-01',
modifiedAt: '2018-01-01',
ownerUuid: 'owner-test123',
- uuid: 'test123'
+ uuid: 'test123',
+ kind: ""
};
const state = projectsReducer(initialState, actions.CREATE_PROJECT(project));
createdAt: '2018-01-01',
modifiedAt: '2018-01-01',
ownerUuid: 'owner-test123',
- uuid: 'test123'
+ uuid: 'test123',
+ kind: ""
};
const projects = [project, project];
const state = projectsReducer(initialState, actions.PROJECTS_SUCCESS({ projects, parentItemId: undefined }));
expect(state).toEqual([{
- active: false,
- open: false,
- id: "test123",
- items: [],
- data: project
- }, {
- active: false,
- open: false,
- id: "test123",
- items: [],
- data: project
- }
+ active: false,
+ open: false,
+ id: "test123",
+ items: [],
+ data: project,
+ status: 0
+ }, {
+ active: false,
+ open: false,
+ id: "test123",
+ items: [],
+ data: project,
+ status: 0
+ }
]);
});
});
active: false,
data: "",
open: false,
+ status: TreeItemStatus.Initial
});
it("should return an array that matches path to the given item", () => {
import { Project } from "../../models/project";
import actions, { ProjectAction } from "./project-action";
-import { TreeItem } from "../../components/tree/tree";
+import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
import * as _ from "lodash";
export type ProjectState = Array<TreeItem<Project>>;
-function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
+export function findTreeItem<T>(tree: Array<TreeItem<T>>, itemId: string): TreeItem<T> | undefined {
let item;
for (const t of tree) {
item = t.id === itemId
let treeItem;
if (parentItemId) {
treeItem = findTreeItem(tree, parentItemId);
+ if (treeItem) {
+ treeItem.status = TreeItemStatus.Loaded;
+ }
}
const items = projects.map((p, idx) => ({
id: p.uuid,
open: false,
active: false,
+ status: TreeItemStatus.Initial,
data: p,
items: []
} as TreeItem<Project>));
return items;
}
-
const projectsReducer = (state: ProjectState = [], action: ProjectAction) => {
return actions.match(action, {
CREATE_PROJECT: project => [...state, project],
REMOVE_PROJECT: () => state,
- PROJECTS_REQUEST: () => state,
+ PROJECTS_REQUEST: itemId => {
+ const tree = _.cloneDeep(state);
+ const item = findTreeItem(tree, itemId);
+ if (item) {
+ item.status = TreeItemStatus.Pending;
+ }
+ return tree;
+ },
PROJECTS_SUCCESS: ({ projects, parentItemId }) => {
return updateProjectTree(state, projects, parentItemId);
},
if (item) {
item.open = !item.open;
item.active = true;
+ item.toggled = true;
}
return tree;
},
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { DataTableProps } from "../../components/data-table";
+import { RouteComponentProps } from 'react-router';
+import { Project } from '../../models/project';
+import { ProjectState, findTreeItem } from '../../store/project/project-reducer';
+import { RootState } from '../../store/store';
+import { connect, DispatchProp } from 'react-redux';
+import { push } from 'react-router-redux';
+import projectActions from "../../store/project/project-action";
+import { DataExplorer, DataItem } from '../../components/data-explorer';
+import { TreeItem } from '../../components/tree/tree';
+
+interface DataExplorerViewDataProps {
+ projects: ProjectState;
+}
+
+type DataExplorerViewProps = DataExplorerViewDataProps & RouteComponentProps<{ name: string }> & DispatchProp;
+
+type DataExplorerViewState = Pick<DataTableProps<Project>, "columns">;
+
+interface MappedProjectItem extends DataItem {
+ uuid: string;
+}
+
+class DataExplorerView extends React.Component<DataExplorerViewProps, DataExplorerViewState> {
+
+ render() {
+ const project = findTreeItem(this.props.projects, this.props.match.params.name);
+ const projectItems = project && project.items || [];
+ return (
+ <DataExplorer
+ items={projectItems.map(mapTreeItem)}
+ onItemClick={this.goToProject}
+ />
+ );
+ }
+
+ goToProject = (project: MappedProjectItem) => {
+ this.props.dispatch(push(`/project/${project.uuid}`));
+ this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(project.uuid));
+ }
+
+}
+
+const mapTreeItem = (item: TreeItem<Project>): MappedProjectItem => ({
+ name: item.data.name,
+ type: item.data.kind,
+ owner: item.data.ownerUuid,
+ lastModified: item.data.modifiedAt,
+ uuid: item.data.uuid
+});
+
+
+export default connect(
+ (state: RootState) => ({
+ projects: state.projects
+ })
+)(DataExplorerView);
import { StyleRulesCallback, Theme, WithStyles, withStyles } from '@material-ui/core/styles';
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, DispatchProp } from "react-redux";
-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 MainAppBar, { MainAppBarActionProps, MainAppBarMenuItems, MainAppBarMenuItem } from '../../components/main-app-bar/main-app-bar';
+import MainAppBar, { MainAppBarActionProps, MainAppBarMenuItem } from '../../components/main-app-bar/main-app-bar';
import { Breadcrumb } from '../../components/breadcrumbs/breadcrumbs';
import { push } from 'react-router-redux';
import projectActions from "../../store/project/project-action";
import ProjectTree from '../../components/project-tree/project-tree';
-import { TreeItem } from "../../components/tree/tree";
+import { TreeItem, TreeItemStatus } from "../../components/tree/tree";
import { Project } from "../../models/project";
import { projectService } from '../../services/services';
import { findTreeBranch } from '../../store/project/project-reducer';
+import DataExplorer from '../data-explorer/data-explorer';
const drawerWidth = 240;
interface NavBreadcrumb extends Breadcrumb {
itemId: string;
+ status: TreeItemStatus;
}
interface NavMenuItem extends MainAppBarMenuItem {
mainAppBarActions: MainAppBarActionProps = {
- onBreadcrumbClick: ({ itemId }: NavBreadcrumb) => {
- this.toggleProjectTreeItem(itemId);
+ onBreadcrumbClick: ({ itemId, status }: NavBreadcrumb) => {
+ this.toggleProjectTreeItem(itemId, status);
},
onSearch: searchText => {
this.setState({ searchText });
onMenuItemClick: (menuItem: NavMenuItem) => menuItem.action()
};
- toggleProjectTreeItem = (itemId: string) => {
+ toggleProjectTreeItem = (itemId: string, status: TreeItemStatus) => {
+ if (status === TreeItemStatus.Loaded) {
+ this.openProjectItem(itemId);
+ } else {
+ this.props.dispatch<any>(projectService.getProjectList(itemId)).then(() => this.openProjectItem(itemId));
+ }
+ }
+
+ openProjectItem = (itemId: string) => {
const branch = findTreeBranch(this.props.projects, itemId);
this.setState({
breadcrumbs: branch.map(item => ({
label: item.data.name,
- itemId: item.data.uuid
+ itemId: item.data.uuid,
+ status: item.status
}))
});
- this.props.dispatch<any>(projectService.getProjectList(itemId)).then(() => {
- this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(itemId));
- });
+ this.props.dispatch(projectActions.TOGGLE_PROJECT_TREE_ITEM(itemId));
+ this.props.dispatch(push(`/project/${itemId}`));
}
render() {
<div className={classes.toolbar} />
<div className={classes.toolbar} />
<Switch>
- <Route path="/project/:name" component={ProjectList} />
+ <Route path="/project/:name" component={DataExplorer} />
</Switch>
</main>
</div>
"@babel/code-frame@^7.0.0-beta.35":
- version "7.0.0-beta.49"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.49.tgz#becd805482734440c9d137e46d77340e64d7f51b"
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.51.tgz#bd71d9b192af978df915829d39d4094456439a0c"
dependencies:
- "@babel/highlight" "7.0.0-beta.49"
+ "@babel/highlight" "7.0.0-beta.51"
-"@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"
+"@babel/highlight@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.51.tgz#e8844ae25a1595ccfd42b89623b4376ca06d225d"
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.49"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.49.tgz#03b3bf07eb982072c8e851dd2ddd5110282e61bf"
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.51.tgz#48b8ed18307034c6620f643514650ca2ccc0165a"
dependencies:
- core-js "^2.5.6"
+ core-js "^2.5.7"
regenerator-runtime "^0.11.1"
-"@material-ui/core@1.2.0":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-1.2.0.tgz#ec372fd44f949faa604c4ccd4b7ee0bc5e08ac8c"
+"@material-ui/core@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-1.2.1.tgz#f8c73da10b875762b37be7167ec2ac79b027499f"
dependencies:
"@babel/runtime" "^7.0.0-beta.42"
"@types/jss" "^9.5.3"
scroll "^2.0.3"
warning "^4.0.1"
-"@material-ui/icons@^1.1.0":
+"@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:
version "0.22.7"
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce"
-"@types/enzyme-adapter-react-16@^1.0.2":
+"@types/enzyme-adapter-react-16@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.2.tgz#15ae37c64d6221a6f4b3a4aacc357cf773859de4"
dependencies:
"@types/enzyme" "*"
-"@types/enzyme@*", "@types/enzyme@^3.1.10":
+"@types/enzyme@*", "@types/enzyme@3.1.10":
version "3.1.10"
resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.1.10.tgz#28108a9864e65699751469551a803a35d2e26160"
dependencies:
version "4.6.2"
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.6.2.tgz#12cfaba693ba20f114ed5765467ff25fdf67ddb0"
-"@types/jest@23.0.0":
- version "23.0.0"
- resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.0.0.tgz#760cac74f00bb9c3075587716d2b3b4435663bc0"
+"@types/jest@23.1.0":
+ version "23.1.0"
+ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.1.0.tgz#8054dd838ba23dc331794d26456b86c7e50bf0f6"
"@types/jss@^9.5.3":
version "9.5.3"
csstype "^2.0.0"
indefinite-observable "^1.0.1"
-"@types/lodash@^4.14.109":
+"@types/lodash@4.14.109":
version "4.14.109"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.109.tgz#b1c4442239730bf35cabaf493c772b18c045886d"
-"@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/node@*", "@types/node@10.3.3":
+ version "10.3.3"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.3.3.tgz#8798d9e39af2fa604f715ee6a6b19796528e46c3"
-"@types/react-dom@16.0.5":
- version "16.0.5"
- resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.5.tgz#a757457662e3819409229e8f86795ff37b371f96"
+"@types/react-dom@16.0.6":
+ version "16.0.6"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.6.tgz#f1a65a4e7be8ed5d123f8b3b9eacc913e35a1a3c"
dependencies:
"@types/node" "*"
"@types/react" "*"
-"@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"
+"@types/react-redux@6.0.2":
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-6.0.2.tgz#10069b53db8e0920fd8656e068dcf10c53c9ad2a"
dependencies:
"@types/react" "*"
redux "^4.0.0"
dependencies:
"@types/react" "*"
-"@types/react@*", "@types/react@16.3.16":
- version "16.3.16"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.16.tgz#78fc44a90b45701f50c8a7008f733680ba51fc86"
+"@types/react@*", "@types/react@16.3.18":
+ version "16.3.18"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.18.tgz#bf195aed4d77dc86f06e4c9bb760214a3b822b8d"
dependencies:
csstype "^2.2.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
acorn@^5.0.0, acorn@^5.3.0:
- version "5.6.1"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.6.1.tgz#c9e50c3e3717cf897f1b071ceadbb543bbc0a8d4"
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8"
address@1.0.3, address@^1.0.1:
version "1.0.3"
json-schema-traverse "^0.3.0"
ajv@^6.1.0:
- version "6.5.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.0.tgz#4c8affdf80887d8f132c9c52ab8a2dc4d0b7b24c"
+ version "6.5.1"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.1.tgz#88ebc1263c7133937d108b80c5572e64e1d9322d"
dependencies:
fast-deep-equal "^2.0.1"
fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.3.0"
+ json-schema-traverse "^0.4.1"
uri-js "^4.2.1"
align-text@^0.1.1, align-text@^0.1.3:
micromatch "^3.1.4"
normalize-path "^2.1.1"
-append-transform@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+append-transform@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab"
dependencies:
- default-require-extensions "^1.0.0"
+ default-require-extensions "^2.0.0"
aproba@^1.0.3, aproba@^1.1.1:
version "1.2.0"
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
- version "1.0.30000848"
- resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000848.tgz#e149c981c72aa20439e3bc12c7cf8b3f7e1237c6"
+ version "1.0.30000856"
+ resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000856.tgz#fbebb99abe15a5654fc7747ebb5315bdfde3358f"
caniuse-lite@^1.0.30000748, caniuse-lite@^1.0.30000792:
- version "1.0.30000848"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000848.tgz#ec9c0a72ec8f9ef812e4f4b8628625af9c85ade0"
+ version "1.0.30000856"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000856.tgz#ecc16978135a6f219b138991eb62009d25ee8daa"
capture-exit@^1.2.0:
version "1.2.0"
static-extend "^0.1.1"
classnames@^2.2.5:
- version "2.2.5"
- resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
+ version "2.2.6"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
clean-css@4.1.x:
version "4.1.11"
object-visit "^1.0.0"
color-convert@^1.3.0, color-convert@^1.9.0:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
+ version "1.9.2"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147"
dependencies:
- color-name "^1.1.1"
+ color-name "1.1.1"
+
+color-name@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689"
-color-name@^1.0.0, color-name@^1.1.1:
+color-name@^1.0.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
compare-versions@^3.1.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.2.1.tgz#a49eb7689d4caaf0b6db5220173fd279614000f7"
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.3.0.tgz#af93ea705a96943f622ab309578b9b90586f39c3"
component-emitter@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
compressible@~2.0.13:
- version "2.0.13"
- resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9"
+ version "2.0.14"
+ resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7"
dependencies:
- mime-db ">= 1.33.0 < 2"
+ mime-db ">= 1.34.0 < 2"
compression@^1.5.2:
version "1.7.2"
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.6:
+core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7:
version "2.5.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
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"
- resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+default-require-extensions@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7"
dependencies:
- strip-bom "^2.0.0"
+ strip-bom "^3.0.0"
define-properties@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
escodegen@^1.9.0:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.1.tgz#dbae17ef96c8e4bedb1356f4504fa4cc2f7cb7e2"
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.10.0.tgz#f647395de22519fbd0d928ffcf1d17e0dec2603e"
dependencies:
esprima "^3.1.3"
estraverse "^4.2.0"
bser "^2.0.0"
fbjs@^0.8.1, fbjs@^0.8.16:
- version "0.8.16"
- resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
+ version "0.8.17"
+ resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
- ua-parser-js "^0.7.9"
+ ua-parser-js "^0.7.18"
figures@^2.0.0:
version "2.0.0"
safe-buffer "^5.0.1"
hash.js@^1.0.0, hash.js@^1.0.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846"
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.4.tgz#8b50e1f35d51bd01e5ed9ece4dbe3549ccfa0a3c"
dependencies:
inherits "^2.0.3"
minimalistic-assert "^1.0.0"
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
-hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40"
+hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0:
+ version "2.5.4"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.4.tgz#fc3b1ac05d2ae3abedec84eba846511b0d4fcc4f"
home-or-tmp@^2.0.0:
version "2.0.0"
postcss "^6.0.1"
ieee754@^1.1.4:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455"
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b"
iferr@^0.1.5:
version "0.1.5"
version "1.1.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
-invariant@^2.0.0, invariant@^2.2.1, invariant@^2.2.2:
+invariant@^2.0.0, invariant@^2.2.1, invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
dependencies:
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz#f7d8f2e42b97e37fe796114cb0f9d68b5e3a4341"
istanbul-lib-hook@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.0.tgz#ae556fd5a41a6e8efa0b1002b1e416dfeaf9816c"
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.1.tgz#f614ec45287b2a8fc4f07f5660af787575601805"
dependencies:
- append-transform "^0.4.0"
+ append-transform "^1.0.0"
istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.8.0:
version "1.10.1"
version "0.3.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
css-vendor "^0.3.8"
jss@^9.3.3, jss@^9.7.0:
- version "9.8.2"
- resolved "https://registry.yarnpkg.com/jss/-/jss-9.8.2.tgz#09cabdfba831545bf094e399cfa45a1743daf4a6"
+ version "9.8.3"
+ resolved "https://registry.yarnpkg.com/jss/-/jss-9.8.3.tgz#399da571c4b2c8f4cf418ca7e8627e44fc287fc8"
dependencies:
is-in-browser "^1.1.3"
symbol-observable "^1.1.0"
bn.js "^4.0.0"
brorand "^1.0.1"
-"mime-db@>= 1.33.0 < 2":
+"mime-db@>= 1.34.0 < 2":
version "1.34.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.34.0.tgz#452d0ecff5c30346a6dc1e64b1eaee0d3719ff9a"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
nwsapi@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.1.tgz#a50d59a2dcb14b6931401171713ced2d0eb3468f"
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.3.tgz#3f4010d6c943f34018d3dfb5f2fbc0de90476959"
oauth-sign@~0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
p-limit@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c"
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
dependencies:
p-try "^1.0.0"
dependencies:
asap "~2.0.3"
-prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1:
+prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1:
version "15.6.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
dependencies:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+psl@^1.1.24:
+ version "1.1.28"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b"
+
public-encrypt@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994"
strip-ansi "3.0.1"
text-table "0.2.0"
-react-dom@16.4.0:
- version "16.4.0"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e"
+react-dom@16.4.1:
+ version "16.4.1"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.1.tgz#7f8b0223b3a5fbe205116c56deb85de32685dad6"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.1.0"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4"
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"
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.1.tgz#41c7a80a66b398c27dd511e22712b02f3d4eccca"
dependencies:
"@babel/runtime" "^7.0.0-beta.42"
prop-types "^15.6.0"
- warning "^3.0.0"
+ warning "^4.0.1"
-react-is@^16.4.0:
- version "16.4.0"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.0.tgz#cc9fdc855ac34d2e7d9d2eb7059bbc240d35ffcf"
+react-is@^16.4.1:
+ version "16.4.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.1.tgz#d624c4650d2c65dbd52c72622bbf389435d9776e"
react-jss@^8.1.0:
- version "8.4.0"
- resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-8.4.0.tgz#7cb43d85dea56afafc8f0fd072ae27fcc0518950"
+ version "8.5.1"
+ resolved "https://registry.yarnpkg.com/react-jss/-/react-jss-8.5.1.tgz#f97c72f6a1c86aa6408932a2a2836ce40c0ab9fc"
dependencies:
- hoist-non-react-statics "^2.3.1"
+ hoist-non-react-statics "^2.5.0"
jss "^9.7.0"
jss-preset-default "^4.3.0"
prop-types "^15.6.0"
loose-envify "^1.1.0"
prop-types "^15.6.0"
-react-router-dom@4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.2.2.tgz#c8a81df3adc58bba8a76782e946cbd4eae649b8d"
+react-router-dom@4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6"
dependencies:
history "^4.7.2"
- invariant "^2.2.2"
+ invariant "^2.2.4"
loose-envify "^1.3.1"
- prop-types "^15.5.4"
- react-router "^4.2.0"
- warning "^3.0.0"
+ prop-types "^15.6.1"
+ react-router "^4.3.1"
+ warning "^4.0.1"
react-router-redux@5.0.0-alpha.9:
version "5.0.0-alpha.9"
prop-types "^15.6.0"
react-router "^4.2.0"
-react-router@4.2.0, react-router@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.2.0.tgz#61f7b3e3770daeb24062dae3eedef1b054155986"
+react-router@4.3.1, react-router@^4.2.0, react-router@^4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.3.1.tgz#aada4aef14c809cb2e686b05cee4742234506c4e"
dependencies:
history "^4.7.2"
- hoist-non-react-statics "^2.3.0"
- invariant "^2.2.2"
+ hoist-non-react-statics "^2.5.0"
+ invariant "^2.2.4"
loose-envify "^1.3.1"
path-to-regexp "^1.7.0"
- prop-types "^15.5.4"
- warning "^3.0.0"
+ prop-types "^15.6.1"
+ warning "^4.0.1"
react-scripts-ts@2.16.0:
version "2.16.0"
fsevents "^1.1.3"
react-test-renderer@^16.0.0-0:
- version "16.4.0"
- resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.4.0.tgz#0dbe0e24263e94e1830c7afb1f403707fad313a3"
+ version "16.4.1"
+ resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.4.1.tgz#f2fb30c2c7b517db6e5b10ed20bb6b0a7ccd8d70"
dependencies:
fbjs "^0.8.16"
object-assign "^4.1.1"
prop-types "^15.6.0"
- react-is "^16.4.0"
+ react-is "^16.4.1"
react-transition-group@^2.2.1:
version "2.3.1"
loose-envify "^1.3.1"
prop-types "^15.6.1"
-react@16.4.0:
- version "16.4.0"
- resolved "https://registry.yarnpkg.com/react/-/react-16.4.0.tgz#402c2db83335336fba1962c08b98c6272617d585"
+react@16.4.1:
+ version "16.4.1"
+ resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.1.0"
path-parse "^1.0.5"
resolve@^1.1.7, resolve@^1.3.2:
- version "1.7.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3"
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.0.tgz#a7f2ac27b78480ecc09c83782741d9f26e4f0c3e"
dependencies:
path-parse "^1.0.5"
dependencies:
ret "~0.1.10"
-"safer-buffer@>= 2.1.2 < 3":
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
sshpk@^1.7.0:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.1.tgz#130f5975eddad963f1d56f92b9ac6c51fa9f83eb"
+ version "1.14.2"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
dashdash "^1.12.0"
getpass "^0.1.1"
+ safer-buffer "^2.0.2"
optionalDependencies:
bcrypt-pbkdf "^1.0.0"
ecc-jsbn "~0.1.1"
version "1.0.7"
resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029"
-tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.3:
+tough-cookie@>=2.3.3, tough-cookie@^2.3.3:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.2.tgz#aa9133154518b494efab98a58247bfc38818c00c"
+ dependencies:
+ psl "^1.1.24"
+ punycode "^1.4.1"
+
+tough-cookie@~2.3.3:
version "2.3.4"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
dependencies:
tsconfig-paths "^3.1.1"
tsconfig-paths@^3.1.1:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.3.2.tgz#bb48b845e221a44387be0f9968ee6c37c2a37c4d"
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.4.0.tgz#d19fe80c5b245f99d17363471971eab54e65a8a7"
dependencies:
deepmerge "^2.0.1"
minimist "^1.2.0"
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
-typescript@2.9.1:
- version "2.9.1"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.1.tgz#fdb19d2c67a15d11995fd15640e373e09ab09961"
+typescript@2.9.2:
+ version "2.9.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
-ua-parser-js@^0.7.9:
+ua-parser-js@^0.7.18:
version "0.7.18"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed"
prepend-http "^1.0.1"
url-parse@^1.1.8, url-parse@~1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.0.tgz#6bfdaad60098c7fe06f623e42b22de62de0d3d75"
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.1.tgz#4dec9dad3dc8585f862fed461d2e19bbf623df30"
dependencies:
querystringify "^2.0.0"
requires-port "^1.0.0"
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz#f0f21d76cbba72362eb609dbed2a30cd17fcc7d4"
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"
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
dependencies:
lodash.sortby "^4.7.0"
tr46 "^1.0.1"