Introduce Patternfly 4

Since Patternfly 4 (PF4) is a complete rewrite of the framework that
doesn't require bootstrap and comes with a new npm package, it's
possible to include both side-by-side in a project.

This change includes the necessary PF4 packages and updates the header,
navbar, drawer (shows the config errors) and global page layout with PF4
components. Once this is done, we should be able to update the other
components step by step to PF4.

Points to keep in mind for the migration phase:
  1. Some Patternfly 3 CSS rules are overridden by Patternfly 4
     wildcards, mostly (re)setting the padding and margin of various
     elements to 0.

     To fix this unwanted behaviour, there is a pf4-migration.css file
     included were we can keep track on those rules and ensure that the
     old padding and margin values are re-applied after Patternfly 4 is
     imported.

Change-Id: I77b81fa0f97fe718207ba5a506cee300371c693b
This commit is contained in:
Felix Edel 2020-06-17 15:54:38 +02:00
parent 22ddf90cc3
commit 65653bcd01
No known key found for this signature in database
GPG Key ID: E95717A102DD3030
27 changed files with 537 additions and 214 deletions

View File

@ -7,6 +7,7 @@
"license": "Apache-2.0",
"private": true,
"dependencies": {
"@patternfly/react-core": "^4.18.5",
"axios": "^0.19.0",
"immutability-helper": "^2.8.1",
"js-yaml": "^3.13.0",

View File

@ -21,18 +21,51 @@ import { matchPath, withRouter } from 'react-router'
import { Link, Redirect, Route, Switch } from 'react-router-dom'
import { connect } from 'react-redux'
import {
Icon,
Masthead,
Notification,
NotificationDrawer,
TimedToastNotification,
ToastNotificationList,
} from 'patternfly-react'
import * as moment from 'moment'
import {
Brand,
Button,
ButtonVariant,
Drawer,
DrawerActions,
DrawerCloseButton,
DrawerContent,
DrawerContentBody,
DrawerPanelContent,
Dropdown,
DropdownItem,
KebabToggle,
Nav,
NavItem,
NavList,
NotificationBadge,
NotificationDrawer,
NotificationDrawerBody,
NotificationDrawerHeader,
NotificationDrawerList,
NotificationDrawerListItem,
NotificationDrawerListItemBody,
NotificationDrawerListItemHeader,
Page,
PageHeader,
PageHeaderTools,
PageHeaderToolsGroup,
PageHeaderToolsItem,
} from '@patternfly/react-core'
import {
BellIcon,
BookIcon,
CodeIcon,
UsersIcon,
} from '@patternfly/react-icons'
import ErrorBoundary from './containers/ErrorBoundary'
import SelectTz from './containers/timezone/SelectTz'
import logo from './images/logo.png'
import logo from './images/logo.svg'
import { clearError } from './actions/errors'
import { fetchConfigErrorsAction } from './actions/configErrors'
import { routes } from './routes'
@ -47,49 +80,45 @@ class App extends React.Component {
timezone: PropTypes.string,
location: PropTypes.object,
history: PropTypes.object,
dispatch: PropTypes.func
dispatch: PropTypes.func,
isKebabDropdownOpen: false,
}
state = {
menuCollapsed: true,
showErrors: false
}
onNavToggleClick = () => {
this.setState({
menuCollapsed: !this.state.menuCollapsed
})
}
onNavClick = () => {
this.setState({
menuCollapsed: true
})
}
constructor() {
super()
this.menu = routes()
showErrors: false,
}
renderMenu() {
const { location } = this.props
const { location, tenant } = this.props
const activeItem = this.menu.find(
item => location.pathname === item.to
)
return (
<ul className='nav navbar-nav navbar-primary'>
{this.menu.filter(item => item.title).map(item => (
<li key={item.to} className={item === activeItem ? 'active' : ''}>
<Link
to={this.props.tenant.linkPrefix + item.to}
onClick={this.onNavClick}>
{item.title}
</Link>
</li>
))}
</ul>
)
if (tenant.name) {
return (
<Nav aria-label="Nav" variant="horizontal">
<NavList>
{this.menu.filter(item => item.title).map(item => (
<NavItem
itemId={item.to}
key={item.to}
isActive={item === activeItem}
>
<Link
to={this.props.tenant.linkPrefix + item.to}
onClick={this.onNavClick}
>
{item.title}
</Link>
</NavItem>
))}
</NavList>
</Nav>
)
} else {
// Return an empty navigation bar in case we don't have an active tenant
return <Nav aria-label="Nav" variant="horizontal"/>
}
}
renderContent = () => {
@ -158,6 +187,43 @@ class App extends React.Component {
}
}
constructor() {
super()
this.menu = routes()
}
handleKebabDropdownToggle = (isKebabDropdownOpen) => {
this.setState({
isKebabDropdownOpen
})
}
handleKebabDropdownSelect = () => {
this.setState({
isKebabDropdownOpen: !this.state.isKebabDropdownOpen
})
}
handleApiLink = () => {
const { history } = this.props
history.push('/openapi')
}
handleDocumentationLink = () => {
window.open('https://zuul-ci.org/docs', '_blank', 'noopener noreferrer')
}
handleTenantLink = () => {
const { history, tenant } = this.props
history.push(tenant.defaultRoute)
}
handleDrawerClose = () => {
this.setState({
showErrors: false
})
}
renderErrors = (errors) => {
return (
<ToastNotificationList>
@ -191,107 +257,163 @@ class App extends React.Component {
ctxPath += ' (' + item.source_context.branch + ')'
}
errors.push(
<Notification
<NotificationDrawerListItem
key={idx}
seen={false}
variant="danger"
onClick={() => {
history.push(this.props.tenant.linkPrefix + '/config-errors')
this.setState({showErrors: false})
}}
>
<Icon className='pull-left' type='pf' name='error-circle-o' />
<Notification.Content>
<Notification.Message>
{error}
</Notification.Message>
<Notification.Info
leftText={item.source_context.project}
rightText={ctxPath}
/>
</Notification.Content>
</Notification>
<NotificationDrawerListItemHeader title={error} variant="danger" />
<NotificationDrawerListItemBody>
{item.source_context.project} | {ctxPath}
</NotificationDrawerListItemBody>
</NotificationDrawerListItem>
)
})
return (
<NotificationDrawer style={{minWidth: '500px'}}>
<NotificationDrawer.Panel>
<NotificationDrawer.PanelHeading>
<NotificationDrawer.PanelTitle>
Config Errors
</NotificationDrawer.PanelTitle>
<NotificationDrawer.PanelCounter
text={errors.length + ' error(s)'} />
</NotificationDrawer.PanelHeading>
<NotificationDrawer.PanelCollapse id={1} collapseIn>
<NotificationDrawer.PanelBody key='containsNotifications'>
{errors.map(item => (item))}
</NotificationDrawer.PanelBody>
</NotificationDrawer.PanelCollapse>
</NotificationDrawer.Panel>
</NotificationDrawer>
return (
<DrawerPanelContent>
<NotificationDrawer>
<NotificationDrawerHeader
count={errors.length}
title="Config Errors"
unreadText="error(s)"
>
<DrawerActions>
<DrawerCloseButton onClick={this.handleDrawerClose} />
</DrawerActions>
</NotificationDrawerHeader>
<NotificationDrawerBody>
<NotificationDrawerList>
{errors.map(item => (item))}
</NotificationDrawerList>
</NotificationDrawerBody>
</NotificationDrawer>
</DrawerPanelContent>
)
}
render() {
const { menuCollapsed, showErrors } = this.state
const { isKebabDropdownOpen, showErrors } = this.state
const { errors, configErrors, tenant } = this.props
const nav = this.renderMenu()
const kebabDropdownItems = [
<DropdownItem key="api" onClick={event => this.handleApiLink(event)}>
<CodeIcon /> API
</DropdownItem>,
<DropdownItem
key="documentation"
onClick={event => this.handleDocumentationLink(event)}
>
<BookIcon /> Documentation
</DropdownItem>,
]
if (tenant.name) {
kebabDropdownItems.push(
<DropdownItem
key="tenant"
onClick={event => this.handleTenantLink(event)}
>
<UsersIcon /> Tenant
</DropdownItem>
)
}
const pageHeaderTools = (
<PageHeaderTools>
{/* The utility navbar is only visible on desktop sizes
and replaced by a kebab dropdown for smaller sizes */}
<PageHeaderToolsGroup
visibility={{ default: 'hidden', lg: 'visible' }}
>
<PageHeaderToolsItem>
<Link to='/openapi'>
<Button variant={ButtonVariant.plain}>
<CodeIcon /> API
</Button>
</Link>
</PageHeaderToolsItem>
<PageHeaderToolsItem>
<a
href='https://zuul-ci.org/docs'
rel='noopener noreferrer'
target='_blank'
>
<Button variant={ButtonVariant.plain}>
<BookIcon /> Documentation
</Button>
</a>
</PageHeaderToolsItem>
{tenant.name && (
<PageHeaderToolsItem>
<Link to={tenant.defaultRoute}>
<Button variant={ButtonVariant.plain}>
<strong>Tenant</strong> {tenant.name}
</Button>
</Link>
</PageHeaderToolsItem>
)}
</PageHeaderToolsGroup>
<PageHeaderToolsGroup>
{/* this kebab dropdown replaces the icon buttons and is hidden for
desktop sizes */}
<PageHeaderToolsItem visibility={{ lg: 'hidden' }}>
<Dropdown
isPlain
position="right"
onSelect={this.handleKebabDropdownSelect}
toggle={<KebabToggle onToggle={this.handleKebabDropdownToggle} />}
isOpen={isKebabDropdownOpen}
dropdownItems={kebabDropdownItems}
/>
</PageHeaderToolsItem>
</PageHeaderToolsGroup>
{configErrors.length > 0 &&
<NotificationBadge
isRead={false}
aria-label="Notifications"
onClick={(e) => {
e.preventDefault()
this.setState({showErrors: !this.state.showErrors})
}}
>
<BellIcon />
</NotificationBadge>
}
<SelectTz/>
</PageHeaderTools>
)
const pageHeader = (
<PageHeader
logo={<Brand src={logo} alt='Zuul logo' className="zuul-brand" />}
logoProps={{href: tenant.defaultRoute}}
headerTools={pageHeaderTools}
topNav={nav}
/>
)
const drawerPanelContent = this.renderConfigErrors(configErrors)
return (
<React.Fragment>
<Masthead
iconImg={logo}
onNavToggleClick={this.onNavToggleClick}
navToggle
thin
>
<div className='collapse navbar-collapse'>
{tenant.name && this.renderMenu()}
<ul className='nav navbar-nav navbar-utility'>
{ configErrors.length > 0 &&
<NotificationDrawer.Toggle
className="zuul-config-errors"
hasUnreadMessages
style={{color: 'orange'}}
onClick={(e) => {
e.preventDefault()
this.setState({showErrors: !this.state.showErrors})}}
/>
}
<li>
<Link to='/openapi'>API</Link>
</li>
<li>
<a href='https://zuul-ci.org/docs'
rel='noopener noreferrer' target='_blank'>
Documentation
</a>
</li>
{tenant.name && (
<li>
<Link to={tenant.defaultRoute}>
<strong>Tenant</strong> {tenant.name}
</Link>
</li>
)}
<li>
<SelectTz/>
</li>
</ul>
{showErrors && this.renderConfigErrors(configErrors)}
</div>
{!menuCollapsed && (
<div className='collapse navbar-collapse navbar-collapse-1 in'>
{tenant.name && this.renderMenu()}
</div>
)}
</Masthead>
{errors.length > 0 && this.renderErrors(errors)}
<div className='container-fluid container-cards-pf'>
<ErrorBoundary>
{this.renderContent()}
</ErrorBoundary>
</div>
<Page header={pageHeader}>
<Drawer isExpanded={showErrors}>
<DrawerContent panelContent={drawerPanelContent}>
<DrawerContentBody>
<ErrorBoundary>
{this.renderContent()}
</ErrorBoundary>
</DrawerContentBody>
</DrawerContent>
</Drawer>
</Page>
</React.Fragment>
)
}

View File

@ -116,7 +116,7 @@ class Pipeline extends React.Component {
const { pipeline, filter, expanded } = this.props
const count = this.createTree(pipeline)
return (
<div className="zuul-pipeline col-sm-6 col-md-4">
<div className="pf-c-content zuul-pipeline col-sm-6 col-md-4">
<div className="zuul-pipeline-header">
<h3>{pipeline.name} <Badge>{count}</Badge></h3>
{pipeline.description ? (

View File

@ -14,7 +14,7 @@ import PropTypes from 'prop-types'
import React from 'react'
import Select from 'react-select'
import moment from 'moment-timezone'
import { Icon } from 'patternfly-react'
import { OutlinedClockIcon } from '@patternfly/react-icons'
import { connect } from 'react-redux'
import { setTimezoneAction } from '../../actions/timezone'
@ -64,12 +64,8 @@ class SelectTz extends React.Component {
borderWidth: '0 0 0 1px',
cursor: 'pointer',
display: 'initial',
fontSize: '11px',
padding: '6px'
}
const iconStyles = {
padding: '5px'
}
const customStyles = {
container: () => ({
display: 'inline-block',
@ -99,8 +95,9 @@ class SelectTz extends React.Component {
}
return (
<div style={containerStyles}>
<Icon style={iconStyles} type="fa" name="clock-o" />
<OutlinedClockIcon/>
<Select
className="zuul-select-tz"
styles={customStyles}
value={this.state.currentValue}
onChange={this.handleChange}

View File

@ -1,8 +1,13 @@
#root {
/* This is needed to make the navigation bar fixed on top */
height: 100%;
}
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
a.refresh {
cursor: pointer;
border-bottom-style: none;
@ -13,9 +18,17 @@ a.refresh {
white-space: nowrap;
}
/* Notification bell color */
.fa-bell {
color: orange;
/* Navigation bar */
.zuul-brand {
/* TODO (felix): If we can define a size in the logo.svg itself, this
shouldn't be necessary. */
height: 30px;
width: 30px;
}
.zuul-select-tz {
/* That's the color PF4 uses for the dropdown items in the navbar */
color: var(--pf-global--Color--dark-100);
}
/* Status page */
@ -301,3 +314,24 @@ details.foldable summary::before {
details.foldable[open] summary::before {
content: "less";
}
/* Overwrite PF4 navbar rules to enforce the 'lg' layout of the navbar also for
'xl' sized screens. This will keep the navbar stacked (like it was in Zuul
before) and prevent PF4 to put all elements in a single line with horizontal
scrolling (which would look something like:
ZUUL | < Status Projects Jobs Labels No... > | API Documentation Tenant */
@media screen and (min-width: 1200px) {
.pf-c-page__header-nav {
grid-column: 1/-1;
grid-row: 2/3;
}
.pf-c-page {
--pf-c-page__header-nav--PaddingRight: var(
--pf-c-page__header-nav--lg--PaddingRight
);
--pf-c-page__header-nav--PaddingLeft: var(
--pf-c-page__header-nav--lg--PaddingLeft
);
}
}

View File

@ -21,7 +21,18 @@ import { BrowserRouter as Router } from 'react-router-dom'
import { Provider } from 'react-redux'
import 'patternfly/dist/css/patternfly.min.css'
import 'patternfly/dist/css/patternfly-additions.min.css'
import './index.css'
// NOTE (felix): The Patternfly 4 CSS file must be imported before the App
// component. Otherwise, the CSS rules are imported in the wrong order and some
// wildcard expressions could break the layout:
// https://forum.patternfly.org/t/wildcard-selector-more-specific-after-upgrade-to-patternfly-4-react-version-3-75-2/261
// Usually it should be imported at the uppermost positon, but as we don't want
// PF3 to overrule PF4, we import PF4 styles after PF3.
import '@patternfly/react-core/dist/styles/base.css'
// To avoid that PF4 breaks existing PF3 components by some wildcard CSS rules,
// we include our own migration CSS file that restores relevant parts of those
// rules.
// TODO (felix): Remove this import after the PF4 migration
import './pf4-migration.css'
import { getHomepageUrl } from './api'
import registerServiceWorker from './registerServiceWorker'
@ -29,6 +40,11 @@ import { fetchInfoIfNeeded } from './actions/info'
import store from './store'
import App from './App'
// Importing our custom css file after the App allows us to also overwrite the
// style attributes of PF4 component (as their CSS is loaded when the component
// is imported within the App).
import './index.css'
// Load info endpoint
store.dispatch(fetchInfoIfNeeded())

View File

@ -15,6 +15,7 @@
import * as React from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuildIfNeeded } from '../actions/build'
import Refreshable from '../containers/Refreshable'
@ -43,7 +44,7 @@ class BuildPage extends Refreshable {
const { remoteData } = this.props
const build = remoteData.builds[this.props.match.params.buildId]
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
@ -51,7 +52,7 @@ class BuildPage extends Refreshable {
<Build build={build} active='summary'>
<Summary build={build}/>
</Build>}
</React.Fragment>
</PageSection>
)
}
}

View File

@ -15,6 +15,7 @@
import * as React from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuildIfNeeded } from '../actions/build'
import Refreshable from '../containers/Refreshable'
@ -45,7 +46,7 @@ class BuildConsolePage extends Refreshable {
const hash = this.props.location.hash.substring(1).split('/')
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
@ -57,7 +58,7 @@ class BuildConsolePage extends Refreshable {
displayPath={hash.length>0?hash:undefined}
/>
</Build>}
</React.Fragment>
</PageSection>
)
}
}

View File

@ -15,6 +15,7 @@
import * as React from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuildIfNeeded } from '../actions/build'
import Refreshable from '../containers/Refreshable'
@ -43,7 +44,7 @@ class BuildLogsPage extends Refreshable {
const { remoteData } = this.props
const build = remoteData.builds[this.props.match.params.buildId]
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
@ -51,7 +52,7 @@ class BuildLogsPage extends Refreshable {
<Build build={build} active='logs'>
<Manifest tenant={this.props.tenant} build={build}/>
</Build>}
</React.Fragment>
</PageSection>
)
}
}

View File

@ -19,6 +19,7 @@ import { Link } from 'react-router-dom'
import { Table } from 'patternfly-react'
import * as moment from 'moment-timezone'
import 'moment-duration-format'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuilds } from '../api'
import TableFilters from '../containers/TableFilters'
@ -168,10 +169,10 @@ class BuildsPage extends TableFilters {
render() {
const { builds } = this.state
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
{this.renderFilter()}
{builds ? this.renderTable(builds) : <p>Loading...</p>}
</React.Fragment>
</PageSection>
)
}
}

