From de86fbded9730127a34542e57473f2aee94c286a Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 28 Feb 2020 15:42:20 +0100 Subject: [PATCH 01/20] wip --- src/dev/storybook/aliases.ts | 1 + .../action_wizard/action_wizard.story.tsx | 184 ++++++++++++++++ .../action_wizard/action_wizard.tsx | 198 ++++++++++++++++++ .../components/action_wizard/index.scss | 6 + .../public/components/action_wizard/index.ts | 0 src/plugins/ui_actions/scripts/storybook.js | 26 +++ 6 files changed, 415 insertions(+) create mode 100644 src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx create mode 100644 src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx create mode 100644 src/plugins/ui_actions/public/components/action_wizard/index.scss create mode 100644 src/plugins/ui_actions/public/components/action_wizard/index.ts create mode 100644 src/plugins/ui_actions/scripts/storybook.js diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index fb91b865097fa..97fa2c51b2fa3 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -24,4 +24,5 @@ export const storybookAliases = { embeddable: 'src/plugins/embeddable/scripts/storybook.js', infra: 'x-pack/legacy/plugins/infra/scripts/storybook.js', siem: 'x-pack/legacy/plugins/siem/scripts/storybook.js', + ui_actions: 'src/plugins/ui_actions/scripts/storybook.js', }; diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx new file mode 100644 index 0000000000000..c0f844f70b196 --- /dev/null +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx @@ -0,0 +1,184 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as React from 'react'; +import { storiesOf } from '@storybook/react'; +import { ActionWizard, ActionFactory } from './action_wizard'; +import { EuiFieldText, EuiFormRow, EuiSelect, EuiSwitch } from '@elastic/eui'; +import { useState } from 'react'; + +const DashboardDrilldownActionFactory: ActionFactory< + { + dashboardId: string; + useCurrentDashboardFilters: boolean; + useCurrentDashboardDataRange: boolean; + }, + { + dashboards: Array<{ id: string; title: string }>; + } +> = { + type: 'Dashboard', + displayName: 'Go to Dashboard', + iconType: 'dashboardApp', + wizard: props => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [config, setConfig] = useState( + props.config || { + dashboardId: undefined, + useCurrentDashboardDataRange: false, + useCurrentDashboardFilters: false, + } + ); + + function setAndSubmit(newConfig: { + dashboardId: string; + useCurrentDashboardFilters: boolean; + useCurrentDashboardDataRange: boolean; + }) { + // validate + if (newConfig.dashboardId) { + props.onConfig(newConfig as any); + } else { + props.onConfig(null); + } + + setConfig(newConfig); + } + + return ( + <> + + ({ id, text: title }))} + value={config.dashboardId} + onChange={e => { + setAndSubmit({ + ...config, + dashboardId: e.target.value, + }); + }} + aria-label="Use aria labels when no actual label is in use" + /> + + + + setAndSubmit({ + ...config, + useCurrentDashboardFilters: !config.useCurrentDashboardFilters, + } as any) + } + /> + + + + setAndSubmit({ + ...config, + useCurrentDashboardDataRange: !config.useCurrentDashboardDataRange, + } as any) + } + /> + + + ); + }, + context: { + dashboards: [ + { id: 'dashboard1', title: 'Dashboard 1' }, + { id: 'dashboard2', title: 'Dashboard 2' }, + ], + }, +}; + +const UrlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTab: boolean }> = { + type: 'Url', + displayName: 'Go to URL', + iconType: 'link', + wizard: props => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [config, setConfig] = useState(props.config || { url: '', openInNewTab: false }); + + function setAndSubmit(newConfig: { url: string; openInNewTab: boolean }) { + // validate + if (newConfig.url) { + props.onConfig(newConfig); + } else { + props.onConfig(null); + } + + setConfig(newConfig); + } + + return ( + <> + + setAndSubmit({ ...config, url: event.target.value })} + /> + + + setAndSubmit({ ...config, openInNewTab: !config.openInNewTab })} + /> + + + ); + }, + context: null, +}; + +function Demo() { + const [state, setState] = useState(); + + return ( + <> + { + setState({ + factory, + config, + }); + }} + /> +
+
+
Action Factory Type: {state?.factory?.type}
+
Action Factory Config: {JSON.stringify(state?.config)}
+ + ); +} + +storiesOf('components/ActionWizard', module).add('default', () => ); diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx new file mode 100644 index 0000000000000..10046cec4bdf9 --- /dev/null +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx @@ -0,0 +1,198 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState } from 'react'; +import { + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiPanel, + EuiSpacer, + EuiText, +} from '@elastic/eui'; + +// TODO: +// import './index.scss'; + +// import { Action } from '../../actions'; +// don't use external interface for now. not sure if it is stabilized + +export interface ActionFactoryWizardProps { + /** + * Context represents environment where this component is being rendered. + */ + context: Context; + + /** + * Current (latest) config of the item. + */ + config: Config | null; + + /** + * Callback called when user updates the config in UI. + */ + onConfig: (config: Config | null) => void; +} + +export interface ActionFactory { + type: string; + displayName: string; + iconType?: string; + context: Context; + wizard: React.FC>; +} + +export interface ActionFactoryPickerProps { + actionFactories: Array>; + onActionFactoryPicked: (actionFactory: ActionFactory) => void; +} + +export interface SelectedActionFactoryProps { + actionFactory: ActionFactory; + onConfigChange: (config: Config | null) => void; + showDeselect: boolean; + onDeselect: () => void; +} +export interface ActionWizardProps { + actionFactories: Array>; + onChange: (actionFactory: ActionFactory | null, config: Config | null) => void; +} + +export const SelectedActionFactory: React.FC = ({ + actionFactory, + onDeselect, + showDeselect, + onConfigChange, +}) => { + const [config, setConfig] = useState(); + return ( +
+
+ + {actionFactory.iconType && ( + + + + )} + + +

{actionFactory.displayName}

