Skip to content

Commit

Permalink
(query assist) update styles for callout and combo box (#1675)
Browse files Browse the repository at this point in the history
Signed-off-by: Joshua Li <[email protected]>
  • Loading branch information
joshuali925 authored Apr 9, 2024
1 parent c14c3f8 commit 7163e2e
Show file tree
Hide file tree
Showing 9 changed files with 754 additions and 464 deletions.

Large diffs are not rendered by default.

60 changes: 11 additions & 49 deletions public/components/common/search/date_picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,25 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { EuiSuperDatePicker, EuiToolTip } from '@elastic/eui';
import { EuiSuperDatePicker } from '@elastic/eui';
import React from 'react';
import { i18n } from '@osd/i18n';
import { uiSettingsService } from '../../../../common/utils';
import { coreRefs } from '../../../framework/core_refs';
import { IDatePickerProps } from './search';
import {
QUERY_ASSIST_END_TIME,
QUERY_ASSIST_START_TIME,
} from '../../../../common/constants/shared';

export function DatePicker(props: IDatePickerProps) {
const {
startTime,
endTime,
handleTimePickerChange,
handleTimeRangePickerRefresh,
isAppAnalytics,
} = props;
const { startTime, endTime, handleTimePickerChange, handleTimeRangePickerRefresh } = props;

const handleTimeChange = (e: any) => handleTimePickerChange([e.start, e.end]);

let finalizedStartTime;
let finalizedEndTime;
let setDisabled;
let toolTipMessage;

if (coreRefs.queryAssistEnabled && !isAppAnalytics) {
// is query assistant inside log explorer
finalizedStartTime = QUERY_ASSIST_START_TIME;
finalizedEndTime = QUERY_ASSIST_END_TIME;
setDisabled = true;
toolTipMessage = i18n.translate('discover.queryAssistant.timePickerDisabledMessage', {
defaultMessage: 'Date range has been disabled to accomodate timerange of all datasets',
});
} else {
finalizedStartTime = startTime;
finalizedEndTime = endTime;
setDisabled = false;
toolTipMessage = false;
}

return (
<>
<EuiToolTip position="bottom" content={toolTipMessage}>
<EuiSuperDatePicker
data-test-subj="pplSearchDatePicker"
start={finalizedStartTime}
end={finalizedEndTime}
dateFormat={uiSettingsService.get('dateFormat')}
onTimeChange={handleTimeChange}
onRefresh={handleTimeRangePickerRefresh}
className="osdQueryBar__datePicker"
showUpdateButton={false}
isDisabled={setDisabled}
/>
</EuiToolTip>
</>
<EuiSuperDatePicker
data-test-subj="pplSearchDatePicker"
start={startTime}
end={endTime}
dateFormat={uiSettingsService.get('dateFormat')}
onTimeChange={handleTimeChange}
onRefresh={handleTimeRangePickerRefresh}
className="osdQueryBar__datePicker"
/>
);
}
8 changes: 7 additions & 1 deletion public/components/common/search/query_area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { QueryAssistInput } from '../../event_analytics/explorer/query_assist/in
import { useFetchEvents } from '../../event_analytics/hooks/use_fetch_events';
import './query_area.scss';

/**
* QueryArea is currently used for query assist only.
*/
export function QueryArea({
tabId,
handleQueryChange,
Expand Down Expand Up @@ -39,6 +42,7 @@ export function QueryArea({
memoizedGetAvailableFields(indexQuery);
}, [selectedIndex, memoizedGetAvailableFields, memoizedHandleQueryChange]);
const [lastFocusedInput, setLastFocusedInput] = useState<'query_area' | 'nlq_input'>('nlq_input');
const [callOut, setCallOut] = useState<React.ReactNode>(null);

const queryEditor = (
<EuiCodeEditor
Expand All @@ -52,8 +56,8 @@ export function QueryArea({
aria-label="Code Editor"
onChange={(query) => {
handleQueryChange(query);
setCallOut(null);
// query is considered updated when the last run query is not the same as whats in the editor
// setUpdatedQuery(runQuery !== query);
setNeedsUpdate(runQuery !== query);
}}
onFocus={() => setLastFocusedInput('query_area')}
Expand Down Expand Up @@ -90,6 +94,8 @@ export function QueryArea({
lastFocusedInput={lastFocusedInput}
setLastFocusedInput={setLastFocusedInput}
runChanges={runChanges}
callOut={callOut}
setCallOut={setCallOut}
>
{queryEditor}
</QueryAssistInput>
Expand Down
4 changes: 2 additions & 2 deletions public/components/common/search/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ export const Search = (props: any) => {
placeholder="Select an index"
isClearable={true}
prepend={<EuiText>Index</EuiText>}
singleSelection={true}
singleSelection={{ asPlainText: true }}
isLoading={loading}
options={indicesAndIndexPatterns}
selectedOptions={selectedIndex}
Expand Down Expand Up @@ -412,7 +412,7 @@ export const Search = (props: any) => {
<EuiFlexItem grow={false} />
{!(queryRedux.selectedTimestamp === '' && queryResults?.datarows) && ( // index with no timestamp, dont show timepicker
<EuiFlexItem className="euiFlexItem--flexGrowZero event-date-picker" grow={false}>
{!isLiveTailOn && (
{!isLiveTailOn && !coreRefs.queryAssistEnabled && (
<DatePicker
startTime={startTime}
endTime={endTime}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Callouts spec EmptyQueryCallOut should match snapshot 1`] = `
<div>
<div
class="euiCallOut euiCallOut--warning euiCallOut--small"
data-test-subj="query-assist-empty-callout"
>
<div
class="euiCallOutHeader"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiIcon--inherit euiIcon-isLoading euiCallOutHeader__icon"
focusable="false"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.277 10.088c.02.014.04.03.057.047.582.55 1.134.812 1.666.812.586 0 1.84-.293 3.713-.88L9 6.212V2H7v4.212l-1.723 3.876Zm-.438.987L3.539 14h8.922l-1.32-2.969C9.096 11.677 7.733 12 7 12c-.74 0-1.463-.315-2.161-.925ZM6 2H5V1h6v1h-1v4l3.375 7.594A1 1 0 0 1 12.461 15H3.54a1 1 0 0 1-.914-1.406L6 6V2Z"
/>
</svg>
<span
class="euiCallOutHeader__title"
>
Enter a natural language question to automatically generate a query to view results.
</span>
</div>
</div>
</div>
`;

exports[`Callouts spec PPLGeneratedCallOut should match snapshot 1`] = `
<div>
<div
class="euiCallOut euiCallOut--success euiCallOut--small"
data-test-subj="query-assist-ppl-callout"
>
<div
class="euiCallOutHeader"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiIcon--inherit euiIcon-isLoading euiCallOutHeader__icon"
focusable="false"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.277 10.088c.02.014.04.03.057.047.582.55 1.134.812 1.666.812.586 0 1.84-.293 3.713-.88L9 6.212V2H7v4.212l-1.723 3.876Zm-.438.987L3.539 14h8.922l-1.32-2.969C9.096 11.677 7.733 12 7 12c-.74 0-1.463-.315-2.161-.925ZM6 2H5V1h6v1h-1v4l3.375 7.594A1 1 0 0 1 12.461 15H3.54a1 1 0 0 1-.914-1.406L6 6V2Z"
/>
</svg>
<span
class="euiCallOutHeader__title"
>
PPL query generated
</span>
</div>
<button
aria-label="dismissible_icon"
class="euiButtonIcon euiButtonIcon--primary euiButtonIcon--empty euiButtonIcon--xSmall euiCallOut__closeIcon"
data-test-subj="closeCallOutButton"
type="button"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiIcon--inherit euiIcon-isLoading euiButtonIcon__icon"
focusable="false"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.277 10.088c.02.014.04.03.057.047.582.55 1.134.812 1.666.812.586 0 1.84-.293 3.713-.88L9 6.212V2H7v4.212l-1.723 3.876Zm-.438.987L3.539 14h8.922l-1.32-2.969C9.096 11.677 7.733 12 7 12c-.74 0-1.463-.315-2.161-.925ZM6 2H5V1h6v1h-1v4l3.375 7.594A1 1 0 0 1 12.461 15H3.54a1 1 0 0 1-.914-1.406L6 6V2Z"
/>
</svg>
</button>
</div>
</div>
`;

exports[`Callouts spec ProhibitedQueryCallOut should match snapshot 1`] = `
<div>
<div
class="euiCallOut euiCallOut--danger euiCallOut--small"
data-test-subj="query-assist-guard-callout"
>
<div
class="euiCallOutHeader"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiIcon--inherit euiIcon-isLoading euiCallOutHeader__icon"
focusable="false"
height="16"
role="img"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.277 10.088c.02.014.04.03.057.047.582.55 1.134.812 1.666.812.586 0 1.84-.293 3.713-.88L9 6.212V2H7v4.212l-1.723 3.876Zm-.438.987L3.539 14h8.922l-1.32-2.969C9.096 11.677 7.733 12 7 12c-.74 0-1.463-.315-2.161-.925ZM6 2H5V1h6v1h-1v4l3.375 7.594A1 1 0 0 1 12.461 15H3.54a1 1 0 0 1-.914-1.406L6 6V2Z"
/>
</svg>
<span
class="euiCallOutHeader__title"
>
I am unable to respond to this query. Try another question.
</span>
</div>
</div>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { EuiCallOutProps } from '@elastic/eui';
import { render } from '@testing-library/react';
import React from 'react';
import { EmptyQueryCallOut, PPLGeneratedCallOut, ProhibitedQueryCallOut } from '../callouts';

const renderCallouts = (
Component: React.FC,
overrideProps: Partial<Pick<EuiCallOutProps, 'onDismiss'>> = {}
) => {
const props: Pick<EuiCallOutProps, 'onDismiss'> = Object.assign(
{
onDismiss: jest.fn(),
},
overrideProps
);
const component = render(<Component {...props} />);
return { component, props };
};

describe('Callouts spec', () => {
test('ProhibitedQueryCallOut should match snapshot', () => {
const { component } = renderCallouts(ProhibitedQueryCallOut);
expect(component.container).toMatchSnapshot();
});

test('EmptyQueryCallOut should match snapshot', () => {
const { component } = renderCallouts(EmptyQueryCallOut);
expect(component.container).toMatchSnapshot();
});

test('PPLGeneratedCallOut should match snapshot', () => {
const { component } = renderCallouts(PPLGeneratedCallOut);
expect(component.container).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ import * as coreServices from '../../../../../../common/utils/core_services';
import { coreRefs } from '../../../../../framework/core_refs';
import { rootReducer } from '../../../../../framework/redux/reducers';
import { initialTabId } from '../../../../../framework/redux/store/shared_state';
import { PPLGeneratedCallOut, ProhibitedQueryCallOut } from '../callouts';
import { QueryAssistInput } from '../input';

const renderQueryAssistInput = (
overrideProps: Partial<ComponentProps<typeof QueryAssistInput>> = {}
) => {
const preloadedState = {};
const store = configureStore({ reducer: rootReducer, preloadedState });
const props: ComponentProps<typeof QueryAssistInput> = Object.assign(
const props: jest.Mocked<ComponentProps<typeof QueryAssistInput>> = Object.assign<
ComponentProps<typeof QueryAssistInput>,
Partial<ComponentProps<typeof QueryAssistInput>>
>(
{
handleQueryChange: jest.fn(),
handleTimeRangePickerRefresh: jest.fn(),
Expand All @@ -29,6 +33,8 @@ const renderQueryAssistInput = (
selectedIndex: [{ label: 'selected-test-index' }],
nlqInput: 'test-input',
setNlqInput: jest.fn(),
callOut: null,
setCallOut: jest.fn(),
handleTimePickerChange: jest.fn(),
},
overrideProps
Expand Down Expand Up @@ -68,6 +74,12 @@ describe('<QueryAssistInput /> spec', () => {
body: '{"question":"test-input","index":"selected-test-index"}',
});
expect(props.handleQueryChange).toBeCalledWith('source = index');
expect(props.setCallOut.mock.calls[0][0]).toBeNull();
expect(props.setCallOut.mock.calls[1][0]).toEqual(
expect.objectContaining({
type: PPLGeneratedCallOut,
})
);
});

it('should display toast for generate errors', async () => {
Expand Down Expand Up @@ -140,7 +152,7 @@ describe('<QueryAssistInput /> spec', () => {
body: { statusCode: 400, message: ERROR_DETAILS.GUARDRAILS_TRIGGERED },
});

const { component } = renderQueryAssistInput();
const { component, props } = renderQueryAssistInput();
await waitFor(() => {
// splitbutton data-test-subj doesn't work in Oui 1.5, this should be query-assist-generate-and-run-button
fireEvent.click(component.getByText('Generate and run'));
Expand All @@ -149,6 +161,11 @@ describe('<QueryAssistInput /> spec', () => {
expect(httpMock.post).toBeCalledWith(QUERY_ASSIST_API.GENERATE_PPL, {
body: '{"question":"test-input","index":"selected-test-index"}',
});
expect(component.getByTestId('query-assist-guard-callout')).toBeInTheDocument();
expect(props.setCallOut.mock.calls[0][0]).toBeNull();
expect(props.setCallOut.mock.calls[1][0]).toEqual(
expect.objectContaining({
type: ProhibitedQueryCallOut,
})
);
});
});
Loading

0 comments on commit 7163e2e

Please sign in to comment.