View File

@ -15,6 +15,7 @@
import * as React from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuildsetIfNeeded } from '../actions/build'
import Refreshable from '../containers/Refreshable'
@ -42,12 +43,12 @@ class BuildsetPage extends Refreshable {
const { remoteData } = this.props
const buildset = remoteData.buildsets[this.props.match.params.buildsetId]
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
{buildset && <Buildset buildset={buildset}/>}
</React.Fragment>
</PageSection>
)
}
}

View File

@ -17,6 +17,7 @@ import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import { Table } from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuildsets } from '../api'
import TableFilters from '../containers/TableFilters'
@ -151,10 +152,10 @@ class BuildsetsPage extends TableFilters {
render() {
const { buildsets } = this.state
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
{this.renderFilter()}
{buildsets ? this.renderTable(buildsets) : <p>Loading...</p>}
</React.Fragment>
</PageSection>
)
}
}

View File

@ -15,6 +15,7 @@
import * as React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchChangeIfNeeded } from '../actions/change'
import ChangePanel from '../containers/status/ChangePanel'
@ -56,19 +57,19 @@ class ChangeStatusPage extends Refreshable {
const { remoteData } = this.props
const change = remoteData.change
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div><br />
{change && change.map((item, idx) => (
<div className='row' key={idx}>
<div className='row zuul-change-content' key={idx}>
<ChangePanel
globalExpanded={true}
change={item}
/>
/>
</div>
))}
</React.Fragment>)
</PageSection>)
}
}

