mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[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:
parent
8c3af56e2b
commit
ead4ebc9f6
6 changed files with 155 additions and 32 deletions
|
@ -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 = () => ({
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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')}
|
||||
/>
|
||||
));
|
|
@ -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}
|
||||
|
|
|
@ -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'],
|
||||
|
|
9
x-pack/plugins/canvas/tasks/mocks/esService.ts
Normal file
9
x-pack/plugins/canvas/tasks/mocks/esService.ts
Normal 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');
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue