Skip to content

Commit

Permalink
fix(toolbarFieldDisplayName): issues/476 search-as-type (#572)
Browse files Browse the repository at this point in the history
* testing, mock for debounce
* textInput, emulate onClear for non-search types
* toolbarFieldDisplayName, debounce on keyup, style adjustment
* rhsmServices, adjust emulated API delays to reflect environments
  • Loading branch information
cdcabrera committed Apr 26, 2021
1 parent d8e6183 commit 61a5b1f
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 48 deletions.
15 changes: 15 additions & 0 deletions src/components/form/__tests__/__snapshots__/textInput.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@ Object {
}
`;

exports[`TextInput Component should return an emulated onClear event on escape with type search: emulated event, esc, type search 1`] = `
Object {
"checked": undefined,
"currentTarget": Object {
"value": "",
},
"id": undefined,
"keyCode": 27,
"name": undefined,
"persist": [Function],
"target": Object {},
"value": "",
}
`;

exports[`TextInput Component should return an emulated onClear event on escape: emulated event, esc 1`] = `
Object {
"checked": undefined,
Expand Down
17 changes: 16 additions & 1 deletion src/components/form/__tests__/textInput.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,28 @@ describe('TextInput Component', () => {
});

it('should return an emulated onClear event on escape', done => {
const props = {
value: 'lorem ipsum'
};

props.onClear = event => {
expect(event).toMatchSnapshot('emulated event, esc');
done();
};

const component = shallow(<TextInput {...props} />);
const mockEvent = { keyCode: 27, currentTarget: { value: '' }, persist: helpers.noop };
component.instance().onKeyUp(mockEvent);
});

it('should return an emulated onClear event on escape with type search', done => {
const props = {
value: 'lorem ipsum',
type: 'search'
};

props.onClear = event => {
expect(event).toMatchSnapshot('emulated event, esc');
expect(event).toMatchSnapshot('emulated event, esc, type search');
done();
};

Expand Down
15 changes: 12 additions & 3 deletions src/components/form/textInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ class TextInput extends React.Component {
* @param {object} event
*/
onKeyUp = event => {
const { onClear, onKeyUp } = this.props;
const { onClear, onKeyUp, type } = this.props;
const { currentTarget, keyCode } = event;
const clonedEvent = { ...event };

onKeyUp(createMockEvent(event, true));

if (keyCode === 27 && currentTarget.value === '') {
onClear(createMockEvent(event));
if (keyCode === 27) {
if (type === 'search' && currentTarget.value === '') {
onClear(createMockEvent(clonedEvent));
} else {
this.setState({ updatedValue: '' }, () => {
onClear(
createMockEvent({ ...clonedEvent, ...{ currentTarget: { ...clonedEvent.currentTarget, value: '' } } })
);
});
}
}
};

Expand Down
8 changes: 0 additions & 8 deletions src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -397,10 +397,6 @@ Array [
"key": "curiosity-toolbar.placeholder",
"match": "t('curiosity-toolbar.placeholder', { context: 'displayName' })",
},
Object {
"key": "curiosity-toolbar.button",
"match": "t('curiosity-toolbar.button', { context: 'displayName' })",
},
],
},
Object {
Expand Down Expand Up @@ -552,10 +548,6 @@ Array [
"file": "./src/components/rhelView/rhelView.js",
"key": "curiosity-inventory.label",
},
Object {
"file": "./src/components/toolbar/toolbarFieldDisplayName.js",
"key": "curiosity-toolbar.button",
},
Object {
"file": "./src/components/toolbar/toolbarFieldGranularity.js",
"key": "curiosity-toolbar.granularity",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ exports[`ToolbarFieldDisplayName Component should render a non-connected compone
<InputGroup>
<TextInput
aria-label="t(curiosity-toolbar.placeholder, {\\"context\\":\\"displayName\\"})"
className=""
className="curiosity-input__display-name"
iconVariant="search"
id={null}
isDisabled={false}
isReadOnly={false}
Expand All @@ -66,19 +67,8 @@ exports[`ToolbarFieldDisplayName Component should render a non-connected compone
onKeyUp={[Function]}
onMouseUp={[Function]}
placeholder="t(curiosity-toolbar.placeholder, {\\"context\\":\\"displayName\\"})"
type="search"
type="text"
value={null}
/>
<Button
aria-label="t(curiosity-toolbar.button, {\\"context\\":\\"displayName\\"})"
onClick={[Function]}
variant="control"
>
<SearchIcon
color="currentColor"
noVerticalAlign={false}
size="sm"
/>
</Button>
</InputGroup>
`;
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { Button } from '@patternfly/react-core';
import { ToolbarFieldDisplayName } from '../toolbarFieldDisplayName';
import { store } from '../../../redux/store';
import { TextInput } from '../../form/textInput';
Expand Down Expand Up @@ -31,7 +30,7 @@ describe('ToolbarFieldDisplayName Component', () => {

const component = shallow(<ToolbarFieldDisplayName {...props} />);
component.find(TextInput).simulate('change', { value: 'dolor sit' });
component.find(Button).simulate('click');
component.find(TextInput).simulate('keyUp', {});

expect(mockDispatch.mock.calls).toMatchSnapshot('dispatch display name');
});
Expand Down
41 changes: 25 additions & 16 deletions src/components/toolbar/toolbarFieldDisplayName.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, ButtonVariant, InputGroup } from '@patternfly/react-core';
import SearchIcon from '@patternfly/react-icons/dist/js/icons/search-icon';
import { InputGroup } from '@patternfly/react-core';
import _debounce from 'lodash/debounce';
import { reduxTypes, store, useSelector } from '../../redux';
import { TextInput } from '../form/textInput';
import { RHSM_API_QUERY_TYPES } from '../../types/rhsmApiTypes';
import { translate } from '../i18n/i18n';

/**
* ToDo: evaluate the debounce milliseconds, currently based off platforms default 800 ms
*/
/**
* Display a display name input field for search.
*
Expand Down Expand Up @@ -42,7 +45,7 @@ const ToolbarFieldDisplayName = ({ value, t, viewId }) => {
{
type: reduxTypes.query.SET_QUERY_RHSM_HOSTS_INVENTORY_TYPES[RHSM_API_QUERY_TYPES.DISPLAY_NAME],
viewId,
[RHSM_API_QUERY_TYPES.DISPLAY_NAME]: updatedValue
[RHSM_API_QUERY_TYPES.DISPLAY_NAME]: updatedValue || null
}
]);

Expand Down Expand Up @@ -79,40 +82,46 @@ const ToolbarFieldDisplayName = ({ value, t, viewId }) => {
updatedValue = event.value;
};

/**
* Set up submit debounce event to allow for bypass.
*/
const debounced = _debounce(onSubmit, 800);

/**
* On enter, submit value. We nest the conditions to allow enter to submit onChange value updates.
*
* @event onKeyUp
* @param {object} event
*/
const onKeyUp = event => {
if (event.keyCode === 13) {
if (event.value?.length) {
updatedValue = event.value;
}
onSubmit();
switch (event.keyCode) {
case 13:
if (event.value?.length) {
updatedValue = event.value;
}
onSubmit();
break;
case 27:
break;
default:
debounced();
break;
}
};

return (
<InputGroup>
<TextInput
aria-label={t('curiosity-toolbar.placeholder', { context: 'displayName' })}
className="curiosity-input__display-name"
iconVariant="search"
maxLength={255}
onChange={onChange}
onClear={onClear}
onKeyUp={onKeyUp}
value={updatedValue}
placeholder={t('curiosity-toolbar.placeholder', { context: 'displayName' })}
type="search"
/>
<Button
onClick={onSubmit}
variant={ButtonVariant.control}
aria-label={t('curiosity-toolbar.button', { context: 'displayName' })}
>
<SearchIcon />
</Button>
</InputGroup>
);
};
Expand Down
8 changes: 4 additions & 4 deletions src/services/rhsmServices.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const getApiVersion = (options = {}) => {
};

/**
* @apiMock {DelayResponse} 2000
* @apiMock {DelayResponse} 250
* @apiMock {RandomSuccess}
* @api {get} /api/rhsm-subscriptions/v1/tally/products/:product_id Get RHSM graph data
* @apiDescription Retrieve graph data.
Expand Down Expand Up @@ -957,7 +957,7 @@ const getGraphCapacity = (id, params = {}, options = {}) => {
};

/**
* @apiMock {DelayResponse} 1000
* @apiMock {DelayResponse} 500
* @api {get} /api/rhsm-subscriptions/v1/hosts/products/:product_id Get RHSM hosts/systems table/inventory data
* @apiDescription Retrieve hosts/systems table/inventory data.
*
Expand Down Expand Up @@ -1154,7 +1154,7 @@ const getHostsInventory = (id, params = {}, options = {}) => {
};

/**
* @apiMock {DelayResponse} 2000
* @apiMock {DelayResponse} 250
* @api {get} /api/rhsm-subscriptions/v1/hosts/:hypervisor_uuid/guests Get RHSM hosts/systems table/inventory guests data
* @apiDescription Retrieve hosts/systems table/inventory guests data.
*
Expand Down Expand Up @@ -1282,7 +1282,7 @@ const getHostsInventoryGuests = (id, params = {}, options = {}) => {
};

/**
* @apiMock {DelayResponse} 1000
* @apiMock {DelayResponse} 250
* @api {get} /api/rhsm-subscriptions/v1/subscriptions/products/:product_id Get RHSM subscriptions table/inventory data
* @apiDescription Retrieve subscriptions table/inventory data.
*
Expand Down
5 changes: 5 additions & 0 deletions src/setupTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import * as pfReactChartComponents from '@patternfly/react-charts';

configure({ adapter: new Adapter() });

/**
* Emulate for component checks
*/
jest.mock('lodash/debounce', () => jest.fn);

/**
* FixMe: Use of arrow functions removes the usefulness of the "displayName" when shallow rendering
* PF appears to have updated components with a "displayName". Because we potentially have internal
Expand Down
7 changes: 7 additions & 0 deletions src/styles/_form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@
display: none;
}
}

.curiosity-input__display-name {
&.pf-c-form-control.pf-m-search {
padding-left: var(--pf-global--spacer--sm);
background-position: var(--pf-c-form-control--m-icon--BackgroundPositionX) var(--pf-c-form-control--m-icon--BackgroundPositionY);
}
}
2 changes: 1 addition & 1 deletion tests/__snapshots__/code.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ exports[`General code checks should only have specific console.[warn|log|info|er
Array [
"redux/common/reduxHelpers.js:250: console.error(\`Error: Property \${prop} does not exist within the passed state.\`, state);",
"redux/common/reduxHelpers.js:254: console.warn(\`Warning: Property \${prop} does not exist within the passed initialState.\`, initialState);",
"setupTests.js:61: console.error = (message, ...args) => {",
"setupTests.js:66: console.error = (message, ...args) => {",
]
`;

0 comments on commit 61a5b1f

Please sign in to comment.