View File

@ -18,6 +18,7 @@ import { connect } from 'react-redux'
import {
Icon
} from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchConfigErrorsAction } from '../actions/configErrors'
@ -35,7 +36,7 @@ class ConfigErrorsPage extends React.Component {
render () {
const { configErrors } = this.props
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div className="pull-right">
{/* Lint warning jsx-a11y/anchor-is-valid */}
{/* eslint-disable-next-line */}
@ -61,7 +62,7 @@ class ConfigErrorsPage extends React.Component {
})}
</ul>
</div>
</React.Fragment>
</PageSection>
)
}
}

View File

@ -15,6 +15,7 @@
import * as React from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import Job from '../containers/job/Job'
import Refreshable from '../containers/Refreshable'
@ -51,12 +52,12 @@ class JobPage extends Refreshable {
const tenantJobs = remoteData.jobs[this.props.tenant.name]
const jobName = this.props.match.params.jobName
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
{tenantJobs && tenantJobs[jobName] && <Job job={tenantJobs[jobName]} />}
</React.Fragment>
</PageSection>
)
}
}

View File

@ -15,6 +15,7 @@
import * as React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchJobsIfNeeded } from '../actions/jobs'
import Refreshable from '../containers/Refreshable'
@ -41,7 +42,7 @@ class JobsPage extends Refreshable {
const { remoteData } = this.props
const jobs = remoteData.jobs[this.props.tenant.name]
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
@ -49,7 +50,8 @@ class JobsPage extends Refreshable {
<Jobs
jobs={jobs}
/>}
</React.Fragment>)
</PageSection>
)
}
}

