import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { actions } from '../../store/actions';
import { Link } from 'react-router-dom';
import { Table, TableHeader, TableBody } from '@patternfly/react-table';
import { Button,
EmptyState, EmptyStateVariant, EmptyStateIcon, EmptyStateBody, EmptyStateSecondaryActions,
Pagination,
Toolbar, ToolbarContent, ToolbarItem,
Title } from '@patternfly/react-core';
import { ExternalLinkAltIcon, PlusCircleIcon } from '@patternfly/react-icons';
import ImageBuildStatus from './ImageBuildStatus';
import Release from './Release';
import Upload from './Upload';
import ImageLink from './ImageLink';
class ImagesTable extends Component {
constructor(props) {
super(props);
this.state = {
page: 1,
perPage: 10,
};
this.pollComposeStatuses = this.pollComposeStatuses.bind(this);
this.onSetPage = this.onSetPage.bind(this);
this.onPerPageSelect = this.onPerPageSelect.bind(this);
this.timestampToDisplayString = this.timestampToDisplayString.bind(this);
}
componentDidMount() {
this.props.composesGet(this.state.perPage, 0);
this.interval = setInterval(() => this.pollComposeStatuses(), 8000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
pollComposeStatuses() {
let { composes } = this.props;
Object.entries(composes.byId).map(([ id, compose ]) => {
/* Skip composes that have been complete */
if (compose.image_status.status === 'success' || compose.image_status.status === 'failure') {
return;
}
this.props.composeGetStatus(id);
});
}
onSetPage(_, page) {
// if the next page's composes haven't been fetched from api yet
// then fetch them with proper page index and offset
if (this.props.composes.count > this.props.composes.allIds.length) {
const pageIndex = page - 1;
const offset = pageIndex * this.state.perPage;
this.props.composesGet(this.state.perPage, offset);
}
this.setState({ page });
}
onPerPageSelect(_, perPage) {
// if the new per page quantity is greater than the number of already fetched composes fetch more composes
// if all composes haven't already been fetched
if (this.props.composes.count > this.props.composes.allIds.length && perPage > this.props.composes.allIds.length) {
this.props.composesGet(perPage, 0);
}
// page should be reset to the first page when the page size is changed.
this.setState({ perPage, page: 1 });
}
timestampToDisplayString(ts) {
// timestamp has format 2021-04-27 12:31:12.794809 +0000 UTC
// must be converted to ms timestamp and then reformatted to Apr 27, 2021
if (!ts) {
return '';
}
// get YYYY-MM-DD format
const date = ts.slice(0, 10);
const ms = Date.parse(date);
const options = { month: 'short', day: 'numeric', year: 'numeric' };
const tsDisplay = new Intl.DateTimeFormat('en-US', options).format(ms);
return tsDisplay;
}
render() {
let { composes } = this.props;
const columns = [
'Image',
'Created',
'Release',
'Target',
'Status',
'Instance'
];
// the state.page is not an index so must be reduced by 1 get the starting index
const itemsStartInclusive = (this.state.page - 1) * this.state.perPage;
const itemsEndExlcusive = itemsStartInclusive + this.state.perPage;
// only display the current pages section of composes. slice is inclusive, exclusive.
const rows = composes.allIds.slice(itemsStartInclusive, itemsEndExlcusive).map(id => {
const compose = composes.byId[id];
return {
cells: [
id,
this.timestampToDisplayString(compose.created_at),
{ title: },
{ title: },
{ title: },
{ title: },
]
};
});
return (
{ composes.allIds.length === 0 && (
Create an image
Create OS images for deployment in Amazon Web Services,
Microsoft Azure and Google Cloud Platform. Images can
include a custom package set and an activation key to
automate the registration process.
Create image
}
iconPosition="right"
isInline
href="
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/uploading_a_customized_rhel_system_image_to_cloud_environments/index
">
Documentation
) || (
Create image