PF4: Update "fetching info ..." and refresh animation

Currently the "refresh" animations look quite different depending on the
page and the type of event (refresh button, initial page load, ...).

This tries to make a start by updating the "Fetching info ..." animation
(shown on initial page load) with Patternfly's "empty state" pattern [1]
in combination with an animated spinner.

For "Refreshable" pages, a similar animation is used in the upper right
corner (like before) but with an updated spinner and icon. By using a
dedicated React component rather than a base class, the "refresh" button
can be more nicely integrated into the layout of the page/container and
it doesn't look "out of scope" for the refreshable component.

For the API page I've removed the refresh completely since it wasn't
implemented at all.

[1] https://www.patternfly.org/v4/documentation/react/components/emptystate

Change-Id: I2274c212f14aece27ff49bfc7900d9b1a0fd01d0
This commit is contained in:
Felix Edel 2020-06-23 09:57:09 +02:00
parent 141347e082
commit ed9d0446d5
No known key found for this signature in database
GPG Key ID: E95717A102DD3030
18 changed files with 313 additions and 155 deletions

View File

@ -64,6 +64,7 @@ import {
} from '@patternfly/react-icons'
import ErrorBoundary from './containers/ErrorBoundary'
import { Fetching } from './containers/Fetching'
import SelectTz from './containers/timezone/SelectTz'
import logo from './images/logo.svg'
import { clearError } from './actions/errors'
@ -126,7 +127,7 @@ class App extends React.Component {
const allRoutes = []
if (info.isFetching) {
return (<h2>Fetching info...</h2>)
return <Fetching />
}
this.menu
// Do not include '/tenants' route in white-label setup

View File

@ -0,0 +1,74 @@
// Copyright 2020 BMW Group
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import * as React from 'react'
import PropTypes from 'prop-types'
import {
Button,
Title,
EmptyState,
EmptyStateVariant,
Spinner,
} from '@patternfly/react-core'
import { SyncIcon } from '@patternfly/react-icons'
function Fetchable(props) {
const { isFetching, fetchCallback } = props
let content = null
if (isFetching) {
content = (
<div>
<Spinner size="md" />
</div>
)
} else {
content = (
<Button
variant="link"
isInline icon={<SyncIcon />}
onClick={() => {fetchCallback({force: true})}}
style={{textDecoration: 'none'}}
>
refresh
</Button>
)
}
return (
<div style={{float: 'right'}}>
{content}
</div>
)
}
Fetchable.propTypes = {
isFetching: PropTypes.bool,
fetchCallback: PropTypes.func,
}
function Fetching() {
return (
<EmptyState variant={EmptyStateVariant.small}>
<Spinner />
<Title headingLevel="h4" size="lg">
Fetching info...
</Title>
</EmptyState>
)
}
export { Fetchable, Fetching }

View File

@ -1,57 +0,0 @@
// Copyright 2018 Red Hat, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
// Boiler plate code to manage refresh button
import * as React from 'react'
import PropTypes from 'prop-types'
import {
Icon,
Spinner
} from 'patternfly-react'
class Refreshable extends React.Component {
static propTypes = {
tenant: PropTypes.object,
remoteData: PropTypes.object,
}
componentDidMount () {
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
renderSpinner () {
const { remoteData } = this.props
return (
<Spinner loading={ remoteData.isFetching }>
{/* Lint warning jsx-a11y/anchor-is-valid */}
{/* eslint-disable-next-line */}
<a className="refresh" onClick={() => {this.updateData(true)}}>
<Icon type="fa" name="refresh" /> refresh&nbsp;&nbsp;
</a>
</Spinner>
)
}
}
export default Refreshable

View File

@ -18,16 +18,17 @@ import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuildIfNeeded } from '../actions/build'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
import Build from '../containers/build/Build'
import Summary from '../containers/build/Summary'
class BuildPage extends Refreshable {
class BuildPage extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
remoteData: PropTypes.object,
tenant: PropTypes.object
tenant: PropTypes.object,
dispatch: PropTypes.func,
}
updateData = (force) => {
@ -37,7 +38,15 @@ class BuildPage extends Refreshable {
componentDidMount () {
document.title = 'Zuul Build'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
render () {
@ -45,9 +54,12 @@ class BuildPage extends Refreshable {
const build = remoteData.builds[this.props.match.params.buildId]
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
{build &&
<Build build={build} active='summary'>
<Summary build={build}/>

View File

@ -18,16 +18,18 @@ import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuildIfNeeded } from '../actions/build'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
import Build from '../containers/build/Build'
import Console from '../containers/build/Console'
class BuildConsolePage extends Refreshable {
class BuildConsolePage extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
remoteData: PropTypes.object,
tenant: PropTypes.object
tenant: PropTypes.object,
dispatch: PropTypes.func,
location: PropTypes.object,
}
updateData = (force) => {
@ -37,7 +39,15 @@ class BuildConsolePage extends Refreshable {
componentDidMount () {
document.title = 'Zuul Build'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
render () {
@ -47,9 +57,12 @@ class BuildConsolePage extends Refreshable {
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
{build && build.output &&
<Build build={build} active='console'>
<Console

View File

@ -18,16 +18,17 @@ import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuildIfNeeded } from '../actions/build'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
import Build from '../containers/build/Build'
import Manifest from '../containers/build/Manifest'
class BuildLogsPage extends Refreshable {
class BuildLogsPage extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
remoteData: PropTypes.object,
tenant: PropTypes.object
tenant: PropTypes.object,
dispatch: PropTypes.func,
}
updateData = (force) => {
@ -37,7 +38,15 @@ class BuildLogsPage extends Refreshable {
componentDidMount () {
document.title = 'Zuul Build'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
render () {
@ -45,9 +54,12 @@ class BuildLogsPage extends Refreshable {
const build = remoteData.builds[this.props.match.params.buildId]
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
{build && build.manifest &&
<Build build={build} active='logs'>
<Manifest tenant={this.props.tenant} build={build}/>

View File

@ -18,15 +18,16 @@ import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchBuildsetIfNeeded } from '../actions/build'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
import Buildset from '../containers/build/Buildset'
class BuildsetPage extends Refreshable {
class BuildsetPage extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
remoteData: PropTypes.object,
tenant: PropTypes.object
tenant: PropTypes.object,
dispatch: PropTypes.func,
}
updateData = (force) => {
@ -36,17 +37,29 @@ class BuildsetPage extends Refreshable {
componentDidMount () {
document.title = 'Zuul Buildset'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
render () {
const { remoteData } = this.props
const buildset = remoteData.buildsets[this.props.match.params.buildsetId]
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
{buildset && <Buildset buildset={buildset}/>}
</PageSection>
)

View File

@ -19,10 +19,10 @@ import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchChangeIfNeeded } from '../actions/change'
import ChangePanel from '../containers/status/ChangePanel'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
class ChangeStatusPage extends Refreshable {
class ChangeStatusPage extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
tenant: PropTypes.object,
@ -43,7 +43,15 @@ class ChangeStatusPage extends Refreshable {
componentDidMount () {
document.title = this.props.match.params.changeId + ' | Zuul Status'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
componentWillUnmount () {
@ -58,9 +66,12 @@ class ChangeStatusPage extends Refreshable {
const change = remoteData.change
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div><br />
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
{change && change.map((item, idx) => (
<div className='row zuul-change-content' key={idx}>
<ChangePanel

View File

@ -18,11 +18,11 @@ import PropTypes from 'prop-types'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import Job from '../containers/job/Job'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
import { fetchJobIfNeeded } from '../actions/job'
class JobPage extends Refreshable {
class JobPage extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
tenant: PropTypes.object,
@ -37,7 +37,9 @@ class JobPage extends Refreshable {
componentDidMount () {
document.title = 'Zuul Job | ' + this.props.match.params.jobName
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
@ -53,9 +55,12 @@ class JobPage extends Refreshable {
const jobName = this.props.match.params.jobName
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
{tenantJobs && tenantJobs[jobName] && <Job job={tenantJobs[jobName]} />}
</PageSection>
)

View File

@ -18,34 +18,46 @@ import { connect } from 'react-redux'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchJobsIfNeeded } from '../actions/jobs'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
import Jobs from '../containers/jobs/Jobs'
class JobsPage extends Refreshable {
class JobsPage extends React.Component {
static propTypes = {
tenant: PropTypes.object,
remoteData: PropTypes.object,
dispatch: PropTypes.func
}
updateData (force) {
updateData = (force) => {
this.props.dispatch(fetchJobsIfNeeded(this.props.tenant, force))
}
componentDidMount () {
document.title = 'Zuul Jobs'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
render () {
const { remoteData } = this.props
const jobs = remoteData.jobs[this.props.tenant.name]
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
{jobs && jobs.length > 0 &&
<Jobs
jobs={jobs}

View File

@ -19,10 +19,10 @@ import { Table } from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchLabelsIfNeeded } from '../actions/labels'
import Refreshable from '../containers/Refreshable'
import { Fetchable, Fetching } from '../containers/Fetching'
class LabelsPage extends Refreshable {
class LabelsPage extends React.Component {
static propTypes = {
tenant: PropTypes.object,
remoteData: PropTypes.object,
@ -35,7 +35,15 @@ class LabelsPage extends Refreshable {
componentDidMount () {
document.title = 'Zuul Labels'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
render () {
@ -43,7 +51,7 @@ class LabelsPage extends Refreshable {
const labels = remoteData.labels[this.props.tenant.name]
if (!labels) {
return (<p>Loading...</p>)
return <Fetching />
}
const headerFormat = value => <Table.Heading>{value}</Table.Heading>
@ -61,9 +69,12 @@ class LabelsPage extends Refreshable {
})
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
<Table.PfProvider
striped
bordered

View File

@ -19,15 +19,18 @@ import { parse } from 'query-string'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchLogfileIfNeeded } from '../actions/logfile'
import Refreshable from '../containers/Refreshable'
import { Fetching } from '../containers/Fetching'
import LogFile from '../containers/logfile/LogFile'
class LogFilePage extends Refreshable {
class LogFilePage extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
remoteData: PropTypes.object,
tenant: PropTypes.object,
dispatch: PropTypes.func,
location: PropTypes.object,
build: PropTypes.object,
}
state = {
@ -45,7 +48,9 @@ class LogFilePage extends Refreshable {
componentDidMount () {
document.title = 'Zuul Build Logfile'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
highlightDidUpdate = (lines) => {
@ -108,13 +113,14 @@ class LogFilePage extends Refreshable {
render () {
const { remoteData } = this.props
if (remoteData.isFetching) {
return <Fetching />
}
const build = this.props.build.builds[this.props.match.params.buildId]
const severity = parse(this.props.location.search).severity
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
{remoteData.data && <LogFile build={build} data={remoteData.data} severity={severity}/>}
</PageSection>
)

View File

@ -20,23 +20,31 @@ import * as moment from 'moment'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchNodesIfNeeded } from '../actions/nodes'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
class NodesPage extends Refreshable {
class NodesPage extends React.Component {
static propTypes = {
tenant: PropTypes.object,
remoteData: PropTypes.object,
dispatch: PropTypes.func
}
updateData (force) {
updateData = (force) => {
this.props.dispatch(fetchNodesIfNeeded(this.props.tenant, force))
}
componentDidMount () {
document.title = 'Zuul Nodes'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
render () {
@ -83,9 +91,12 @@ class NodesPage extends Refreshable {
})
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
<Table.PfProvider
striped
bordered

View File

@ -20,10 +20,9 @@ import 'swagger-ui/dist/swagger-ui.css'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchOpenApiIfNeeded } from '../actions/openapi'
import Refreshable from '../containers/Refreshable'
class OpenApiPage extends Refreshable {
class OpenApiPage extends React.Component {
static propTypes = {
tenant: PropTypes.object,
remoteData: PropTypes.object,
@ -53,9 +52,6 @@ class OpenApiPage extends Refreshable {
render() {
return (
<PageSection variant={PageSectionVariants.light}>
<div className="pull-right" style={{display: 'flex'}}>
{this.renderSpinner()}
</div>
<div id="swaggerContainer" />
</PageSection>
)

View File

@ -19,10 +19,10 @@ import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import Project from '../containers/project/Project'
import { fetchProjectIfNeeded } from '../actions/project'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
class ProjectPage extends Refreshable {
class ProjectPage extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
tenant: PropTypes.object,
@ -37,7 +37,15 @@ class ProjectPage extends Refreshable {
componentDidMount () {
document.title = 'Zuul Project | ' + this.props.match.params.projectName
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
render () {
@ -46,9 +54,12 @@ class ProjectPage extends Refreshable {
const projectName = this.props.match.params.projectName
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
{tenantProjects && tenantProjects[projectName] &&
<Project project={tenantProjects[projectName]} />}
</PageSection>

View File

@ -20,31 +20,43 @@ import { Table } from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchProjectsIfNeeded } from '../actions/projects'
import Refreshable from '../containers/Refreshable'
import { Fetchable, Fetching } from '../containers/Fetching'
class ProjectsPage extends Refreshable {
class ProjectsPage extends React.Component {
static propTypes = {
tenant: PropTypes.object,
remoteData: PropTypes.object,
dispatch: PropTypes.func
}
updateData (force) {
updateData = (force) => {
this.props.dispatch(fetchProjectsIfNeeded(this.props.tenant, force))
}
componentDidMount () {
document.title = 'Zuul Projects'
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
render () {
const { remoteData } = this.props
const projects = remoteData.projects[this.props.tenant.name]
// TODO (felix): Can we somehow differentiate between "no projects yet" (due
// to fetching) and "no projects at all", so we could show an empty state
// in the latter case. The same applies for other pages like labels, nodes,
// buildsets, ... as well.
if (!projects) {
return (<p>Loading...</p>)
return <Fetching />
}
const headerFormat = value => <Table.Heading>{value}</Table.Heading>
@ -86,9 +98,12 @@ class ProjectsPage extends Refreshable {
})
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<PageSection style={{paddingRight: '5px'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
</PageSection>
<Table.PfProvider
striped
bordered

View File

@ -27,10 +27,10 @@ import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import { fetchStatusIfNeeded } from '../actions/status'
import Pipeline from '../containers/status/Pipeline'
import Refreshable from '../containers/Refreshable'
import { Fetchable } from '../containers/Fetching'
class StatusPage extends Refreshable {
class StatusPage extends React.Component {
static propTypes = {
location: PropTypes.object,
tenant: PropTypes.object,
@ -96,10 +96,18 @@ class StatusPage extends Refreshable {
componentDidMount () {
document.title = 'Zuul Status'
this.loadState()
super.componentDidMount()
if (this.props.tenant.name) {
this.updateData()
}
window.addEventListener('storage', this.loadState)
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
componentWillUnmount () {
if (this.timer) {
clearTimeout(this.timer)
@ -214,12 +222,15 @@ class StatusPage extends Refreshable {
)
return (
<PageSection variant={PageSectionVariants.light}>
<div className="pull-right" style={{display: 'flex'}}>
{this.renderSpinner()}
<div style={{display: 'flex', float: 'right'}}>
<Fetchable
isFetching={remoteData.isFetching}
fetchCallback={this.updateData}
/>
<Checkbox
defaultChecked={autoReload}
onChange={(e) => {this.setState({autoReload: e.target.checked})}}
style={{marginTop: '0px'}}>
style={{marginTop: '0px', marginLeft: '10px'}}>
auto reload
</Checkbox>
</div>

View File

@ -19,11 +19,11 @@ import { Link } from 'react-router-dom'
import { Table } from 'patternfly-react'
import { PageSection, PageSectionVariants } from '@patternfly/react-core'
import Refreshable from '../containers/Refreshable'
import { Fetching } from '../containers/Fetching'
import { fetchTenantsIfNeeded } from '../actions/tenants'
class TenantsPage extends Refreshable {
class TenantsPage extends React.Component {
static propTypes = {
remoteData: PropTypes.object,
dispatch: PropTypes.func
@ -43,6 +43,10 @@ class TenantsPage extends Refreshable {
render () {
const { remoteData } = this.props
if (remoteData.isFetching) {
return <Fetching />
}
const tenants = remoteData.tenants
const headerFormat = value => <Table.Heading>{value}</Table.Heading>
const cellFormat = (value) => (
@ -79,9 +83,6 @@ class TenantsPage extends Refreshable {
})
return (
<PageSection variant={PageSectionVariants.light}>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<Table.PfProvider
striped
bordered