View File

@ -16,6 +16,7 @@ import * as React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Table } from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchLabelsIfNeeded } from '../actions/labels'
import Refreshable from '../containers/Refreshable'
@ -59,7 +60,7 @@ class LabelsPage extends Refreshable {
})
})
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
@ -75,7 +76,8 @@ class LabelsPage extends Refreshable {
rowKey="name"
/>
</Table.PfProvider>
</React.Fragment>)
</PageSection>
)
}
}

View File

@ -16,6 +16,7 @@ import * as React from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { parse } from 'query-string'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchLogfileIfNeeded } from '../actions/logfile'
import Refreshable from '../containers/Refreshable'
@ -110,12 +111,12 @@ class LogFilePage extends Refreshable {
const build = this.props.build.builds[this.props.match.params.buildId]
const severity = parse(this.props.location.search).severity
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
{remoteData.data && <LogFile build={build} data={remoteData.data} severity={severity}/>}
</React.Fragment>
</PageSection>
)
}
}

View File

@ -17,6 +17,7 @@ import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Table } from 'patternfly-react'
import * as moment from 'moment'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchNodesIfNeeded } from '../actions/nodes'
import Refreshable from '../containers/Refreshable'
@ -81,7 +82,7 @@ class NodesPage extends Refreshable {
})
})
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
@ -97,7 +98,7 @@ class NodesPage extends Refreshable {
rowKey="id"
/>
</Table.PfProvider>
</React.Fragment>
</PageSection>
)
}
}

