mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[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:
parent
ca67b80460
commit
1ede10ccbc
22 changed files with 212 additions and 252 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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
|
||||
);
|
||||
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -143,6 +143,7 @@ describe('Transform: Common', () => {
|
|||
isAdvancedPivotEditorEnabled: false,
|
||||
isAdvancedSourceEditorEnabled: false,
|
||||
sourceConfigUpdated: false,
|
||||
searchLanguage: 'kuery',
|
||||
searchString: 'the-query',
|
||||
searchQuery: 'the-search-query',
|
||||
valid: true,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
)}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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": "グループ分けの条件",
|
||||
|
|
|
@ -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": "分组依据",
|
||||
|
|
|
@ -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})`
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue