KEYCLOAK-10739: Device Activity UI

This commit is contained in:
Stan Silvert 2019-09-04 17:55:16 -04:00 committed by Bruno Oliveira da Silva
parent a1d8850373
commit a43af40228
9 changed files with 1595 additions and 688 deletions

4
.gitignore vendored
View file

@ -25,6 +25,10 @@ nb-configuration.xml
catalog.xml
nbproject
# VS Code #
###########
*.code-workspace
# Compiled source #
###################
*.com

View file

@ -3,4 +3,24 @@
pageNotFound=Page Not Found
invalidRoute={0} is not a valid route.
actionRequiresIDP=This action requires redirection to your identity provider.
continue=Continue
continue=Continue
refreshPage=Refresh the page
# Device Activity Page
signedInDevices=Signed In Devices
signedInDevicesExplanation=Sign out any device that is unfamiliar.
signOutWarning=Sign out the session?
signOutAllDevices=Sign Out All Devices
signOutAllDevicesWarning=This action will sign out all the devices that have signed in to your account, including the current device you are using.
recentlyUsedDevices=Recently Used Devices
recentlyUsedDevicesExplanation=Devices used in the last month, but not currently logged in.
lastAccess=Last Access
unknownOperatingSystem=Unknown Operating System
currentDevice=Current Device
currentSession=Current Session
signedOutSession=Signed out {0}/{1}
lastAccessedOn=Last accessed on
clients=Clients
startedAt=Started at
expiresAt=Expires at
ipAddress=IP Address

View file