View File

@ -17,6 +17,7 @@ import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import SwaggerUi from 'swagger-ui'
import 'swagger-ui/dist/swagger-ui.css'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchOpenApiIfNeeded } from '../actions/openapi'
import Refreshable from '../containers/Refreshable'
@ -51,12 +52,12 @@ class OpenApiPage extends Refreshable {
render() {
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div className="pull-right" style={{display: 'flex'}}>
{this.renderSpinner()}
</div>
<div id="swaggerContainer" />
</React.Fragment>
</PageSection>
)
}
}

View File

@ -15,6 +15,7 @@
import * as React from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import Project from '../containers/project/Project'
import { fetchProjectIfNeeded } from '../actions/project'
@ -44,13 +45,13 @@ class ProjectPage extends Refreshable {
const tenantProjects = remoteData.projects[this.props.tenant.name]
const projectName = this.props.match.params.projectName
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
{tenantProjects && tenantProjects[projectName] &&
<Project project={tenantProjects[projectName]} />}
</React.Fragment>
</PageSection>
)
}
}

View File

@ -17,6 +17,7 @@ import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import { Table } from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchProjectsIfNeeded } from '../actions/projects'
import Refreshable from '../containers/Refreshable'
@ -84,7 +85,7 @@ class ProjectsPage extends Refreshable {
})
})
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
@ -100,7 +101,7 @@ class ProjectsPage extends Refreshable {
rowKey="name"
/>
</Table.PfProvider>
</React.Fragment>
</PageSection>
)
}
}

