diff --git a/src/components/form/__tests__/__snapshots__/textInput.test.js.snap b/src/components/form/__tests__/__snapshots__/textInput.test.js.snap index 38a3a0704..abbf52b14 100644 --- a/src/components/form/__tests__/__snapshots__/textInput.test.js.snap +++ b/src/components/form/__tests__/__snapshots__/textInput.test.js.snap @@ -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, diff --git a/src/components/form/__tests__/textInput.test.js b/src/components/form/__tests__/textInput.test.js index 9adf52d7b..9ef7e52ed 100644 --- a/src/components/form/__tests__/textInput.test.js +++ b/src/components/form/__tests__/textInput.test.js @@ -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(); + 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(); }; diff --git a/src/components/form/textInput.js b/src/components/form/textInput.js index 3ed3f10da..57e14777d 100644 --- a/src/components/form/textInput.js +++ b/src/components/form/textInput.js @@ -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: '' } } }) + ); + }); + } } }; diff --git a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap index 17282a41f..8dd5559f1 100644 --- a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap +++ b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap @@ -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 { @@ -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", diff --git a/src/components/toolbar/__tests__/__snapshots__/toolbarFieldDisplayName.test.js.snap b/src/components/toolbar/__tests__/__snapshots__/toolbarFieldDisplayName.test.js.snap index cdb2c7baa..b069bf625 100644 --- a/src/components/toolbar/__tests__/__snapshots__/toolbarFieldDisplayName.test.js.snap +++ b/src/components/toolbar/__tests__/__snapshots__/toolbarFieldDisplayName.test.js.snap @@ -55,7 +55,8 @@ exports[`ToolbarFieldDisplayName Component should render a non-connected compone - `; diff --git a/src/components/toolbar/__tests__/toolbarFieldDisplayName.test.js b/src/components/toolbar/__tests__/toolbarFieldDisplayName.test.js index c422872c9..d7867eb58 100644 --- a/src/components/toolbar/__tests__/toolbarFieldDisplayName.test.js +++ b/src/components/toolbar/__tests__/toolbarFieldDisplayName.test.js @@ -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'; @@ -31,7 +30,7 @@ describe('ToolbarFieldDisplayName Component', () => { const component = shallow(); 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'); }); diff --git a/src/components/toolbar/toolbarFieldDisplayName.js b/src/components/toolbar/toolbarFieldDisplayName.js index 9af4e6fdb..26cc0f30b 100644 --- a/src/components/toolbar/toolbarFieldDisplayName.js +++ b/src/components/toolbar/toolbarFieldDisplayName.js @@ -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. * @@ -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 } ]); @@ -79,6 +82,11 @@ 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. * @@ -86,11 +94,18 @@ const ToolbarFieldDisplayName = ({ value, t, viewId }) => { * @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; } }; @@ -98,21 +113,15 @@ const ToolbarFieldDisplayName = ({ value, t, viewId }) => { - ); }; diff --git a/src/services/rhsmServices.js b/src/services/rhsmServices.js index 8be0bc053..f9a2c10b1 100644 --- a/src/services/rhsmServices.js +++ b/src/services/rhsmServices.js @@ -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. @@ -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. * @@ -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. * @@ -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. * diff --git a/src/setupTests.js b/src/setupTests.js index 9e5918b70..c4cd4bfe6 100644 --- a/src/setupTests.js +++ b/src/setupTests.js @@ -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 diff --git a/src/styles/_form.scss b/src/styles/_form.scss index ce9487d78..804d4415e 100644 --- a/src/styles/_form.scss +++ b/src/styles/_form.scss @@ -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); + } +} diff --git a/tests/__snapshots__/code.test.js.snap b/tests/__snapshots__/code.test.js.snap index 307d4ac00..f6f5fdfb9 100644 --- a/tests/__snapshots__/code.test.js.snap +++ b/tests/__snapshots__/code.test.js.snap @@ -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) => {", ] `;