Skip to content
This repository has been archived by the owner on Jul 21, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1031 from mturley/list-view-table-structure
Browse files Browse the repository at this point in the history
Convert list views to table structure to fix alignment issues

(cherry picked from commit 40746f1)

https://bugzilla.redhat.com/show_bug.cgi?id=1716845
  • Loading branch information
mzazrivec authored and simaishi committed Apr 13, 2020
1 parent 6b8cf4d commit b2f2397
Show file tree
Hide file tree
Showing 18 changed files with 608 additions and 203 deletions.
1 change: 1 addition & 0 deletions app/javascript/react/screens/App/App.scss
Expand Up @@ -3,6 +3,7 @@
@import './Settings/Settings.scss';
@import './Plan/Plan.scss';
@import './Mappings/Mappings.scss';
@import './common/ListViewTable/ListViewTable.scss';
@import './common/ModalWizard/ModalWizard.scss';
@import './common/ShowWizardEmptyState/ShowWizardEmptyState.scss';
@import './common/forms/TextFileInput/TextFileInput.scss';
Expand Down
Expand Up @@ -33,33 +33,31 @@ exports[`MappingWizard component renders the mapping wizard 1`] = `
<WizardFooter
className=""
>
<React.Fragment>
<Button
active={false}
block={false}
bsClass="btn"
bsStyle="default"
className="btn-cancel"
disabled={false}
onClick={[MockFunction]}
>
Cancel
</Button>
<Button
active={false}
block={false}
bsClass="btn"
bsStyle="default"
disabled={true}
onClick={[Function]}
>
<Icon
name="angle-left"
type="fa"
/>
Back
</Button>
</React.Fragment>
<Button
active={false}
block={false}
bsClass="btn"
bsStyle="default"
className="btn-cancel"
disabled={false}
onClick={[MockFunction]}
>
Cancel
</Button>
<Button
active={false}
block={false}
bsClass="btn"
bsStyle="default"
disabled={true}
onClick={[Function]}
>
<Icon
name="angle-left"
type="fa"
/>
Back
</Button>
<Button
active={false}
block={false}
Expand Down
Expand Up @@ -27,6 +27,10 @@
}
}

.list-view-pf-additional-info-item.num-vms-migrated strong.total {
margin-left: 5px;
}

@media (min-width: 992px) {
.migrations .list-view-pf-main-info .list-view-pf-body {
.list-view-pf-description {
Expand Down
Expand Up @@ -19,6 +19,8 @@ import DeleteMigrationMenuItem from './DeleteMigrationMenuItem';
import StopPropagationOnClick from '../../../common/StopPropagationOnClick';
import Visibility from '../../../common/Visibility';
import getPlanScheduleInfo from './helpers/getPlanScheduleInfo';
import ListViewTable from '../../../common/ListViewTable/ListViewTable';
import ScheduledTimeInfoItem from './ScheduledTimeInfoItem';

const MigrationsCompletedList = ({
finishedTransformationPlans,
Expand Down Expand Up @@ -70,7 +72,7 @@ const MigrationsCompletedList = ({
{renderActiveFilters(filteredSortedPaginatedListItems)}
</Toolbar>
</Grid.Row>
<ListView className="plans-complete-list" style={{ marginTop: 10 }}>
<ListViewTable className="plans-complete-list" style={{ marginTop: 10 }}>
{filteredSortedPaginatedListItems.items.map(plan => {
const {
migrationScheduled,
Expand Down Expand Up @@ -170,10 +172,10 @@ const MigrationsCompletedList = ({

const isMissingMapping = !plan.infraMappingName;

const showScheduledTime = migrationScheduled && !staleMigrationSchedule && !migrationStarting;
const showScheduledTime = !!migrationScheduled && !staleMigrationSchedule && !migrationStarting;

return (
<ListView.Item
<ListViewTable.Row
stacked
className="plans-complete-list__list-item"
onClick={e => {
Expand Down Expand Up @@ -209,19 +211,18 @@ const MigrationsCompletedList = ({
heading={plan.name}
description={plan.description}
additionalInfo={[
<ListView.InfoItem key={`${plan.id}-migrated`} style={{ paddingRight: 40 }}>
<ListView.InfoItem className="num-vms-migrated" key={`${plan.id}-migrated`}>
<ListView.Icon type="pf" size="lg" name="screen" />
&nbsp;
<strong>{succeedCount}</strong> {__('of')} &nbsp;
<strong>{Object.keys(tasks).length} </strong>
<strong>{succeedCount}</strong>
{__('of')}
<strong className="total">{Object.keys(tasks).length} </strong>
{__('VMs successfully migrated.')}
</ListView.InfoItem>,
isMissingMapping && (
isMissingMapping ? (
<ListView.InfoItem key={`${plan.id}-infraMappingWarning`}>
<Icon type="pf" name="warning-triangle-o" /> {__('Infrastucture mapping does not exist.')}
</ListView.InfoItem>
),
!isMissingMapping && (
) : (
<ListView.InfoItem key={`${plan.id}-infraMappingName`}>
{plan.infraMappingName}
</ListView.InfoItem>
Expand All @@ -240,19 +241,12 @@ const MigrationsCompletedList = ({
{formatDateTime(mostRecentRequest.fulfilled_on)}
</ListView.InfoItem>
) : null,
showScheduledTime ? (
<ListView.InfoItem key={`${plan.id}-scheduledTime`} style={{ textAlign: 'left' }}>
<Icon type="fa" name="clock-o" />
{__('Migration scheduled')}
<br />
{formatDateTime(migrationScheduled)}
</ListView.InfoItem>
) : null,
migrationStarting && (
<ListView.InfoItem key={`${plan.id}-starting`} style={{ textAlign: 'left' }}>
{__('Migration in progress')}
</ListView.InfoItem>
)
<ScheduledTimeInfoItem
planId={plan.id}
migrationStarting={migrationStarting}
showScheduledTime={showScheduledTime}
migrationScheduled={migrationScheduled}
/>
]}
actions={
// Visibility helper is used instead of conditional rendering
Expand Down Expand Up @@ -334,7 +328,7 @@ const MigrationsCompletedList = ({
/>
);
})}
</ListView>
</ListViewTable>
{renderPaginationRow(filteredSortedPaginatedListItems)}
</React.Fragment>
)}
Expand Down
Expand Up @@ -4,15 +4,15 @@ import { noop, Button, ListView, Grid, Icon, Spinner, Toolbar, DropdownKebab, Me
import EllipsisWithTooltip from 'react-ellipsis-with-tooltip';
import ShowWizardEmptyState from '../../../common/ShowWizardEmptyState/ShowWizardEmptyState';
import ScheduleMigrationModal from '../ScheduleMigrationModal/ScheduleMigrationModal';
import { formatDateTime } from '../../../../../../components/dates/MomentDate';
import { MIGRATIONS_NOT_STARTED_SORT_FIELDS, MIGRATIONS_FILTER_TYPES } from './MigrationsConstants';
import ScheduleMigrationButton from './ScheduleMigrationButton';
import EditScheduleMenuItems from './EditScheduleMenuItems';
import StopPropagationOnClick from '../../../common/StopPropagationOnClick';
import Visibility from '../../../common/Visibility';
import ListViewToolbar from '../../../common/ListViewToolbar/ListViewToolbar';
import DeleteMigrationMenuItem from './DeleteMigrationMenuItem';
import getPlanScheduleInfo from './helpers/getPlanScheduleInfo';
import ListViewTable from '../../../common/ListViewTable/ListViewTable';
import ScheduledTimeInfoItem from './ScheduledTimeInfoItem';

const MigrationsNotStartedList = ({
migrateClick,
Expand Down Expand Up @@ -58,7 +58,7 @@ const MigrationsNotStartedList = ({
{renderActiveFilters(filteredSortedPaginatedListItems)}
</Toolbar>
</Grid.Row>
<ListView className="plans-not-started-list" style={{ marginTop: 10 }}>
<ListViewTable className="plans-not-started-list" style={{ marginTop: 10 }}>
{filteredSortedPaginatedListItems.items.map(plan => {
const { migrationScheduled, migrationStarting, showInitialScheduleButton } = getPlanScheduleInfo(
plan
Expand All @@ -68,24 +68,22 @@ const MigrationsNotStartedList = ({
const editPlanDisabled = loading === plan.href;

return (
<ListView.Item
<ListViewTable.Row
stacked
className="plans-not-started-list__list-item"
onClick={() => {
redirectTo(`/plan/${plan.id}`);
}}
actions={
// Visibility helper is used instead of conditional rendering
// so hidden buttons still take up space and the list rows stay aligned
<div>
<Visibility hidden={!showInitialScheduleButton}>
{showInitialScheduleButton && (
<ScheduleMigrationButton
loading={loading}
toggleScheduleMigrationModal={toggleScheduleMigrationModal}
plan={plan}
isMissingMapping={isMissingMapping}
/>
</Visibility>
)}
<Button
id={`migrate_${plan.id}`}
onClick={e => {
Expand Down Expand Up @@ -141,7 +139,6 @@ const MigrationsNotStartedList = ({
</StopPropagationOnClick>
</div>
}
leftContent={<div />}
heading={plan.name}
description={
<EllipsisWithTooltip id={plan.description}>
Expand All @@ -153,35 +150,28 @@ const MigrationsNotStartedList = ({
<Icon type="pf" name="virtual-machine" />
<strong>{plan.options.config_info.actions.length}</strong> {__('VMs')}
</ListView.InfoItem>,
isMissingMapping && (
<ListView.InfoItem key={`${plan.id}-infraMappingWarning`}>
<Icon type="pf" name="warning-triangle-o" /> {__('Infrastucture mapping does not exist.')}
</ListView.InfoItem>
),
!isMissingMapping && (
<ListView.InfoItem key={`${plan.id}-infraMappingName`}>
{plan.infraMappingName}
</ListView.InfoItem>
),
migrationScheduled && !migrationStarting ? (
<ListView.InfoItem key={`${plan.id}-scheduledTime`} style={{ textAlign: 'left' }}>
<Icon type="fa" name="clock-o" />
{__('Migration scheduled')}
<br />
{formatDateTime(migrationScheduled)}
</ListView.InfoItem>
) : null,
migrationStarting && (
<ListView.InfoItem key={`${plan.id}-starting`} style={{ textAlign: 'left' }}>
{__('Migration in progress')}
</ListView.InfoItem>
)
<ListView.InfoItem key={`${plan.id}-infraMappingName`}>
{isMissingMapping ? (
<React.Fragment>
<Icon type="pf" name="warning-triangle-o" />{' '}
{__('Infrastucture mapping does not exist.')}
</React.Fragment>
) : (
plan.infraMappingName
)}
</ListView.InfoItem>,
<ScheduledTimeInfoItem
planId={plan.id}
migrationStarting={migrationStarting}
showScheduledTime={!!migrationScheduled}
migrationScheduled={migrationScheduled}
/>
]}
key={plan.id}
/>
);
})}
</ListView>
</ListViewTable>
{renderPaginationRow(filteredSortedPaginatedListItems)}
</React.Fragment>
)}
Expand Down
@@ -0,0 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ListView, Icon } from 'patternfly-react';
import { formatDateTime } from '../../../../../../components/dates/MomentDate';

const ScheduledTimeInfoItem = ({ planId, migrationStarting, showScheduledTime, migrationScheduled }) =>
migrationStarting ? (
<ListView.InfoItem key={`${planId}-starting`} style={{ textAlign: 'left' }}>
{__('Migration in progress')}
</ListView.InfoItem>
) : showScheduledTime ? (
<ListView.InfoItem key={`${planId}-scheduledTime`} style={{ textAlign: 'left' }}>
<Icon type="fa" name="clock-o" />
{__('Migration scheduled')}
<br />
{formatDateTime(migrationScheduled)}
</ListView.InfoItem>
) : null;

ScheduledTimeInfoItem.propTypes = {
planId: PropTypes.string,
migrationStarting: PropTypes.bool,
showScheduledTime: PropTypes.bool,
migrationScheduled: PropTypes.number
};

export default ScheduledTimeInfoItem;
Expand Up @@ -5,6 +5,7 @@ import { shallow, mount } from 'enzyme';
import { transformationPlans } from '../../../overview.transformationPlans.fixtures';
import { allRequestsWithTasks } from '../../../overview.requestWithTasks.fixtures';
import MigrationsCompletedList from '../MigrationsCompletedList';
import ListViewTableRow from '../../../../common/ListViewTable/ListViewTableRow';

const [, , , finishedPlanOne, finishedPlanTwo] = transformationPlans.resources;
const finishedTransformationPlans = [
Expand All @@ -25,7 +26,7 @@ describe('when displaying archived migration plans', () => {
/>
);

wrapper.find('ListViewItem').forEach(item => {
wrapper.find(ListViewTableRow).forEach(item => {
expect(item.prop('actions')).toBeTruthy();
});
});
Expand All @@ -41,7 +42,7 @@ describe('when displaying archived migration plans', () => {
/>
);

wrapper.find('ListViewItem').forEach(item => {
wrapper.find(ListViewTableRow).forEach(item => {
const archiveButton = item.find('a').filterWhere(link => link.text() === 'Archive plan');
expect(archiveButton).toHaveLength(0);
});
Expand Down Expand Up @@ -72,13 +73,13 @@ describe('when displaying active (not archived) migration plans', () => {
});

test('each list item renders an actions node', () => {
wrapper.find('ListViewItem').forEach(item => {
wrapper.find(ListViewTableRow).forEach(item => {
expect(item.prop('actions')).toBeTruthy();
});
});

test('clicking the archive button launches the confirmation modal', () => {
wrapper.find('ListViewItem').forEach(item => {
wrapper.find(ListViewTableRow).forEach(item => {
const archiveButton = item.find('a').filterWhere(link => link.text() === 'Archive plan');

archiveButton.simulate('click');
Expand Down
Expand Up @@ -3,6 +3,7 @@ import { mount } from 'enzyme';

import MigrationsNotStartedList from '../MigrationsNotStartedList';
import { transformationPlans } from '../../../overview.transformationPlans.fixtures';
import ListViewTableRow from '../../../../common/ListViewTable/ListViewTableRow';

const { resources: plans } = transformationPlans;
const [notStartedPlan] = plans;
Expand All @@ -25,7 +26,7 @@ beforeEach(() => {

test('clicking on a plan fires redirectTo with the path to its details page', () => {
wrapper
.find('ListViewItem')
.find(ListViewTableRow)
.at(0)
.simulate('click');

Expand Down

0 comments on commit b2f2397

Please sign in to comment.