View File

@ -23,6 +23,7 @@ import {
FormGroup,
FormControl,
} from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchStatusIfNeeded } from '../actions/status'
import Pipeline from '../containers/status/Pipeline'
@ -212,7 +213,7 @@ class StatusPage extends Refreshable {
</Form>
)
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div className="pull-right" style={{display: 'flex'}}>
{this.renderSpinner()}
<Checkbox
@ -225,7 +226,7 @@ class StatusPage extends Refreshable {
{status && this.renderStatusHeader(status)}
{statusControl}
<div className='row'>
<div className='row zuul-status-content'>
{status && status.pipelines.map(item => (
<Pipeline
pipeline={item}
@ -236,7 +237,7 @@ class StatusPage extends Refreshable {
))}
</div>
{status && this.renderStatusFooter(status)}
</React.Fragment>)
</PageSection>)
}
}

View File

@ -17,6 +17,7 @@ import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import Sockette from 'sockette'
import {Checkbox, Form, FormGroup, FormControl} from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import 'xterm/dist/xterm.css'
import { Terminal } from 'xterm'
@ -176,7 +177,7 @@ class StreamPage extends React.Component {
render () {
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<Form inline>
<FormGroup controlId='stream'>
<FormControl
@ -202,7 +203,7 @@ class StreamPage extends React.Component {
</FormGroup>
</Form>
<div ref={ref => this.terminal = ref}/>
</React.Fragment>
</PageSection>
)
}
}

View File

@ -17,6 +17,7 @@ import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { Link } from 'react-router-dom'
import { Table } from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import Refreshable from '../containers/Refreshable'
import { fetchTenantsIfNeeded } from '../actions/tenants'
@ -77,7 +78,7 @@ class TenantsPage extends Refreshable {
<Link to={'/t/' + tenant.name + '/buildsets'}>Buildsets</Link>)
})
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
@ -93,7 +94,7 @@ class TenantsPage extends Refreshable {
rowKey="name"
/>
</Table.PfProvider>
</React.Fragment>
</PageSection>
)
}
}

92
web/src/pf4-migration.css Normal file
View File

