import React, { Component } from 'react'; import _ from 'lodash'; import { translate as __ } from 'foremanReact/common/I18n'; import PropTypes from 'prop-types'; import { LinkContainer } from 'react-router-bootstrap'; import { Grid, Row, Col } from 'react-bootstrap'; import BreadcrumbsBar from 'foremanReact/components/BreadcrumbBar'; import { Button } from 'patternfly-react'; import { stringIsPositiveNumber } from 'foremanReact/common/helpers'; import { urlBuilder } from 'foremanReact/common/urlHelpers'; import { LoadingState } from '../../../components/LoadingState'; import { Table } from '../../../components/pf3Table'; import { columns } from './UpstreamSubscriptionsTableSchema'; class UpstreamSubscriptionsPage extends Component { constructor(props) { super(props); this.state = { selectedRows: [], }; } componentDidMount() { this.loadData(); } onChange = (value, rowData) => { const { selectedRows } = this.state; const pool = { ...rowData, id: rowData.id, updatedQuantity: value, selected: true, }; const match = this.poolInSelectedRows(pool); const index = _.indexOf(selectedRows, match); if (value) { if (match) { selectedRows.splice(index, 1, pool); } else { selectedRows.push(pool); } } else if (match) { selectedRows.splice(index, 1); } this.setState({ selectedRows }); }; // eslint-disable-next-line class-methods-use-this quantityValidation(pool) { const origQuantity = pool.updatedQuantity; if (origQuantity && stringIsPositiveNumber(origQuantity)) { const parsedQuantity = parseInt(origQuantity, 10); const aboveZeroMsg = [false, __('Please enter a positive number above zero')]; if (parsedQuantity.toString().length > 10) return [false, __('Please limit number to 10 digits')]; if (!pool.available) return [false, __('No pools available')]; // handling unlimited subscriptions, they show as -1 if (pool.available === -1) return parsedQuantity ? [true, ''] : aboveZeroMsg; if (parsedQuantity > pool.available) return [false, __(`Quantity must not be above ${pool.available}`)]; if (parsedQuantity <= 0) return aboveZeroMsg; } else { return [false, __('Please enter digits only')]; } return [true, '']; } poolInSelectedRows(pool) { const { selectedRows } = this.state; return _.find( selectedRows, foundPool => pool.id === foundPool.id, ); } quantityValidationInput = (pool) => { if (!pool || pool.updatedQuantity === undefined) return null; if (this.quantityValidation(pool)[0]) { return 'success'; } return 'error'; }; validateSelectedRows = () => Array.isArray(this.state.selectedRows) && this.state.selectedRows.length && this.state.selectedRows.every(pool => this.quantityValidation(pool)[0]); saveUpstreamSubscriptions = async () => { const updatedPools = _.map( this.state.selectedRows, pool => ({ ...pool, quantity: parseInt(pool.updatedQuantity, 10) }), ); const updatedSubscriptions = { pools: updatedPools }; await this.props.saveUpstreamSubscriptions(updatedSubscriptions); const { task } = this.props.upstreamSubscriptions; // TODO: could probably factor this out into a task response component if (task) { const message = ( {__('Subscriptions have been saved and are being updated. ')} {__('Click here to go to the tasks page for the task.')} ); window.tfm.toastNotifications.notify({ message, type: 'success' }); this.props.history.push('/subscriptions'); } }; loadData() { this.props.loadUpstreamSubscriptions(); } render() { const { upstreamSubscriptions } = this.props; const getSubscriptionActions = () => { let actions = ''; if (upstreamSubscriptions.results.length > 0) { actions = ( ); } return actions; }; const onPaginationChange = (pagination) => { this.props.loadUpstreamSubscriptions({ ...pagination, }); }; const getSelectedUpstreamSubscriptions = () => { const newUpstreamSubscriptions = []; upstreamSubscriptions.results.forEach((sub) => { let row = this.poolInSelectedRows(sub); if (row) { row = { ...row, selected: true }; } else { const foundRow = upstreamSubscriptions.results.find(foundSub => sub.id === foundSub.id); row = { ...foundRow, selected: false }; } newUpstreamSubscriptions.push(row); }); return newUpstreamSubscriptions; }; const emptyStateData = () => ({ header: __('There are no Manifests to display'), description: __('Manifests allow you to find, access, synchronize, and download content ' + 'from upstream Red Hat repositories for use in Red Hat Satellite.'), action: { title: __('Import a Manifest to Begin'), url: '/subscriptions', }, }); const checkAllRowsSelected = () => upstreamSubscriptions.results.length === this.state.selectedRows.length; const selectionController = { allRowsSelected: () => checkAllRowsSelected(), selectAllRows: () => { if (checkAllRowsSelected()) { this.setState({ selectedRows: [] }); } else { this.setState({ selectedRows: [...upstreamSubscriptions.results] }); } }, selectRow: ({ rowData }) => { let { selectedRows } = this.state; if (selectedRows.find(r => r.id === rowData.id)) { selectedRows = selectedRows.filter(e => e.id !== rowData.id); } else { selectedRows.push(rowData); } this.setState({ selectedRows }); }, isSelected: ({ rowData }) => ( this.state.selectedRows.find(r => r.id === rowData.id) !== undefined ), }; const tableColumns = columns(this, selectionController); const rows = getSelectedUpstreamSubscriptions(); return ( this.props.history.push('/subscriptions'), }, { caption: __('Add Subscriptions'), }, ], }} /> {getSubscriptionActions()} ); } } UpstreamSubscriptionsPage.propTypes = { loadUpstreamSubscriptions: PropTypes.func.isRequired, saveUpstreamSubscriptions: PropTypes.func.isRequired, upstreamSubscriptions: PropTypes.shape({ loading: PropTypes.bool, itemCount: PropTypes.number, // Disabling rule as existing code failed due to an eslint-plugin-react update // eslint-disable-next-line react/forbid-prop-types results: PropTypes.array, pagination: PropTypes.shape({}), task: PropTypes.shape({ id: PropTypes.string, }), }).isRequired, history: PropTypes.shape({ push: PropTypes.func.isRequired }).isRequired, }; export default UpstreamSubscriptionsPage;