From c323e853a85d482bc9a25cfbc4db25684e47e748 Mon Sep 17 00:00:00 2001 From: Raghunandan Balachandran Date: Wed, 5 Feb 2020 11:35:19 +0100 Subject: [PATCH] fix tests --- frontend/packages/core/package.json | 3 +- .../core/src/assets/bursts/bursts.css | 19 -- .../core/src/assets/bursts/circle-1.svg | 1 - .../core/src/assets/bursts/circle-2.svg | 1 - .../core/src/assets/bursts/rectangle-1.svg | 1 - .../core/src/assets/bursts/rectangle-2.svg | 1 - .../core/src/assets/bursts/rectangle-3.svg | 1 - .../core/src/assets/bursts/triangle-1.svg | 1 - .../core/src/assets/bursts/triangle-2.svg | 1 - .../core/src/assets/bursts/triangle-3.svg | 1 - .../src/components/Lifecycle/Lifecycle.js | 44 +++ .../core/src/components/Lifecycle/index.js | 1 + .../core/src/components/Status/Status.js | 79 ++++++ .../core/src/components/Status/index.js | 1 + frontend/packages/core/src/index.ts | 2 +- .../packages/core/src/layout/Header/Burst.js | 40 ++- .../HeaderActionMenu/HeaderActionMenu.js | 2 +- .../layout/HeaderActionMenu/MenuVertical.tsx | 11 + .../src/layout/HeaderLabel/HeaderLabel.js | 2 +- .../layout/HeaderLabel/OwnerHeaderLabel.js | 9 +- .../HeaderLabel/OwnerHeaderLabel.test.js | 2 +- .../core/src/layout/InfoCard/BottomLink.js | 2 +- .../layout/Navigation/GcpProjectByTools.tsx | 14 - .../src/layout/Navigation/InfoSquared.tsx | 11 - .../core/src/layout/Navigation/NavItem.js | 168 ----------- .../src/layout/Navigation/NavItem.test.js | 94 ------- .../core/src/layout/Navigation/Navigation.js | 91 ------ .../src/layout/Navigation/Navigation.test.js | 75 ----- .../core/src/layout/Page/PageThemeProvider.js | 135 +-------- .../packages/core/src/layout/Page/index.ts | 2 +- .../src/layout/SupportButton/SupportButton.js | 114 -------- .../SupportButton/SupportButton.test.js | 36 --- frontend/packages/core/src/testUtils/index.js | 264 +----------------- .../packages/core/src/theme/BackstageTheme.js | 2 +- frontend/yarn.lock | 83 +++++- 35 files changed, 275 insertions(+), 1039 deletions(-) delete mode 100644 frontend/packages/core/src/assets/bursts/bursts.css delete mode 100644 frontend/packages/core/src/assets/bursts/circle-1.svg delete mode 100644 frontend/packages/core/src/assets/bursts/circle-2.svg delete mode 100644 frontend/packages/core/src/assets/bursts/rectangle-1.svg delete mode 100644 frontend/packages/core/src/assets/bursts/rectangle-2.svg delete mode 100644 frontend/packages/core/src/assets/bursts/rectangle-3.svg delete mode 100644 frontend/packages/core/src/assets/bursts/triangle-1.svg delete mode 100644 frontend/packages/core/src/assets/bursts/triangle-2.svg delete mode 100644 frontend/packages/core/src/assets/bursts/triangle-3.svg create mode 100644 frontend/packages/core/src/components/Lifecycle/Lifecycle.js create mode 100644 frontend/packages/core/src/components/Lifecycle/index.js create mode 100644 frontend/packages/core/src/components/Status/Status.js create mode 100644 frontend/packages/core/src/components/Status/index.js create mode 100644 frontend/packages/core/src/layout/HeaderActionMenu/MenuVertical.tsx delete mode 100644 frontend/packages/core/src/layout/Navigation/GcpProjectByTools.tsx delete mode 100644 frontend/packages/core/src/layout/Navigation/InfoSquared.tsx delete mode 100644 frontend/packages/core/src/layout/Navigation/NavItem.js delete mode 100644 frontend/packages/core/src/layout/Navigation/NavItem.test.js delete mode 100644 frontend/packages/core/src/layout/Navigation/Navigation.js delete mode 100644 frontend/packages/core/src/layout/Navigation/Navigation.test.js delete mode 100644 frontend/packages/core/src/layout/SupportButton/SupportButton.js delete mode 100644 frontend/packages/core/src/layout/SupportButton/SupportButton.test.js diff --git a/frontend/packages/core/package.json b/frontend/packages/core/package.json index fb5f3cc6de..7e6782bbb2 100644 --- a/frontend/packages/core/package.json +++ b/frontend/packages/core/package.json @@ -16,7 +16,8 @@ "react-dom": "^16.12.0", "react-helmet":"5.2.1", "tinycolor2": "1.4.1", - "react-addons-text-content": "0.0.4" + "react-addons-text-content": "0.0.4", + "recompose": "0.30.0" }, "scripts": { "lint": "web-scripts lint", diff --git a/frontend/packages/core/src/assets/bursts/bursts.css b/frontend/packages/core/src/assets/bursts/bursts.css deleted file mode 100644 index 92499bf056..0000000000 --- a/frontend/packages/core/src/assets/bursts/bursts.css +++ /dev/null @@ -1,19 +0,0 @@ - -.burst { - position: absolute; - top: 0; - left: 0; - height: 100%; - width: 100%; - z-index: -1; -} - -/* base style of burst shape SVGs */ -.burst-shape { - position: absolute; - right: 0; - height: 100%; - background-repeat: no-repeat; - background-size: cover; - opacity:0.1; -} diff --git a/frontend/packages/core/src/assets/bursts/circle-1.svg b/frontend/packages/core/src/assets/bursts/circle-1.svg deleted file mode 100644 index 9ee5157ab8..0000000000 --- a/frontend/packages/core/src/assets/bursts/circle-1.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/packages/core/src/assets/bursts/circle-2.svg b/frontend/packages/core/src/assets/bursts/circle-2.svg deleted file mode 100644 index 15b89e96db..0000000000 --- a/frontend/packages/core/src/assets/bursts/circle-2.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/packages/core/src/assets/bursts/rectangle-1.svg b/frontend/packages/core/src/assets/bursts/rectangle-1.svg deleted file mode 100644 index 4403b0031a..0000000000 --- a/frontend/packages/core/src/assets/bursts/rectangle-1.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/packages/core/src/assets/bursts/rectangle-2.svg b/frontend/packages/core/src/assets/bursts/rectangle-2.svg deleted file mode 100644 index 2d307d75f6..0000000000 --- a/frontend/packages/core/src/assets/bursts/rectangle-2.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/packages/core/src/assets/bursts/rectangle-3.svg b/frontend/packages/core/src/assets/bursts/rectangle-3.svg deleted file mode 100644 index 947df51df9..0000000000 --- a/frontend/packages/core/src/assets/bursts/rectangle-3.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/packages/core/src/assets/bursts/triangle-1.svg b/frontend/packages/core/src/assets/bursts/triangle-1.svg deleted file mode 100644 index 7a33cf3f5c..0000000000 --- a/frontend/packages/core/src/assets/bursts/triangle-1.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/packages/core/src/assets/bursts/triangle-2.svg b/frontend/packages/core/src/assets/bursts/triangle-2.svg deleted file mode 100644 index 184e714b89..0000000000 --- a/frontend/packages/core/src/assets/bursts/triangle-2.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/packages/core/src/assets/bursts/triangle-3.svg b/frontend/packages/core/src/assets/bursts/triangle-3.svg deleted file mode 100644 index e8b0cb1f7c..0000000000 --- a/frontend/packages/core/src/assets/bursts/triangle-3.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/packages/core/src/components/Lifecycle/Lifecycle.js b/frontend/packages/core/src/components/Lifecycle/Lifecycle.js new file mode 100644 index 0000000000..5c11599f92 --- /dev/null +++ b/frontend/packages/core/src/components/Lifecycle/Lifecycle.js @@ -0,0 +1,44 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +class Lifecycle extends Component { + static propTypes = { + isShorthand: PropTypes.bool, + fontSize: PropTypes.string, + }; +} + +const styles = { + alpha: { + color: '#d00150', + fontFamily: 'serif', + fontWeight: 'normal', + fontStyle: 'italic', + }, + beta: { + color: '#4d65cc', + fontFamily: 'serif', + fontWeight: 'normal', + fontStyle: 'italic', + }, +}; + +export class AlphaLabel extends Lifecycle { + render() { + const style = fontSize => ({ ...styles.alpha, fontSize, ...this.props.style }); + return this.props.isShorthand ? ( + α + ) : ( + Alpha + ); + } +} + +export class BetaLabel extends Lifecycle { + render() { + const fontSize = this.props.fontSize ? this.props.fontSize : this.props.isShorthand ? '120%' : '100%'; + const style = { ...styles.beta, fontSize, ...this.props.style }; + + return this.props.isShorthand ? β : Beta; + } +} diff --git a/frontend/packages/core/src/components/Lifecycle/index.js b/frontend/packages/core/src/components/Lifecycle/index.js new file mode 100644 index 0000000000..a5b40c210e --- /dev/null +++ b/frontend/packages/core/src/components/Lifecycle/index.js @@ -0,0 +1 @@ +export { AlphaLabel, BetaLabel } from './Lifecycle'; diff --git a/frontend/packages/core/src/components/Status/Status.js b/frontend/packages/core/src/components/Status/Status.js new file mode 100644 index 0000000000..04fff2a552 --- /dev/null +++ b/frontend/packages/core/src/components/Status/Status.js @@ -0,0 +1,79 @@ +import React from 'react'; +import { pure } from 'recompose'; +import { withStyles } from '@material-ui/core'; + +const styles = theme => ({ + status: { + width: 12, + height: 12, + display: 'inline-block', + marginRight: 1, + }, + ok: { + backgroundColor: theme.palette.status.ok, + borderRadius: '50%', + }, + warning: { + backgroundColor: theme.palette.status.warning, + }, + error: { + width: '0', + height: '0', + borderLeft: '7px solid transparent', + borderRight: '7px solid transparent', + borderBottom: `14px solid ${theme.palette.status.error}`, + }, + pending: { + backgroundColor: theme.palette.status.pending, + }, + failed: { + backgroundColor: 'rgba(245, 155, 35, 0.5)', + }, + running: { + animation: 'blink 0.8s step-start 0s infinite', + backgroundColor: theme.palette.status.running, + }, + '@keyframes blink': { + '50%': { + backgroundColor: theme.palette.status.background, + }, + }, +}); + +export const StatusOK = pure( + withStyles(styles)(props => ( + + )), +); + +export const StatusWarning = pure( + withStyles(styles)(props => ( + + )), +); + +export const StatusError = pure( + withStyles(styles)(props => ( + + )), +); + +export const StatusNA = pure(() => N/A); + +export const StatusPending = pure( + withStyles(styles)(props => ( + + )), +); + +export const StatusRunning = pure( + withStyles(styles)(props => ( + + )), +); + +export const StatusFailed = pure( + withStyles(styles)(props => ( + + )), +); diff --git a/frontend/packages/core/src/components/Status/index.js b/frontend/packages/core/src/components/Status/index.js new file mode 100644 index 0000000000..4b037648e3 --- /dev/null +++ b/frontend/packages/core/src/components/Status/index.js @@ -0,0 +1 @@ +export { StatusError, StatusFailed, StatusNA, StatusOK, StatusPending, StatusRunning, StatusWarning } from './Status'; diff --git a/frontend/packages/core/src/index.ts b/frontend/packages/core/src/index.ts index f741f0e384..353b29ff72 100644 --- a/frontend/packages/core/src/index.ts +++ b/frontend/packages/core/src/index.ts @@ -1,7 +1,7 @@ export * from './types'; export { default as createPlugin } from './createPlugin'; export { default as Page } from '../src/layout/Page'; -export { shapes, gradients, theme } from '../src/layout/Page'; +export { gradients, theme } from '../src/layout/Page'; export { default as Header } from '../src/layout/Header/Header'; export { default as HeaderLabel } from '../src/layout/HeaderLabel'; export { default as InfoCard } from '../src/layout/InfoCard'; diff --git a/frontend/packages/core/src/layout/Header/Burst.js b/frontend/packages/core/src/layout/Header/Burst.js index 64d95f7e07..f61da40956 100644 --- a/frontend/packages/core/src/layout/Header/Burst.js +++ b/frontend/packages/core/src/layout/Header/Burst.js @@ -1,16 +1,34 @@ -import React, { Component } from 'react'; -import '../../assets/bursts/bursts.css'; +import React from 'react'; +import { makeStyles } from '@material-ui/core'; -class Burst extends Component { - render() { - const { theme } = this.props; - - return ( -
-
-
- ); +const useStyles = makeStyles(theme => ({ + burst: { + position: 'absolute', + top: 0, + left: 0, + height: '100%', + width: '100%', + 'z-index': -1, + }, + /* base style of burst shape SVGs */ + burstShape: { + position: 'absolute', + right: 0, + height: '100%', + 'background-repeat': 'no-repeat', + 'background-size': 'cover', + opacity:0.1, } +})); + +const Burst = ({theme}) => { + const classes = useStyles(); + + return ( +
+
+
+ ); } export default Burst; diff --git a/frontend/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.js b/frontend/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.js index d16556d4c2..4fc30019a3 100644 --- a/frontend/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.js +++ b/frontend/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.js @@ -1,6 +1,6 @@ import React, { Fragment } from 'react'; import { IconButton, List, ListItem, ListItemIcon, ListItemText, Popover } from '@material-ui/core'; -import { KebabMenuIcon } from 'shared/icons'; +import { default as KebabMenuIcon } from './MenuVertical'; const ActionItem = ({ label, secondaryLabel, icon, disabled = false, onClick, WrapperComponent = React.Fragment }) => { return ( diff --git a/frontend/packages/core/src/layout/HeaderActionMenu/MenuVertical.tsx b/frontend/packages/core/src/layout/HeaderActionMenu/MenuVertical.tsx new file mode 100644 index 0000000000..fa744f861e --- /dev/null +++ b/frontend/packages/core/src/layout/HeaderActionMenu/MenuVertical.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; + +const SvgMenuVertical = (props: SvgIconProps) => + React.createElement( + SvgIcon, + props, + , + ); + +export default SvgMenuVertical; diff --git a/frontend/packages/core/src/layout/HeaderLabel/HeaderLabel.js b/frontend/packages/core/src/layout/HeaderLabel/HeaderLabel.js index 91290412b3..72f2cc86a0 100644 --- a/frontend/packages/core/src/layout/HeaderLabel/HeaderLabel.js +++ b/frontend/packages/core/src/layout/HeaderLabel/HeaderLabel.js @@ -41,7 +41,7 @@ class HeaderLabel extends Component { return ( {label} - {url ? {content} : content} + {url ? {content} : content} ); } diff --git a/frontend/packages/core/src/layout/HeaderLabel/OwnerHeaderLabel.js b/frontend/packages/core/src/layout/HeaderLabel/OwnerHeaderLabel.js index 5c71c1b6ea..01a694e99a 100644 --- a/frontend/packages/core/src/layout/HeaderLabel/OwnerHeaderLabel.js +++ b/frontend/packages/core/src/layout/HeaderLabel/OwnerHeaderLabel.js @@ -1,10 +1,9 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { Tooltip, withStyles } from '@material-ui/core'; +import { Tooltip, Link, withStyles } from '@material-ui/core'; -import { StatusError } from 'shared/components/Status'; -import Link from 'shared/components/Link'; -import HeaderLabel from 'shared/components/layout/HeaderLabel'; +import { StatusError } from '../../components/Status'; +import HeaderLabel from './HeaderLabel'; const style = theme => ({ notVerified: { @@ -33,7 +32,7 @@ class OwnerHeaderLabel extends Component { const isBadSquad = owner.type !== 'squad'; const notVerified = isBadSquad && ( - + Squad not verified! diff --git a/frontend/packages/core/src/layout/HeaderLabel/OwnerHeaderLabel.test.js b/frontend/packages/core/src/layout/HeaderLabel/OwnerHeaderLabel.test.js index b4e64f64b0..8ced9035e0 100644 --- a/frontend/packages/core/src/layout/HeaderLabel/OwnerHeaderLabel.test.js +++ b/frontend/packages/core/src/layout/HeaderLabel/OwnerHeaderLabel.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { render } from '@testing-library/react'; +import { render, prettyDOM } from '@testing-library/react'; import OwnerHeaderLabel from './OwnerHeaderLabel'; import { wrapInThemedTestApp } from '../../testUtils'; diff --git a/frontend/packages/core/src/layout/InfoCard/BottomLink.js b/frontend/packages/core/src/layout/InfoCard/BottomLink.js index c6b259cb72..d248da6063 100644 --- a/frontend/packages/core/src/layout/InfoCard/BottomLink.js +++ b/frontend/packages/core/src/layout/InfoCard/BottomLink.js @@ -17,7 +17,7 @@ export default class BottomLink extends Component { return (
- + diff --git a/frontend/packages/core/src/layout/Navigation/GcpProjectByTools.tsx b/frontend/packages/core/src/layout/Navigation/GcpProjectByTools.tsx deleted file mode 100644 index 104fcee7d3..0000000000 --- a/frontend/packages/core/src/layout/Navigation/GcpProjectByTools.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; - -const SvgGcpProjectByTools = (props: SvgIconProps) => - React.createElement( - SvgIcon, - props, - , - ); - -export default SvgGcpProjectByTools; diff --git a/frontend/packages/core/src/layout/Navigation/InfoSquared.tsx b/frontend/packages/core/src/layout/Navigation/InfoSquared.tsx deleted file mode 100644 index 0f51727069..0000000000 --- a/frontend/packages/core/src/layout/Navigation/InfoSquared.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; - -const SvgInfoSquared = (props: SvgIconProps) => - React.createElement( - SvgIcon, - props, - , - ); - -export default SvgInfoSquared; diff --git a/frontend/packages/core/src/layout/Navigation/NavItem.js b/frontend/packages/core/src/layout/Navigation/NavItem.js deleted file mode 100644 index b6d47ab9f6..0000000000 --- a/frontend/packages/core/src/layout/Navigation/NavItem.js +++ /dev/null @@ -1,168 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import { matchPath } from 'react-router'; -import { ListItem, ListItemIcon, ListItemText, Typography, withStyles, Tooltip, IconButton } from '@material-ui/core'; -import { AlphaLabel, BetaLabel } from 'shared/components/Lifecycle'; -import Link from 'shared/components/Link'; -import { Theme } from 'shared/components/layout/Page'; -import ArrowDropUp from '@material-ui/icons/ArrowDropUp'; -import ArrowDropDown from '@material-ui/icons/ArrowDropDown'; - -const styles = theme => ({ - root: { - display: 'block', - overflow: 'hidden', - '&:first-child': { - borderTopRightRadius: 6, - borderTopLeftRadius: 6, - }, - '&:last-child': { - borderBottomRightRadius: 6, - borderBottomLeftRadius: 6, - }, - }, - child: { - paddingLeft: theme.spacing(7), - '&:last-child': { - borderBottom: '1px solid #727272', - }, - }, - boldLabel: { - color: '#FFFFFF', - fontWeight: 'bolder', - }, - childLabel: { - color: theme.palette.textVerySubtle, - fontSize: 14, - }, - label: { - whiteSpace: 'nowrap', - lineHeight: 1.0, - }, - iconImg: { - width: 24, - height: 24, - }, - icon: { - margin: theme.spacing(0.5, 2, 0.5, 0), - minWidth: 0, - }, - expand: { - color: 'white', - }, -}); - -class NavItem extends Component { - static defaultProps = { - title: 'Mystery Link', - href: '/', - exact: true, // Only used for react-router matchPath to see if this sidebar item is active - icon: null, - isAlpha: false, - isBeta: false, - type: 'other', // Provided by Navigation - child: false, // Whether this is a child of another NavItem (for indenting) - }; - - // If NavItem has React children, the sub-navigation can be expanded or collapsed - state = { - expanded: false, - }; - - static isActive(href, exact) { - return matchPath(window.location.pathname, { path: href, exact: exact }); - } - - maybeActiveNavStyle(theme) { - return NavItem.isActive(this.props.href, this.props.exact) - ? { - background: `linear-gradient(to right, ${theme.activeNavLinkColor} 0px, ${theme.activeNavLinkColor} 6px, #4F4F4F 6px, #4F4F4F 100%)`, - } - : {}; - } - - renderIcon = (condensed, iconElement, title, classes) => { - if (!iconElement) return null; - const listItemIcon = {iconElement}; - return condensed ? ( - - {listItemIcon} - - ) : ( - listItemIcon - ); - }; - - render() { - const { title, href, icon, isAlpha, isBeta, classes, condensed, child, children } = this.props; - const { expanded } = this.state; - const isSection = !!children; - - // Automatically expand nested nav if one of the child elements is active - const isChildActive = React.Children.toArray(children).some(c => NavItem.isActive(c.props.href, c.props.exact)); - const isExpanded = expanded || isChildActive; - const selfAwareChildren = children && React.cloneElement(children, { child: true }); - - let iconElement; - - if (icon) { - iconElement = typeof icon === 'object' ? icon : {title}; - } - - return ( - - {theme => ( - <> - - - {this.renderIcon(condensed, iconElement, title, classes)} - {!condensed && ( - <> - - {title} - {isAlpha && ( - -   - - - )} - {isBeta && ( - -   - - - )} - - } - disableTypography - /> - {isSection && ( - this.setState(prev => ({ expanded: !prev.expanded }))} - style={{ padding: 4 }} - data-testid="expand-toggle" - > - {isExpanded ? ( - - ) : ( - - )} - - )} - - )} - - - {isExpanded && selfAwareChildren} - - )} - - ); - } -} - -export default withStyles(styles)(NavItem); diff --git a/frontend/packages/core/src/layout/Navigation/NavItem.test.js b/frontend/packages/core/src/layout/Navigation/NavItem.test.js deleted file mode 100644 index 3cc95b635b..0000000000 --- a/frontend/packages/core/src/layout/Navigation/NavItem.test.js +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react'; -import { matchPath } from 'react-router'; -import { fireEvent, render } from '@testing-library/react'; -import NavItem from './NavItem'; -import { wrapInThemedTestApp } from '../../testUtils'; - -jest.mock('react-router', () => ({ - ...jest.requireActual('react-router'), - matchPath: jest.fn(), -})); - -const minProps = { - title: 'A link title', - href: '/mocked', -}; - -const minChildProps = { - title: 'A child title', - href: '/child', -}; - -describe('', () => { - it('renders without exploding', () => { - const rendered = render(wrapInThemedTestApp()); - expect(rendered.getByText('A link title')).toBeInTheDocument(); - }); - - it('should have an anchor with correct href', () => { - const rendered = render(wrapInThemedTestApp()); - const anchor = rendered.container.querySelector('a'); - expect(anchor.href).toBe('http://localhost/mocked'); - }); - - it('renders with icon src', () => { - const rendered = render(wrapInThemedTestApp()); - const icon = rendered.getByAltText('A link title'); - expect(icon.src).toBe('http://localhost/mocked-icon.png'); - }); - - it('renders with icon component', () => { - const Falafel = () =>
falafel
; - const rendered = render(wrapInThemedTestApp(} {...minProps} />)); - const icon = rendered.getByText('falafel'); - expect(icon).toBeInTheDocument(); - }); - - it('shows alpha icon', () => { - const rendered = render(wrapInThemedTestApp()); - expect(rendered.getByText('α')).toBeInTheDocument(); - }); - - it('shows beta icon', () => { - const rendered = render(wrapInThemedTestApp()); - expect(rendered.getByText('β')).toBeInTheDocument(); - }); - - it('renders nested navigation without exploding', () => { - const { getByText, getByTestId } = render( - wrapInThemedTestApp( - - - , - ), - ); - expect(getByText('A link title')).toBeInTheDocument(); - expect(getByTestId('expand-toggle')).toBeInTheDocument(); - }); - - it('toggles nested navigation', () => { - const { getByText, getByTestId, queryByText } = render( - wrapInThemedTestApp( - - - , - ), - ); - expect(queryByText('A child link')).not.toBeInTheDocument(); - fireEvent.click(getByTestId('expand-toggle')); - expect(getByText('A child title')).toBeInTheDocument(); - }); - - it('shows nested navigation automatically if the child is active', () => { - matchPath.mockReturnValue(true); - const { getByText } = render( - wrapInThemedTestApp( - - - , - ), - ); - expect(getByText('A link title')).toBeInTheDocument(); - expect(getByText('A child title')).toBeInTheDocument(); - }); -}); diff --git a/frontend/packages/core/src/layout/Navigation/Navigation.js b/frontend/packages/core/src/layout/Navigation/Navigation.js deleted file mode 100644 index fc5c15340f..0000000000 --- a/frontend/packages/core/src/layout/Navigation/Navigation.js +++ /dev/null @@ -1,91 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { List, withStyles } from '@material-ui/core'; -import ChevronLeft from '@material-ui/icons/ChevronLeft'; -import ChevronRight from '@material-ui/icons/ChevronRight'; - -import { IconButton } from 'shared/components'; -import { getFromStore, saveToStore } from 'shared/apis/storage/persistentStore'; - -const styles = theme => ({ - nav: { - gridArea: 'pageNav', - width: 62, - marginLeft: theme.spacing(3), - marginTop: theme.spacing(3), - transition: 'width 0.07s, height 0s', - transitionTimingFunction: 'ease-in', - }, - item: { - display: 'block', - }, - list: { - padding: 0, - border: '0px solid #333333', - borderRadius: 6, - backgroundColor: '#333333', - }, - buttonContainer: { - marginLeft: 'auto', - marginRight: 'auto', - marginTop: theme.spacing(0.5), - width: 48, - }, - button: { - color: '#888', - }, -}); - -class Navigation extends Component { - static propTypes = { - condensable: PropTypes.bool, - }; - - state = { - condensed: false, - }; - - constructor(props) { - super(props); - - const condensedPref = getFromStore('navigation', 'condensed', false); - this.state.condensed = this.props.condensable && condensedPref; - } - - buttonClicked = () => { - const condensed = !this.state.condensed; - saveToStore('navigation', 'condensed', condensed); - this.setState({ condensed }); - }; - - render() { - const { classes, condensable } = this.props; - const { condensed } = this.state; - - const ExpandButton = condensable && ( -
- - {condensed ? : } - -
- ); - - const children = React.Children.map(this.props.children, child => { - if (!child) return null; - return React.cloneElement(child, { - condensed: condensed, - }); - }); - - return ( - - ); - } -} - -export default withStyles(styles)(Navigation); diff --git a/frontend/packages/core/src/layout/Navigation/Navigation.test.js b/frontend/packages/core/src/layout/Navigation/Navigation.test.js deleted file mode 100644 index ed18457637..0000000000 --- a/frontend/packages/core/src/layout/Navigation/Navigation.test.js +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; -import { render, fireEvent } from '@testing-library/react'; - -import Navigation from './Navigation'; -import NavItem from './NavItem'; -import { wrapInThemedTestApp } from '../../testUtils'; - -import { default as GcpProjectIcon } from './GcpProjectByTools'; -import { default as OverviewIcon } from './InfoSquared'; - -describe('', () => { - it('renders without exploding', () => { - const nav = ( - - } href={'/'} /> - } - href={'/projects'} - /> - - ); - const rendered = render(wrapInThemedTestApp(nav)); - expect(rendered.getByText('Overview')).toBeInTheDocument(); - expect(rendered.getByText('Projects')).toBeInTheDocument(); - }); - - it('renders a condenseable navigation bar', () => { - const nav = ( - - } href={'/'} /> - } - href={'/projects'} - /> - - ); - const rendered = render(wrapInThemedTestApp(nav)); - const btn = rendered.getByTestId('nav-expand-toggle'); - expect(btn).toBeInTheDocument(); - }); - - it('is condenseable', () => { - const nav = ( - - } href={'/'} /> - } - href={'/projects'} - /> - - ); - const rendered = render(wrapInThemedTestApp(nav)); - const btn = rendered.getByTestId('nav-expand-toggle'); - fireEvent.click(btn); - expect(rendered.queryByText('Overview')).not.toBeInTheDocument(); - }); - - it('should have an anchor with correct href', () => { - const nav = ( - - } - href={'/projects'} - /> - - ); - const rendered = render(wrapInThemedTestApp(nav)); - const anchor = rendered.container.querySelector('a'); - expect(anchor.href).toBe('http://localhost/projects'); - }); -}); diff --git a/frontend/packages/core/src/layout/Page/PageThemeProvider.js b/frontend/packages/core/src/layout/Page/PageThemeProvider.js index d6832b82d3..60fef3487e 100644 --- a/frontend/packages/core/src/layout/Page/PageThemeProvider.js +++ b/frontend/packages/core/src/layout/Page/PageThemeProvider.js @@ -1,52 +1,3 @@ -import '../../assets/bursts/bursts.css'; -import circle1 from '../../assets/bursts/circle-1.svg'; -import circle2 from '../../assets/bursts/circle-2.svg'; -import triangle1 from '../../assets/bursts/triangle-1.svg'; -import triangle2 from '../../assets/bursts/triangle-2.svg'; -import triangle3 from '../../assets/bursts/triangle-3.svg'; -import rectangle1 from '../../assets/bursts/rectangle-1.svg'; -import rectangle2 from '../../assets/bursts/rectangle-2.svg'; - -// TODO move this file to shared and out of core - -export const shapes = { - circle1: { - backgroundImage: `url(${circle1})`, - width: 'calc(400px + 20%)', - backgroundPosition: '100px 60%', - }, - circle2: { - backgroundImage: `url(${circle2})`, - width: 'calc(400px + 20%)', - backgroundPosition: '100px 58%', - }, - rectangle1: { - backgroundImage: `url(${rectangle1})`, - width: 'calc(400px + 20%)', - backgroundPosition: '100px 60%', - }, - rectangle2: { - backgroundImage: `url(${rectangle2})`, - width: 'calc(400px + 20%)', - backgroundPosition: '30px 35%', - }, - triangle1: { - backgroundImage: `url(${triangle1})`, - width: 'calc(500px + 30%)', - backgroundPosition: '100px calc(50px + 45%)', - }, - triangle2: { - backgroundImage: `url(${triangle2})`, - width: 'calc(400px + 20%)', - backgroundPosition: '100px 38%', - }, - triangle3: { - backgroundImage: `url(${triangle3})`, - width: 'calc(400px + 20%)', - backgroundPosition: '100px 76%', - }, -}; - export const gradients = { blue: 'linear-gradient(135deg, #2D46B9 0%, #509BF5 100%)', darkBlue: 'linear-gradient(44deg, #1E3264 0%, #A0C3D2 100%)', @@ -71,102 +22,26 @@ export const theme = { service: { activeNavLinkColor: '#1D7F6E', gradient: gradients.tealGreen, - burstShape: shapes.rectangle2, - }, - appFeature: { - activeNavLinkColor: '#FF6437', - gradient: gradients.orangeYellow, - burstShape: shapes.triangle1, - }, - app: { - activeNavLinkColor: '#A72525', - gradient: gradients.redOrange, - burstShape: shapes.triangle1, - }, - endpoint: { - activeNavLinkColor: '#9315b0', - gradient: gradients.purpleBlue, - burstShape: shapes.circle1, - }, - pipeline: { - activeNavLinkColor: '#9315b0', - gradient: gradients.purpleBlue, - burstShape: shapes.circle1, + burstShape: null, }, website: { activeNavLinkColor: '#765d90', gradient: gradients.purple, - burstShape: shapes.rectangle2, - }, - workflow: { - activeNavLinkColor: '#AF2996', - secondary: '#9315b0', - gradient: gradients.purpleBlue, - burstShape: shapes.circle1, - }, - library: { - activeNavLinkColor: '#B39AC8', - gradient: gradients.sunset, - burstShape: shapes.triangle3, - }, - other: { - activeNavLinkColor: '#8f6858', - gradient: gradients.brown, - burstShape: shapes.rectangle1, - }, - system: { - activeNavLinkColor: '#526C90', - gradient: gradients.darkBlue, - burstShape: shapes.triangle2, - }, - project: { - activeNavLinkColor: '#F13DA2', - gradient: gradients.pinkOrange, - burstShape: shapes.triangle3, - }, - tool: { - activeNavLinkColor: '#B39AC8', - gradient: gradients.violetPeach, - burstShape: shapes.rectangle1, + burstShape: null, }, home: { activeNavLinkColor: '#00814e', gradient: gradients.green, - burstShape: shapes.triangle2, + burstShape: null, }, org: { activeNavLinkColor: '#6044ef', gradient: gradients.violetGreen, - burstShape: shapes.triangle3, + burstShape: null, }, documentation: { activeNavLinkColor: '#04c2ba', gradient: gradients.tpm, - burstShape: shapes.circle2, - }, - blogPost: { - activeNavLinkColor: '#FFF', - gradient: 'linear-gradient(90deg, #033A45 0%, #033A45 100%)', - burstShape: shapes.circle2, - }, - machineLearning: { - activeNavLinkColor: '#0033DD', - gradient: gradients.royalBlue, - burstShape: shapes.circle1, - }, - partnership: { - activeNavLinkColor: '#000000', - gradient: gradients.grey, - burstShape: shapes.rectangle2, - }, - ml: { - activeNavLinkColor: '#B39AC8', - gradient: gradients.blue, - burstShape: shapes.circle1, - }, - scienceBox: { - activeNavLinkColor: '#69B9FF', // matches sky gradient beginning point - gradient: gradients.sky, - burstShape: shapes.circle1, + burstShape: null, }, }; \ No newline at end of file diff --git a/frontend/packages/core/src/layout/Page/index.ts b/frontend/packages/core/src/layout/Page/index.ts index 889778f7e8..34a8b93753 100644 --- a/frontend/packages/core/src/layout/Page/index.ts +++ b/frontend/packages/core/src/layout/Page/index.ts @@ -1,2 +1,2 @@ export { default } from './Page'; -export { shapes, gradients, theme } from './PageThemeProvider'; \ No newline at end of file +export { gradients, theme } from './PageThemeProvider'; \ No newline at end of file diff --git a/frontend/packages/core/src/layout/SupportButton/SupportButton.js b/frontend/packages/core/src/layout/SupportButton/SupportButton.js deleted file mode 100644 index b8663fcb77..0000000000 --- a/frontend/packages/core/src/layout/SupportButton/SupportButton.js +++ /dev/null @@ -1,114 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import { compose } from 'recompose'; -import { List, ListItem, ListItemIcon, Popover, Typography, withStyles } from '@material-ui/core'; -import { withPluginContext } from 'core/app/withPluginContext'; -import { EmailIcon, SlackIcon, SupportIcon } from 'shared/icons'; -import { Button, Link } from 'shared/components'; -import { StackOverflow, StackOverflowTag } from 'shared/components/layout'; - -class SupportButton extends Component { - static defaultProps = { - slackChannel: '#backstage', - }; - - static propTypes = { - slackChannel: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), - }; - - state = { - popoverOpen: false, - anchorEl: null, - }; - - button_clickHandler = event => { - this.setState({ anchorEl: event.currentTarget, popoverOpen: true }); - }; - - popover_closeHandler = () => { - this.setState({ popoverOpen: false }); - }; - - render() { - const { slackChannel, email, children, classes, plugin } = this.props; - const tags = plugin ? plugin.stackoverflowTags : undefined; // plugin is undefined on base routes - const { popoverOpen, anchorEl } = this.state; - const slackChannels = slackChannel ? (Array.isArray(slackChannel) ? slackChannel : [slackChannel]) : null; - const contactEmails = email ? (Array.isArray(email) ? email : [email]) : null; - - return ( - - - - - {React.Children.map(children, (child, index) => ( - - {child} - - ))} - {tags && tags.length > 0 && ( - - - {tags.map((tag, idx) => ( - - ))} - - - )} - {slackChannels && ( - - - - -
- Support - {slackChannels.map((channel, index) => ( - - {channel} - - ))} -
-
- )} - {contactEmails && ( - - - - -
- Contact - {contactEmails.map((email, index) => ( - - {email} - - ))} -
-
- )} -
-
-
- ); - } -} - -const styles = theme => ({ - leftIcon: { - marginRight: theme.spacing(1), - }, - popoverList: { - minWidth: 260, - maxWidth: 320, - }, -}); - -export default compose(withStyles(styles), withPluginContext)(SupportButton); diff --git a/frontend/packages/core/src/layout/SupportButton/SupportButton.test.js b/frontend/packages/core/src/layout/SupportButton/SupportButton.test.js deleted file mode 100644 index d008fc42b6..0000000000 --- a/frontend/packages/core/src/layout/SupportButton/SupportButton.test.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { render, fireEvent, waitForElement } from '@testing-library/react'; - -import SupportButton from './SupportButton'; -import { wrapInThemedTestApp, Keyboard } from '../../testUtils'; - -describe('', () => { - it('renders without exploding', () => { - const rendered = render(); - rendered.getByText('Support'); - - fireEvent.click(rendered.baseElement); - }); - - it('should show popover', () => { - const rendered = render( - wrapInThemedTestApp(), - ); - - expect(rendered.queryByText('Contact')).not.toBeInTheDocument(); - fireEvent.click(rendered.getByText('Support')); - expect(rendered.queryByText('Contact')).toBeInTheDocument(); - rendered.getByText('a@b.com'); - rendered.getByText('a-tag'); - }); - - it('should close popover when hitting escape', async () => { - const rendered = render(wrapInThemedTestApp()); - - fireEvent.click(rendered.getByText('Support')); - expect(rendered.queryByText('Contact')).toBeInTheDocument(); - await Keyboard.type(rendered, ''); - await waitForElement(() => !rendered.queryByText('Contact')); - expect(rendered.queryByText('Contact')).not.toBeInTheDocument(); - }); -}); diff --git a/frontend/packages/core/src/testUtils/index.js b/frontend/packages/core/src/testUtils/index.js index 5c5ed40741..ae521780e7 100644 --- a/frontend/packages/core/src/testUtils/index.js +++ b/frontend/packages/core/src/testUtils/index.js @@ -1,46 +1,31 @@ /** - * Helpers for testing redux components and containers + * Helpers for testing components */ +import React from 'react'; import { MuiThemeProvider } from '@material-ui/core'; import { ThemeProvider } from '@material-ui/styles'; -import React from 'react'; -import { act } from 'react-dom/test-utils'; -import { ApolloProvider } from '@apollo/react-hooks'; -import { Provider } from 'react-redux'; + import { MemoryRouter } from 'react-router'; import { Route } from 'react-router-dom'; -import configureStore from 'redux-mock-store'; -import thunk from 'redux-thunk'; -import { V1 } from 'core/app/Themes'; -import defaultAppState from 'core/defaultAppState'; -import store from 'core/store'; -import ErrorBoundary from 'shared/components/ErrorBoundary'; -import { SearchProvider } from 'plugins/searchPage/SearchContext'; - -import { render } from '@testing-library/react'; -import { FirestoreProvider } from 'shared/apis/firestore'; -import MockFirestoreStorage from 'shared/apis/firestore/MockFirestoreStorage'; -import { UserInfoProvider, defaultMockUser } from 'shared/apis/user'; +import { V1 } from '../theme/BackstageTheme'; +import ErrorBoundary from '../layout/ErrorBoundary'; export { default as Keyboard } from './Keyboard'; export { default as mockBreakpoint } from './mockBreakpoint'; -export function wrapInTestApp(Component, initialRouterEntries, user = defaultMockUser) { +export function wrapInTestApp( + Component, + initialRouterEntries, +) { const Wrapper = Component instanceof Function ? Component : () => Component; return ( - - - - - - - - - - - + + + + + ); } @@ -53,227 +38,6 @@ export function wrapInThemedTestApp(component, initialRouterEntries) { return wrapInTestApp(themed, initialRouterEntries); } -export function wrapInSearchTestApp(component) { - const search = {component}; - return wrapInThemedTestApp(search); -} - -export function getTestStore(state) { - const appState = state ? state : defaultAppState; - const mockStore = configureStore([thunk]); - return mockStore(appState); -} - -export function getGoogleProfile() { - return { - getName: () => 'Niklas', - getGivenName: () => 'Niklas', - getEmail: () => 'niklas@spotify.com', - getImageUrl: () => 'http://img.url', - getId: () => '123456', - }; -} - -const DEFAULT_APOLLO_STATE = { - data: { loading: true }, -}; - -export const ApolloMock = ({ children, state = DEFAULT_APOLLO_STATE }) => { - // Hideous mocking of the ApolloClient to use the ApolloProvider - // The test do not have information about the GraphQL queries made by the components - // and hence we cant use MockedProvider and use the one below. - const mockClient = { - query: async () => state, - watchQuery: () => { - return { - refetch: () => {}, - fetchMore: () => {}, - updateQuery: () => {}, - startPolling: () => {}, - stopPolling: () => {}, - subscribeToMore: () => {}, - options: { - fetchPolicy: {}, - }, - getLastResult: () => {}, - currentResult: () => state, - getCurrentResult: () => state, - resetQueryStoreErrors: () => {}, - subscribe: () => {}, - setOptions: () => Promise.resolve({}), - }; - }, - }; - return {children}; -}; - -/** - * Return a builder for a given Component which will permit fluent immutable - * configuration and access to @testing-library/react rendering functions. - * - * A full example will make the utility of this more clear: - * - * const builder = buildComponentInApp(MyComponent) - * .withProps({myProp: 'myValue'}) - * - * // MuiThemeProvider will wrap MyComponent when this is called: - * .withTheme() - * - * // MemoryRouter can be configured with initialEntries: - * .withRouterEntries(['/']) - * - * // ApolloProvider wraps MyComponent with a mock client setup to - * // provide the given data: - * .withApolloData({ - * component: {id: 'my-component', system: 'my-system'} - * }); - * - * // Test 1: Use the defaults from above when mounting - * const { getByText } = builder.render(); - * expect(getByText('Display Text').querySelectorAll('td')).toHaveLength(1); - - * // Test 2: ApolloRouter provides loading=true state instead of valid data - * const { queryByText } = builder.withApolloLoading().render(); - * queryByText('Content').toBeNull(); - */ -export function buildComponentInApp(Component) { - function createBuilder(opt = {}) { - const builder = { - withProps: (props = {}) => - createBuilder({ - ...opt, - props: Object.assign(opt.props || {}, props), - }), - withTheme: (theme = V1) => - createBuilder({ - ...opt, - theme, - }), - withRouterEntries: routerEntries => - createBuilder({ - ...opt, - routerEntries, - }), - withApolloLoading: () => - // Support `data.loading` (errorOrLoading) or just `loading` (Query) - createBuilder({ - ...opt, - apolloState: { data: { loading: true }, loading: true }, - }), - withApolloData: data => - createBuilder({ - ...opt, - apolloState: { data: { loading: false, ...data } }, - }), - withApolloError: error => - createBuilder({ - ...opt, - apolloState: { error: error }, - }), - withUser: user => - createBuilder({ - ...opt, - user, - }), - build: (argProps = {}) => { - const props = { ...(opt.props || {}), ...argProps }; - const component = ; - const routed = wrapInTestApp(component, opt.routerEntries, opt.user); - const themed = opt.theme ? {routed} : routed; - return opt.apolloState ? {themed} : themed; - }, - render: props => { - return render(builder.build(props)); - }, - renderWithEffects: async props => { - return renderWithEffects(builder.build(props)); - }, - }; - return builder; - } - return createBuilder(); -} - -// Components using useEffect to perform an asynchronous action (such as fetch) must be rendered within an async -// act call to properly get the final state, even with mocked responses. This utility method makes the signature a bit -// cleaner, since act doesn't return the result of the evaluated function. -// https://github.com/testing-library/react-testing-library/issues/281 -// https://github.com/facebook/react/pull/14853 -export async function renderWithEffects(nodes) { - let value; - await act(async () => { - value = await render(nodes); - }); - return value; -} - -export function logBoundaryErrors() { - ErrorBoundary.onError = error => console.error('ErrorBoundary received error', error); -} - -// Runs a function with all error logging captured and returned as an array. -// If the callback function is async this one will be too. -export function withLogCollector(logsToCollect, callback) { - if (typeof logsToCollect === 'function') { - callback = logsToCollect; - logsToCollect = ['log', 'warn', 'error']; - } - const logs = { - log: [], - warn: [], - error: [], - }; - - const origLog = console.log; - const origWarn = console.warn; - const origError = console.error; - - if (logsToCollect.includes('log')) { - console.log = message => { - logs.log.push(message); - }; - } - if (logsToCollect.includes('warn')) { - console.warn = message => { - logs.warn.push(message); - }; - } - if (logsToCollect.includes('error')) { - console.error = message => { - logs.error.push(message); - }; - } - - const restore = () => { - console.log = origLog; - console.warn = origWarn; - console.error = origError; - }; - - try { - const ret = callback(); - - if (!ret || !ret.then) { - restore(); - return logs; - } - - return ret.then( - () => { - restore(); - return logs; - }, - error => { - restore(); - throw error; - }, - ); - } catch (error) { - restore(); - throw error; - } -} - export const wrapInTheme = (component, theme = V1) => ( {component} diff --git a/frontend/packages/core/src/theme/BackstageTheme.js b/frontend/packages/core/src/theme/BackstageTheme.js index d69a86ac37..5185aa8cd7 100644 --- a/frontend/packages/core/src/theme/BackstageTheme.js +++ b/frontend/packages/core/src/theme/BackstageTheme.js @@ -355,4 +355,4 @@ const styles = theme => ({ }); export const withGlobalStyles = withStyles(styles); -export default BackstageTheme; \ No newline at end of file +export default BackstageTheme; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 64df4b69f2..cd1327d08d 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -3596,7 +3596,7 @@ arrify@^1.0.1: resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asap@^2.0.0, asap@~2.0.6: +asap@^2.0.0, asap@~2.0.3, asap@~2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -4452,6 +4452,11 @@ chalk@^1.0.0, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +change-emitter@^0.1.2: + version "0.1.6" + resolved "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" + integrity sha1-6LL+PX8at9aaMhma/5HqaTFAlRU= + chardet@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -5123,6 +5128,11 @@ core-js-pure@^3.0.0: resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a" integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw== +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= + core-js@^2.4.0, core-js@^2.5.0: version "2.6.11" resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" @@ -6776,6 +6786,19 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fbjs@^0.8.1: + version "0.8.17" + resolved "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" + integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" @@ -7685,6 +7708,11 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^2.3.1: + version "2.5.5" + resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" + integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== + hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.2.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -8572,7 +8600,7 @@ is-ssh@^1.3.0: dependencies: protocols "^1.1.0" -is-stream@^1.0.0, is-stream@^1.1.0: +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -8665,6 +8693,14 @@ isobject@^4.0.0: resolved "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + isstream@~0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -11053,6 +11089,14 @@ node-fetch-npm@^2.0.2: json-parse-better-errors "^1.0.0" safe-buffer "^5.1.1" +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-fetch@^2.3.0, node-fetch@^2.5.0: version "2.6.0" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" @@ -13015,6 +13059,13 @@ promise-retry@^1.1.1: err-code "^1.0.0" retry "^0.10.0" +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + promise@^8.0.3: version "8.0.3" resolved "https://registry.npmjs.org/promise/-/promise-8.0.3.tgz#f592e099c6cddc000d538ee7283bb190452b0bf6" @@ -13329,6 +13380,11 @@ react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-i resolved "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== +react-lifecycles-compat@^3.0.2: + version "3.0.4" + resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + react-router-dom@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18" @@ -13583,6 +13639,18 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" +recompose@0.30.0: + version "0.30.0" + resolved "https://registry.npmjs.org/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0" + integrity sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w== + dependencies: + "@babel/runtime" "^7.0.0" + change-emitter "^0.1.2" + fbjs "^0.8.1" + hoist-non-react-statics "^2.3.1" + react-lifecycles-compat "^3.0.2" + symbol-observable "^1.0.4" + recursive-readdir@2.2.2: version "2.2.2" resolved "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" @@ -14287,7 +14355,7 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -15093,7 +15161,7 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" -symbol-observable@^1.1.0: +symbol-observable@^1.0.4, symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== @@ -15548,6 +15616,11 @@ typescript@^3.7.4, typescript@^3.7.5: resolved "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== +ua-parser-js@^0.7.18: + version "0.7.21" + resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777" + integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ== + uglify-js@3.4.x: version "3.4.10" resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" @@ -16057,7 +16130,7 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" -whatwg-fetch@^3.0.0: +whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==