@ -0,0 +1,92 @@
/* Patternfly 4 migration:
* These are extracts from the original Patternfly 3 CSS rules which are
* overridden by some Patternfly 4 CSS wildcard expression. These expressions
* mostly affect the padding and margin of various HTML tags being set to 0.
*
* Those wildcard rules can be found in
* node_modules/@patternfly/react-core/dist/styles/base.css by searching for
* "[class*="pf-c-"]" (without quotes).
*
* To "restore" those original values, we can copy the overwritten parts from
* the original CSS rules and paste them here.
*
* This file should be save to delete after the transition is finished.
*/
.h1, .h2, .h3, h1, h2, h3, .pf-c-title {
margin-top: 20px;
margin-bottom: 10px;
}
pre {
padding: 9.5px;
margin: 0 0 10px;
}
p {
margin: 0 0 10px;
}
/** Global **/
/* Overwrite a PF3 rule that sets a padding-top for the whole body. Most
probably because they placed the menu/navbar atop of the whole body. */
.layout-pf.layout-pf-fixed body {
padding-top: 0;
}
/** Status page **/
/* Correct line height for job result labels on status page due to larger
font size */
span.zuul-job-result.label {
line-height: 0.7;
}
.zuul-job-result {
font-size: small;
}
/* Don't let the "row" class break the page layout */
.zuul-status-content, .zuul-change-content {
margin-left: 0;
margin-right: 0;
}
/* Don't indent the jobs inside a change box */
.zuul-status-content .list-group {
padding-left: 0;
margin-left: 0;
}
/* Avoid that the change boxes are stretched out (too much space in between) */
.zuul-status-content .pf-c-content table:not(:last-child) {
margin-bottom: 0;
}
/* Align the build status indicator (icon left of the change box) at the top */
.zuul-build-status {
vertical-align: top;
}
/* Avoid duplicated lines/borders for the job items on the status page */
.zuul-status-content .pf-c-content li+li {
margin-top: 0;
}
/* Restore padding values for the coluns on the status page */
.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4,
.col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8,
.col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12,
.col-md-1, .col-md-2, .col-md-3, .col-md-4,
.col-md-5, .col-md-6, .col-md-7, .col-md-8,
.col-md-9, .col-md-10, .col-md-11, .col-md-12,
.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4,
.col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8,
.col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12,
.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4,
.col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8,
.col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
padding-right: 20px;
padding-left: 20px;
}

View File