@ -46,6 +46,11 @@ export class AccountServiceClient {
config?: AxiosRequestConfig): Promise<AxiosResponse> {
return this.doRequest(endpoint, {...config, method: 'get'});
}
public doDelete(endpoint: string,
config?: AxiosRequestConfig): Promise<AxiosResponse> {
return this.doRequest(endpoint, {...config, method: 'delete'});
}
public doPut(endpoint: string,
config?: AxiosRequestConfig): Promise<AxiosResponse> {

View file

@ -15,12 +15,16 @@
*/
import * as React from 'react';
import {Button, Grid, GridItem, Title, Tooltip} from '@patternfly/react-core';
import {RedoIcon} from '@patternfly/react-icons';
import {Msg} from '../widgets/Msg';
import {ContentAlert} from './ContentAlert';
interface ContentPageProps {
title: string; // Literal title or key into message bundle
introMessage?: string; // Literal message or key into message bundle
onRefresh?: () => void;
children: React.ReactNode;
}
@ -38,13 +42,17 @@ export class ContentPage extends React.Component<ContentPageProps> {
<React.Fragment>
<ContentAlert/>
<section className="pf-c-page__main-section pf-m-light">
<div className="pf-c-content">
<h1><Msg msgKey={this.props.title}/></h1>
<p>
{this.props.introMessage && <Msg msgKey={this.props.introMessage}/>}
</p>
</div>
<Grid>
<GridItem span={11}><Title headingLevel='h1' size='3xl'><strong><Msg msgKey={this.props.title}/></strong></Title></GridItem>
{this.props.onRefresh &&
<GridItem span={1}>
<Tooltip content={<Msg msgKey='refreshPage'/>}><Button variant='plain' onClick={this.props.onRefresh}><RedoIcon size='sm'/></Button></Tooltip>
</GridItem>
}
{this.props.introMessage && <GridItem span={12}> <Msg msgKey={this.props.introMessage}/></GridItem>}
</Grid>
</section>
<section className="pf-c-page__main-section">
{this.props.children}
</section>

View file

@ -15,21 +15,410 @@
*/
import * as React from 'react';
import * as moment from 'moment';
import {AxiosResponse} from 'axios';
import {AccountServiceClient} from '../../account-service/account.service';
import {
Bullseye,
DataList,
DataListItem,
DataListItemRow,
DataListCell,
DataListToggle,
DataListContent,
DataListItemCells,
Grid,
GridItem,
Level,
LevelItem,
Stack,
StackItem
} from '@patternfly/react-core';
import {
AmazonIcon,
ChromeIcon,
EdgeIcon,
FirefoxIcon,
GlobeIcon,
InternetExplorerIcon,
LaptopIcon,
MobileAltIcon,
OperaIcon,
SafariIcon,
TabletAltIcon,
YandexInternationalIcon,
} from '@patternfly/react-icons';
import {Msg} from '../../widgets/Msg';
import {ContinueCancelModal} from '../../widgets/ContinueCancelModal';
import {KeycloakService} from '../../keycloak-service/keycloak.service';
import {ContentPage} from '../ContentPage';
import { ContentAlert } from '../ContentAlert';
declare const baseUrl: string;
export interface DeviceActivityPageProps {
}
export interface DeviceActivityPageState {
isRowOpen: boolean[];
devices: Device[];
}
interface Device {
browser: string;
current: boolean;
device: string;
ipAddress: string;
lastAccess: number;
mobile: boolean;
os: string;
osVersion: string;
sessions: Session[];
}
interface Session {
browser: string;
current: boolean;
clients: Client[];
expires: number;
id: string;
ipAddress: string;
lastAccess: number;
started: number;
}
interface Client {
clientId: string;
clientName: string;
}
/**
* @author Stan Silvert ssilvert@redhat.com (C) 2019 Red Hat Inc.
*
*/
export class DeviceActivityPage extends React.Component<DeviceActivityPageProps, DeviceActivityPageState> {
export class DeviceActivityPage extends React.Component<DeviceActivityPageProps> {
public constructor(props: DeviceActivityPageProps) {
super(props);
this.state = {
isRowOpen: [],
devices: []
};
this.fetchDevices();
}
private onToggle = (row: number): void => {
const newIsRowOpen: boolean[] = this.state.isRowOpen;
newIsRowOpen[row] = !newIsRowOpen[row];
this.setState({isRowOpen: newIsRowOpen});
};
private signOutAll = () => {
AccountServiceClient.Instance.doDelete("/sessions")
.then( (response: AxiosResponse<Object>) => {
KeycloakService.Instance.logout(baseUrl);
});
}
private signOutSession = (device: Device, session: Session) => {
AccountServiceClient.Instance.doDelete("/sessions/" + session.id)
.then (() => {
this.fetchDevices();
ContentAlert.success(Msg.localize('signedOutSession', [session.browser, device.os]));
});
}
private fetchDevices(): void {
const sessionsOnOpenRow: string[] = this.findSessionsOnOpenRow();
AccountServiceClient.Instance.doGet("/sessions/devices")
.then((response: AxiosResponse<Object>) => {
console.log({response});
let devices = response.data as Device[];
devices = this.moveCurrentToTop(devices);
this.setState({
isRowOpen: this.openRows(devices, sessionsOnOpenRow),
devices: devices
});
});
}
// calculating open rows this way assures that when a session is signed out
// or on refresh, the open rows stay open
private findSessionsOnOpenRow() : string[] {
let sessionsOnOpenRow: string[] = [];
this.state.devices.forEach( (device: Device, index: number) => {
if (this.state.isRowOpen[index]) {
device.sessions.forEach( (session: Session) => {
sessionsOnOpenRow.push(session.id);
})
}
});
return sessionsOnOpenRow;
}
private openRows(devices: Device[], sessionsOnOpenRow: string[]): boolean[] {
const openRows: boolean[] = new Array<boolean>().fill(false);
devices.forEach((device: Device, deviceIndex: number) => {
device.sessions.forEach( (session: Session) => {
if (sessionsOnOpenRow.includes(session.id)) {
openRows[deviceIndex] = true;
}
})
});
return openRows;
}
// current device and session should display at the top of their respective lists
private moveCurrentToTop(devices: Device[]): Device[] {
let currentDevice: Device = devices[0];
devices.forEach((device: Device, index: number) => {
if (device.current) {
currentDevice = device;
devices.splice(index, 1);
devices.unshift(device);
}
});
currentDevice.sessions.forEach((session: Session, index: number) => {
if (session.current) {
const currentSession: Session[] = currentDevice.sessions.splice(index, 1);
currentDevice.sessions.unshift(currentSession[0]);
}
});
return devices;
}
private time(time: number): string {
return moment(time * 1000).format('LLLL');
}
private findDeviceName(device: Device): string {
let deviceName: string = device.device;
const deviceNameLower = deviceName.toLowerCase();
if (deviceNameLower.includes('other') || deviceNameLower.includes('generic') ) {
deviceName = this.findOS(device) + ' ' + this.findOSVersion(device);
}
if (deviceName.trim() === 'Other') {
deviceName = this.makeClientsString(device.sessions[0].clients);
}
return deviceName;
}
private findDeviceIcon(device: Device): React.ReactNode {
const deviceName = device.device.toLowerCase();
if (deviceName.includes('kindle') || deviceName.includes('ipad')) {
return (<TabletAltIcon size='lg' />);
}
if (device.mobile) return (<MobileAltIcon size='lg' />);
return (<LaptopIcon size='lg'/>);
}
private findBrowserIcon(session: Session): React.ReactNode {
const browserName: string = session.browser.toLowerCase();
if (browserName.includes("chrom")) return (<ChromeIcon size='lg'/>); // chrome or chromium
if (browserName.includes("firefox")) return (<FirefoxIcon size='lg'/>);
if (browserName.includes("edge")) return (<EdgeIcon size='lg'/>);
if (browserName.startsWith("ie/")) return (<InternetExplorerIcon size='lg'/>);
if (browserName.includes("safari")) return (<SafariIcon size='lg'/>);
if (browserName.includes("opera")) return (<OperaIcon size='lg'/>);
if (browserName.includes("yandex")) return (<YandexInternationalIcon size='lg'/>);
if (browserName.includes("amazon")) return (<AmazonIcon size='lg'/>);
return (<GlobeIcon size='lg'/>);
}
private findOS(device: Device): string {
if (device.os.toLowerCase().includes('unknown')) return Msg.localize('unknownOperatingSystem');
return device.os;
}
private findOSVersion(device: Device): string {
if (device.osVersion.toLowerCase().includes('unknown')) return '';
return device.osVersion;
}
private makeClientsString(clients: Client[]): string {
let clientsString: string = "";
clients.map( (client: Client, index: number) => {
let clientName: string;
if (client.hasOwnProperty('clientName') && (client.clientName != undefined) && (client.clientName != '')) {
clientName = Msg.localize(client.clientName);
} else {
clientName = client.clientId;
}
clientsString += clientName;
if (clients.length > index + 1) clientsString += ', ';
})
return clientsString;
}
private isShowSignOutAll(devices: Device[]): boolean {
if (devices.length === 0) return false;
if (devices.length > 1) return true;
if (devices[0].sessions.length > 1) return true;
return false;
}
public render(): React.ReactNode {
return (
<div>
<h2>Hello Device Activity Page</h2>
</div>
return (
<ContentPage title="device-activity" onRefresh={this.fetchDevices.bind(this)}>
<Stack gutter="md">
<StackItem isFilled>
<DataList aria-label={Msg.localize('signedInDevices')}>
<DataListItem key="SignedInDevicesHeader" aria-labelledby="signedInDevicesTitle" isExpanded={false}>
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key='signedInDevicesTitle' width={4}>
<div id="signedInDevicesTitle" className="pf-c-content">
<h2><Msg msgKey="signedInDevices"/></h2>
<p>
<Msg msgKey="signedInDevicesExplanation"/>
</p>
</div>
</DataListCell>,
<DataListCell key='signOutAllButton' width={1}>
{this.isShowSignOutAll(this.state.devices) &&
<ContinueCancelModal buttonTitle='signOutAllDevices'
modalTitle='signOutAllDevices'
modalMessage='signOutAllDevicesWarning'
onContinue={this.signOutAll}
/>
}
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
{this.state.devices.map((device: Device, deviceIndex: number) => {
return (
<DataListItem key={'device-' + deviceIndex} aria-labelledby="ex-item1" isExpanded={this.state.isRowOpen[deviceIndex]}>
<DataListItemRow onClick={() => this.onToggle(deviceIndex)}>
<DataListToggle
isExpanded={this.state.isRowOpen[deviceIndex]}
id={'deviceToggle-' + deviceIndex}
aria-controls="ex-expand1"
/>
<DataListItemCells
dataListCells={[
<DataListCell isIcon key={"icon-" + deviceIndex} width={1}>
{this.findDeviceIcon(device)}
</DataListCell>,
<DataListCell key={"os-" + deviceIndex} width={1}>
<strong>{this.findDeviceName(device)}</strong>
</DataListCell>,
<DataListCell key={"lastAccess-" + deviceIndex} width={5}>
{device.current && <p><span className='pf-c-badge pf-m-read'><strong><Msg msgKey="currentDevice"/></strong></span></p>}
{!device.current && <p><strong><Msg msgKey="lastAccess"/>: </strong><span>{this.time(device.lastAccess)}</span></p>}
</DataListCell>
]}
/>
</DataListItemRow>
<DataListContent
noPadding={false}
aria-label="Session Details"
id="ex-expand1"
isHidden={!this.state.isRowOpen[deviceIndex]}
>
<Grid gutter='sm'>
{device.sessions.map((session: Session, sessionIndex: number) => {
return (
<React.Fragment key={'device-' + deviceIndex + '-session-' + sessionIndex}>
<GridItem span={3}>
<Stack>
<StackItem isFilled={false}>
<Bullseye>{this.findBrowserIcon(session)}</Bullseye>
</StackItem>
{!this.state.devices[0].mobile &&
<StackItem isFilled={false}>
<Bullseye>{session.ipAddress}</Bullseye>
</StackItem>
}
{session.current &&
<StackItem isFilled={false}>
<Bullseye><strong className='pf-c-badge pf-m-read'><Msg msgKey="currentSession"/></strong></Bullseye>
</StackItem>
}
</Stack>
</GridItem>
<GridItem span={9}>
{!session.browser.toLowerCase().includes('unknown') &&
<p><strong>{session.browser} / {this.findOS(device)} {this.findOSVersion(device)}</strong></p>
}
{this.state.devices[0].mobile &&
<p><strong>{Msg.localize('ipAddress')} </strong> {session.ipAddress}</p>
}
<p><strong>{Msg.localize('lastAccessedOn')}</strong> {this.time(session.lastAccess)}</p>
<p><strong>{Msg.localize('clients')}</strong> {this.makeClientsString(session.clients)}</p>
<p><strong>{Msg.localize('startedAt')}</strong> {this.time(session.started)}</p>
<p><strong>{Msg.localize('expiresAt')}</strong> {this.time(session.expires)}</p>
{!session.current &&
<ContinueCancelModal buttonTitle='doSignOut'
modalTitle='doSignOut'
buttonVariant='secondary'
modalMessage='signOutWarning'
onContinue={() => this.signOutSession(device, session)}
/>
}
</GridItem>
</React.Fragment>
)})
}
</Grid>
</DataListContent>
</DataListItem>
)})}
</DataList>
</StackItem>
</Stack>
</ContentPage>
);
}
};
};
class IconGridItem extends React.Component {
render() {
return (
<GridItem span={1}>
<Level gutter='lg'>
<LevelItem/>
<LevelItem>{this.props.children}</LevelItem>
<LevelItem/>
</Level>
</GridItem>
);
}
}

View file

@ -36,7 +36,7 @@ export class Msg extends React.Component<MsgProps> {
}
public static localize(msgKey: string, params?: string[]): string {
let message: string = l18nMsg[msgKey];
let message: string = l18nMsg[this.processKey(msgKey)];
if (message === undefined) message = msgKey;
if ((params !== undefined) && (params.length > 0)) {
@ -48,6 +48,14 @@ export class Msg extends React.Component<MsgProps> {
return message;
}
// if the message key has Freemarker syntax, remove it
private static processKey(msgKey: string): string {
if (!(msgKey.startsWith('${') && msgKey.endsWith('}'))) return msgKey;
// remove Freemarker syntax
return msgKey.substring(2, msgKey.length - 1);
}
// if the param has Freemarker syntax, try to look up its value
private static processParam(param: string): string {

View file

@ -86,9 +86,9 @@
"dev": true
},
"@babel/runtime": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.4.tgz",
"integrity": "sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==",
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz",
"integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==",
"requires": {
"regenerator-runtime": "^0.13.2"
}
@ -204,19 +204,32 @@
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.8.2.tgz",
"integrity": "sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw=="
},
"@fortawesome/fontawesome-common-types": {
"version": "0.2.21",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.21.tgz",
"integrity": "sha512-iJtcrU2BtF9Wyr0zm3tHEJy3HqA6sADExhCqCv3SKaJJKKp4ORJ40t4nyHvcWXSVFtd7r1gcdqcRsAfoREGTFA=="
},
"@fortawesome/free-brands-svg-icons": {
"version": "5.10.1",
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.10.1.tgz",
"integrity": "sha512-xrq2+coLZUGcQsmbdoyyp5O5X4a6FhEQj3cGdlM14/bZ6lHCeKlZElsvr/ETtFtD8w2UgQpb3E7Eylo69utD1g==",
"requires": {
"@fortawesome/fontawesome-common-types": "^0.2.21"
}
},
"@patternfly/patternfly": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-2.6.6.tgz",
"integrity": "sha512-lKbsTE/VlU1BiVzeo0BhfDe/qeqIqheejBz0qAm3CYuHyfUXd4+Uu+/9lfEB2EMb+wXpK4Np74OHtYCC82fP0Q=="
"version": "2.26.5",
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-2.26.5.tgz",
"integrity": "sha512-/S39BXo2eLNot0CATepKkYoyFSK5jqw0Eqz69INYzE6BSs37jfEVOnMBYtiTTtrebzk5DiYMNrZyG4WVVXcq9g=="
},
"@patternfly/react-core": {
"version": "3.16.10",
"resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-3.16.10.tgz",
"integrity": "sha512-ASoNNuC+S2UjUeT2aR7LsAuDJpvXzMHYCjRc9WmXD9S52nvqA5p4SS9cXV60RCTvRpUbXJ7/55gnxi4Dt9u6/A==",
"version": "3.35.0",
"resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-3.35.0.tgz",
"integrity": "sha512-KFqC15cmB++H+AQZrh13v/PRvQwIsvxd7AvN26TdkoDd/YlKgu818tMFj48aoeD1jJnvd09YigfOF8I0t7BX4Q==",
"requires": {
"@patternfly/react-icons": "^3.8.1",
"@patternfly/react-styles": "^3.2.0",
"@patternfly/react-tokens": "^2.5.1",
"@patternfly/react-icons": "^3.9.3",
"@patternfly/react-styles": "^3.2.4",
"@patternfly/react-tokens": "^2.5.3",
"@tippy.js/react": "^1.1.1",
"emotion": "^9.2.9",
"exenv": "^1.2.2",
@ -224,14 +237,17 @@
}
},
"@patternfly/react-icons": {
"version": "3.8.1",
"resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-3.8.1.tgz",
"integrity": "sha512-0LCuW4qdDQdiRcnmDBhTdnJZIk1ZlP0mn9VcnnUQ5qkLlJPFtiipcgr+RoQl56ht3xt6pXDKy6Gvv7Wwz/BVkw=="
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-3.11.0.tgz",
"integrity": "sha512-ZDQdNCyet7NVUmfHJSQE28PdTZNptYLwUOOuQPIlYhpJaj+oAmYvurYuF6Zoz6INALvsH5EdgyLQucF83Rmqhw==",
"requires": {
"@fortawesome/free-brands-svg-icons": "^5.8.1"
}
},
"@patternfly/react-styles": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-3.2.0.tgz",
"integrity": "sha512-8M7bo4kPvypHlbzuynV53xjk5176EktfEgZ283sfHmvUlU3Yvq2+m8hS9ERHE9gd91Ip4HiyucAVVACd2gtHNQ==",
"version": "3.5.13",
"resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-3.5.13.tgz",
"integrity": "sha512-aiyOp/n4cMxWhNmokG9EAFt06YmWDi3EdGfa5gyjYRwABGLUhyHo2r7kBqT3xxw0bLcOYDTPU94SaH63uAaRag==",
"requires": {
"@babel/helper-plugin-utils": "^7.0.0-beta.48",
"camel-case": "^3.0.0",
@ -242,15 +258,23 @@
"emotion-server": "^9.2.9",
"fbjs-scripts": "^0.8.3",
"fs-extra": "^6.0.1",
"jsdom": "^11.11.0",
"jsdom": "^15.1.0",
"relative": "^3.0.2",
"resolve-from": "^4.0.0"
"resolve-from": "^4.0.0",
"typescript": "3.4.5"
},
"dependencies": {
"typescript": {
"version": "3.4.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz",
"integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw=="
}
}
},
"@patternfly/react-tokens": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-2.5.1.tgz",
"integrity": "sha512-ZykUfWT4yCELXhGGwQxcNqnXwe3sqfSuoL6IlQRV6wtUKk+/et7NkVvrRwvci926+Usemr4IQVc8V9gbHqRN/A=="
"version": "2.6.16",
"resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-2.6.16.tgz",
"integrity": "sha512-dhr4ne4thSmSKBr4anV07KSzUXEs6KpCMDxxNiwrgFdZwNHtyNcaPc+F9pQZ5A0n4qYmMLpCrprb7m5o/83riQ=="
},
"@tippy.js/react": {
"version": "1.1.1",
@ -267,6 +291,11 @@
"integrity": "sha512-ui3WwXmjTaY73fOQ3/m3nnajU/Orhi6cEu5rzX+BrAAJxa3eITXZ5ch9suPqtM03OWhAHhPSyBGCN4UKoxO20Q==",
"dev": true
},
"@types/node": {
"version": "12.7.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.2.tgz",
"integrity": "sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg=="
},
"@types/prop-types": {
"version": "15.7.0",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.0.tgz",
@ -368,9 +397,9 @@
"integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA=="
},
"acorn-globals": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz",
"integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==",
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.3.tgz",
"integrity": "sha512-vkR40VwS2SYO98AIeFvzWWh+xyc2qi9s7OoXSFEGIP/rOJKzjnhykaZJNnHdoq4BL2gGxI5EZOU16z896EYnOQ==",
"requires": {
"acorn": "^6.0.1",
"acorn-walk": "^6.0.1"
@ -383,9 +412,9 @@
"dev": true
},
"acorn-walk": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
"integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw=="
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA=="
},
"ajv": {
"version": "6.10.0",
@ -539,9 +568,9 @@
"dev": true
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"asynckit": {
"version": "0.4.0",
@ -846,9 +875,9 @@
}
},
"babel-plugin-macros": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.5.1.tgz",
"integrity": "sha512-xN3KhAxPzsJ6OQTktCanNpIFnnMsCV+t8OloKxIL72D6+SUZYFn9qfklPgef5HyyDtzYZqqb+fs1S12+gQY82Q==",
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.6.1.tgz",
"integrity": "sha512-6W2nwiXme6j1n2erPOnmRiWfObUhWH7Qw1LMi9XZy8cj+KtESu3T6asZvtk5bMQQjX8te35o7CFueiSdL/2NmQ==",
"requires": {
"@babel/runtime": "^7.4.2",
"cosmiconfig": "^5.2.0",
@ -1356,9 +1385,9 @@
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="
},
"combined-stream": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
@ -1395,9 +1424,9 @@
}
},
"core-js": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz",
"integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A=="
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
"integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A=="
},
"core-util-is": {
"version": "1.0.2",
@ -1405,13 +1434,13 @@
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cosmiconfig": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.0.tgz",
"integrity": "sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
"integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
"requires": {
"import-fresh": "^2.0.0",
"is-directory": "^0.3.1",
"js-yaml": "^3.13.0",
"js-yaml": "^3.13.1",
"parse-json": "^4.0.0"
},
"dependencies": {
@ -1496,9 +1525,9 @@
}
},
"cssom": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz",
"integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A=="
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
"integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
},
"cssstyle": {
"version": "0.3.1",
@ -1535,18 +1564,6 @@
"abab": "^2.0.0",
"whatwg-mimetype": "^2.2.0",
"whatwg-url": "^7.0.0"
},
"dependencies": {
"whatwg-url": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
"integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
"webidl-conversions": "^4.0.2"
}
}
}
},
"debug": {
@ -1714,9 +1731,9 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"escodegen": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz",
"integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==",
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz",
"integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==",
"requires": {
"esprima": "^3.1.3",
"estraverse": "^4.2.0",
@ -2142,9 +2159,9 @@
}
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}
}
},
@ -2207,9 +2224,9 @@
},
"dependencies": {
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}
}
},
@ -2518,6 +2535,11 @@
"loose-envify": "^1.0.0"
}
},
"ip-regex": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
"integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
},
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@ -2638,47 +2660,42 @@
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
},
"jsdom": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
"integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
"version": "15.1.1",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.1.1.tgz",
"integrity": "sha512-cQZRBB33arrDAeCrAEWn1U3SvrvC8XysBua9Oqg1yWrsY/gYcusloJC3RZJXuY5eehSCmws8f2YeliCqGSkrtQ==",
"requires": {
"abab": "^2.0.0",
"acorn": "^5.5.3",
"acorn-globals": "^4.1.0",
"acorn": "^6.1.1",
"acorn-globals": "^4.3.2",
"array-equal": "^1.0.0",
"cssom": ">= 0.3.2 < 0.4.0",
"cssstyle": "^1.0.0",
"data-urls": "^1.0.0",
"cssom": "^0.3.6",
"cssstyle": "^1.2.2",
"data-urls": "^1.1.0",
"domexception": "^1.0.1",
"escodegen": "^1.9.1",
"escodegen": "^1.11.1",
"html-encoding-sniffer": "^1.0.2",
"left-pad": "^1.3.0",
"nwsapi": "^2.0.7",
"parse5": "4.0.0",
"nwsapi": "^2.1.4",
"parse5": "5.1.0",
"pn": "^1.1.0",
"request": "^2.87.0",
"request-promise-native": "^1.0.5",
"sax": "^1.2.4",
"request": "^2.88.0",
"request-promise-native": "^1.0.7",
"saxes": "^3.1.9",
"symbol-tree": "^3.2.2",
"tough-cookie": "^2.3.4",
"tough-cookie": "^3.0.1",
"w3c-hr-time": "^1.0.1",
"w3c-xmlserializer": "^1.1.2",
"webidl-conversions": "^4.0.2",
"whatwg-encoding": "^1.0.3",
"whatwg-mimetype": "^2.1.0",
"whatwg-url": "^6.4.1",
"ws": "^5.2.0",
"whatwg-encoding": "^1.0.5",
"whatwg-mimetype": "^2.3.0",
"whatwg-url": "^7.0.0",
"ws": "^7.0.0",
"xml-name-validator": "^3.0.0"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
},
"cssstyle": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz",
"integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz",
"integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==",
"requires": {
"cssom": "0.3.x"
}
@ -2755,11 +2772,6 @@
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
"integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ="
},
"left-pad": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
"integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA=="
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@ -3061,9 +3073,9 @@
"integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA=="
},
"parse5": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
"integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
"integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ=="
},
"path-exists": {
"version": "3.0.0",
@ -3163,9 +3175,9 @@
"integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"progress": {
"version": "2.0.3",
@ -3188,9 +3200,9 @@
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"psl": {
"version": "1.1.31",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
"integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw=="
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz",
"integrity": "sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag=="
},
"punycode": {
"version": "2.1.1",
@ -3284,9 +3296,9 @@
}
},
"regenerator-runtime": {
"version": "0.13.2",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz",
"integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA=="
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
},
"regexpp": {
"version": "2.0.1",
@ -3369,6 +3381,17 @@
"request-promise-core": "1.1.2",
"stealthy-require": "^1.1.1",
"tough-cookie": "^2.3.3"
},
"dependencies": {
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
}
}
}
},
"requireindex": {
@ -3447,10 +3470,13 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
"saxes": {
"version": "3.1.11",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz",
"integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==",
"requires": {
"xmlchars": "^2.1.1"
}
},
"scheduler": {
"version": "0.13.5",
@ -3645,9 +3671,9 @@
}
},
"symbol-tree": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
"integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY="
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
},
"systemjs": {
"version": "0.20.19",
@ -3760,10 +3786,11 @@
}
},
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
"integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
"requires": {
"ip-regex": "^2.1.0",
"psl": "^1.1.28",
"punycode": "^2.1.1"
}
@ -3852,9 +3879,9 @@
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
},
"validate-npm-package-license": {
"version": "3.0.4",
@ -3889,6 +3916,16 @@
"browser-process-hrtime": "^0.1.2"
}
},
"w3c-xmlserializer": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz",
"integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==",
"requires": {
"domexception": "^1.0.1",
"webidl-conversions": "^4.0.2",
"xml-name-validator": "^3.0.0"
}
},
"warning": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.2.tgz",
@ -3916,9 +3953,9 @@
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
},
"whatwg-url": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
"integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
@ -3954,11 +3991,11 @@
}
},
"ws": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.1.2.tgz",
"integrity": "sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg==",
"requires": {
"async-limiter": "~1.0.0"
"async-limiter": "^1.0.0"
}
},
"xml-name-validator": {
@ -3966,6 +4003,11 @@
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
},
"xmlchars": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.1.1.tgz",
"integrity": "sha512-7hew1RPJ1iIuje/Y01bGD/mXokXxegAgVS+e+E0wSi2ILHQkYAH1+JXARwTjZSM4Z4Z+c73aKspEcqj+zPPL/w=="
},
"xtend": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",

View file

@ -11,8 +11,9 @@
"author": "Stan Silvert",
"license": "Apache-2.0",
"dependencies": {
"@patternfly/patternfly": "^2.6.6",
"@patternfly/react-core": "^3.16.10",
"@patternfly/patternfly": "^2.26.5",
"@patternfly/react-core": "^3.35.0",
"@types/node": "^12.7.2",
"axios": "^0.19.0",
"moment": "^2.22.2",
"react": "^16.8.5",