+
+
+ {showDeselect && ( + + onDeselect()}> + change + + + )} +
+
+ +
+ {actionFactory.wizard({ + context: actionFactory.context, + config, + onConfig: newConfig => { + setConfig(newConfig); + onConfigChange(newConfig); + }, + })} +
+
+ ); +}; + +export const ActionFactoryPicker: React.FC = ({ + actionFactories, + onActionFactoryPicked, +}) => { + if (actionFactories.length === 0) return
No action factories to pick from :(
; + + return ( + + {actionFactories.map(actionFactory => ( + + onActionFactoryPicked(actionFactory)} + className="eui-textCenter" + paddingSize="s" + > + {actionFactory.iconType && ( + <> + + + + )} + +

{actionFactory.displayName}

+
+
+
+ ))} +
+ ); +}; + +export const ActionWizard: React.FC = ({ actionFactories, onChange }) => { + // eslint-disable-next-line prefer-const + let [selectedActionFactory, setSelectedActionFactory] = useState | null>(null); + + // auto pick action factory if there is only 1 available + if (!selectedActionFactory && actionFactories.length === 1) { + selectedActionFactory = actionFactories[0]; + } + + if (selectedActionFactory) { + return ( + 1} + onDeselect={() => { + setSelectedActionFactory(null); + onChange(null, null); + }} + onConfigChange={newConfig => { + onChange(selectedActionFactory, newConfig); + }} + /> + ); + } + + return ( + { + setSelectedActionFactory(actionFactory); + onChange(actionFactory, null); + }} + /> + ); +}; diff --git a/src/plugins/ui_actions/public/components/action_wizard/index.scss b/src/plugins/ui_actions/public/components/action_wizard/index.scss new file mode 100644 index 0000000000000..c098223792c49 --- /dev/null +++ b/src/plugins/ui_actions/public/components/action_wizard/index.scss @@ -0,0 +1,6 @@ +// TODO: +// @import 'src/legacy/ui/public/styles/_styling_constants'; + +//.uiActions__selectedActionFactoryContainer { +// +//} diff --git a/src/plugins/ui_actions/public/components/action_wizard/index.ts b/src/plugins/ui_actions/public/components/action_wizard/index.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/plugins/ui_actions/scripts/storybook.js b/src/plugins/ui_actions/scripts/storybook.js new file mode 100644 index 0000000000000..cb2eda610170d --- /dev/null +++ b/src/plugins/ui_actions/scripts/storybook.js @@ -0,0 +1,26 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { join } from 'path'; + +// eslint-disable-next-line +require('@kbn/storybook').runStorybookCli({ + name: 'ui_actions', + storyGlobs: [join(__dirname, '..', 'public', 'components', '**', '*.story.tsx')], +}); From 21d82328f494478b6fdb140bfa4fa8d7558ae053 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 2 Mar 2020 15:12:02 +0100 Subject: [PATCH 02/20] wip --- .../storybook_config/webpack.config.js | 28 ++- src/dev/jest/config.js | 1 + src/dev/jest/setup/react_testing_library.js | 23 +++ .../action_wizard/action_wizard.story.tsx | 161 ++-------------- .../action_wizard/action_wizard.test.tsx | 124 +++++++++++++ .../action_wizard/action_wizard.tsx | 173 ++++++++++-------- .../public/components/action_wizard/i18n.ts | 24 +++ .../components/action_wizard/index.scss | 15 +- .../components/action_wizard/test_data.tsx | 164 +++++++++++++++++ 9 files changed, 489 insertions(+), 224 deletions(-) create mode 100644 src/dev/jest/setup/react_testing_library.js create mode 100644 src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx create mode 100644 src/plugins/ui_actions/public/components/action_wizard/i18n.ts create mode 100644 src/plugins/ui_actions/public/components/action_wizard/test_data.tsx diff --git a/packages/kbn-storybook/storybook_config/webpack.config.js b/packages/kbn-storybook/storybook_config/webpack.config.js index 72ff9162ffe6c..230c8af81f8b5 100644 --- a/packages/kbn-storybook/storybook_config/webpack.config.js +++ b/packages/kbn-storybook/storybook_config/webpack.config.js @@ -72,6 +72,32 @@ module.exports = async ({ config }) => { ], }); + // Enable SASS + config.module.rules.push({ + test: /\.scss$/, + exclude: /\.module.(s(a|c)ss)$/, + use: [ + { loader: 'style-loader' }, + { loader: 'css-loader', options: { importLoaders: 2 } }, + { + loader: 'postcss-loader', + options: { + config: { + path: resolve(REPO_ROOT, 'src/optimize/'), + }, + }, + }, + { + loader: 'sass-loader', + options: { + sassOptions: { + includePaths: [resolve(REPO_ROOT, 'node_modules')], + }, + }, + }, + ], + }); + // Reference the built DLL file of static(ish) dependencies, which are removed // during kbn:bootstrap and rebuilt if missing. config.plugins.push( @@ -96,7 +122,7 @@ module.exports = async ({ config }) => { ); // Tell Webpack about the ts/x extensions - config.resolve.extensions.push('.ts', '.tsx'); + config.resolve.extensions.push('.ts', '.tsx', '.scss'); // Load custom Webpack config specified by a plugin. if (currentConfig.webpackHook) { diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js index 807a3fbf4782b..3ac044ce888df 100644 --- a/src/dev/jest/config.js +++ b/src/dev/jest/config.js @@ -67,6 +67,7 @@ export default { '/src/dev/jest/setup/babel_polyfill.js', '/src/dev/jest/setup/polyfills.js', '/src/dev/jest/setup/enzyme.js', + '/src/dev/jest/setup/react_testing_library.js', ], setupFilesAfterEnv: ['/src/dev/jest/setup/mocks.js'], coverageDirectory: '/target/kibana-coverage/jest', diff --git a/src/dev/jest/setup/react_testing_library.js b/src/dev/jest/setup/react_testing_library.js new file mode 100644 index 0000000000000..14a064acdc54f --- /dev/null +++ b/src/dev/jest/setup/react_testing_library.js @@ -0,0 +1,23 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { configure } from '@testing-library/react'; + +// instead of default 'data-test-id', use kibana's 'data-test-subj' +configure({ testIdAttribute: 'data-test-subj' }); diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx index c0f844f70b196..2886815eb5304 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx @@ -17,146 +17,11 @@ * under the License. */ -import * as React from 'react'; -import { storiesOf } from '@storybook/react'; -import { ActionWizard, ActionFactory } from './action_wizard'; -import { EuiFieldText, EuiFormRow, EuiSelect, EuiSwitch } from '@elastic/eui'; -import { useState } from 'react'; - -const DashboardDrilldownActionFactory: ActionFactory< - { - dashboardId: string; - useCurrentDashboardFilters: boolean; - useCurrentDashboardDataRange: boolean; - }, - { - dashboards: Array<{ id: string; title: string }>; - } -> = { - type: 'Dashboard', - displayName: 'Go to Dashboard', - iconType: 'dashboardApp', - wizard: props => { - // eslint-disable-next-line react-hooks/rules-of-hooks - const [config, setConfig] = useState( - props.config || { - dashboardId: undefined, - useCurrentDashboardDataRange: false, - useCurrentDashboardFilters: false, - } - ); - - function setAndSubmit(newConfig: { - dashboardId: string; - useCurrentDashboardFilters: boolean; - useCurrentDashboardDataRange: boolean; - }) { - // validate - if (newConfig.dashboardId) { - props.onConfig(newConfig as any); - } else { - props.onConfig(null); - } - - setConfig(newConfig); - } - - return ( - <> - - ({ id, text: title }))} - value={config.dashboardId} - onChange={e => { - setAndSubmit({ - ...config, - dashboardId: e.target.value, - }); - }} - aria-label="Use aria labels when no actual label is in use" - /> - - - - setAndSubmit({ - ...config, - useCurrentDashboardFilters: !config.useCurrentDashboardFilters, - } as any) - } - /> - - - - setAndSubmit({ - ...config, - useCurrentDashboardDataRange: !config.useCurrentDashboardDataRange, - } as any) - } - /> - - - ); - }, - context: { - dashboards: [ - { id: 'dashboard1', title: 'Dashboard 1' }, - { id: 'dashboard2', title: 'Dashboard 2' }, - ], - }, -}; +import React, { useState } from 'react'; -const UrlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTab: boolean }> = { - type: 'Url', - displayName: 'Go to URL', - iconType: 'link', - wizard: props => { - // eslint-disable-next-line react-hooks/rules-of-hooks - const [config, setConfig] = useState(props.config || { url: '', openInNewTab: false }); - - function setAndSubmit(newConfig: { url: string; openInNewTab: boolean }) { - // validate - if (newConfig.url) { - props.onConfig(newConfig); - } else { - props.onConfig(null); - } - - setConfig(newConfig); - } - - return ( - <> - - setAndSubmit({ ...config, url: event.target.value })} - /> - - - setAndSubmit({ ...config, openInNewTab: !config.openInNewTab })} - /> - - - ); - }, - context: null, -}; +import { storiesOf } from '@storybook/react'; +import { ActionWizard } from './action_wizard'; +import { ACTION_FACTORIES } from './test_data'; function Demo() { const [state, setState] = useState(); @@ -164,8 +29,7 @@ function Demo() { return ( <> { setState({ factory, @@ -181,4 +45,17 @@ function Demo() { ); } -storiesOf('components/ActionWizard', module).add('default', () => ); +storiesOf('components/ActionWizard', module) + .add('default', () => ) + .add('Long list of action factories', () => ( + // to make sure layout doesn't break + {}} + /> + )); diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx new file mode 100644 index 0000000000000..0d0bec5f9469c --- /dev/null +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -0,0 +1,124 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { render, cleanup, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; // TODO: this should be global +import { + ActionFactory, + ActionWizard, + BaseConfig, + TEST_SUBJ_ACTION_FACTORY_ITEM, + TEST_SUBJ_SELECTED_ACTION_FACTORY, +} from './action_wizard'; +import { + DashboardDrilldownActionFactory, + UrlDrilldownActionFactory, + dashboards, +} from './test_data'; + +// TODO: for some reason global cleanup from RTL doesn't work +// afterEach is not available for it globally during setup +afterEach(cleanup); + +test('Pick and configure action', () => { + const wizardChangeFn = jest.fn(); + + const screen = render( + + > + } + onChange={wizardChangeFn} + /> + ); + + // check that all factories are displayed to pick + expect(screen.getAllByTestId(TEST_SUBJ_ACTION_FACTORY_ITEM)).toHaveLength(2); + + // select URL one + fireEvent.click(screen.getByText(/Go to URL/i)); + + // check that wizard emitted change event. null means config is invalid. this is because URL is empty string yet + expect(wizardChangeFn).lastCalledWith(UrlDrilldownActionFactory, null); + + // Input url + const URL = 'https://elastic.co'; + fireEvent.change(screen.getByLabelText(/url/i), { + target: { value: URL }, + }); + + // check that wizard emitted change event + expect(wizardChangeFn).lastCalledWith(UrlDrilldownActionFactory, { + url: URL, + openInNewTab: false, + }); + + // change to dashboard + fireEvent.click(screen.getByText(/change/i)); + fireEvent.click(screen.getByText(/Go to Dashboard/i)); + + // check that wizard emitted change event + // null config means it is invalid. This is because no dashboard selected yet + expect(wizardChangeFn).lastCalledWith(DashboardDrilldownActionFactory, null); + + // Select dashboard + fireEvent.change(screen.getByLabelText(/Choose destination dashboard/i), { + target: { value: dashboards[1].title }, + }); + + // check that wizard emitted change event + expect(wizardChangeFn).lastCalledWith(DashboardDrilldownActionFactory, { + dashboardId: dashboards[1].id, + useCurrentDashboardDataRange: false, + useCurrentDashboardFilters: false, + }); +}); + +test('If only one actions factory is available, then no selection step is rendered and no change button displayed', () => { + const wizardChangeFn = jest.fn(); + + const screen = render( + >} + onChange={wizardChangeFn} + /> + ); + + // check that no factories are displayed to pick from + expect(screen.queryByTestId(TEST_SUBJ_ACTION_FACTORY_ITEM)).not.toBeInTheDocument(); + expect(screen.queryByTestId(TEST_SUBJ_SELECTED_ACTION_FACTORY)).toBeInTheDocument(); + + // Input url + const URL = 'https://elastic.co'; + fireEvent.change(screen.getByLabelText(/url/i), { + target: { value: URL }, + }); + + // check that wizard emitted change event + expect(wizardChangeFn).lastCalledWith(UrlDrilldownActionFactory, { + url: URL, + openInNewTab: false, + }); + + // check that can't change to action factory type + expect(screen.queryByTestId(/change/i)).not.toBeInTheDocument(); +}); diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx index 10046cec4bdf9..7914355d63f1a 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx @@ -27,68 +27,118 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; +import { txtChangeButton } from './i18n'; +import './index.scss'; + +// TODO: this interface is temporary for just moving forward with the component +// and it will be imported from the ../ui_actions when implemented properly +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type BaseConfig = {}; +export interface ActionFactory { + type: string; + displayName: string; + iconType?: string; + wizard: React.FC>; + context: Context; +} -// TODO: -// import './index.scss'; - -// import { Action } from '../../actions'; -// don't use external interface for now. not sure if it is stabilized - -export interface ActionFactoryWizardProps { +export interface ActionFactoryWizardProps { /** * Context represents environment where this component is being rendered. */ context: Context; /** - * Current (latest) config of the item. + * Current (latest) config of the item. (state) */ config: Config | null; /** * Callback called when user updates the config in UI. + * ActionFactory's wizard should do validations to the user's input + * In case input is complete and valid - config: Config object should be emitted + * In case input has changed to the invalid state: null should be emitted */ onConfig: (config: Config | null) => void; } -export interface ActionFactory { - type: string; - displayName: string; - iconType?: string; - context: Context; - wizard: React.FC>; -} +export interface ActionWizardProps { + /** + * List of available action factories + */ + actionFactories: Array>; -export interface ActionFactoryPickerProps { - actionFactories: Array>; - onActionFactoryPicked: (actionFactory: ActionFactory) => void; + /** + * Notifies when wizard's state changes because of user's interaction + * + * @param actionFactory - current selected action factory. null if none is selected + * @param config - current config for current action factory. null if no action factory or if wizard's inputs are invalid or incomplete + */ + onChange: ( + actionFactory: ActionFactory | null, + config: BaseConfig | null + ) => void; } +export const ActionWizard: React.FC = ({ actionFactories, onChange }) => { + // eslint-disable-next-line prefer-const + let [selectedActionFactory, setSelectedActionFactory] = useState | null>(null); -export interface SelectedActionFactoryProps { - actionFactory: ActionFactory; + // auto pick action factory if there is only 1 available + if (!selectedActionFactory && actionFactories.length === 1) { + selectedActionFactory = actionFactories[0]; + } + + if (selectedActionFactory) { + return ( + 1} + onDeselect={() => { + setSelectedActionFactory(null); + onChange(null, null); + }} + onConfigChange={newConfig => { + onChange(selectedActionFactory, newConfig); + }} + /> + ); + } + + return ( + { + setSelectedActionFactory(actionFactory); + onChange(actionFactory, null); + }} + /> + ); +}; + +interface SelectedActionFactoryProps { + actionFactory: ActionFactory; onConfigChange: (config: Config | null) => void; showDeselect: boolean; onDeselect: () => void; } -export interface ActionWizardProps { - actionFactories: Array>; - onChange: (actionFactory: ActionFactory | null, config: Config | null) => void; -} - -export const SelectedActionFactory: React.FC = ({ +export const TEST_SUBJ_SELECTED_ACTION_FACTORY = 'selected-action-factory'; +const SelectedActionFactory: React.FC> = ({ actionFactory, onDeselect, showDeselect, onConfigChange, }) => { - const [config, setConfig] = useState(); + const [config, setConfig] = useState(null); return (
- + {actionFactory.iconType && ( @@ -102,7 +152,7 @@ export const SelectedActionFactory: React.FC = ({ {showDeselect && ( onDeselect()}> - change + {txtChangeButton} )} @@ -123,22 +173,32 @@ export const SelectedActionFactory: React.FC = ({ ); }; -export const ActionFactoryPicker: React.FC = ({ +interface ActionFactorySelectorProps { + actionFactories: Array>; + onActionFactorySelected: (actionFactory: ActionFactory) => void; +} +export const TEST_SUBJ_ACTION_FACTORY_ITEM = 'action-factory-item'; +const ActionFactorySelector: React.FC = ({ actionFactories, - onActionFactoryPicked, + onActionFactorySelected, }) => { - if (actionFactories.length === 0) return
No action factories to pick from :(
; + if (actionFactories.length === 0) { + // this is not user facing, as it would be impossible to get into this state + // just leaving for dev purposes for troubleshooting + return
No action factories to pick from
; + } return ( - + {actionFactories.map(actionFactory => ( onActionFactoryPicked(actionFactory)} + onClick={() => onActionFactorySelected(actionFactory)} className="eui-textCenter" paddingSize="s" > @@ -157,42 +217,3 @@ export const ActionFactoryPicker: React.FC = ({ ); }; - -export const ActionWizard: React.FC = ({ actionFactories, onChange }) => { - // eslint-disable-next-line prefer-const - let [selectedActionFactory, setSelectedActionFactory] = useState | null>(null); - - // auto pick action factory if there is only 1 available - if (!selectedActionFactory && actionFactories.length === 1) { - selectedActionFactory = actionFactories[0]; - } - - if (selectedActionFactory) { - return ( - 1} - onDeselect={() => { - setSelectedActionFactory(null); - onChange(null, null); - }} - onConfigChange={newConfig => { - onChange(selectedActionFactory, newConfig); - }} - /> - ); - } - - return ( - { - setSelectedActionFactory(actionFactory); - onChange(actionFactory, null); - }} - /> - ); -}; diff --git a/src/plugins/ui_actions/public/components/action_wizard/i18n.ts b/src/plugins/ui_actions/public/components/action_wizard/i18n.ts new file mode 100644 index 0000000000000..dedd9d593fcf9 --- /dev/null +++ b/src/plugins/ui_actions/public/components/action_wizard/i18n.ts @@ -0,0 +1,24 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; + +export const txtChangeButton = i18n.translate('ui_actions.components.actionWizard.changeButton', { + defaultMessage: 'change', +}); diff --git a/src/plugins/ui_actions/public/components/action_wizard/index.scss b/src/plugins/ui_actions/public/components/action_wizard/index.scss index c098223792c49..33368656ace4d 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/index.scss +++ b/src/plugins/ui_actions/public/components/action_wizard/index.scss @@ -1,6 +1,11 @@ -// TODO: -// @import 'src/legacy/ui/public/styles/_styling_constants'; +@import '../../../../../../src/legacy/ui/public/styles/_styling_constants'; -//.uiActions__selectedActionFactoryContainer { -// -//} +.uiActions__selectedActionFactoryContainer { + background-color: $euiColorLightestShade; + padding: $euiSize; +} + +.uiActions__ActionFactory { + width: 120px; + min-height: 100px; +} diff --git a/src/plugins/ui_actions/public/components/action_wizard/test_data.tsx b/src/plugins/ui_actions/public/components/action_wizard/test_data.tsx new file mode 100644 index 0000000000000..dd134930e26b4 --- /dev/null +++ b/src/plugins/ui_actions/public/components/action_wizard/test_data.tsx @@ -0,0 +1,164 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState } from 'react'; +import { EuiFieldText, EuiFormRow, EuiSelect, EuiSwitch } from '@elastic/eui'; +import { ActionFactory, BaseConfig } from './action_wizard'; + +export const dashboards = [ + { id: 'dashboard1', title: 'Dashboard 1' }, + { id: 'dashboard2', title: 'Dashboard 2' }, +]; + +export const DashboardDrilldownActionFactory: ActionFactory< + { + dashboardId: string; + useCurrentDashboardFilters: boolean; + useCurrentDashboardDataRange: boolean; + }, + { + dashboards: Array<{ id: string; title: string }>; + } +> = { + type: 'Dashboard', + displayName: 'Go to Dashboard', + iconType: 'dashboardApp', + wizard: props => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [config, setConfig] = useState( + props.config || { + dashboardId: undefined, + useCurrentDashboardDataRange: false, + useCurrentDashboardFilters: false, + } + ); + + function setAndSubmit(newConfig: { + dashboardId: string | undefined; + useCurrentDashboardFilters: boolean; + useCurrentDashboardDataRange: boolean; + }) { + // validate + if (newConfig.dashboardId) { + props.onConfig({ ...newConfig, dashboardId: newConfig.dashboardId }); + } else { + props.onConfig(null); + } + + setConfig(newConfig); + } + + return ( + <> + + ({ id, text: title }))} + value={config.dashboardId} + onChange={e => { + setAndSubmit({ + ...config, + dashboardId: dashboards.find(d => d.title === e.target.value)?.id, + }); + }} + aria-label="Use aria labels when no actual label is in use" + /> + + + + setAndSubmit({ + ...config, + useCurrentDashboardFilters: !config.useCurrentDashboardFilters, + }) + } + /> + + + + setAndSubmit({ + ...config, + useCurrentDashboardDataRange: !config.useCurrentDashboardDataRange, + }) + } + /> + + + ); + }, + context: { + dashboards, + }, +}; + +export const UrlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTab: boolean }> = { + type: 'Url', + displayName: 'Go to URL', + iconType: 'link', + wizard: props => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [config, setConfig] = useState(props.config || { url: '', openInNewTab: false }); + + function setAndSubmit(newConfig: { url: string; openInNewTab: boolean }) { + // validate + if (newConfig.url) { + props.onConfig(newConfig); + } else { + props.onConfig(null); + } + + setConfig(newConfig); + } + + return ( + <> + + setAndSubmit({ ...config, url: event.target.value })} + /> + + + setAndSubmit({ ...config, openInNewTab: !config.openInNewTab })} + /> + + + ); + }, + context: null, +}; + +export const ACTION_FACTORIES = [ + DashboardDrilldownActionFactory, + UrlDrilldownActionFactory, +] as Array>; From bd601c60eaca10cc17224f5d8f4391556ef9ac46 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 2 Mar 2020 16:03:20 +0100 Subject: [PATCH 03/20] lint --- .../action_wizard/action_wizard.test.tsx | 4 ++-- .../action_wizard/action_wizard.tsx | 24 +++++++++---------- .../public/components/action_wizard/index.ts | 20 ++++++++++++++++ 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx index 0d0bec5f9469c..63459878c06a1 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -23,7 +23,7 @@ import '@testing-library/jest-dom/extend-expect'; // TODO: this should be global import { ActionFactory, ActionWizard, - BaseConfig, + ActionFactoryBaseConfig, TEST_SUBJ_ACTION_FACTORY_ITEM, TEST_SUBJ_SELECTED_ACTION_FACTORY, } from './action_wizard'; @@ -44,7 +44,7 @@ test('Pick and configure action', () => { + ActionFactory > } onChange={wizardChangeFn} diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx index 7914355d63f1a..14677890eb08a 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx @@ -33,8 +33,8 @@ import './index.scss'; // TODO: this interface is temporary for just moving forward with the component // and it will be imported from the ../ui_actions when implemented properly // eslint-disable-next-line @typescript-eslint/consistent-type-definitions -export type BaseConfig = {}; -export interface ActionFactory { +export type ActionFactoryBaseConfig = {}; +export interface ActionFactory { type: string; displayName: string; iconType?: string; @@ -42,7 +42,7 @@ export interface ActionFactory { context: Context; } -export interface ActionFactoryWizardProps { +export interface ActionFactoryWizardProps { /** * Context represents environment where this component is being rendered. */ @@ -66,7 +66,7 @@ export interface ActionWizardProps { /** * List of available action factories */ - actionFactories: Array>; + actionFactories: Array>; /** * Notifies when wizard's state changes because of user's interaction @@ -75,14 +75,14 @@ export interface ActionWizardProps { * @param config - current config for current action factory. null if no action factory or if wizard's inputs are invalid or incomplete */ onChange: ( - actionFactory: ActionFactory | null, - config: BaseConfig | null + actionFactory: ActionFactory | null, + config: ActionFactoryBaseConfig | null ) => void; } export const ActionWizard: React.FC = ({ actionFactories, onChange }) => { // eslint-disable-next-line prefer-const let [selectedActionFactory, setSelectedActionFactory] = useState | null>(null); @@ -118,20 +118,20 @@ export const ActionWizard: React.FC = ({ actionFactories, onC ); }; -interface SelectedActionFactoryProps { +interface SelectedActionFactoryProps { actionFactory: ActionFactory; onConfigChange: (config: Config | null) => void; showDeselect: boolean; onDeselect: () => void; } export const TEST_SUBJ_SELECTED_ACTION_FACTORY = 'selected-action-factory'; -const SelectedActionFactory: React.FC> = ({ +const SelectedActionFactory: React.FC> = ({ actionFactory, onDeselect, showDeselect, onConfigChange, }) => { - const [config, setConfig] = useState(null); + const [config, setConfig] = useState(null); return (
> = }; interface ActionFactorySelectorProps { - actionFactories: Array>; - onActionFactorySelected: (actionFactory: ActionFactory) => void; + actionFactories: Array>; + onActionFactorySelected: (actionFactory: ActionFactory) => void; } export const TEST_SUBJ_ACTION_FACTORY_ITEM = 'action-factory-item'; const ActionFactorySelector: React.FC = ({ diff --git a/src/plugins/ui_actions/public/components/action_wizard/index.ts b/src/plugins/ui_actions/public/components/action_wizard/index.ts index e69de29bb2d1d..6a85c196dfda9 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/index.ts +++ b/src/plugins/ui_actions/public/components/action_wizard/index.ts @@ -0,0 +1,20 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { ActionFactory, ActionWizard } from './action_wizard'; From 9d181d39414b641842ee535e6b66d906e53298ac Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 2 Mar 2020 16:16:08 +0100 Subject: [PATCH 04/20] improve --- .../components/action_wizard/action_wizard.test.tsx | 2 +- .../public/components/action_wizard/test_data.tsx | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx index 63459878c06a1..18971e199253e 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -82,7 +82,7 @@ test('Pick and configure action', () => { // Select dashboard fireEvent.change(screen.getByLabelText(/Choose destination dashboard/i), { - target: { value: dashboards[1].title }, + target: { value: dashboards[1].id }, }); // check that wizard emitted change event diff --git a/src/plugins/ui_actions/public/components/action_wizard/test_data.tsx b/src/plugins/ui_actions/public/components/action_wizard/test_data.tsx index dd134930e26b4..cef991c4d4a86 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/test_data.tsx +++ b/src/plugins/ui_actions/public/components/action_wizard/test_data.tsx @@ -19,7 +19,7 @@ import React, { useState } from 'react'; import { EuiFieldText, EuiFormRow, EuiSelect, EuiSwitch } from '@elastic/eui'; -import { ActionFactory, BaseConfig } from './action_wizard'; +import { ActionFactory, ActionFactoryBaseConfig } from './action_wizard'; export const dashboards = [ { id: 'dashboard1', title: 'Dashboard 1' }, @@ -70,15 +70,14 @@ export const DashboardDrilldownActionFactory: ActionFactory< ({ id, text: title }))} + options={props.context.dashboards.map(({ id, title }) => ({ value: id, text: title }))} value={config.dashboardId} onChange={e => { setAndSubmit({ ...config, - dashboardId: dashboards.find(d => d.title === e.target.value)?.id, + dashboardId: e.target.value, }); }} - aria-label="Use aria labels when no actual label is in use" /> @@ -161,4 +160,4 @@ export const UrlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTa export const ACTION_FACTORIES = [ DashboardDrilldownActionFactory, UrlDrilldownActionFactory, -] as Array>; +] as Array>; From 9e994a1852523acb53a6de2857a86a5f1fe529dc Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 2 Mar 2020 17:10:51 +0100 Subject: [PATCH 05/20] fix --- src/plugins/ui_actions/public/components/action_wizard/i18n.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/ui_actions/public/components/action_wizard/i18n.ts b/src/plugins/ui_actions/public/components/action_wizard/i18n.ts index dedd9d593fcf9..fff52f43bc1db 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/i18n.ts +++ b/src/plugins/ui_actions/public/components/action_wizard/i18n.ts @@ -19,6 +19,6 @@ import { i18n } from '@kbn/i18n'; -export const txtChangeButton = i18n.translate('ui_actions.components.actionWizard.changeButton', { +export const txtChangeButton = i18n.translate('uiActions.components.actionWizard.changeButton', { defaultMessage: 'change', }); From a08ea95025362ac17b1cb0426df662073d745855 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Tue, 3 Mar 2020 18:09:57 +0100 Subject: [PATCH 06/20] @cchaos review --- .../components/action_wizard/action_wizard.scss | 11 +++++++++++ .../public/components/action_wizard/action_wizard.tsx | 6 +++--- .../public/components/action_wizard/index.scss | 11 ----------- 3 files changed, 14 insertions(+), 14 deletions(-) create mode 100644 src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss delete mode 100644 src/plugins/ui_actions/public/components/action_wizard/index.scss diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss new file mode 100644 index 0000000000000..e0cff73b53e5c --- /dev/null +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss @@ -0,0 +1,11 @@ +@import '../../../../../../src/legacy/ui/public/styles/_styling_constants'; + +.uiaActionWizard__selectedActionFactoryContainer { + background-color: $euiColorLightestShade; + padding: $euiSize; +} + +.uiaActionWizard__actionFactoryItem { + width: #{$euiSize * 7.5}; + min-height: #{$euiSize * 6}; +} diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx index 14677890eb08a..8aec8821e8990 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx @@ -28,7 +28,7 @@ import { EuiText, } from '@elastic/eui'; import { txtChangeButton } from './i18n'; -import './index.scss'; +import './action_wizard.scss'; // TODO: this interface is temporary for just moving forward with the component // and it will be imported from the ../ui_actions when implemented properly @@ -134,7 +134,7 @@ const SelectedActionFactory: React.FC(null); return (
@@ -192,7 +192,7 @@ const ActionFactorySelector: React.FC = ({ {actionFactories.map(actionFactory => ( Date: Tue, 3 Mar 2020 18:22:23 +0100 Subject: [PATCH 07/20] improve storybook setup to autoimport scss mixins --- packages/kbn-storybook/storybook_config/webpack.config.js | 7 +++++++ .../public/components/action_wizard/action_wizard.scss | 2 -- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/kbn-storybook/storybook_config/webpack.config.js b/packages/kbn-storybook/storybook_config/webpack.config.js index 230c8af81f8b5..1531c1d22b01b 100644 --- a/packages/kbn-storybook/storybook_config/webpack.config.js +++ b/packages/kbn-storybook/storybook_config/webpack.config.js @@ -19,6 +19,7 @@ const { resolve } = require('path'); const webpack = require('webpack'); +const { stringifyRequest } = require('loader-utils'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const { REPO_ROOT, DLL_DIST_DIR } = require('../lib/constants'); // eslint-disable-next-line import/no-unresolved @@ -90,6 +91,12 @@ module.exports = async ({ config }) => { { loader: 'sass-loader', options: { + prependData(loaderContext) { + return `@import ${stringifyRequest( + loaderContext, + resolve(REPO_ROOT, 'src/legacy/ui/public/styles/_styling_constants.scss') + )};\n`; + }, sassOptions: { includePaths: [resolve(REPO_ROOT, 'node_modules')], }, diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss index e0cff73b53e5c..c22c3125143f4 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss @@ -1,5 +1,3 @@ -@import '../../../../../../src/legacy/ui/public/styles/_styling_constants'; - .uiaActionWizard__selectedActionFactoryContainer { background-color: $euiColorLightestShade; padding: $euiSize; From 34ee67d680c1bb694d7bda255dada2edaea1a8c0 Mon Sep 17 00:00:00 2001 From: Andrea Del Rio Date: Tue, 3 Mar 2020 13:52:49 -0800 Subject: [PATCH 08/20] using keypadmenuitem --- .../action_wizard/action_wizard.scss | 5 ++-- .../action_wizard/action_wizard.tsx | 25 ++++++------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss index c22c3125143f4..cd8ec0e7238e6 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss @@ -4,6 +4,7 @@ } .uiaActionWizard__actionFactoryItem { - width: #{$euiSize * 7.5}; - min-height: #{$euiSize * 6}; + .euiKeyPadMenuItem__label { + height: #{$euiSizeXL}; + } } diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx index 8aec8821e8990..f292b2618c6f5 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx @@ -26,6 +26,7 @@ import { EuiPanel, EuiSpacer, EuiText, + EuiKeyPadMenuItem, } from '@elastic/eui'; import { txtChangeButton } from './i18n'; import './action_wizard.scss'; @@ -189,30 +190,18 @@ const ActionFactorySelector: React.FC = ({ } return ( - + {actionFactories.map(actionFactory => ( - onActionFactorySelected(actionFactory)} > - onActionFactorySelected(actionFactory)} - className="eui-textCenter" - paddingSize="s" - > - {actionFactory.iconType && ( - <> - - - - )} - -

{actionFactory.displayName}

-
-
-
+ {actionFactory.iconType && } + ))}
); From 56565dc4efacae5915637c9fced6a3d6611de1b5 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 4 Mar 2020 11:28:39 +0100 Subject: [PATCH 09/20] fix ts --- .../public/components/action_wizard/action_wizard.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx index f292b2618c6f5..ebd94ee410f58 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx @@ -23,7 +23,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiIcon, - EuiPanel, EuiSpacer, EuiText, EuiKeyPadMenuItem, @@ -194,7 +193,6 @@ const ActionFactorySelector: React.FC = ({ {actionFactories.map(actionFactory => ( Date: Wed, 4 Mar 2020 16:02:20 +0100 Subject: [PATCH 10/20] move to x-pack --- src/dev/storybook/aliases.ts | 2 +- .../public/components/action_wizard/i18n.ts | 24 ----------------- .../public/components/action_wizard/index.ts | 20 -------------- src/plugins/ui_actions/scripts/storybook.js | 26 ------------------- x-pack/dev-tools/jest/setup/setup_test.js | 4 +++ .../action_wizard/action_wizard.scss | 4 +-- .../action_wizard/action_wizard.story.tsx | 19 +++----------- .../action_wizard/action_wizard.test.tsx | 19 +++----------- .../action_wizard/action_wizard.tsx | 23 ++++------------ .../public/components/action_wizard/i18n.ts | 11 ++++++++ .../public/components/action_wizard/index.ts | 7 +++++ .../components/action_wizard/test_data.tsx | 19 +++----------- .../advanced_ui_actions/scripts/storybook.js | 13 ++++++++++ 13 files changed, 52 insertions(+), 139 deletions(-) delete mode 100644 src/plugins/ui_actions/public/components/action_wizard/i18n.ts delete mode 100644 src/plugins/ui_actions/public/components/action_wizard/index.ts delete mode 100644 src/plugins/ui_actions/scripts/storybook.js rename {src/plugins/ui_actions => x-pack/plugins/advanced_ui_actions}/public/components/action_wizard/action_wizard.scss (59%) rename {src/plugins/ui_actions => x-pack/plugins/advanced_ui_actions}/public/components/action_wizard/action_wizard.story.tsx (57%) rename {src/plugins/ui_actions => x-pack/plugins/advanced_ui_actions}/public/components/action_wizard/action_wizard.test.tsx (80%) rename {src/plugins/ui_actions => x-pack/plugins/advanced_ui_actions}/public/components/action_wizard/action_wizard.tsx (86%) create mode 100644 x-pack/plugins/advanced_ui_actions/public/components/action_wizard/i18n.ts create mode 100644 x-pack/plugins/advanced_ui_actions/public/components/action_wizard/index.ts rename {src/plugins/ui_actions => x-pack/plugins/advanced_ui_actions}/public/components/action_wizard/test_data.tsx (84%) create mode 100644 x-pack/plugins/advanced_ui_actions/scripts/storybook.js diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index 97fa2c51b2fa3..de2dbd68b544b 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -24,5 +24,5 @@ export const storybookAliases = { embeddable: 'src/plugins/embeddable/scripts/storybook.js', infra: 'x-pack/legacy/plugins/infra/scripts/storybook.js', siem: 'x-pack/legacy/plugins/siem/scripts/storybook.js', - ui_actions: 'src/plugins/ui_actions/scripts/storybook.js', + ui_actions: 'x-pack/plugins/advanced_ui_actions/scripts/storybook.js', }; diff --git a/src/plugins/ui_actions/public/components/action_wizard/i18n.ts b/src/plugins/ui_actions/public/components/action_wizard/i18n.ts deleted file mode 100644 index fff52f43bc1db..0000000000000 --- a/src/plugins/ui_actions/public/components/action_wizard/i18n.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; - -export const txtChangeButton = i18n.translate('uiActions.components.actionWizard.changeButton', { - defaultMessage: 'change', -}); diff --git a/src/plugins/ui_actions/public/components/action_wizard/index.ts b/src/plugins/ui_actions/public/components/action_wizard/index.ts deleted file mode 100644 index 6a85c196dfda9..0000000000000 --- a/src/plugins/ui_actions/public/components/action_wizard/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export { ActionFactory, ActionWizard } from './action_wizard'; diff --git a/src/plugins/ui_actions/scripts/storybook.js b/src/plugins/ui_actions/scripts/storybook.js deleted file mode 100644 index cb2eda610170d..0000000000000 --- a/src/plugins/ui_actions/scripts/storybook.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { join } from 'path'; - -// eslint-disable-next-line -require('@kbn/storybook').runStorybookCli({ - name: 'ui_actions', - storyGlobs: [join(__dirname, '..', 'public', 'components', '**', '*.story.tsx')], -}); diff --git a/x-pack/dev-tools/jest/setup/setup_test.js b/x-pack/dev-tools/jest/setup/setup_test.js index f54be89f30955..4df2564aad01f 100644 --- a/x-pack/dev-tools/jest/setup/setup_test.js +++ b/x-pack/dev-tools/jest/setup/setup_test.js @@ -11,3 +11,7 @@ import 'jest-styled-components'; import '@testing-library/jest-dom/extend-expect'; +import { configure } from '@testing-library/react'; + +// instead of default 'data-test-id', use kibana's 'data-test-subj' +configure({ testIdAttribute: 'data-test-subj' }); diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.scss similarity index 59% rename from src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss rename to x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.scss index cd8ec0e7238e6..2ba6f9baca90d 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.scss +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.scss @@ -1,9 +1,9 @@ -.uiaActionWizard__selectedActionFactoryContainer { +.auaActionWizard__selectedActionFactoryContainer { background-color: $euiColorLightestShade; padding: $euiSize; } -.uiaActionWizard__actionFactoryItem { +.auaActionWizard__actionFactoryItem { .euiKeyPadMenuItem__label { height: #{$euiSizeXL}; } diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.story.tsx similarity index 57% rename from src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx rename to x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.story.tsx index 2886815eb5304..9921028c7cb0b 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.story.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.story.tsx @@ -1,20 +1,7 @@ /* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. */ import React, { useState } from 'react'; diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx similarity index 80% rename from src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx rename to x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx index 18971e199253e..24ba84c430963 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -1,20 +1,7 @@ /* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; diff --git a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx similarity index 86% rename from src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx rename to x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index ebd94ee410f58..3c94e80d91856 100644 --- a/src/plugins/ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -1,20 +1,7 @@ /* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. */ import React, { useState } from 'react'; @@ -134,7 +121,7 @@ const SelectedActionFactory: React.FC(null); return (
@@ -192,7 +179,7 @@ const ActionFactorySelector: React.FC = ({ {actionFactories.map(actionFactory => ( Date: Wed, 4 Mar 2020 16:16:18 +0100 Subject: [PATCH 11/20] fix i18n x-pack --- .../public/components/action_wizard/i18n.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/i18n.ts b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/i18n.ts index 1a52dceceddef..641f25176264a 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/i18n.ts +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/i18n.ts @@ -6,6 +6,9 @@ import { i18n } from '@kbn/i18n'; -export const txtChangeButton = i18n.translate('uiActions.components.actionWizard.changeButton', { - defaultMessage: 'change', -}); +export const txtChangeButton = i18n.translate( + 'xpack.advancedUiActions.components.actionWizard.changeButton', + { + defaultMessage: 'change', + } +); From 068b4850be21053e0777d98f3da90504f977c003 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 4 Mar 2020 18:19:58 +0100 Subject: [PATCH 12/20] fix capitalization --- .../action_wizard/action_wizard.test.tsx | 18 +++++++++--------- .../components/action_wizard/test_data.tsx | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx index 24ba84c430963..e7ad95c8829fa 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -15,8 +15,8 @@ import { TEST_SUBJ_SELECTED_ACTION_FACTORY, } from './action_wizard'; import { - DashboardDrilldownActionFactory, - UrlDrilldownActionFactory, + dashboardDrilldownActionFactory, + urlDrilldownActionFactory, dashboards, } from './test_data'; @@ -30,7 +30,7 @@ test('Pick and configure action', () => { const screen = render( > } @@ -45,7 +45,7 @@ test('Pick and configure action', () => { fireEvent.click(screen.getByText(/Go to URL/i)); // check that wizard emitted change event. null means config is invalid. this is because URL is empty string yet - expect(wizardChangeFn).lastCalledWith(UrlDrilldownActionFactory, null); + expect(wizardChangeFn).lastCalledWith(urlDrilldownActionFactory, null); // Input url const URL = 'https://elastic.co'; @@ -54,7 +54,7 @@ test('Pick and configure action', () => { }); // check that wizard emitted change event - expect(wizardChangeFn).lastCalledWith(UrlDrilldownActionFactory, { + expect(wizardChangeFn).lastCalledWith(urlDrilldownActionFactory, { url: URL, openInNewTab: false, }); @@ -65,7 +65,7 @@ test('Pick and configure action', () => { // check that wizard emitted change event // null config means it is invalid. This is because no dashboard selected yet - expect(wizardChangeFn).lastCalledWith(DashboardDrilldownActionFactory, null); + expect(wizardChangeFn).lastCalledWith(dashboardDrilldownActionFactory, null); // Select dashboard fireEvent.change(screen.getByLabelText(/Choose destination dashboard/i), { @@ -73,7 +73,7 @@ test('Pick and configure action', () => { }); // check that wizard emitted change event - expect(wizardChangeFn).lastCalledWith(DashboardDrilldownActionFactory, { + expect(wizardChangeFn).lastCalledWith(dashboardDrilldownActionFactory, { dashboardId: dashboards[1].id, useCurrentDashboardDataRange: false, useCurrentDashboardFilters: false, @@ -85,7 +85,7 @@ test('If only one actions factory is available, then no selection step is render const screen = render( >} + actionFactories={[urlDrilldownActionFactory] as Array>} onChange={wizardChangeFn} /> ); @@ -101,7 +101,7 @@ test('If only one actions factory is available, then no selection step is render }); // check that wizard emitted change event - expect(wizardChangeFn).lastCalledWith(UrlDrilldownActionFactory, { + expect(wizardChangeFn).lastCalledWith(urlDrilldownActionFactory, { url: URL, openInNewTab: false, }); diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx index 14ccb7d44997b..d0222aa483105 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx @@ -13,7 +13,7 @@ export const dashboards = [ { id: 'dashboard2', title: 'Dashboard 2' }, ]; -export const DashboardDrilldownActionFactory: ActionFactory< +export const dashboardDrilldownActionFactory: ActionFactory< { dashboardId: string; useCurrentDashboardFilters: boolean; @@ -101,7 +101,7 @@ export const DashboardDrilldownActionFactory: ActionFactory< }, }; -export const UrlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTab: boolean }> = { +export const urlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTab: boolean }> = { type: 'Url', displayName: 'Go to URL', iconType: 'link', @@ -145,6 +145,6 @@ export const UrlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTa }; export const ACTION_FACTORIES = [ - DashboardDrilldownActionFactory, - UrlDrilldownActionFactory, + dashboardDrilldownActionFactory, + urlDrilldownActionFactory, ] as Array>; From 845673163be26400afd1b5a6c7411264f9d140fe Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 4 Mar 2020 18:29:47 +0100 Subject: [PATCH 13/20] =?UTF-8?q?simplify=20-=20don=E2=80=99t=20expose=20c?= =?UTF-8?q?ontext=20on=20action=20factory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../action_wizard/action_wizard.test.tsx | 9 ++---- .../action_wizard/action_wizard.tsx | 28 +++++++------------ .../components/action_wizard/test_data.tsx | 25 ++++++----------- 3 files changed, 20 insertions(+), 42 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx index e7ad95c8829fa..b38036d478c26 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -10,7 +10,6 @@ import '@testing-library/jest-dom/extend-expect'; // TODO: this should be global import { ActionFactory, ActionWizard, - ActionFactoryBaseConfig, TEST_SUBJ_ACTION_FACTORY_ITEM, TEST_SUBJ_SELECTED_ACTION_FACTORY, } from './action_wizard'; @@ -29,11 +28,7 @@ test('Pick and configure action', () => { const screen = render( - > - } + actionFactories={[dashboardDrilldownActionFactory, urlDrilldownActionFactory]} onChange={wizardChangeFn} /> ); @@ -85,7 +80,7 @@ test('If only one actions factory is available, then no selection step is render const screen = render( >} + actionFactories={[urlDrilldownActionFactory] as Array>} onChange={wizardChangeFn} /> ); diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index 3c94e80d91856..91a4e55b656c0 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -21,20 +21,14 @@ import './action_wizard.scss'; // and it will be imported from the ../ui_actions when implemented properly // eslint-disable-next-line @typescript-eslint/consistent-type-definitions export type ActionFactoryBaseConfig = {}; -export interface ActionFactory { +export interface ActionFactory { type: string; displayName: string; iconType?: string; - wizard: React.FC>; - context: Context; + wizard: React.FC>; } -export interface ActionFactoryWizardProps { - /** - * Context represents environment where this component is being rendered. - */ - context: Context; - +export interface ActionFactoryWizardProps { /** * Current (latest) config of the item. (state) */ @@ -53,7 +47,7 @@ export interface ActionWizardProps { /** * List of available action factories */ - actionFactories: Array>; + actionFactories: Array>; /** * Notifies when wizard's state changes because of user's interaction @@ -62,15 +56,14 @@ export interface ActionWizardProps { * @param config - current config for current action factory. null if no action factory or if wizard's inputs are invalid or incomplete */ onChange: ( - actionFactory: ActionFactory | null, + actionFactory: ActionFactory | null, config: ActionFactoryBaseConfig | null ) => void; } export const ActionWizard: React.FC = ({ actionFactories, onChange }) => { // eslint-disable-next-line prefer-const let [selectedActionFactory, setSelectedActionFactory] = useState | null>(null); // auto pick action factory if there is only 1 available @@ -105,8 +98,8 @@ export const ActionWizard: React.FC = ({ actionFactories, onC ); }; -interface SelectedActionFactoryProps { - actionFactory: ActionFactory; +interface SelectedActionFactoryProps { + actionFactory: ActionFactory; onConfigChange: (config: Config | null) => void; showDeselect: boolean; onDeselect: () => void; @@ -148,7 +141,6 @@ const SelectedActionFactory: React.FC
{actionFactory.wizard({ - context: actionFactory.context, config, onConfig: newConfig => { setConfig(newConfig); @@ -161,8 +153,8 @@ const SelectedActionFactory: React.FC>; - onActionFactorySelected: (actionFactory: ActionFactory) => void; + actionFactories: Array>; + onActionFactorySelected: (actionFactory: ActionFactory) => void; } export const TEST_SUBJ_ACTION_FACTORY_ITEM = 'action-factory-item'; const ActionFactorySelector: React.FC = ({ diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx index d0222aa483105..8a8d678897625 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx @@ -13,16 +13,11 @@ export const dashboards = [ { id: 'dashboard2', title: 'Dashboard 2' }, ]; -export const dashboardDrilldownActionFactory: ActionFactory< - { - dashboardId: string; - useCurrentDashboardFilters: boolean; - useCurrentDashboardDataRange: boolean; - }, - { - dashboards: Array<{ id: string; title: string }>; - } -> = { +export const dashboardDrilldownActionFactory: ActionFactory<{ + dashboardId: string; + useCurrentDashboardFilters: boolean; + useCurrentDashboardDataRange: boolean; +}> = { type: 'Dashboard', displayName: 'Go to Dashboard', iconType: 'dashboardApp', @@ -57,7 +52,7 @@ export const dashboardDrilldownActionFactory: ActionFactory< ({ value: id, text: title }))} + options={dashboards.map(({ id, title }) => ({ value: id, text: title }))} value={config.dashboardId} onChange={e => { setAndSubmit({ @@ -96,9 +91,6 @@ export const dashboardDrilldownActionFactory: ActionFactory< ); }, - context: { - dashboards, - }, }; export const urlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTab: boolean }> = { @@ -141,10 +133,9 @@ export const urlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTa ); }, - context: null, }; -export const ACTION_FACTORIES = [ +export const ACTION_FACTORIES = ([ dashboardDrilldownActionFactory, urlDrilldownActionFactory, -] as Array>; +] as unknown) as Array>; From 439bdea3b8b86428f5fa7e9fbadc8f9f419b4642 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 4 Mar 2020 22:20:51 +0100 Subject: [PATCH 14/20] fix --- .../public/components/action_wizard/action_wizard.test.tsx | 7 ++++++- .../public/components/action_wizard/action_wizard.tsx | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx index b38036d478c26..85b41d5cc493b 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -9,6 +9,7 @@ import { render, cleanup, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; // TODO: this should be global import { ActionFactory, + ActionFactoryBaseConfig, ActionWizard, TEST_SUBJ_ACTION_FACTORY_ITEM, TEST_SUBJ_SELECTED_ACTION_FACTORY, @@ -28,7 +29,11 @@ test('Pick and configure action', () => { const screen = render( + > + } onChange={wizardChangeFn} /> ); diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index 91a4e55b656c0..7f7d2224f9604 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -22,7 +22,7 @@ import './action_wizard.scss'; // eslint-disable-next-line @typescript-eslint/consistent-type-definitions export type ActionFactoryBaseConfig = {}; export interface ActionFactory { - type: string; + type: string; // TODO: type should be tied to Action and ActionByType displayName: string; iconType?: string; wizard: React.FC>; From 1c37f653d7d017dab16086985a7930f6eeaa029d Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 5 Mar 2020 12:49:18 +0100 Subject: [PATCH 15/20] improve. make stateless. Simplify interfaces. --- .../action_wizard/action_wizard.story.tsx | 51 +++---- .../action_wizard/action_wizard.test.tsx | 61 +------- .../action_wizard/action_wizard.tsx | 90 ++++++------ .../components/action_wizard/test_data.tsx | 136 +++++++++++------- 4 files changed, 158 insertions(+), 180 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.story.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.story.tsx index 9921028c7cb0b..62f16890cade2 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.story.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.story.tsx @@ -4,45 +4,30 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState } from 'react'; - +import React from 'react'; import { storiesOf } from '@storybook/react'; -import { ActionWizard } from './action_wizard'; -import { ACTION_FACTORIES } from './test_data'; - -function Demo() { - const [state, setState] = useState(); - - return ( - <> - { - setState({ - factory, - config, - }); - }} - /> -
-
-
Action Factory Type: {state?.factory?.type}
-
Action Factory Config: {JSON.stringify(state?.config)}
- - ); -} +import { dashboardDrilldownActionFactory, Demo, urlDrilldownActionFactory } from './test_data'; storiesOf('components/ActionWizard', module) - .add('default', () => ) + .add('default', () => ( + + )) + .add('Only one factory is available', () => ( + // to make sure layout doesn't break + + )) .add('Long list of action factories', () => ( // to make sure layout doesn't break - {}} /> )); diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx index 85b41d5cc493b..cd990e7a41b82 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -5,19 +5,14 @@ */ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { cleanup, fireEvent, render } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; // TODO: this should be global -import { - ActionFactory, - ActionFactoryBaseConfig, - ActionWizard, - TEST_SUBJ_ACTION_FACTORY_ITEM, - TEST_SUBJ_SELECTED_ACTION_FACTORY, -} from './action_wizard'; +import { TEST_SUBJ_ACTION_FACTORY_ITEM, TEST_SUBJ_SELECTED_ACTION_FACTORY } from './action_wizard'; import { dashboardDrilldownActionFactory, - urlDrilldownActionFactory, dashboards, + Demo, + urlDrilldownActionFactory, } from './test_data'; // TODO: for some reason global cleanup from RTL doesn't work @@ -25,17 +20,8 @@ import { afterEach(cleanup); test('Pick and configure action', () => { - const wizardChangeFn = jest.fn(); - const screen = render( - - > - } - onChange={wizardChangeFn} - /> + ); // check that all factories are displayed to pick @@ -44,51 +30,24 @@ test('Pick and configure action', () => { // select URL one fireEvent.click(screen.getByText(/Go to URL/i)); - // check that wizard emitted change event. null means config is invalid. this is because URL is empty string yet - expect(wizardChangeFn).lastCalledWith(urlDrilldownActionFactory, null); - // Input url const URL = 'https://elastic.co'; fireEvent.change(screen.getByLabelText(/url/i), { target: { value: URL }, }); - // check that wizard emitted change event - expect(wizardChangeFn).lastCalledWith(urlDrilldownActionFactory, { - url: URL, - openInNewTab: false, - }); - // change to dashboard fireEvent.click(screen.getByText(/change/i)); fireEvent.click(screen.getByText(/Go to Dashboard/i)); - // check that wizard emitted change event - // null config means it is invalid. This is because no dashboard selected yet - expect(wizardChangeFn).lastCalledWith(dashboardDrilldownActionFactory, null); - // Select dashboard fireEvent.change(screen.getByLabelText(/Choose destination dashboard/i), { target: { value: dashboards[1].id }, }); - - // check that wizard emitted change event - expect(wizardChangeFn).lastCalledWith(dashboardDrilldownActionFactory, { - dashboardId: dashboards[1].id, - useCurrentDashboardDataRange: false, - useCurrentDashboardFilters: false, - }); }); -test('If only one actions factory is available, then no selection step is rendered and no change button displayed', () => { - const wizardChangeFn = jest.fn(); - - const screen = render( - >} - onChange={wizardChangeFn} - /> - ); +test('If only one actions factory is available then actionFactory selection is emitted without user input', () => { + const screen = render(); // check that no factories are displayed to pick from expect(screen.queryByTestId(TEST_SUBJ_ACTION_FACTORY_ITEM)).not.toBeInTheDocument(); @@ -100,12 +59,6 @@ test('If only one actions factory is available, then no selection step is render target: { value: URL }, }); - // check that wizard emitted change event - expect(wizardChangeFn).lastCalledWith(urlDrilldownActionFactory, { - url: URL, - openInNewTab: false, - }); - // check that can't change to action factory type expect(screen.queryByTestId(/change/i)).not.toBeInTheDocument(); }); diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index 7f7d2224f9604..689a6ed549d41 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState } from 'react'; +import React from 'react'; import { EuiButtonEmpty, EuiFlexGroup, @@ -21,67 +21,74 @@ import './action_wizard.scss'; // and it will be imported from the ../ui_actions when implemented properly // eslint-disable-next-line @typescript-eslint/consistent-type-definitions export type ActionFactoryBaseConfig = {}; -export interface ActionFactory { +export interface ActionFactory { type: string; // TODO: type should be tied to Action and ActionByType displayName: string; iconType?: string; wizard: React.FC>; + createConfig: () => Config; + isValid: (name: string, config: Config) => boolean; } export interface ActionFactoryWizardProps { - /** - * Current (latest) config of the item. (state) - */ - config: Config | null; + config?: Config; /** * Callback called when user updates the config in UI. - * ActionFactory's wizard should do validations to the user's input - * In case input is complete and valid - config: Config object should be emitted - * In case input has changed to the invalid state: null should be emitted */ - onConfig: (config: Config | null) => void; + onConfig: (config: Config) => void; } export interface ActionWizardProps { /** * List of available action factories */ - actionFactories: Array>; + actionFactories: Array>; // any here to be able to pass array of ActionFactory with different configs /** - * Notifies when wizard's state changes because of user's interaction - * - * @param actionFactory - current selected action factory. null if none is selected - * @param config - current config for current action factory. null if no action factory or if wizard's inputs are invalid or incomplete + * Currently selected action factory + * undefined - is allowed and means that non is selected */ - onChange: ( - actionFactory: ActionFactory | null, - config: ActionFactoryBaseConfig | null - ) => void; -} -export const ActionWizard: React.FC = ({ actionFactories, onChange }) => { - // eslint-disable-next-line prefer-const - let [selectedActionFactory, setSelectedActionFactory] = useState | null>(null); + currentActionFactory?: ActionFactory; + /** + * Action factory selected changed + * null - means user click "change" and removed action factory selection + */ + onActionFactoryChange: (actionFactory: ActionFactory | null) => void; + + /** + * current config for currently selected action factory + */ + config?: ActionFactoryBaseConfig; + /** + * config changed + */ + onConfigChange: (config: ActionFactoryBaseConfig) => void; +} +export const ActionWizard: React.FC = ({ + currentActionFactory, + actionFactories, + onActionFactoryChange, + onConfigChange, + config, +}) => { // auto pick action factory if there is only 1 available - if (!selectedActionFactory && actionFactories.length === 1) { - selectedActionFactory = actionFactories[0]; + if (!currentActionFactory && actionFactories.length === 1) { + onActionFactoryChange(actionFactories[0]); } - if (selectedActionFactory) { + if (currentActionFactory && config) { return ( 1} onDeselect={() => { - setSelectedActionFactory(null); - onChange(null, null); + onActionFactoryChange(null); }} + config={config} onConfigChange={newConfig => { - onChange(selectedActionFactory, newConfig); + onConfigChange(newConfig); }} /> ); @@ -91,27 +98,29 @@ export const ActionWizard: React.FC = ({ actionFactories, onC { - setSelectedActionFactory(actionFactory); - onChange(actionFactory, null); + onActionFactoryChange(actionFactory); }} /> ); }; -interface SelectedActionFactoryProps { +interface SelectedActionFactoryProps< + Config extends ActionFactoryBaseConfig = ActionFactoryBaseConfig +> { actionFactory: ActionFactory; - onConfigChange: (config: Config | null) => void; + config: Config; + onConfigChange: (config: Config) => void; showDeselect: boolean; onDeselect: () => void; } export const TEST_SUBJ_SELECTED_ACTION_FACTORY = 'selected-action-factory'; -const SelectedActionFactory: React.FC> = ({ +const SelectedActionFactory: React.FC = ({ actionFactory, onDeselect, showDeselect, onConfigChange, + config, }) => { - const [config, setConfig] = useState(null); return (
{ - setConfig(newConfig); onConfigChange(newConfig); }, })} @@ -153,8 +161,8 @@ const SelectedActionFactory: React.FC>; - onActionFactorySelected: (actionFactory: ActionFactory) => void; + actionFactories: ActionFactory[]; + onActionFactorySelected: (actionFactory: ActionFactory) => void; } export const TEST_SUBJ_ACTION_FACTORY_ITEM = 'action-factory-item'; const ActionFactorySelector: React.FC = ({ diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx index 8a8d678897625..b103c76657d87 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx @@ -6,7 +6,7 @@ import React, { useState } from 'react'; import { EuiFieldText, EuiFormRow, EuiSelect, EuiSwitch } from '@elastic/eui'; -import { ActionFactory, ActionFactoryBaseConfig } from './action_wizard'; +import { ActionFactory, ActionFactoryBaseConfig, ActionWizard } from './action_wizard'; export const dashboards = [ { id: 'dashboard1', title: 'Dashboard 1' }, @@ -14,38 +14,31 @@ export const dashboards = [ ]; export const dashboardDrilldownActionFactory: ActionFactory<{ - dashboardId: string; + dashboardId?: string; useCurrentDashboardFilters: boolean; useCurrentDashboardDataRange: boolean; }> = { type: 'Dashboard', displayName: 'Go to Dashboard', iconType: 'dashboardApp', + createConfig: () => { + return { + dashboardId: undefined, + useCurrentDashboardDataRange: true, + useCurrentDashboardFilters: true, + }; + }, + isValid: (name, config) => { + if (!name) return false; + if (!config.dashboardId) return false; + return true; + }, wizard: props => { - // eslint-disable-next-line react-hooks/rules-of-hooks - const [config, setConfig] = useState( - props.config || { - dashboardId: undefined, - useCurrentDashboardDataRange: false, - useCurrentDashboardFilters: false, - } - ); - - function setAndSubmit(newConfig: { - dashboardId: string | undefined; - useCurrentDashboardFilters: boolean; - useCurrentDashboardDataRange: boolean; - }) { - // validate - if (newConfig.dashboardId) { - props.onConfig({ ...newConfig, dashboardId: newConfig.dashboardId }); - } else { - props.onConfig(null); - } - - setConfig(newConfig); - } - + const config = props.config ?? { + dashboardId: undefined, + useCurrentDashboardDataRange: true, + useCurrentDashboardFilters: true, + }; return ( <> @@ -55,10 +48,7 @@ export const dashboardDrilldownActionFactory: ActionFactory<{ options={dashboards.map(({ id, title }) => ({ value: id, text: title }))} value={config.dashboardId} onChange={e => { - setAndSubmit({ - ...config, - dashboardId: e.target.value, - }); + props.onConfig({ ...config, dashboardId: e.target.value }); }} /> @@ -68,7 +58,7 @@ export const dashboardDrilldownActionFactory: ActionFactory<{ label="Use current dashboard's filters" checked={config.useCurrentDashboardFilters} onChange={() => - setAndSubmit({ + props.onConfig({ ...config, useCurrentDashboardFilters: !config.useCurrentDashboardFilters, }) @@ -81,7 +71,7 @@ export const dashboardDrilldownActionFactory: ActionFactory<{ label="Use current dashboard's date range" checked={config.useCurrentDashboardDataRange} onChange={() => - setAndSubmit({ + props.onConfig({ ...config, useCurrentDashboardDataRange: !config.useCurrentDashboardDataRange, }) @@ -97,21 +87,22 @@ export const urlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTa type: 'Url', displayName: 'Go to URL', iconType: 'link', + createConfig: () => { + return { + url: '', + openInNewTab: false, + }; + }, + isValid: (name, config) => { + if (!name) return false; + if (!config.url) return false; + return true; + }, wizard: props => { - // eslint-disable-next-line react-hooks/rules-of-hooks - const [config, setConfig] = useState(props.config || { url: '', openInNewTab: false }); - - function setAndSubmit(newConfig: { url: string; openInNewTab: boolean }) { - // validate - if (newConfig.url) { - props.onConfig(newConfig); - } else { - props.onConfig(null); - } - - setConfig(newConfig); - } - + const config = props.config ?? { + url: '', + openInNewTab: false, + }; return ( <> @@ -119,7 +110,7 @@ export const urlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTa placeholder="Enter URL" name="url" value={config.url} - onChange={event => setAndSubmit({ ...config, url: event.target.value })} + onChange={event => props.onConfig({ ...config, url: event.target.value })} /> @@ -127,7 +118,7 @@ export const urlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTa name="openInNewTab" label="Open in new tab?" checked={config.openInNewTab} - onChange={() => setAndSubmit({ ...config, openInNewTab: !config.openInNewTab })} + onChange={() => props.onConfig({ ...config, openInNewTab: !config.openInNewTab })} /> @@ -135,7 +126,48 @@ export const urlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTa }, }; -export const ACTION_FACTORIES = ([ - dashboardDrilldownActionFactory, - urlDrilldownActionFactory, -] as unknown) as Array>; +export function Demo({ actionFactories }: { actionFactories: Array> }) { + const [state, setState] = useState<{ + currentActionFactory?: ActionFactory; + config?: ActionFactoryBaseConfig; + }>({}); + + function changeActionFactory(newActionFactory: ActionFactory | null) { + if (!newActionFactory) { + // removing action factory + return setState({}); + } + + setState({ + currentActionFactory: newActionFactory, + config: newActionFactory.createConfig(), + }); + } + + return ( + <> + { + setState({ + ...state, + config: newConfig, + }); + }} + onActionFactoryChange={newActionFactory => { + changeActionFactory(newActionFactory); + }} + currentActionFactory={state.currentActionFactory} + /> +
+
+
Action Factory Type: {state.currentActionFactory?.type}
+
Action Factory Config: {JSON.stringify(state.config)}
+
+ Is config valid:{' '} + {JSON.stringify(state.currentActionFactory?.isValid('fake name', state.config!) ?? false)} +
+ + ); +} From ae07675ec24d0bb5a68e2d2a2c3e1f946778acbe Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 5 Mar 2020 13:42:00 +0100 Subject: [PATCH 16/20] rename --- .../components/action_wizard/action_wizard.tsx | 12 ++++++------ .../public/components/action_wizard/test_data.tsx | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index 689a6ed549d41..be321eb71ccad 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -20,8 +20,8 @@ import './action_wizard.scss'; // TODO: this interface is temporary for just moving forward with the component // and it will be imported from the ../ui_actions when implemented properly // eslint-disable-next-line @typescript-eslint/consistent-type-definitions -export type ActionFactoryBaseConfig = {}; -export interface ActionFactory { +export type ActionBaseConfig = {}; +export interface ActionFactory { type: string; // TODO: type should be tied to Action and ActionByType displayName: string; iconType?: string; @@ -30,7 +30,7 @@ export interface ActionFactory boolean; } -export interface ActionFactoryWizardProps { +export interface ActionFactoryWizardProps { config?: Config; /** @@ -59,12 +59,12 @@ export interface ActionWizardProps { /** * current config for currently selected action factory */ - config?: ActionFactoryBaseConfig; + config?: ActionBaseConfig; /** * config changed */ - onConfigChange: (config: ActionFactoryBaseConfig) => void; + onConfigChange: (config: ActionBaseConfig) => void; } export const ActionWizard: React.FC = ({ currentActionFactory, @@ -105,7 +105,7 @@ export const ActionWizard: React.FC = ({ }; interface SelectedActionFactoryProps< - Config extends ActionFactoryBaseConfig = ActionFactoryBaseConfig + Config extends ActionBaseConfig = ActionBaseConfig > { actionFactory: ActionFactory; config: Config; diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx index b103c76657d87..fc186b113915d 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx @@ -6,7 +6,7 @@ import React, { useState } from 'react'; import { EuiFieldText, EuiFormRow, EuiSelect, EuiSwitch } from '@elastic/eui'; -import { ActionFactory, ActionFactoryBaseConfig, ActionWizard } from './action_wizard'; +import { ActionFactory, ActionBaseConfig, ActionWizard } from './action_wizard'; export const dashboards = [ { id: 'dashboard1', title: 'Dashboard 1' }, @@ -129,7 +129,7 @@ export const urlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTa export function Demo({ actionFactories }: { actionFactories: Array> }) { const [state, setState] = useState<{ currentActionFactory?: ActionFactory; - config?: ActionFactoryBaseConfig; + config?: ActionBaseConfig; }>({}); function changeActionFactory(newActionFactory: ActionFactory | null) { From 6d05a1726a4bdac07ad2f97245cf2f37d2cea208 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 5 Mar 2020 13:42:11 +0100 Subject: [PATCH 17/20] fix --- .../public/components/action_wizard/action_wizard.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index be321eb71ccad..88ab792d2ff7e 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -104,9 +104,7 @@ export const ActionWizard: React.FC = ({ ); }; -interface SelectedActionFactoryProps< - Config extends ActionBaseConfig = ActionBaseConfig -> { +interface SelectedActionFactoryProps { actionFactory: ActionFactory; config: Config; onConfigChange: (config: Config) => void; From ea0d5c1500915b3fe6cc3b69ef7a2dab34a0db40 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 5 Mar 2020 19:07:59 +0100 Subject: [PATCH 18/20] nit fixes --- .../public/components/action_wizard/action_wizard.tsx | 11 +++++++---- .../public/components/action_wizard/test_data.tsx | 8 +++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index 88ab792d2ff7e..a1d6d26f01812 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -27,7 +27,7 @@ export interface ActionFactory>; createConfig: () => Config; - isValid: (name: string, config: Config) => boolean; + isValid: (config: Config) => boolean; } export interface ActionFactoryWizardProps { @@ -66,6 +66,7 @@ export interface ActionWizardProps { */ onConfigChange: (config: ActionBaseConfig) => void; } + export const ActionWizard: React.FC = ({ currentActionFactory, actionFactories, @@ -111,7 +112,9 @@ interface SelectedActionFactoryProps void; } + export const TEST_SUBJ_SELECTED_ACTION_FACTORY = 'selected-action-factory'; + const SelectedActionFactory: React.FC = ({ actionFactory, onDeselect, @@ -149,9 +152,7 @@ const SelectedActionFactory: React.FC = ({
{actionFactory.wizard({ config, - onConfig: newConfig => { - onConfigChange(newConfig); - }, + onConfig: onConfigChange, })}
@@ -162,7 +163,9 @@ interface ActionFactorySelectorProps { actionFactories: ActionFactory[]; onActionFactorySelected: (actionFactory: ActionFactory) => void; } + export const TEST_SUBJ_ACTION_FACTORY_ITEM = 'action-factory-item'; + const ActionFactorySelector: React.FC = ({ actionFactories, onActionFactorySelected, diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx index fc186b113915d..8ecdde681069e 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/test_data.tsx @@ -28,8 +28,7 @@ export const dashboardDrilldownActionFactory: ActionFactory<{ useCurrentDashboardFilters: true, }; }, - isValid: (name, config) => { - if (!name) return false; + isValid: config => { if (!config.dashboardId) return false; return true; }, @@ -93,8 +92,7 @@ export const urlDrilldownActionFactory: ActionFactory<{ url: string; openInNewTa openInNewTab: false, }; }, - isValid: (name, config) => { - if (!name) return false; + isValid: config => { if (!config.url) return false; return true; }, @@ -166,7 +164,7 @@ export function Demo({ actionFactories }: { actionFactories: ArrayAction Factory Config: {JSON.stringify(state.config)}
Is config valid:{' '} - {JSON.stringify(state.currentActionFactory?.isValid('fake name', state.config!) ?? false)} + {JSON.stringify(state.currentActionFactory?.isValid(state.config!) ?? false)}
); From 2f100c83debbcaf505cdcf07b82458bd2b79ccec Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 6 Mar 2020 07:01:23 +0100 Subject: [PATCH 19/20] revert react testing library configuration extracted to separate pr --- src/dev/jest/config.js | 1 - src/dev/jest/setup/react_testing_library.js | 23 ------------------- x-pack/dev-tools/jest/setup/setup_test.js | 4 ---- .../action_wizard/action_wizard.test.tsx | 10 ++++---- 4 files changed, 6 insertions(+), 32 deletions(-) delete mode 100644 src/dev/jest/setup/react_testing_library.js diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js index 3ac044ce888df..807a3fbf4782b 100644 --- a/src/dev/jest/config.js +++ b/src/dev/jest/config.js @@ -67,7 +67,6 @@ export default { '/src/dev/jest/setup/babel_polyfill.js', '/src/dev/jest/setup/polyfills.js', '/src/dev/jest/setup/enzyme.js', - '/src/dev/jest/setup/react_testing_library.js', ], setupFilesAfterEnv: ['/src/dev/jest/setup/mocks.js'], coverageDirectory: '/target/kibana-coverage/jest', diff --git a/src/dev/jest/setup/react_testing_library.js b/src/dev/jest/setup/react_testing_library.js deleted file mode 100644 index 14a064acdc54f..0000000000000 --- a/src/dev/jest/setup/react_testing_library.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { configure } from '@testing-library/react'; - -// instead of default 'data-test-id', use kibana's 'data-test-subj' -configure({ testIdAttribute: 'data-test-subj' }); diff --git a/x-pack/dev-tools/jest/setup/setup_test.js b/x-pack/dev-tools/jest/setup/setup_test.js index 4df2564aad01f..f54be89f30955 100644 --- a/x-pack/dev-tools/jest/setup/setup_test.js +++ b/x-pack/dev-tools/jest/setup/setup_test.js @@ -11,7 +11,3 @@ import 'jest-styled-components'; import '@testing-library/jest-dom/extend-expect'; -import { configure } from '@testing-library/react'; - -// instead of default 'data-test-id', use kibana's 'data-test-subj' -configure({ testIdAttribute: 'data-test-subj' }); diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx index cd990e7a41b82..9d8e9d48e281c 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -15,11 +15,12 @@ import { urlDrilldownActionFactory, } from './test_data'; -// TODO: for some reason global cleanup from RTL doesn't work -// afterEach is not available for it globally during setup +// TODO: afterEach is not available for it globally during setup +// https://github.com/elastic/kibana/issues/59469 afterEach(cleanup); -test('Pick and configure action', () => { +// TEMP until https://github.com/elastic/kibana/pull/59445 is merged +test.skip('Pick and configure action', () => { const screen = render( ); @@ -46,7 +47,8 @@ test('Pick and configure action', () => { }); }); -test('If only one actions factory is available then actionFactory selection is emitted without user input', () => { +// TEMP until https://github.com/elastic/kibana/pull/59445 is merged +test.skip('If only one actions factory is available then actionFactory selection is emitted without user input', () => { const screen = render(); // check that no factories are displayed to pick from From 4641454d0f41ec6055d1a444edc14000e41d4a87 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 6 Mar 2020 11:30:27 +0100 Subject: [PATCH 20/20] fix tests and use buttons instead of links --- .../components/action_wizard/action_wizard.test.tsx | 8 +++----- .../public/components/action_wizard/action_wizard.tsx | 8 +++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx index 9d8e9d48e281c..aea47be693b8f 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.test.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; -import { cleanup, fireEvent, render } from '@testing-library/react'; +import { cleanup, fireEvent, render } from '@testing-library/react/pure'; import '@testing-library/jest-dom/extend-expect'; // TODO: this should be global import { TEST_SUBJ_ACTION_FACTORY_ITEM, TEST_SUBJ_SELECTED_ACTION_FACTORY } from './action_wizard'; import { @@ -19,8 +19,7 @@ import { // https://github.com/elastic/kibana/issues/59469 afterEach(cleanup); -// TEMP until https://github.com/elastic/kibana/pull/59445 is merged -test.skip('Pick and configure action', () => { +test('Pick and configure action', () => { const screen = render( ); @@ -47,8 +46,7 @@ test.skip('Pick and configure action', () => { }); }); -// TEMP until https://github.com/elastic/kibana/pull/59445 is merged -test.skip('If only one actions factory is available then actionFactory selection is emitted without user input', () => { +test('If only one actions factory is available then actionFactory selection is emitted without user input', () => { const screen = render(); // check that no factories are displayed to pick from diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index a1d6d26f01812..41ef863c00e44 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -12,7 +12,7 @@ import { EuiIcon, EuiSpacer, EuiText, - EuiKeyPadMenuItem, + EuiKeyPadMenuItemButton, } from '@elastic/eui'; import { txtChangeButton } from './i18n'; import './action_wizard.scss'; @@ -126,6 +126,7 @@ const SelectedActionFactory: React.FC = ({
@@ -179,15 +180,16 @@ const ActionFactorySelector: React.FC = ({ return ( {actionFactories.map(actionFactory => ( - onActionFactorySelected(actionFactory)} > {actionFactory.iconType && } - + ))} );