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 ) || ( Create image
)}
); } } function mapStateToProps(state) { return { composes: state.composes, }; } function mapDispatchToProps(dispatch) { return { composesGet: (limit, offset) => dispatch(actions.composesGet(limit, offset)), composeGetStatus: (id) => dispatch(actions.composeGetStatus(id)), }; } ImagesTable.propTypes = { composes: PropTypes.object, composesGet: PropTypes.func, composeGetStatus: PropTypes.func, }; export default connect(mapStateToProps, mapDispatchToProps)(ImagesTable);