@ -1510,6 +1510,34 @@
dependencies:
"@types/node" ">= 8"
"@patternfly/react-core@^4.18.5":
version "4.18.5"
resolved "https://registry.yarnpkg.com/@patternfly/react-core/-/react-core-4.18.5.tgz#465ee3be0e58f7fdead9644ed2667f18eff0d684"
integrity sha512-wUHLXPOklcAVA9nCnmUvGwdfTZnypxNUnA0l+eEiq1QWhQoSRdI7S/HNOelYhpRjMMwPwy3yMsJUjHsXdqv2FQ==
dependencies:
"@patternfly/react-icons" "^4.3.5"
"@patternfly/react-styles" "^4.3.4"
"@patternfly/react-tokens" "^4.4.4"
focus-trap "4.0.2"
react-dropzone "9.0.0"
tippy.js "5.1.2"
tslib "^1.11.1"
"@patternfly/react-icons@^4.3.5":
version "4.3.5"
resolved "https://registry.yarnpkg.com/@patternfly/react-icons/-/react-icons-4.3.5.tgz#b98c5af80f4729e6203c8e799ace2f57308b3b9a"
integrity sha512-+GublxpFXR+y/5zygf9q00/LvIvso8jr0mxZGhVxsKmi2dUu7xAvN+T+5vjS9fiMbXf7WXsSPXST/UTiBIVTdQ==
"@patternfly/react-styles@^4.3.4":
version "4.3.4"
resolved "https://registry.yarnpkg.com/@patternfly/react-styles/-/react-styles-4.3.4.tgz#ba62f983f1bd2586d2878d8a38912442ebca85e8"
integrity sha512-d5W5G9g7sr7DthGPFiF6Oa33w8JFJ+ocLZDogyZcS1Oq0BJJX8j+hZNXZfhXxmHoXufxQL6RJ4dOyoa2zEZUvA==
"@patternfly/react-tokens@^4.4.4":
version "4.4.4"
resolved "https://registry.yarnpkg.com/@patternfly/react-tokens/-/react-tokens-4.4.4.tgz#4a6fc7234908343087ccbc8e1ae53336d7fc7311"
integrity sha512-vhDBtwkp1PTAqXDjAsUPRf/ewBh2Asong8MPr9ZGeXAeOULW8creW7GJx+JZX9eaEJMA3ESMeZ6wZ5j/yyWMGQ==
"@semantic-release/commit-analyzer@^6.1.0":
version "6.3.3"
resolved "https://registry.yarnpkg.com/@semantic-release/commit-analyzer/-/commit-analyzer-6.3.3.tgz#885f7e46e2f0aef23a23be0904dbf18d6ece45ca"
@ -2714,6 +2742,13 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
attr-accept@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-1.1.3.tgz#48230c79f93790ef2775fcec4f0db0f5db41ca52"
integrity sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ==
dependencies:
core-js "^2.5.0"
autolinker@~0.28.0:
version "0.28.1"
resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47"
@ -4139,7 +4174,7 @@ core-js@^1.0.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=
core-js@^2.4.0, core-js@^2.5.1, core-js@^2.6.5:
core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.1, core-js@^2.6.5:
version "2.6.11"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
@ -4655,7 +4690,7 @@ debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5:
dependencies:
ms "^2.1.1"
debuglog@*, debuglog@^1.0.1:
debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
@ -5910,6 +5945,13 @@ file-loader@4.3.0:
loader-utils "^1.2.3"
schema-utils "^2.5.0"
file-selector@^0.1.8:
version "0.1.12"
resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.1.12.tgz#fe726547be219a787a9dcc640575a04a032b1fd0"
integrity sha512-Kx7RTzxyQipHuiqyZGf+Nz4vY9R1XGxuQl/hLoJwq+J4avk/9wxxgZyHKtbyIPJmbD4A66DWGYfyykWNpcYutQ==
dependencies:
tslib "^1.9.0"
file-uri-to-path@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
@ -6077,6 +6119,14 @@ flux@^3.1.3:
fbemitter "^2.0.0"
fbjs "^0.8.0"
focus-trap@4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-4.0.2.tgz#4ee2b96547c9ea0e4252a2d4b2cca68944194663"
integrity sha512-HtLjfAK7Hp2qbBtLS6wEznID1mPT+48ZnP2nkHzgjpL4kroYHg0CdqJ5cTXk+UO5znAxF5fRUkhdyfgrhh8Lzw==
dependencies:
tabbable "^3.1.2"
xtend "^4.0.1"
follow-redirects@1.5.10:
version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
@ -7093,7 +7143,7 @@ import-local@^2.0.0:
pkg-dir "^3.0.0"
resolve-cwd "^2.0.0"
imurmurhash@*, imurmurhash@^0.1.4:
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
@ -8708,11 +8758,6 @@ lodash-es@^4.2.1:
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
lodash._baseindexof@*:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=
lodash._baseuniq@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
@ -8721,33 +8766,11 @@ lodash._baseuniq@~4.6.0:
lodash._createset "~4.0.0"
lodash._root "~3.0.0"
lodash._bindcallback@*:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
lodash._cacheindexof@*:
version "3.0.2"
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=
lodash._createcache@*:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
dependencies:
lodash._getnative "^3.0.0"
lodash._createset@~4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
lodash._getnative@*, lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
lodash._reinterpolate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
@ -8818,11 +8841,6 @@ lodash.memoize@^4.1.2:
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
lodash.restparam@*:
version "3.6.1"
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
lodash.set@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
@ -10750,7 +10768,7 @@ pnp-webpack-plugin@1.6.4:
dependencies:
ts-pnp "^1.1.6"
popper.js@^1.14.4:
popper.js@^1.14.4, popper.js@^1.16.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
@ -11525,7 +11543,7 @@ promzard@^0.3.0:
dependencies:
read "1"
prop-types-extra@^1.0.1:
prop-types-extra@^1.0.1, prop-types-extra@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/prop-types-extra/-/prop-types-extra-1.1.1.tgz#58c3b74cbfbb95d304625975aa2f0848329a010b"
integrity sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==
@ -11893,6 +11911,16 @@ react-dom@^16.13.1:
prop-types "^15.6.2"
scheduler "^0.19.1"
react-dropzone@9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-9.0.0.tgz#4f5223cdcb4d3bd8a66e3298c4041eb0c75c4634"
integrity sha512-wZ2o9B2qkdE3RumWhfyZT9swgJYJPeU5qHEcMU8weYpmLex1eeWX0CC32/Y0VutB+BBi2D+iePV/YZIiB4kZGw==
dependencies:
attr-accept "^1.1.3"
file-selector "^0.1.8"
prop-types "^15.6.2"
prop-types-extra "^1.1.0"
react-ellipsis-with-tooltip@^1.0.8:
version "1.1.1"
resolved "https://registry.yarnpkg.com/react-ellipsis-with-tooltip/-/react-ellipsis-with-tooltip-1.1.1.tgz#8de6df1f43529a17f840ff9be0003f2080fb8df3"
@ -13925,6 +13953,11 @@ symbol-tree@^3.2.2:
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
tabbable@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.2.tgz#f2d16cccd01f400e38635c7181adfe0ad965a4a2"
integrity sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==
table-resolver@^3.2.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/table-resolver/-/table-resolver-3.3.0.tgz#22e575d3c6aed15404ab71a0f2046c4ff55e556e"
@ -14108,6 +14141,13 @@ tiny-warning@^1.0.0:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tippy.js@5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-5.1.2.tgz#5ac91233c59ab482ef5988cffe6e08bd26528e66"
integrity sha512-Qtrv2wqbRbaKMUb6bWWBQWPayvcDKNrGlvihxtsyowhT7RLGEh1STWuy6EMXC6QLkfKPB2MLnf8W2mzql9VDAw==
dependencies:
popper.js "^1.16.0"
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@ -14207,7 +14247,7 @@ ts-pnp@^1.1.6:
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==
tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
@ -15158,7 +15198,7 @@ xregexp@^4.3.0:
dependencies:
"@babel/runtime-corejs3" "^7.8.3"
xtend@^4.0.0, xtend@~4.0.1:
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==