WelcomePageHTML: string;
InactivePageHTML: string;
SSHHelpPageHTML: string;
+ SSHHelpHostSuffix: string;
SiteName: string;
};
Login: {
return Axios.get<ClusterConfigJSON>(getClusterConfigURL(workbenchConfig.API_HOST)).then(async response => {
const clusterConfigJSON = response.data;
const apiRevision = await getApiRevision(clusterConfigJSON.Services.Controller.ExternalURL);
- const config = {...buildConfig(clusterConfigJSON), apiRevision};
+ const config = { ...buildConfig(clusterConfigJSON), apiRevision };
const warnLocalConfig = (varName: string) => console.warn(
`A value for ${varName} was found in ${WORKBENCH_CONFIG_URL}. To use the Arvados centralized configuration instead, \
remove the entire ${varName} entry from ${WORKBENCH_CONFIG_URL}`);
WelcomePageHTML: "",
InactivePageHTML: "",
SSHHelpPageHTML: "",
+ SSHHelpHostSuffix: "",
SiteName: "",
},
Login: {
);
export const ColumnSelectorTrigger = (props: IconButtonProps) =>
- <Tooltip title="Filters">
+ <Tooltip disableFocusListener title="Select columns">
<IconButton {...props}>
- <MenuIcon aria-label="Filters" />
+ <MenuIcon aria-label="Select columns" />
</IconButton>
</Tooltip>;
--- /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 { DataTableFiltersPopover } from "./data-table-filters-popover";
+import * as Adapter from 'enzyme-adapter-react-16';
+import { Checkbox, IconButton } from "@material-ui/core";
+import { getInitialProcessStatusFilters } from "~/store/resource-type-filters/resource-type-filters"
+
+configure({ adapter: new Adapter() });
+
+describe("<DataTableFiltersPopover />", () => {
+ it("renders filters according to their state", () => {
+ // 1st filter (All) is selected, the rest aren't.
+ const filters = getInitialProcessStatusFilters()
+
+ const dataTableFilter = mount(<DataTableFiltersPopover name="" filters={filters} />);
+ dataTableFilter.find(IconButton).simulate("click");
+ expect(dataTableFilter.find(Checkbox).at(0).prop("checked")).toBeTruthy();
+ expect(dataTableFilter.find(Checkbox).at(1).prop("checked")).toBeFalsy();
+ });
+});
: f.selected
);
return <>
- <Tooltip title='Filters'>
+ <Tooltip disableFocusListener title='Filters'>
<ButtonBase
className={classnames([classes.root, { [classes.active]: isActive }])}
component="span"
mutuallyExclusive={this.props.mutuallyExclusive}
onChange={filters => {
this.setState({ filters });
+ if (this.props.mutuallyExclusive) {
+ const { onChange } = this.props;
+ if (onChange) {
+ onChange(filters);
+ }
+ this.setState({ anchorEl: undefined });
+ }
}} />
+ {this.props.mutuallyExclusive ||
<CardActions>
<Button
color="primary"
Cancel
</Button>
</CardActions >
+ }
</Card>
</Popover>
</>;
render={renderItem}
showSelection
useRadioButtons={this.props.mutuallyExclusive}
- toggleItemRadioButton={this.toggleRadioButtonFilter}
disableRipple
onContextMenu={noop}
- toggleItemActive={noop}
+ toggleItemActive={
+ this.props.mutuallyExclusive
+ ? this.toggleRadioButtonFilter
+ : this.toggleFilter
+ }
toggleItemOpen={this.toggleOpen}
- toggleItemSelection={this.toggleFilter}
/>;
}
* Handler for when a tree item is toggled via a radio button.
* Ensures mutual exclusivity among filter tree items.
*/
- toggleRadioButtonFilter = (item: TreeItem<DataTableFilterItem>) => {
+ toggleRadioButtonFilter = (_: any, item: TreeItem<DataTableFilterItem>) => {
const { onChange = noop } = this.props;
// If the filter is already selected, do nothing.
+++ /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 { DataTableFilters } from "./data-table-filters";
-import * as Adapter from 'enzyme-adapter-react-16';
-import { Checkbox, ButtonBase } from "@material-ui/core";
-
-configure({ adapter: new Adapter() });
-
-describe("<DataTableFilter />", () => {
- it("renders filters according to their state", () => {
- const filters = [{
- name: "Filter 1",
- selected: true
- }, {
- name: "Filter 2",
- selected: false
- }];
- const dataTableFilter = mount(<DataTableFilters name="" filters={filters} />);
- dataTableFilter.find(ButtonBase).simulate("click");
- expect(dataTableFilter.find(Checkbox).at(0).prop("checked")).toBeTruthy();
- expect(dataTableFilter.find(Checkbox).at(1).prop("checked")).toBeFalsy();
- });
-});
//
// SPDX-License-Identifier: AGPL-3.0
-import * as React from "react";
-import {
- WithStyles,
- withStyles,
- ButtonBase,
- StyleRulesCallback,
- Theme,
- Popover,
- List,
- ListItem,
- Checkbox,
- ListItemText,
- Button,
- Card,
- CardActions,
- Typography,
- CardContent,
- Tooltip
-} from "@material-ui/core";
-import * as classnames from "classnames";
-import { DefaultTransformOrigin } from "../popover/helpers";
-import { createTree, initTreeNode, mapTree } from '~/models/tree';
-import { DataTableFilters as DataTableFiltersModel, DataTableFiltersTree } from "./data-table-filters-tree";
-import { pipe } from 'lodash/fp';
-import { setNode } from '~/models/tree';
-
-export type CssRules = "root" | "icon" | "active" | "checkbox";
-
-const styles: StyleRulesCallback<CssRules> = (theme: Theme) => ({
- root: {
- cursor: "pointer",
- display: "inline-flex",
- justifyContent: "flex-start",
- flexDirection: "inherit",
- alignItems: "center",
- "&:hover": {
- color: theme.palette.text.primary,
- },
- "&:focus": {
- color: theme.palette.text.primary,
- },
- },
- active: {
- color: theme.palette.text.primary,
- '& $icon': {
- opacity: 1,
- },
- },
- icon: {
- marginRight: 4,
- marginLeft: 4,
- opacity: 0.7,
- userSelect: "none",
- width: 16
- },
- checkbox: {
- width: 24,
- height: 24
- }
-});
-
export interface DataTableFilterItem {
name: string;
selected: boolean;
}
-
-export interface DataTableFilterProps {
- name: string;
- filters: DataTableFilterItem[];
- onChange?: (filters: DataTableFilterItem[]) => void;
-}
-
-interface DataTableFilterState {
- anchorEl?: HTMLElement;
- filters: DataTableFilterItem[];
- prevFilters: DataTableFilterItem[];
- filtersTree: DataTableFiltersModel;
-}
-
-const filters: DataTableFiltersModel = pipe(
- createTree,
- setNode(initTreeNode({ id: 'Project', value: { name: 'Project' } })),
- setNode(initTreeNode({ id: 'Process', value: { name: 'Process' } })),
- setNode(initTreeNode({ id: 'Data collection', value: { name: 'Data collection' } })),
- setNode(initTreeNode({ id: 'General', parent: 'Data collection', value: { name: 'General' } })),
- setNode(initTreeNode({ id: 'Output', parent: 'Data collection', value: { name: 'Output' } })),
- setNode(initTreeNode({ id: 'Log', parent: 'Data collection', value: { name: 'Log' } })),
- mapTree(node => ({...node, selected: true})),
-)();
-
-export const DataTableFilters = withStyles(styles)(
- class extends React.Component<DataTableFilterProps & WithStyles<CssRules>, DataTableFilterState> {
- state: DataTableFilterState = {
- anchorEl: undefined,
- filters: [],
- prevFilters: [],
- filtersTree: filters,
- };
- icon = React.createRef<HTMLElement>();
-
- render() {
- const { name, classes, children } = this.props;
- const isActive = this.state.filters.some(f => f.selected);
- return <>
- <Tooltip title='Filters'>
- <ButtonBase
- className={classnames([classes.root, { [classes.active]: isActive }])}
- component="span"
- onClick={this.open}
- disableRipple>
- {children}
- <i className={classnames(["fas fa-filter", classes.icon])}
- data-fa-transform="shrink-3"
- ref={this.icon} />
- </ButtonBase>
- </Tooltip>
- <Popover
- anchorEl={this.state.anchorEl}
- open={!!this.state.anchorEl}
- anchorOrigin={DefaultTransformOrigin}
- transformOrigin={DefaultTransformOrigin}
- onClose={this.cancel}>
- <Card>
- <CardContent>
- <Typography variant="caption">
- {name}
- </Typography>
- </CardContent>
- <List dense>
- {this.state.filters.map((filter, index) =>
- <ListItem
- key={index}>
- <Checkbox
- onClick={this.toggleFilter(filter)}
- color="primary"
- checked={filter.selected}
- className={classes.checkbox} />
- <ListItemText>
- {filter.name}
- </ListItemText>
- </ListItem>
- )}
- </List>
- <DataTableFiltersTree
- filters={this.state.filtersTree}
- onChange={filtersTree => this.setState({ filtersTree })} />
- <CardActions>
- <Button
- color="primary"
- variant='contained'
- size="small"
- onClick={this.submit}>
- Ok
- </Button>
- <Button
- color="primary"
- variant="outlined"
- size="small"
- onClick={this.cancel}>
- Cancel
- </Button>
- </CardActions >
- </Card>
- </Popover>
- </>;
- }
-
- static getDerivedStateFromProps(props: DataTableFilterProps, state: DataTableFilterState): DataTableFilterState {
- return props.filters !== state.prevFilters
- ? { ...state, filters: props.filters, prevFilters: props.filters }
- : state;
- }
-
- open = () => {
- this.setState({ anchorEl: this.icon.current || undefined });
- }
-
- submit = () => {
- const { onChange } = this.props;
- if (onChange) {
- onChange(this.state.filters);
- }
- this.setState({ anchorEl: undefined });
- }
-
- cancel = () => {
- this.setState(prev => ({
- ...prev,
- filters: prev.prevFilters,
- anchorEl: undefined
- }));
- }
-
- toggleFilter = (toggledFilter: DataTableFilterItem) => () => {
- this.setState(prev => ({
- ...prev,
- filters: prev.filters.map(filter =>
- filter === toggledFilter
- ? { ...filter, selected: !filter.selected }
- : filter)
- }));
- }
- }
-);
import { TableHead, TableCell, Typography, TableBody, Button, TableSortLabel } from "@material-ui/core";
import * as Adapter from "enzyme-adapter-react-16";
import { DataTable, DataColumns } from "./data-table";
-import { DataTableFilters } from "~/components/data-table-filters/data-table-filters";
import { SortDirection, createDataColumn } from "./data-column";
import { DataTableFiltersPopover } from '~/components/data-table-filters/data-table-filters-popover';
import { createTree, setNode, initTreeNode } from '~/models/tree';
expect(onSortToggle).toHaveBeenCalledWith(columns[0]);
});
- it("does not display <DataTableFilter /> if there is no filters provided", () => {
+ it("does not display <DataTableFiltersPopover /> if there is no filters provided", () => {
const columns: DataColumns<string> = [{
name: "Column 1",
sortDirection: SortDirection.ASC,
onRowDoubleClick={jest.fn()}
onSortToggle={jest.fn()}
onContextMenu={jest.fn()} />);
- expect(dataTable.find(DataTableFilters)).toHaveLength(0);
+ expect(dataTable.find(DataTableFiltersPopover)).toHaveLength(0);
});
it("passes filter props to <DataTableFiltersPopover />", () => {
dataTable.find(DataTableFiltersPopover).prop("onChange")([]);
expect(onFiltersChange).toHaveBeenCalledWith([], columns[0]);
});
-
- // it("shows default view if there is no items", () => {
- // const columns: DataColumns<string> = [
- // createDataColumn({
- // name: "Column 1",
- // render: () => <span />,
- // selected: true,
- // configurable: true
- // }),
- // ];
- // const dataTable = mount(<DataTable
- // columns={columns}
- // items={[]}
- // onFiltersChange={jest.fn()}
- // onRowClick={jest.fn()}
- // onRowDoubleClick={jest.fn()}
- // onContextMenu={jest.fn()}
- // onSortToggle={jest.fn()} />);
- // expect(dataTable.find(DataTableDefaultView)).toHaveLength(1);
- // });
});
/**
* When set to true use radio buttons instead of checkboxes for item selection.
* This does not guarantee radio group behavior (i.e item mutual exclusivity).
- * Any item selection logic must be done in the toggleItemRadioButton callback prop.
+ * Any item selection logic must be done in the toggleItemActive callback prop.
*/
useRadioButtons?: boolean;
-
- /**
- * Called when selection of an item in the tree is toggled via a radio button.
- * Use this callback prop to implement any selection logic (i.e item mutual exclusivity).
- */
- toggleItemRadioButton?: (item: TreeItem<T>) => void;
}
export const Tree = withStyles(styles)(
<Radio
checked={it.selected}
className={classes.checkbox}
- color="primary"
- onChange={this.handleRadioButtonChange(it)} />}
+ color="primary" />}
<div className={renderContainer}>
{render(it, level)}
</div>
: undefined;
}
- handleRadioButtonChange = (item: TreeItem<T>) => {
- const { toggleItemRadioButton } = this.props;
- return toggleItemRadioButton
- ? (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => {
- event.stopPropagation();
- toggleItemRadioButton(item);
- }
- : undefined;
- }
-
handleToggleItemOpen = (item: TreeItem<T>) => (event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation();
this.props.toggleItemOpen(event, item);
);
const attributes = (user: UserResource, classes: any) => {
- const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid, firstName, lastName, href, username } = user;
+ const { uuid, ownerUuid, createdAt, modifiedAt, modifiedByClientUuid, modifiedByUserUuid,
+ firstName, lastName, username, email, isActive, isAdmin } = user;
return (
<span>
<Grid container direction="row">
<Grid item xs={5} className={classes.rightContainer}>
+ {uuid && <Grid item>Uuid</Grid>}
{firstName && <Grid item>First name</Grid>}
{lastName && <Grid item>Last name</Grid>}
- {ownerUuid && <Grid item>Owner uuid</Grid>}
+ {email && <Grid item>Email</Grid>}
+ {username && <Grid item>Username</Grid>}
+ {isActive && <Grid item>Is active</Grid>}
+ {isAdmin && <Grid item>Is admin</Grid>}
{createdAt && <Grid item>Created at</Grid>}
{modifiedAt && <Grid item>Modified at</Grid>}
+ {ownerUuid && <Grid item>Owner uuid</Grid>}
{modifiedByUserUuid && <Grid item>Modified by user uuid</Grid>}
{modifiedByClientUuid && <Grid item>Modified by client uuid</Grid>}
- {uuid && <Grid item>uuid</Grid>}
- {href && <Grid item>Href</Grid>}
- {username && <Grid item>Username</Grid>}
- {username && <Grid item>Username</Grid>}
</Grid>
<Grid item xs={7} className={classes.leftContainer}>
+ <Grid item>{uuid}</Grid>
<Grid item>{firstName}</Grid>
<Grid item>{lastName}</Grid>
- <Grid item>{ownerUuid}</Grid>
+ <Grid item>{email}</Grid>
+ <Grid item>{username}</Grid>
+ <Grid item>{isActive}</Grid>
+ <Grid item>{isAdmin}</Grid>
<Grid item>{createdAt}</Grid>
<Grid item>{modifiedAt}</Grid>
+ <Grid item>{ownerUuid}</Grid>
<Grid item>{modifiedByUserUuid}</Grid>
<Grid item>{modifiedByClientUuid}</Grid>
- <Grid item>{uuid}</Grid>
- <Grid item>{href}</Grid>
- <Grid item>{username}</Grid>
- <Grid item>{username}</Grid>
</Grid>
</Grid>
</span>
import { RootState } from '~/store/store';
import { ListResults } from '~/services/common-service/common-service';
import { HelpIcon } from '~/components/icon/icon';
+// import * as CopyToClipboard from 'react-copy-to-clipboard';
type CssRules = 'button' | 'codeSnippet' | 'link' | 'linkIcon' | 'rightAlign' | 'cardWithoutMachines' | 'icon';
requestedDate: state.virtualMachines.date,
userUuid: state.auth.user!.uuid,
helpText: state.auth.config.clusterConfig.Workbench.SSHHelpPageHTML,
+ hostSuffix: state.auth.config.clusterConfig.Workbench.SSHHelpHostSuffix || "",
webShell: state.auth.config.clusterConfig.Services.WebShell.ExternalURL,
...state.virtualMachines
};
userUuid: string;
links: ListResults<any>;
helpText: string;
+ hostSuffix: string;
webShell: string;
}
</TableRow>
</TableHead>
<TableBody>
- {props.virtualMachines.items.map((it, index) =>
- <TableRow key={index}>
- <TableCell>{it.hostname}</TableCell>
- <TableCell>{getUsername(props.links, props.userUuid)}</TableCell>
- <TableCell>ssh {getUsername(props.links, props.userUuid)}@{it.hostname}</TableCell>
- {props.webShell !== "" && <TableCell>
- <a href={`${props.webShell}${it.href}/webshell/${getUsername(props.links, props.userUuid)}`} target="_blank" className={props.classes.link}>
- Log in as {getUsername(props.links, props.userUuid)}
- </a>
- </TableCell>}
- </TableRow>
- )}
+ {props.virtualMachines.items.map(it =>
+ props.links.items.map(lk => {
+ if (lk.tailUuid === props.userUuid) {
+ const username = lk.properties.username;
+ const command = `ssh ${username}@${it.hostname}${props.hostSuffix}`;
+ return <TableRow key={lk.uuid}>
+ <TableCell>{it.hostname}</TableCell>
+ <TableCell>{username}</TableCell>
+ <TableCell>
+ {command}
+ </TableCell>
+ {props.webShell !== "" && <TableCell>
+ <a href={`${props.webShell}${it.href}/webshell/${username}`} target="_blank" className={props.classes.link}>
+ Log in as {username}
+ </a>
+ </TableCell>}
+ </TableRow>;
+ }
+ return;
+ }
+ ))}
</TableBody>
</Table>;
-const getUsername = (links: ListResults<any>, userUuid: string) => {
- return links.items.map(it => it.tailUuid === userUuid ? it.properties.username : '');
-};
-
const CardSSHSection = (props: VirtualMachineProps) =>
<Grid item xs={12}>
<Card>
integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=
acorn@^5.0.0, acorn@^5.5.3:
- version "5.7.3"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
- integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+ version "5.7.4"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
+ integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==
-acorn@^6.0.1:
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784"
- integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==
-
-acorn@^6.2.1:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e"
- integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==
+acorn@^6.0.1, acorn@^6.2.1:
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
+ integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
address@1.0.3:
version "1.0.3"
integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
handlebars@^4.0.3:
- version "4.7.2"
- resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.2.tgz#01127b3840156a0927058779482031afe0e730d7"
- integrity sha512-4PwqDL2laXtTWZghzzCtunQUTLbo31pcCJrd/B/9JP8XbhVzpS5ZXuKqlOzsd1rtcaLo4KqAn8nl8mkknS4MHw==
+ version "4.7.6"
+ resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e"
+ integrity sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==
dependencies:
+ minimist "^1.2.5"
neo-async "^2.6.0"
- optimist "^0.6.1"
source-map "^0.6.1"
+ wordwrap "^1.0.0"
optionalDependencies:
uglify-js "^3.1.4"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
-minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
- integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
-
-minimist@~0.0.1:
- version "0.0.10"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
- integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
+minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
+ integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
mississippi@^2.0.0:
version "2.0.0"
dependencies:
is-wsl "^1.1.0"
-optimist@^0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
- integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
- dependencies:
- minimist "~0.0.1"
- wordwrap "~0.0.2"
-
optionator@^0.8.1:
version "0.8.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
-wordwrap@~0.0.2:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
- integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
+wordwrap@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+ integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
worker-farm@^1.3.1, worker-farm@^1.5.2, worker-farm@^1.7.0:
version "1.7.0"