diff --git a/packages/filters/src/Type.ts b/packages/filters/src/Type.ts index 4a1970c4ff..b35869fffe 100644 --- a/packages/filters/src/Type.ts +++ b/packages/filters/src/Type.ts @@ -36,6 +36,8 @@ export class Type { static readonly notContains = 'notContains'; + static readonly containsIgnoreCase = 'containsIgnoreCase'; + static readonly startsWith = 'startsWith'; static readonly endsWith = 'endsWith'; diff --git a/packages/iris-grid/src/GotoRow.scss b/packages/iris-grid/src/GotoRow.scss index 0cfac268d3..7fe067c457 100644 --- a/packages/iris-grid/src/GotoRow.scss +++ b/packages/iris-grid/src/GotoRow.scss @@ -26,6 +26,8 @@ .goto-row-text { min-width: 10ch; + margin: 0; + font-size: 14px; } .goto-row-close { @@ -36,7 +38,7 @@ max-width: calc($input-padding-x + 12ch + $input-padding-x); } select { - max-width: calc($input-padding-x + 20ch + $input-padding-x); + max-width: calc($input-padding-x + 25ch + $input-padding-x); } .is-inactive { color: $gray-400; diff --git a/packages/iris-grid/src/GotoRow.test.tsx b/packages/iris-grid/src/GotoRow.test.tsx new file mode 100644 index 0000000000..87a633a388 --- /dev/null +++ b/packages/iris-grid/src/GotoRow.test.tsx @@ -0,0 +1,167 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import dh from '@deephaven/jsapi-shim'; +import { + Type as FilterType, + TypeValue as FilterTypeValue, +} from '@deephaven/filters'; +import { TableUtils } from '@deephaven/jsapi-utils'; +import GotoRow from './GotoRow'; +import IrisGridTestUtils from './IrisGridTestUtils'; + +function makeGotoRow({ + gotoRow = '', + gotoRowError = '', + gotoValueError = '', + onGotoRowSubmit = jest.fn(), + model = new IrisGridTestUtils(dh).makeModel(), + onGotoRowNumberChanged = jest.fn(), + onClose = jest.fn(), + isShown = true, + onEntering = jest.fn(), + onEntered = jest.fn(), + onExiting = jest.fn(), + onExited = jest.fn(), + gotoValueSelectedColumnName = '', + gotoValue = '', + gotoValueFilter = FilterType.eq, + onGotoValueSelectedColumnNameChanged = jest.fn(), + onGotoValueSelectedFilterChanged = jest.fn(), + onGotoValueChanged = jest.fn(), + onGotoValueSubmit = jest.fn(), +} = {}) { + return render( + + ); +} + +beforeEach(() => { + jest.useFakeTimers(); +}); + +afterEach(() => { + jest.useRealTimers(); +}); + +it('mounts and unmounts properly', () => { + makeGotoRow(); +}); + +describe('Go to row', () => { + it('calls onGotoRowSubmit on Enter key press', async () => { + const user = userEvent.setup({ delay: null }); + const onGotoRowSubmitMock = jest.fn(); + const component = makeGotoRow({ onGotoRowSubmit: onGotoRowSubmitMock }); + + const inputElement = screen.getByRole('spinbutton'); + await user.type(inputElement, '{Enter}'); + + expect(onGotoRowSubmitMock).toHaveBeenCalledTimes(1); + + component.unmount(); + }); + + it('does not call onGotoRowSubmit on non-Enter key press', async () => { + const user = userEvent.setup({ delay: null }); + const onGotoRowSubmitMock = jest.fn(); + const component = makeGotoRow({ onGotoRowSubmit: onGotoRowSubmitMock }); + + const inputElement = screen.getByRole('spinbutton'); + await user.type(inputElement, 'a1`'); + + expect(onGotoRowSubmitMock).not.toHaveBeenCalled(); + + component.unmount(); + }); + + it('calls onGotoRowNumberChanged on number key press', async () => { + const user = userEvent.setup({ delay: null }); + const onGotoRowNumberChangedMock = jest.fn(); + const component = makeGotoRow({ + onGotoRowNumberChanged: onGotoRowNumberChangedMock, + }); + + const inputElement = screen.getByRole('spinbutton'); + await user.type(inputElement, '1'); + + expect(onGotoRowNumberChangedMock).toHaveBeenCalledTimes(1); + + component.unmount(); + }); +}); + +describe('Go to value', () => { + it('calls onGotoValueInputChanged when input value changes', async () => { + const user = userEvent.setup({ delay: null }); + const onGotoValueInputChangedMock = jest.fn(); + const component = makeGotoRow({ + onGotoValueChanged: onGotoValueInputChangedMock, + }); + + const inputElement = screen.getByPlaceholderText('value'); + await user.type(inputElement, 'a'); + + expect(onGotoValueInputChangedMock).toHaveBeenCalledTimes(1); + + component.unmount(); + }); + + it('calls onGotoValueSelectedFilterChanged when select value changes', async () => { + const user = userEvent.setup({ delay: null }); + const onGotoValueSelectedFilterChangedMock = jest.fn(); + + jest + .spyOn(TableUtils, 'getNormalizedType') + .mockImplementation(() => TableUtils.dataType.STRING); + + const component = makeGotoRow({ + onGotoValueSelectedFilterChanged: onGotoValueSelectedFilterChangedMock, + }); + + const inputElement = screen.getByLabelText('filter-type-select'); + await user.selectOptions(inputElement, [FilterType.contains]); + + expect(onGotoValueSelectedFilterChangedMock).toHaveBeenCalledTimes(1); + + component.unmount(); + }); + + it('calls onGotoValueSelectedColumnNameChanged when select value changes', async () => { + const user = userEvent.setup({ delay: null }); + const onGotoValueSelectedColumnNameChangedMock = jest.fn(); + const component = makeGotoRow({ + onGotoValueSelectedColumnNameChanged: onGotoValueSelectedColumnNameChangedMock, + }); + + const inputElement = screen.getByLabelText('column-name-select'); + await user.selectOptions(inputElement, ['1']); + + expect(onGotoValueSelectedColumnNameChangedMock).toHaveBeenCalledTimes(1); + + component.unmount(); + }); +}); diff --git a/packages/iris-grid/src/GotoRow.tsx b/packages/iris-grid/src/GotoRow.tsx index 9651c45362..7c509572e0 100644 --- a/packages/iris-grid/src/GotoRow.tsx +++ b/packages/iris-grid/src/GotoRow.tsx @@ -5,6 +5,7 @@ import React, { KeyboardEvent, ReactElement, useEffect, + useMemo, useRef, useState, } from 'react'; @@ -17,6 +18,7 @@ import { Button, DateTimeInput } from '@deephaven/components'; import { TableUtils } from '@deephaven/jsapi-utils'; import classNames from 'classnames'; import './GotoRow.scss'; +import shortid from 'shortid'; import IrisGridModel from './IrisGridModel'; import IrisGridProxyModel from './IrisGridProxyModel'; import IrisGridBottomBar from './IrisGridBottomBar'; @@ -84,10 +86,10 @@ function GotoRow({ ({ columns } = model.table); } - const res = 'Row number'; - const { dh, rowCount } = model; + const gotoRowInputId = useMemo(() => `goto-row-input-${shortid()}`, []); + const handleGotoValueNumberKeyDown = (e: KeyboardEvent) => { if (e.key === 'Enter') { e.stopPropagation(); @@ -158,6 +160,7 @@ function GotoRow({ } }} value={gotoValue} + aria-label="Value Input" /> ); @@ -176,6 +179,7 @@ function GotoRow({ defaultValue={gotoValue} onChange={onGotoValueInputChanged} onSubmit={handleGotoValueKeySubmit} + aria-label="Value Input" /> ); @@ -191,19 +195,26 @@ function GotoRow({ ); }} value={gotoValueFilter} + aria-label="filter-type-select" > + + -
@@ -216,6 +227,7 @@ function GotoRow({ placeholder="value" onChange={e => onGotoValueInputChanged(e.target.value)} value={gotoValue} + aria-label="Value Input" />
@@ -229,6 +241,7 @@ function GotoRow({ onGotoValueInputChanged(event.target.value); }} value={gotoValue} + aria-label="Value Input" >