Bug 1585966 - Centered header titles from Compare views should be editable

This commit is contained in:
octavian-negru 2019-11-06 17:28:38 +02:00 коммит произвёл ionutgoldan
Родитель b2c6b5c76a
Коммит 979573904e
4 изменённых файлов: 261 добавлений и 4 удалений

Просмотреть файл

@ -9,8 +9,9 @@ import {
import projects from '../mock/repositories';
import CompareTableControls from '../../../ui/perfherder/compare/CompareTableControls';
import { compareTableText, filterText } from '../../../ui/perfherder/constants';
import CompareTable from '../../../ui/perfherder/compare/CompareTable';
import ComparePageTitle from '../../../ui/perfherder/compare/ComparePageTitle';
import { compareTableText, filterText } from '../../../ui/perfherder/constants';
// TODO addtional tests:
// 1) that the table is receiving the correct data structure after data
@ -132,6 +133,15 @@ const compareTable = (
/>,
);
const comparepageTitle = () =>
render(
<ComparePageTitle
title="Perfherder Compare Revisions"
updateParams={() => {}}
pageTitleQueryParam="Perfherder Compare Revisions"
/>,
);
test('toggle buttons should filter results by selected filter', async () => {
const { getByText } = compareTableControls();
@ -313,3 +323,100 @@ test('retrigger button should not appear for test with no jobs', async () => {
expect(mockDataRetrigger.retriggers).toHaveLength(0);
});
test('display of page title', async () => {
const { getAllByTitle, getAllByText } = comparepageTitle();
const pageTitleTitle = getAllByTitle('Click to change the page title');
const pageTitleDefaultText = getAllByText('Perfherder Compare Revisions');
// title defaults to 'Perfherder Compare Revisions'
expect(pageTitleTitle[0]).toHaveTextContent('Perfherder Compare Revisions');
expect(pageTitleDefaultText).toHaveLength(1);
});
test('Button hides when clicking on it and a Input is displayed', async () => {
const { queryByText, container } = comparepageTitle();
const pageTitleDefaultText = queryByText('Perfherder Compare Revisions');
await fireEvent.click(pageTitleDefaultText);
expect(container.firstChild).toHaveClass('input-group');
});
test('clicking the title button does not change the title', async () => {
const { getByText, getByDisplayValue } = comparepageTitle();
const pageTitleDefaultText = await waitForElement(() =>
getByText('Perfherder Compare Revisions'),
);
fireEvent.click(pageTitleDefaultText);
await waitForElement(() => getByDisplayValue('Perfherder Compare Revisions'));
await waitForElement(() => getByDisplayValue('Perfherder Compare Revisions'));
});
test('setting a title on page updates the title accordingly', async () => {
const { getByText, getByDisplayValue } = comparepageTitle();
const pageTitleDefaultText = await waitForElement(() =>
getByText('Perfherder Compare Revisions'),
);
fireEvent.click(pageTitleDefaultText);
const inputField = await waitForElement(() =>
getByDisplayValue('Perfherder Compare Revisions'),
);
fireEvent.change(inputField, {
target: { value: 'some new value' },
});
// pressing 'Enter' has some issues on react-testing-library;
// found workaround on https://github.com/testing-library/react-testing-library/issues/269
fireEvent.keyPress(inputField, { key: 'Enter', keyCode: 13 });
// ensure this updated the title
await waitForElement(() => getByDisplayValue('some new value'));
});
test('re-editing the title is possible', async () => {
const { getByText, getByDisplayValue } = comparepageTitle();
const pageTitleDefaultText = await waitForElement(() =>
getByText('Perfherder Compare Revisions'),
);
fireEvent.click(pageTitleDefaultText);
const inputField = await waitForElement(() =>
getByDisplayValue('Perfherder Compare Revisions'),
);
fireEvent.change(inputField, {
target: { value: 'some new value' },
});
fireEvent.keyPress(inputField, { key: 'Enter', keyCode: 13 });
await waitForElement(() => getByDisplayValue('some new value'));
fireEvent.change(inputField, {
target: { value: 'another new value' },
});
fireEvent.keyPress(inputField, { key: 'Enter', keyCode: 13 });
await waitForElement(() => getByDisplayValue('another new value'));
});
test("'Escape' from partially edited title does not update original title", async () => {
const { getByText, getByDisplayValue } = comparepageTitle();
const pageTitleDefaultText = await waitForElement(() =>
getByText('Perfherder Compare Revisions'),
);
fireEvent.click(pageTitleDefaultText);
const inputField = await waitForElement(() =>
getByDisplayValue('Perfherder Compare Revisions'),
);
fireEvent.change(inputField, {
target: { value: 'new value' },
});
fireEvent.keyDown(inputField, { key: 'Escape' });
await waitForElement(() => getByText('Perfherder Compare Revisions'));
});

Просмотреть файл

@ -454,3 +454,13 @@ li.pagination-active.active > button {
max-width: 100%;
}
}
.edit-icon {
visibility: hidden;
font-size: 14px;
vertical-align: middle;
}
.page-title-text:hover .edit-icon {
visibility: visible;
}

Просмотреть файл

@ -0,0 +1,133 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Input, InputGroup } from 'reactstrap';
import { faEdit } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { replaceLocation, getAllUrlParams } from '../../helpers/location';
export default class ComparePageTitle extends React.Component {
constructor(props) {
super(props);
this.state = {
inEditMode: false,
pageTitle: props.pageTitleQueryParam || props.title,
newPageTitle: props.pageTitleQueryParam || props.title,
};
}
goToEditMode = () => {
this.setState({
inEditMode: true,
});
};
resetToDefault = async event => {
const { title } = this.props;
const { newPageTitle } = this.state || event.target.value;
this.setState({
inEditMode: false,
pageTitle: title,
newPageTitle: title,
});
this.changeQueryParam(newPageTitle);
};
editpageTitle = newPageTitle => {
this.setState({ newPageTitle });
};
changeTitle = async newTitle => {
const { pageTitle } = this.state;
this.setState({ inEditMode: false });
if (newTitle !== pageTitle) {
this.setState({ pageTitle: newTitle });
this.changeQueryParam(newTitle);
}
};
changeQueryParam = newTitle => {
const params = getAllUrlParams();
params.set('pageTitle', newTitle);
replaceLocation(params, '/compare');
};
userActionListener = async event => {
const { pageTitle } = this.state;
const { newPageTitle } = this.state || event.target.value;
if (!newPageTitle && event.key !== 'Escape') {
this.resetToDefault(event);
} else if (event.key === 'Enter') {
this.changeTitle(newPageTitle);
} else if (event.key === 'Escape') {
this.setState({ inEditMode: false, newPageTitle: pageTitle });
}
};
injectEnter = () => {
const keyboardEvent = new KeyboardEvent('keydown', { key: 'Enter' });
this.userActionListener(keyboardEvent);
};
injectEscape = () => {
const keyboardEvent = new KeyboardEvent('keydown', { key: 'Escape' });
this.userActionListener(keyboardEvent);
};
render() {
const { inEditMode, pageTitle, newPageTitle } = this.state;
return !inEditMode ? (
<Button
className="text-center"
size="lg"
color="white"
onClick={this.goToEditMode}
title="Click to change the page title"
>
<h1 className="page-title-text">
{pageTitle}
<FontAwesomeIcon
icon={faEdit}
className="fa-xs align-top edit-icon"
/>
</h1>
</Button>
) : (
<InputGroup>
<Input
className="pb-1 col-sm-12 page-title-input"
ref={this.inputRef}
color="white"
style={{
textAlign: 'center',
fontSize: 'xx-large',
}}
value={newPageTitle}
onChange={event => this.editpageTitle(event.target.value)}
onKeyDown={event => this.userActionListener(event)}
autoFocus
/>
<Button
className="ml-3 my-2"
vertical="center"
size="lg"
color="secondary"
onClick={this.injectEnter}
>
Save
</Button>
<Button size="lg" color="link" onClick={this.injectEscape}>
Cancel
</Button>
</InputGroup>
);
}
}
ComparePageTitle.propTypes = {
title: PropTypes.string.isRequired,
pageTitleQueryParam: PropTypes.string.isRequired,
};

Просмотреть файл

@ -22,6 +22,7 @@ import LoadingSpinner from '../../shared/LoadingSpinner';
import { scrollToLine } from '../../helpers/utils';
import RevisionInformation from './RevisionInformation';
import ComparePageTitle from './ComparePageTitle';
import CompareTableControls from './CompareTableControls';
import NoiseTable from './NoiseTable';
@ -189,6 +190,7 @@ export default class CompareTableView extends React.Component {
newRevision,
originalResultSet,
newResultSet,
pageTitle,
} = this.props.validated;
const {
@ -274,9 +276,14 @@ export default class CompareTableView extends React.Component {
<Row>
<Col sm="12" className="text-center pb-1">
<h1>
{hasSubtests
? `${title} subtest summary`
: 'Perfherder Compare Revisions'}
<ComparePageTitle
title={
hasSubtests
? `${title} subtest summary`
: 'Perfherder Compare Revisions'
}
pageTitleQueryParam={pageTitle}
/>
</h1>
<RevisionInformation
originalProject={originalProject}