Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add contains ignore case in go to row #1291

Merged
merged 4 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/filters/src/Type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export class Type {

static readonly notContains = 'notContains';

static readonly containsIgnoreCase = 'containsIgnoreCase';

static readonly startsWith = 'startsWith';

static readonly endsWith = 'endsWith';
Expand Down
4 changes: 3 additions & 1 deletion packages/iris-grid/src/GotoRow.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

.goto-row-text {
min-width: 10ch;
margin: 0;
font-size: 14px;
}

.goto-row-close {
Expand All @@ -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;
Expand Down
167 changes: 167 additions & 0 deletions packages/iris-grid/src/GotoRow.test.tsx
Original file line number Diff line number Diff line change
@@ -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(
<GotoRow
dh={dh}
gotoRow={gotoRow}
gotoRowError={gotoRowError}
gotoValueError={gotoValueError}
onGotoRowSubmit={onGotoRowSubmit}
model={model}
onGotoRowNumberChanged={onGotoRowNumberChanged}
onClose={onClose}
isShown={isShown}
onEntering={onEntering}
onEntered={onEntered}
onExiting={onExiting}
onExited={onExited}
gotoValueSelectedColumnName={gotoValueSelectedColumnName}
gotoValue={gotoValue}
gotoValueFilter={gotoValueFilter as FilterTypeValue}
onGotoValueSelectedColumnNameChanged={
onGotoValueSelectedColumnNameChanged
}
onGotoValueSelectedFilterChanged={onGotoValueSelectedFilterChanged}
onGotoValueChanged={onGotoValueChanged}
onGotoValueSubmit={onGotoValueSubmit}
/>
);
}

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();
});
});
39 changes: 29 additions & 10 deletions packages/iris-grid/src/GotoRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, {
KeyboardEvent,
ReactElement,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
Expand All @@ -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';
Expand Down Expand Up @@ -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<HTMLInputElement>) => {
if (e.key === 'Enter') {
e.stopPropagation();
Expand Down Expand Up @@ -158,6 +160,7 @@ function GotoRow({
}
}}
value={gotoValue}
aria-label="Value Input"
/>
</div>
);
Expand All @@ -176,6 +179,7 @@ function GotoRow({
defaultValue={gotoValue}
onChange={onGotoValueInputChanged}
onSubmit={handleGotoValueKeySubmit}
aria-label="Value Input"
/>
</div>
);
Expand All @@ -191,19 +195,26 @@ function GotoRow({
);
}}
value={gotoValueFilter}
aria-label="filter-type-select"
>
<option
key={FilterType.eqIgnoreCase}
value={FilterType.eqIgnoreCase}
>
Equals (case-insensitive)
</option>
<option
key={FilterType.containsIgnoreCase}
value={FilterType.containsIgnoreCase}
>
Contains (case-insensitive)
</option>
<option key={FilterType.eq} value={FilterType.eq}>
Equals
</option>
<option key={FilterType.contains} value={FilterType.contains}>
Contains
</option>
<option
key={FilterType.eqIgnoreCase}
value={FilterType.eqIgnoreCase}
>
EqIgnoreCase
</option>
</select>
</div>
<div className="goto-row-input">
Expand All @@ -216,6 +227,7 @@ function GotoRow({
placeholder="value"
onChange={e => onGotoValueInputChanged(e.target.value)}
value={gotoValue}
aria-label="Value Input"
/>
</div>
</>
Expand All @@ -229,6 +241,7 @@ function GotoRow({
onGotoValueInputChanged(event.target.value);
}}
value={gotoValue}
aria-label="Value Input"
>
<option aria-label="null value" key="null" value="" />
<option key="true" value="true">
Expand All @@ -250,6 +263,7 @@ function GotoRow({
placeholder="value"
onChange={e => onGotoValueInputChanged(e.target.value)}
value={gotoValue}
aria-label="Value Input"
/>
</div>
);
Expand Down Expand Up @@ -277,10 +291,13 @@ function GotoRow({
onFocus={() => setIsGotoRowActive(true)}
role="group"
>
<div className="goto-row-text">Go to row</div>
<label className="goto-row-text" htmlFor={gotoRowInputId}>
Go to row
</label>
<div className="goto-row-input">
<input
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
ref={gotoRowInputRef}
data-testid="goto-row-input"
type="number"
onKeyDown={e => {
if (e.key === 'Enter') {
Expand All @@ -292,11 +309,12 @@ function GotoRow({
className={classNames('form-control', {
'is-invalid': gotoRowError !== '',
})}
placeholder={res}
placeholder="Row number"
onChange={event => {
onGotoRowNumberChanged(event);
}}
value={gotoRow}
id={gotoRowInputId}
/>
</div>
<div className="goto-row-text">
Expand Down Expand Up @@ -329,6 +347,7 @@ function GotoRow({
onGotoValueSelectedColumnNameChanged(columnName);
}}
value={gotoValueSelectedColumnName}
aria-label="column-name-select"
>
{columns.map(column => (
<option key={column.name} value={column.name}>
Expand Down
14 changes: 8 additions & 6 deletions packages/iris-grid/src/IrisGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ export class IrisGrid extends Component<IrisGridProps, IrisGridState> {
gotoValueError: '',

gotoValueSelectedColumnName: model.columns[0]?.name ?? '',
gotoValueSelectedFilter: FilterType.eq,
gotoValueSelectedFilter: FilterType.eqIgnoreCase,
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
gotoValue: '',
columnHeaderGroups: columnHeaderGroups ?? model.initialColumnHeaderGroups,
};
Expand Down Expand Up @@ -3336,10 +3336,12 @@ export class IrisGrid extends Component<IrisGridProps, IrisGridState> {
searchFromRow = 0;
}

const isContains = gotoValueSelectedFilter === FilterType.contains;
const isEquals =
gotoValueSelectedFilter === FilterType.eq ||
gotoValueSelectedFilter === FilterType.eqIgnoreCase;
const isContains =
gotoValueSelectedFilter === FilterType.contains ||
gotoValueSelectedFilter === FilterType.containsIgnoreCase;
const isIgnoreCase =
gotoValueSelectedFilter === FilterType.eqIgnoreCase ||
gotoValueSelectedFilter === FilterType.containsIgnoreCase;

try {
const { formatter } = model;
Expand All @@ -3355,7 +3357,7 @@ export class IrisGrid extends Component<IrisGridProps, IrisGridState> {
selectedColumn,
dh.ValueType.STRING,
inputString,
isEquals,
isIgnoreCase,
ethanalvizo marked this conversation as resolved.
Show resolved Hide resolved
isContains,
isBackwards ?? false
);
Expand Down