[ML] Transforms: Replace KqlFilterBar with QueryStringInput. (#59723)

- Replaces the custom KqlFilterBar with Kibana's QueryStringInput. This means the wizard now supports both lucene and kuery input.
- Using this component we no longer need to do cross-imports from the ML plugin. The use of setDependencyCache is no longer necessary.
- Replaces the custom AppDependencies provider code with Kibana's KibanaContextProvider.
This commit is contained in:
Walter Rafelsberger 2020-03-12 15:55:41 +01:00 committed by GitHub
parent ca67b80460
commit 1ede10ccbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 212 additions and 252 deletions

View file

@ -4,11 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
jest.mock('ui/new_platform');
export const expandLiteralStrings = jest.fn();
export const XJsonMode = jest.fn();
export const setDependencyCache = jest.fn();
export const useRequest = jest.fn(() => ({
isLoading: false,
error: null,
@ -16,4 +13,3 @@ export const useRequest = jest.fn(() => ({
}));
export { mlInMemoryTableBasicFactory } from '../../../../legacy/plugins/ml/public/application/components/ml_in_memory_table';
export const SORT_DIRECTION = { ASC: 'asc' };
export const KqlFilterBar = jest.fn(() => null);

View file

@ -4,25 +4,31 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { coreMock } from '../../../../../src/core/public/mocks';
import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks';
import { getAppProviders, AppDependencies } from './app_dependencies';
import { coreMock } from '../../../../../../src/core/public/mocks';
import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks';
import { Storage } from '../../../../../../src/plugins/kibana_utils/public';
const coreSetup = coreMock.createSetup();
const coreStart = coreMock.createStart();
const dataStart = dataPluginMock.createStartContract();
const appDependencies: AppDependencies = {
const appDependencies = {
chrome: coreStart.chrome,
data: dataStart,
docLinks: coreStart.docLinks,
i18n: coreStart.i18n,
notifications: coreStart.notifications,
notifications: coreSetup.notifications,
uiSettings: coreStart.uiSettings,
savedObjects: coreStart.savedObjects,
storage: ({ get: jest.fn() } as unknown) as Storage,
overlays: coreStart.overlays,
http: coreSetup.http,
};
export const Providers = getAppProviders(appDependencies);
export const useAppDependencies = () => {
return appDependencies;
};
export const useToastNotifications = () => {
return coreSetup.notifications;
};

View file

@ -10,10 +10,13 @@ import { HashRouter, Redirect, Route, Switch } from 'react-router-dom';
import { FormattedMessage } from '@kbn/i18n/react';
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
import { API_BASE_PATH } from '../../common/constants';
import { SectionError } from './components';
import { CLIENT_BASE_PATH, SECTION_SLUG } from './constants';
import { getAppProviders } from './app_dependencies';
import { AuthorizationContext } from './lib/authorization';
import { AuthorizationContext, AuthorizationProvider } from './lib/authorization';
import { AppDependencies } from './app_dependencies';
import { CloneTransformSection } from './sections/clone_transform';
@ -61,12 +64,16 @@ export const App: FC = () => {
};
export const renderApp = (element: HTMLElement, appDependencies: AppDependencies) => {
const Providers = getAppProviders(appDependencies);
const I18nContext = appDependencies.i18n.Context;
render(
<Providers>
<App />
</Providers>,
<KibanaContextProvider services={appDependencies}>
<AuthorizationProvider privilegesEndpoint={`${API_BASE_PATH}privileges`}>
<I18nContext>
<App />
</I18nContext>
</AuthorizationProvider>
</KibanaContextProvider>,
element
);

View file

@ -4,17 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React, { createContext, useContext, ReactNode } from 'react';
import { HashRouter } from 'react-router-dom';
import { CoreSetup, CoreStart } from 'src/core/public';
import { DataPublicPluginStart } from 'src/plugins/data/public';
import { API_BASE_PATH } from '../../common/constants';
import { setDependencyCache } from '../shared_imports';
import { AuthorizationProvider } from './lib/authorization';
import { useKibana } from '../../../../../src/plugins/kibana_react/public';
import { Storage } from '../../../../../src/plugins/kibana_utils/public';
export interface AppDependencies {
chrome: CoreStart['chrome'];
@ -22,36 +16,15 @@ export interface AppDependencies {
docLinks: CoreStart['docLinks'];
http: CoreSetup['http'];
i18n: CoreStart['i18n'];
notifications: CoreStart['notifications'];
notifications: CoreSetup['notifications'];
uiSettings: CoreStart['uiSettings'];
savedObjects: CoreStart['savedObjects'];
storage: Storage;
overlays: CoreStart['overlays'];
}
let DependenciesContext: React.Context<AppDependencies>;
const setAppDependencies = (deps: AppDependencies) => {
const legacyBasePath = {
prepend: deps.http.basePath.prepend,
get: deps.http.basePath.get,
remove: () => {},
};
setDependencyCache({
autocomplete: deps.data.autocomplete,
docLinks: deps.docLinks,
basePath: legacyBasePath as any,
});
DependenciesContext = createContext<AppDependencies>(deps);
return DependenciesContext.Provider;
};
export const useAppDependencies = () => {
if (!DependenciesContext) {
throw new Error(`The app dependencies Context hasn't been set.
Use the "setAppDependencies()" method when bootstrapping the app.`);
}
return useContext<AppDependencies>(DependenciesContext);
return useKibana().services as AppDependencies;
};
export const useToastNotifications = () => {
@ -60,20 +33,3 @@ export const useToastNotifications = () => {
} = useAppDependencies();
return toastNotifications;
};
export const getAppProviders = (deps: AppDependencies) => {
const I18nContext = deps.i18n.Context;
// Create App dependencies context and get its provider
const AppDependenciesProvider = setAppDependencies(deps);
return ({ children }: { children: ReactNode }) => (
<AuthorizationProvider privilegesEndpoint={`${API_BASE_PATH}privileges`}>
<I18nContext>
<HashRouter>
<AppDependenciesProvider value={deps}>{children}</AppDependenciesProvider>
</HashRouter>
</I18nContext>
</AuthorizationProvider>
);
};

View file

@ -143,6 +143,7 @@ describe('Transform: Common', () => {
isAdvancedPivotEditorEnabled: false,
isAdvancedSourceEditorEnabled: false,
sourceConfigUpdated: false,
searchLanguage: 'kuery',
searchString: 'the-query',
searchQuery: 'the-search-query',
valid: true,

View file

@ -8,7 +8,6 @@ import React from 'react';
import { render, wait } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Providers } from '../../app_dependencies.mock';
import {
getPivotQuery,
PivotAggsConfig,
@ -19,8 +18,8 @@ import {
import { PivotPreview } from './pivot_preview';
jest.mock('ui/new_platform');
jest.mock('../../../shared_imports');
jest.mock('../../../app/app_dependencies');
describe('Transform: <PivotPreview />', () => {
// Using the async/await wait()/done() pattern to avoid act() errors.
@ -45,11 +44,7 @@ describe('Transform: <PivotPreview />', () => {
query: getPivotQuery('the-query'),
};
const { getByText } = render(
<Providers>
<PivotPreview {...props} />
</Providers>
);
const { getByText } = render(<PivotPreview {...props} />);
// Act
// Assert

View file

@ -7,23 +7,17 @@
import React from 'react';
import { render } from '@testing-library/react';
import { Providers } from '../app_dependencies.mock';
import { ToastNotificationText } from './toast_notification_text';
jest.mock('../../shared_imports');
jest.mock('ui/new_platform');
jest.mock('../../app/app_dependencies');
describe('ToastNotificationText', () => {
test('should render the text as plain text', () => {
const props = {
text: 'a short text message',
};
const { container } = render(
<Providers>
<ToastNotificationText {...props} />
</Providers>
);
const { container } = render(<ToastNotificationText {...props} />);
expect(container.textContent).toBe('a short text message');
});
@ -32,11 +26,7 @@ describe('ToastNotificationText', () => {
text:
'a text message that is longer than 140 characters. a text message that is longer than 140 characters. a text message that is longer than 140 characters. ',
};
const { container } = render(
<Providers>
<ToastNotificationText {...props} />
</Providers>
);
const { container } = render(<ToastNotificationText {...props} />);
expect(container.textContent).toBe(
'a text message that is longer than 140 characters. a text message that is longer than 140 characters. a text message that is longer than 140 ...View details'
);

View file

@ -8,14 +8,13 @@ import React from 'react';
import { render, wait } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Providers } from '../../../../app_dependencies.mock';
import { getPivotQuery } from '../../../../common';
import { SearchItems } from '../../../../hooks/use_search_items';
import { SourceIndexPreview } from './source_index_preview';
jest.mock('ui/new_platform');
jest.mock('../../../../../shared_imports');
jest.mock('../../../../../app/app_dependencies');
describe('Transform: <SourceIndexPreview />', () => {
// Using the async/await wait()/done() pattern to avoid act() errors.
@ -28,11 +27,7 @@ describe('Transform: <SourceIndexPreview />', () => {
} as SearchItems['indexPattern'],
query: getPivotQuery('the-query'),
};
const { getByText } = render(
<Providers>
<SourceIndexPreview {...props} />
</Providers>
);
const { getByText } = render(<SourceIndexPreview {...props} />);
// Act
// Assert

View file

@ -8,12 +8,10 @@ import React from 'react';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Providers } from '../../../../app_dependencies.mock';
import { StepCreateForm } from './step_create_form';
jest.mock('ui/new_platform');
jest.mock('../../../../../shared_imports');
jest.mock('../../../../../app/app_dependencies');
describe('Transform: <StepCreateForm />', () => {
test('Minimal initialization', () => {
@ -26,11 +24,7 @@ describe('Transform: <StepCreateForm />', () => {
onChange() {},
};
const { getByText } = render(
<Providers>
<StepCreateForm {...props} />
</Providers>
);
const { getByText } = render(<StepCreateForm {...props} />);
// Act
// Assert

View file

@ -8,7 +8,14 @@ import React from 'react';
import { render, wait } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Providers } from '../../../../app_dependencies.mock';
import { I18nProvider } from '@kbn/i18n/react';
import { KibanaContextProvider } from '../../../../../../../../../src/plugins/kibana_react/public';
import { coreMock } from '../../../../../../../../../src/core/public/mocks';
import { dataPluginMock } from '../../../../../../../../../src/plugins/data/public/mocks';
const startMock = coreMock.createStart();
import {
PivotAggsConfigDict,
PivotGroupByConfigDict,
@ -19,8 +26,25 @@ import { SearchItems } from '../../../../hooks/use_search_items';
import { StepDefineForm, getAggNameConflictToastMessages } from './step_define_form';
jest.mock('ui/new_platform');
jest.mock('../../../../../shared_imports');
jest.mock('../../../../../app/app_dependencies');
const createMockWebStorage = () => ({
clear: jest.fn(),
getItem: jest.fn(),
key: jest.fn(),
removeItem: jest.fn(),
setItem: jest.fn(),
length: 0,
});
const createMockStorage = () => ({
storage: createMockWebStorage(),
get: jest.fn(),
set: jest.fn(),
remove: jest.fn(),
clear: jest.fn(),
});
describe('Transform: <DefinePivotForm />', () => {
// Using the async/await wait()/done() pattern to avoid act() errors.
@ -32,10 +56,21 @@ describe('Transform: <DefinePivotForm />', () => {
fields: [] as any[],
} as SearchItems['indexPattern'],
};
// mock services for QueryStringInput
const services = {
...startMock,
data: dataPluginMock.createStartContract(),
appName: 'the-test-app',
storage: createMockStorage(),
};
const { getByLabelText } = render(
<Providers>
<StepDefineForm onChange={jest.fn()} searchItems={searchItems as SearchItems} />
</Providers>
<I18nProvider>
<KibanaContextProvider services={services}>
<StepDefineForm onChange={jest.fn()} searchItems={searchItems as SearchItems} />
</KibanaContextProvider>
</I18nProvider>
);
// Act

View file

@ -20,13 +20,19 @@ import {
EuiHorizontalRule,
EuiLink,
EuiPanel,
// @ts-ignore
EuiSearchBar,
EuiSpacer,
EuiSwitch,
} from '@elastic/eui';
import {
esKuery,
esQuery,
Query,
QueryStringInput,
} from '../../../../../../../../../src/plugins/data/public';
import { PivotPreview } from '../../../../components/pivot_preview';
import { useDocumentationLinks } from '../../../../hooks/use_documentation_links';
import { SavedSearchQuery, SearchItems } from '../../../../hooks/use_search_items';
import { useXJsonMode, xJsonMode } from '../../../../hooks/use_x_json_mode';
@ -37,13 +43,11 @@ import { DropDown } from '../aggregation_dropdown';
import { AggListForm } from '../aggregation_list';
import { GroupByListForm } from '../group_by_list';
import { SourceIndexPreview } from '../source_index_preview';
import { KqlFilterBar } from '../../../../../shared_imports';
import { SwitchModal } from './switch_modal';
import {
getPivotQuery,
getPreviewRequestBody,
isMatchAllQuery,
matchAllQuery,
AggName,
DropDownLabel,
@ -65,14 +69,18 @@ export interface StepDefineExposedState {
groupByList: PivotGroupByConfigDict;
isAdvancedPivotEditorEnabled: boolean;
isAdvancedSourceEditorEnabled: boolean;
searchString: string | SavedSearchQuery;
searchLanguage: QUERY_LANGUAGE;
searchString: string | undefined;
searchQuery: string | SavedSearchQuery;
sourceConfigUpdated: boolean;
valid: boolean;
}
const defaultSearch = '*';
const emptySearch = '';
const QUERY_LANGUAGE_KUERY = 'kuery';
const QUERY_LANGUAGE_LUCENE = 'lucene';
type QUERY_LANGUAGE = 'kuery' | 'lucene';
export function getDefaultStepDefineState(searchItems: SearchItems): StepDefineExposedState {
return {
@ -80,7 +88,8 @@ export function getDefaultStepDefineState(searchItems: SearchItems): StepDefineE
groupByList: {} as PivotGroupByConfigDict,
isAdvancedPivotEditorEnabled: false,
isAdvancedSourceEditorEnabled: false,
searchString: searchItems.savedSearch !== undefined ? searchItems.combinedQuery : defaultSearch,
searchLanguage: QUERY_LANGUAGE_KUERY,
searchString: undefined,
searchQuery: searchItems.savedSearch !== undefined ? searchItems.combinedQuery : defaultSearch,
sourceConfigUpdated: false,
valid: false,
@ -126,7 +135,6 @@ export function applyTransformConfigToDefineState(
const query = transformConfig.source.query;
if (query !== undefined && !isEqual(query, matchAllQuery)) {
state.isAdvancedSourceEditorEnabled = true;
state.searchString = '';
state.searchQuery = query;
state.sourceConfigUpdated = true;
}
@ -243,24 +251,45 @@ export const StepDefineForm: FC<Props> = React.memo(({ overrides = {}, onChange,
const defaults = { ...getDefaultStepDefineState(searchItems), ...overrides };
// The search filter
const [searchString, setSearchString] = useState(defaults.searchString);
const [searchQuery, setSearchQuery] = useState(defaults.searchQuery);
const [useKQL] = useState(true);
// The internal state of the input query bar updated on every key stroke.
const [searchInput, setSearchInput] = useState<Query>({
query: defaults.searchString || '',
language: defaults.searchLanguage,
});
const searchHandler = (d: Record<string, any>) => {
const { filterQuery, queryString } = d;
const newSearch = queryString === emptySearch ? defaultSearch : queryString;
const newSearchQuery = isMatchAllQuery(filterQuery) ? defaultSearch : filterQuery;
setSearchString(newSearch);
setSearchQuery(newSearchQuery);
// The state of the input query bar updated on every submit and to be exposed.
const [searchLanguage, setSearchLanguage] = useState<StepDefineExposedState['searchLanguage']>(
defaults.searchLanguage
);
const [searchString, setSearchString] = useState<StepDefineExposedState['searchString']>(
defaults.searchString
);
const [searchQuery, setSearchQuery] = useState(defaults.searchQuery);
const { indexPattern } = searchItems;
const searchChangeHandler = (query: Query) => setSearchInput(query);
const searchSubmitHandler = (query: Query) => {
setSearchLanguage(query.language as QUERY_LANGUAGE);
setSearchString(query.query !== '' ? (query.query as string) : undefined);
switch (query.language) {
case QUERY_LANGUAGE_KUERY:
setSearchQuery(
esKuery.toElasticsearchQuery(
esKuery.fromKueryExpression(query.query as string),
indexPattern
)
);
return;
case QUERY_LANGUAGE_LUCENE:
setSearchQuery(esQuery.luceneStringToDsl(query.query as string));
return;
}
};
// The list of selected group by fields
const [groupByList, setGroupByList] = useState(defaults.groupByList);
const { indexPattern } = searchItems;
const {
groupByOptions,
groupByOptionsData,
@ -349,7 +378,7 @@ export const StepDefineForm: FC<Props> = React.memo(({ overrides = {}, onChange,
const pivotAggsArr = dictionaryToArray(aggList);
const pivotGroupByArr = dictionaryToArray(groupByList);
const pivotQuery = useKQL ? getPivotQuery(searchQuery) : getPivotQuery(searchString);
const pivotQuery = getPivotQuery(searchQuery);
// Advanced editor for pivot config state
const [isAdvancedEditorSwitchModalVisible, setAdvancedEditorSwitchModalVisible] = useState(false);
@ -409,8 +438,6 @@ export const StepDefineForm: FC<Props> = React.memo(({ overrides = {}, onChange,
const applyAdvancedSourceEditorChanges = () => {
const sourceConfig = JSON.parse(advancedEditorSourceConfig);
const prettySourceConfig = JSON.stringify(sourceConfig, null, 2);
// Switched to editor so we clear out the search string as the bar won't be visible
setSearchString(emptySearch);
setSearchQuery(sourceConfig);
setSourceConfigUpdated(true);
setAdvancedEditorSourceConfig(prettySourceConfig);
@ -471,7 +498,6 @@ export const StepDefineForm: FC<Props> = React.memo(({ overrides = {}, onChange,
const toggleAdvancedSourceEditor = (reset = false) => {
if (reset === true) {
setSearchQuery(defaultSearch);
setSearchString(defaultSearch);
setSourceConfigUpdated(false);
}
if (isAdvancedSourceEditorEnabled === false) {
@ -532,6 +558,7 @@ export const StepDefineForm: FC<Props> = React.memo(({ overrides = {}, onChange,
groupByList,
isAdvancedPivotEditorEnabled,
isAdvancedSourceEditorEnabled,
searchLanguage,
searchString,
searchQuery,
sourceConfigUpdated,
@ -544,6 +571,7 @@ export const StepDefineForm: FC<Props> = React.memo(({ overrides = {}, onChange,
JSON.stringify(pivotGroupByArr),
isAdvancedPivotEditorEnabled,
isAdvancedSourceEditorEnabled,
searchLanguage,
searchString,
searchQuery,
valid,
@ -560,7 +588,7 @@ export const StepDefineForm: FC<Props> = React.memo(({ overrides = {}, onChange,
<EuiFlexItem grow={false} className="transform__stepDefineFormLeftColumn">
<div data-test-subj="transformStepDefineForm">
<EuiForm>
{searchItems.savedSearch === undefined && typeof searchString === 'string' && (
{searchItems.savedSearch === undefined && (
<Fragment>
<EuiFormRow
label={i18n.translate('xpack.transform.stepDefineForm.indexPatternLabel', {
@ -592,18 +620,32 @@ export const StepDefineForm: FC<Props> = React.memo(({ overrides = {}, onChange,
defaultMessage: 'Use a query to filter the source data (optional).',
})}
>
<KqlFilterBar
indexPattern={indexPattern}
onSubmit={searchHandler}
initialValue={searchString === defaultSearch ? emptySearch : searchString}
placeholder={i18n.translate(
'xpack.transform.stepDefineForm.queryPlaceholder',
{
defaultMessage: 'e.g. {example}',
values: { example: 'method : "GET" or status : "404"' },
}
)}
testSubj="tarnsformQueryInput"
<QueryStringInput
bubbleSubmitEvent={true}
query={searchInput}
indexPatterns={[indexPattern]}
onChange={searchChangeHandler}
onSubmit={searchSubmitHandler}
placeholder={
searchInput.language === QUERY_LANGUAGE_KUERY
? i18n.translate(
'xpack.transform.stepDefineForm.queryPlaceholderKql',
{
defaultMessage: 'e.g. {example}',
values: { example: 'method : "GET" or status : "404"' },
}
)
: i18n.translate(
'xpack.transform.stepDefineForm.queryPlaceholderLucene',
{
defaultMessage: 'e.g. {example}',
values: { example: 'method:GET OR status:404' },
}
)
}
disableAutoFocus={true}
dataTestSubj="transformQueryInput"
languageSwitcherPopoverAnchorPosition="rightDown"
/>
</EuiFormRow>
)}

View file

@ -8,7 +8,6 @@ import React from 'react';
import { render, wait } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Providers } from '../../../../app_dependencies.mock';
import {
PivotAggsConfig,
PivotGroupByConfig,
@ -20,8 +19,8 @@ import { SearchItems } from '../../../../hooks/use_search_items';
import { StepDefineExposedState } from './step_define_form';
import { StepDefineSummary } from './step_define_summary';
jest.mock('ui/new_platform');
jest.mock('../../../../../shared_imports');
jest.mock('../../../../../app/app_dependencies');
describe('Transform: <DefinePivotSummary />', () => {
// Using the async/await wait()/done() pattern to avoid act() errors.
@ -51,15 +50,14 @@ describe('Transform: <DefinePivotSummary />', () => {
isAdvancedPivotEditorEnabled: false,
isAdvancedSourceEditorEnabled: false,
sourceConfigUpdated: false,
searchLanguage: 'kuery',
searchString: 'the-query',
searchQuery: 'the-search-query',
valid: true,
};
const { getByText } = render(
<Providers>
<StepDefineSummary formState={formState} searchItems={searchItems as SearchItems} />
</Providers>
<StepDefineSummary formState={formState} searchItems={searchItems as SearchItems} />
);
// Act

View file

@ -26,9 +26,6 @@ import { GroupByListSummary } from '../group_by_list';
import { StepDefineExposedState } from './step_define_form';
const defaultSearch = '*';
const emptySearch = '';
interface Props {
formState: StepDefineExposedState;
searchItems: SearchItems;
@ -39,66 +36,50 @@ export const StepDefineSummary: FC<Props> = ({
searchItems,
}) => {
const pivotQuery = getPivotQuery(searchQuery);
let useCodeBlock = false;
let displaySearch;
// searchString set to empty once source config editor used - display query instead
if (searchString === emptySearch) {
displaySearch = JSON.stringify(searchQuery, null, 2);
useCodeBlock = true;
} else if (searchString === defaultSearch) {
displaySearch = emptySearch;
} else {
displaySearch = searchString;
}
return (
<EuiFlexGroup>
<EuiFlexItem grow={false} style={{ minWidth: '420px' }}>
<div data-test-subj="transformStepDefineSummary">
<EuiForm>
{searchItems.savedSearch !== undefined &&
searchItems.savedSearch.id === undefined &&
typeof searchString === 'string' && (
<Fragment>
{searchItems.savedSearch === undefined && (
<Fragment>
<EuiFormRow
label={i18n.translate('xpack.transform.stepDefineSummary.indexPatternLabel', {
defaultMessage: 'Index pattern',
})}
>
<span>{searchItems.indexPattern.title}</span>
</EuiFormRow>
{typeof searchString === 'string' && (
<EuiFormRow
label={i18n.translate('xpack.transform.stepDefineSummary.indexPatternLabel', {
defaultMessage: 'Index pattern',
label={i18n.translate('xpack.transform.stepDefineSummary.queryLabel', {
defaultMessage: 'Query',
})}
>
<span>{searchItems.indexPattern.title}</span>
<span>{searchString}</span>
</EuiFormRow>
{useCodeBlock === false && displaySearch !== emptySearch && (
<EuiFormRow
label={i18n.translate('xpack.transform.stepDefineSummary.queryLabel', {
defaultMessage: 'Query',
})}
)}
{typeof searchString === 'undefined' && (
<EuiFormRow
label={i18n.translate('xpack.transform.stepDefineSummary.queryCodeBlockLabel', {
defaultMessage: 'Query',
})}
>
<EuiCodeBlock
language="js"
fontSize="s"
paddingSize="s"
color="light"
overflowHeight={300}
isCopyable
>
<span>{displaySearch}</span>
</EuiFormRow>
)}
{useCodeBlock === true && displaySearch !== emptySearch && (
<EuiFormRow
label={i18n.translate(
'xpack.transform.stepDefineSummary.queryCodeBlockLabel',
{
defaultMessage: 'Query',
}
)}
>
<EuiCodeBlock
language="js"
fontSize="s"
paddingSize="s"
color="light"
overflowHeight={300}
isCopyable
>
{displaySearch}
</EuiCodeBlock>
</EuiFormRow>
)}
</Fragment>
)}
{JSON.stringify(searchQuery, null, 2)}
</EuiCodeBlock>
</EuiFormRow>
)}
</Fragment>
)}
{searchItems.savedSearch !== undefined && searchItems.savedSearch.id !== undefined && (
<EuiFormRow

View file

@ -34,7 +34,7 @@ const pivotModalMessage = i18n.translate(
const sourceModalMessage = i18n.translate(
'xpack.transform.stepDefineForm.advancedSourceEditorSwitchModalBodyText',
{
defaultMessage: `By switching back to KQL query bar you will lose your edits.`,
defaultMessage: `By switching back to the query bar you will lose your edits.`,
}
);
const pivotModalConfirmButtonText = i18n.translate(
@ -46,7 +46,7 @@ const pivotModalConfirmButtonText = i18n.translate(
const sourceModalConfirmButtonText = i18n.translate(
'xpack.transform.stepDefineForm.advancedSourceEditorSwitchModalConfirmButtonText',
{
defaultMessage: 'Switch to KQL',
defaultMessage: 'Switch to query bar',
}
);
const cancelButtonText = i18n.translate(

View file

@ -7,15 +7,13 @@
import { shallow } from 'enzyme';
import React from 'react';
import { Providers } from '../../../../app_dependencies.mock';
import { TransformListRow } from '../../../../common';
import { DeleteAction } from './action_delete';
import transformListRow from '../../../../common/__mocks__/transform_list_row.json';
jest.mock('ui/new_platform');
jest.mock('../../../../../shared_imports');
jest.mock('../../../../../app/app_dependencies');
describe('Transform: Transform List Actions <DeleteAction />', () => {
test('Minimal initialization', () => {
@ -26,14 +24,7 @@ describe('Transform: Transform List Actions <DeleteAction />', () => {
deleteTransform(d: TransformListRow) {},
};
const wrapper = shallow(
<Providers>
<DeleteAction {...props} />
</Providers>
)
.find(DeleteAction)
.shallow();
const wrapper = shallow(<DeleteAction {...props} />);
expect(wrapper).toMatchSnapshot();
});
});

View file

@ -7,15 +7,13 @@
import { shallow } from 'enzyme';
import React from 'react';
import { Providers } from '../../../../app_dependencies.mock';
import { TransformListRow } from '../../../../common';
import { StartAction } from './action_start';
import transformListRow from '../../../../common/__mocks__/transform_list_row.json';
jest.mock('ui/new_platform');
jest.mock('../../../../../shared_imports');
jest.mock('../../../../../app/app_dependencies');
describe('Transform: Transform List Actions <StartAction />', () => {
test('Minimal initialization', () => {
@ -26,13 +24,7 @@ describe('Transform: Transform List Actions <StartAction />', () => {
startTransform(d: TransformListRow) {},
};
const wrapper = shallow(
<Providers>
<StartAction {...props} />
</Providers>
)
.find(StartAction)
.shallow();
const wrapper = shallow(<StartAction {...props} />);
expect(wrapper).toMatchSnapshot();
});

View file

@ -7,15 +7,13 @@
import { shallow } from 'enzyme';
import React from 'react';
import { Providers } from '../../../../app_dependencies.mock';
import { TransformListRow } from '../../../../common';
import { StopAction } from './action_stop';
import transformListRow from '../../../../common/__mocks__/transform_list_row.json';
jest.mock('ui/new_platform');
jest.mock('../../../../../shared_imports');
jest.mock('../../../../../app/app_dependencies');
describe('Transform: Transform List Actions <StopAction />', () => {
test('Minimal initialization', () => {
@ -26,13 +24,7 @@ describe('Transform: Transform List Actions <StopAction />', () => {
stopTransform(d: TransformListRow) {},
};
const wrapper = shallow(
<Providers>
<StopAction {...props} />
</Providers>
)
.find(StopAction)
.shallow();
const wrapper = shallow(<StopAction {...props} />);
expect(wrapper).toMatchSnapshot();
});

View file

@ -9,12 +9,16 @@ import { CoreSetup } from 'src/core/public';
import { DataPublicPluginStart } from 'src/plugins/data/public';
import { ManagementSetup } from 'src/plugins/management/public';
import { Storage } from '../../../../src/plugins/kibana_utils/public';
import { renderApp } from './app/app';
import { AppDependencies } from './app/app_dependencies';
import { breadcrumbService } from './app/services/navigation';
import { docTitleService } from './app/services/navigation';
import { textService } from './app/services/text';
const localStorage = new Storage(window.localStorage);
export interface PluginsDependencies {
data: DataPublicPluginStart;
management: ManagementSetup;
@ -56,6 +60,7 @@ export class TransformUiPlugin {
notifications,
overlays,
savedObjects,
storage: localStorage,
uiSettings,
};

View file

@ -12,20 +12,6 @@ export {
} from '../../../../src/plugins/es_ui_shared/console_lang/lib';
export {
SendRequestConfig,
SendRequestResponse,
UseRequestConfig,
sendRequest,
useRequest,
} from '../../../../src/plugins/es_ui_shared/public/request/np_ready_request';
export {
CronEditor,
DAY,
} from '../../../../src/plugins/es_ui_shared/public/components/cron_editor';
// Needs to be imported because we're reusing KqlFilterBar which depends on it.
export { setDependencyCache } from '../../../legacy/plugins/ml/public/application/util/dependency_cache';
// @ts-ignore: could not find declaration file for module
export { KqlFilterBar } from '../../../legacy/plugins/ml/public/application/components/kql_filter_bar';

View file

@ -12428,7 +12428,6 @@
"xpack.transform.stepDefineForm.nestedGroupByListConflictErrorMessage": "「{groupByListName}」とネスティングの矛盾があるため、構成「{aggName}」を追加できませんでした。",
"xpack.transform.stepDefineForm.queryHelpText": "クエリ文字列でソースデータをフィルタリングしてください (オプション)。",
"xpack.transform.stepDefineForm.queryLabel": "クエリ",
"xpack.transform.stepDefineForm.queryPlaceholder": "例: {example}.",
"xpack.transform.stepDefineForm.savedSearchLabel": "保存検索",
"xpack.transform.stepDefineSummary.aggregationsLabel": "アグリゲーション(集計)",
"xpack.transform.stepDefineSummary.groupByLabel": "グループ分けの条件",

View file

@ -12428,7 +12428,6 @@
"xpack.transform.stepDefineForm.nestedGroupByListConflictErrorMessage": "无法添加配置“{aggName}”,因为与“{groupByListName}”有嵌套冲突。",
"xpack.transform.stepDefineForm.queryHelpText": "使用查询字符串筛选源数据(可选)。",
"xpack.transform.stepDefineForm.queryLabel": "查询",
"xpack.transform.stepDefineForm.queryPlaceholder": "例如,{example}",
"xpack.transform.stepDefineForm.savedSearchLabel": "已保存搜索",
"xpack.transform.stepDefineSummary.aggregationsLabel": "聚合",
"xpack.transform.stepDefineSummary.groupByLabel": "分组依据",

View file

@ -160,15 +160,15 @@ export function TransformWizardProvider({ getService }: FtrProviderContext) {
},
async assertQueryInputExists() {
await testSubjects.existOrFail('tarnsformQueryInput');
await testSubjects.existOrFail('transformQueryInput');
},
async assertQueryInputMissing() {
await testSubjects.missingOrFail('tarnsformQueryInput');
await testSubjects.missingOrFail('transformQueryInput');
},
async assertQueryValue(expectedQuery: string) {
const actualQuery = await testSubjects.getVisibleText('tarnsformQueryInput');
const actualQuery = await testSubjects.getVisibleText('transformQueryInput');
expect(actualQuery).to.eql(
expectedQuery,
`Query input text should be '${expectedQuery}' (got ${actualQuery})`