[Canvas] Disable datasource UI when expression contains an expression argument (#79369)

* Disable datasource UI when expression contains an expression argument

* Removing unnecessary type coercion
This commit is contained in:
Poff Poffenberger 2020-10-05 12:52:12 -05:00 committed by GitHub
parent 8c3af56e2b
commit ead4ebc9f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 155 additions and 32 deletions

View file

@ -5,16 +5,18 @@
*/
import React from 'react';
import { EuiText } from '@elastic/eui';
import { EuiCallOut, EuiText } from '@elastic/eui';
import { templateFromReactComponent } from '../../../public/lib/template_from_react_component';
import { DataSourceStrings } from '../../../i18n';
const { DemoData: strings } = DataSourceStrings;
const DemodataDatasource = () => (
<EuiText size="s">
<p>{strings.getDescription()}</p>
</EuiText>
<EuiCallOut title={strings.getHeading()} iconType="iInCircle">
<EuiText size="s">
<p>{strings.getDescription()}</p>
</EuiText>
</EuiCallOut>
);
export const demodata = () => ({

View file

@ -235,6 +235,11 @@ export const ComponentStrings = {
i18n.translate('xpack.canvas.datasourceDatasourceComponent.changeButtonLabel', {
defaultMessage: 'Change element data source',
}),
getExpressionArgDescription: () =>
i18n.translate('xpack.canvas.datasourceDatasourceComponent.expressionArgDescription', {
defaultMessage:
'The datasource has an argument controlled by an expression. Use the expression editor to modify the datasource.',
}),
getPreviewButtonLabel: () =>
i18n.translate('xpack.canvas.datasourceDatasourceComponent.previewButtonLabel', {
defaultMessage: 'Preview data',

View file

@ -0,0 +1,93 @@
/*
* 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 { action } from '@storybook/addon-actions';
import { storiesOf } from '@storybook/react';
import { EuiCallOut, EuiText } from '@elastic/eui';
import React from 'react';
// @ts-expect-error untyped local
import { DatasourceComponent } from '../datasource_component';
import { templateFromReactComponent } from '../../../../public/lib/template_from_react_component';
// @ts-expect-error untyped local
import { Datasource } from '../../../../public/expression_types/datasource';
const TestDatasource = ({ args }: any) => (
<EuiCallOut title="My Test Data Source" iconType="iInCircle">
<EuiText size="s">
<p>Hello! I am a datasource with a query arg of: {args.query}</p>
</EuiText>
</EuiCallOut>
);
const testDatasource = () => ({
name: 'test',
displayName: 'Test Datasource',
help: 'This is a test data source',
image: 'training',
template: templateFromReactComponent(TestDatasource),
});
const wrappedTestDatasource = new Datasource(testDatasource());
const args = {
query: ['select * from kibana'],
};
storiesOf('components/datasource/DatasourceComponent', module)
.addParameters({
info: {
inline: true,
styles: {
infoBody: {
margin: 20,
},
infoStory: {
margin: '40px 60px',
width: '320px',
},
},
},
})
.add('simple datasource', () => (
<DatasourceComponent
args={args}
datasources={[wrappedTestDatasource]}
datasource={wrappedTestDatasource}
datasourceDef={{}}
stateArgs={args}
stateDatasource={wrappedTestDatasource}
selectDatasouce={action('selectDatasouce')}
setDatasourceAst={action('setDatasourceAst')}
updateArgs={action('updateArgs')}
resetArgs={action('resetArgs')}
selecting={false}
setSelecting={action('setSelecting')}
previewing={false}
setPreviewing={action('setPreviewing')}
isInvalid={false}
setInvalid={action('setInvalid')}
/>
))
.add('datasource with expression arguments', () => (
<DatasourceComponent
args={{ query: [{ name: 'expression' }] }}
datasources={[wrappedTestDatasource]}
datasource={wrappedTestDatasource}
datasourceDef={{}}
stateArgs={{ query: [{ name: 'expression' }] }}
stateDatasource={wrappedTestDatasource}
selectDatasouce={action('selectDatasouce')}
setDatasourceAst={action('setDatasourceAst')}
updateArgs={action('updateArgs')}
resetArgs={action('resetArgs')}
selecting={false}
setSelecting={action('setSelecting')}
previewing={false}
setPreviewing={action('setPreviewing')}
isInvalid={false}
setInvalid={action('setInvalid')}
/>
));

View file

@ -17,13 +17,12 @@ import {
EuiHorizontalRule,
} from '@elastic/eui';
import { isEqual } from 'lodash';
import { ComponentStrings, DataSourceStrings } from '../../../i18n';
import { ComponentStrings } from '../../../i18n';
import { getDefaultIndex } from '../../lib/es_service';
import { DatasourceSelector } from './datasource_selector';
import { DatasourcePreview } from './datasource_preview';
const { DatasourceDatasourceComponent: strings } = ComponentStrings;
const { DemoData: demoDataStrings } = DataSourceStrings;
export class DatasourceComponent extends PureComponent {
static propTypes = {
@ -133,14 +132,17 @@ export class DatasourceComponent extends PureComponent {
/>
) : null;
const datasourceRender = stateDatasource.render({
args: stateArgs,
updateArgs,
datasourceDef,
isInvalid,
setInvalid,
defaultIndex,
});
const datasourceRender = () =>
stateDatasource.render({
args: stateArgs,
updateArgs,
datasourceDef,
isInvalid,
setInvalid,
defaultIndex,
});
const hasExpressionArgs = Object.values(stateArgs).some((a) => a && typeof a[0] === 'object');
return (
<Fragment>
@ -157,26 +159,34 @@ export class DatasourceComponent extends PureComponent {
{stateDatasource.displayName}
</EuiButtonEmpty>
<EuiSpacer size="s" />
{stateDatasource.name === 'demodata' ? (
<EuiCallOut title={demoDataStrings.getHeading()} iconType="iInCircle">
{datasourceRender}
</EuiCallOut>
{!hasExpressionArgs ? (
<>
{datasourceRender()}
<EuiHorizontalRule margin="m" />
<EuiFlexGroup justifyContent="flexEnd" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiButtonEmpty size="s" onClick={() => setPreviewing(true)}>
{strings.getPreviewButtonLabel()}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
disabled={isInvalid}
size="s"
onClick={this.save}
fill
color="secondary"
>
{strings.getSaveButtonLabel()}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</>
) : (
datasourceRender
<EuiCallOut color="warning">
<p>{strings.getExpressionArgDescription()}</p>
</EuiCallOut>
)}
<EuiHorizontalRule margin="m" />
<EuiFlexGroup justifyContent="flexEnd" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiButtonEmpty size="s" onClick={() => setPreviewing(true)}>
{strings.getPreviewButtonLabel()}
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton disabled={isInvalid} size="s" onClick={this.save} fill color="secondary">
{strings.getSaveButtonLabel()}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</div>
{datasourcePreview}

View file

@ -176,6 +176,10 @@ module.exports = async ({ config: storybookConfig }) => {
/(lib)?\/ui_metric/,
path.resolve(__dirname, '../tasks/mocks/uiMetric')
),
new webpack.NormalModuleReplacementPlugin(
/lib\/es_service/,
path.resolve(__dirname, '../tasks/mocks/esService')
),
],
resolve: {
extensions: ['.ts', '.tsx', '.scss', '.mjs', '.html'],

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
export function getDefaultIndex() {
return Promise.resolve('default-index');
}