mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
* Basic setup of error plugin. * Removed not used `function` files at `error` expression. * Moved related components from canvas. * Changed imports of components. * Fixed renderer and storybook. * Fixed types errors. * Added limits. * Removed useless translations and fixed .i18nrc.json * added `done` handler call. * Added more fixes fo i18nc. * Added docs. * More fixes of i18nrc. * Fixed async functions. Written current code, based on https://github.com/storybookjs/storybook/issues/7745 * Fixed one test with Expression input. After changing the way of rendering in stories, all elements are mounting and componentDidMount is involved. The previous snapshot was without mounted `monaco` editor. * Fixed storybook error. * More fixes. * removed unused translations. * Removed handlers and changed the way of handling `resize` and calling `done`. * Fixed i18n error. * Fixed storybook. * Replaced Popover with EuiPopover. * Moved `Popover` back to `canvas` * Removed `Popover` export from presentation_utils components. * Moved error_component and debug_component from presentation_util to expression_error. * Fixed translations and imports. * Moved `debug renderer` to `expression_error` plugin. * Fixed error. * Fixed lazy exports. * Fixed imports * Fixed storybook snapshot. * Removed `.i18nrc.json`. * Fixed color of `error`. * Exported concrete elements from popover. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> # Conflicts: # packages/kbn-optimizer/limits.yml # src/plugins/expression_error/public/components/debug/debug.tsx
214 lines
6.1 KiB
JavaScript
214 lines
6.1 KiB
JavaScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the Elastic License
|
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
|
* 2.0.
|
|
*/
|
|
|
|
import React, { Fragment, PureComponent } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import {
|
|
EuiFlexGroup,
|
|
EuiFlexItem,
|
|
EuiButton,
|
|
EuiSpacer,
|
|
EuiIcon,
|
|
EuiCallOut,
|
|
EuiButtonEmpty,
|
|
EuiHorizontalRule,
|
|
} from '@elastic/eui';
|
|
import { isEqual } from 'lodash';
|
|
import { i18n } from '@kbn/i18n';
|
|
|
|
import { getDefaultIndex } from '../../lib/es_service';
|
|
import { DatasourceSelector } from './datasource_selector';
|
|
import { DatasourcePreview } from './datasource_preview';
|
|
|
|
const strings = {
|
|
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',
|
|
}),
|
|
getSaveButtonLabel: () =>
|
|
i18n.translate('xpack.canvas.datasourceDatasourceComponent.saveButtonLabel', {
|
|
defaultMessage: 'Save',
|
|
}),
|
|
};
|
|
export class DatasourceComponent extends PureComponent {
|
|
static propTypes = {
|
|
args: PropTypes.object.isRequired,
|
|
datasources: PropTypes.array.isRequired,
|
|
datasource: PropTypes.object.isRequired,
|
|
datasourceDef: PropTypes.object.isRequired,
|
|
stateDatasource: PropTypes.shape({
|
|
name: PropTypes.string.isRequired,
|
|
render: PropTypes.func.isRequired,
|
|
}).isRequired,
|
|
selectDatasource: PropTypes.func,
|
|
setDatasourceAst: PropTypes.func,
|
|
stateArgs: PropTypes.object.isRequired,
|
|
updateArgs: PropTypes.func,
|
|
resetArgs: PropTypes.func.isRequired,
|
|
selecting: PropTypes.bool,
|
|
setSelecting: PropTypes.func,
|
|
previewing: PropTypes.bool,
|
|
setPreviewing: PropTypes.func,
|
|
isInvalid: PropTypes.bool,
|
|
setInvalid: PropTypes.func,
|
|
renderError: PropTypes.func,
|
|
};
|
|
|
|
state = { defaultIndex: '' };
|
|
|
|
componentDidMount() {
|
|
getDefaultIndex().then((defaultIndex) => this.setState({ defaultIndex }));
|
|
}
|
|
|
|
componentDidUpdate(prevProps) {
|
|
const { args, resetArgs, datasource, selectDatasource } = this.props;
|
|
if (!isEqual(prevProps.args, args)) {
|
|
resetArgs();
|
|
}
|
|
|
|
if (!isEqual(prevProps.datasource, datasource)) {
|
|
selectDatasource(datasource);
|
|
}
|
|
}
|
|
|
|
getDatasourceFunctionNode = (name, args) => ({
|
|
arguments: args,
|
|
function: name,
|
|
type: 'function',
|
|
});
|
|
|
|
setSelectedDatasource = (value) => {
|
|
const {
|
|
datasource,
|
|
resetArgs,
|
|
updateArgs,
|
|
selectDatasource,
|
|
datasources,
|
|
setSelecting,
|
|
} = this.props;
|
|
|
|
if (datasource.name === value) {
|
|
// if selecting the current datasource, reset the arguments
|
|
resetArgs && resetArgs();
|
|
} else {
|
|
// otherwise, clear the arguments, the form will update them
|
|
updateArgs && updateArgs({});
|
|
}
|
|
selectDatasource && selectDatasource(datasources.find((d) => d.name === value));
|
|
setSelecting(false);
|
|
};
|
|
|
|
save = () => {
|
|
const { stateDatasource, stateArgs, setDatasourceAst } = this.props;
|
|
const datasourceAst = this.getDatasourceFunctionNode(stateDatasource.name, stateArgs);
|
|
setDatasourceAst && setDatasourceAst(datasourceAst);
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
datasources,
|
|
datasourceDef,
|
|
stateDatasource,
|
|
stateArgs,
|
|
updateArgs,
|
|
selecting,
|
|
setSelecting,
|
|
previewing,
|
|
setPreviewing,
|
|
isInvalid,
|
|
setInvalid,
|
|
renderError,
|
|
} = this.props;
|
|
|
|
const { defaultIndex } = this.state;
|
|
|
|
if (selecting) {
|
|
return (
|
|
<DatasourceSelector
|
|
datasources={datasources}
|
|
onSelect={this.setSelectedDatasource}
|
|
current={stateDatasource.name}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const datasourcePreview = previewing ? (
|
|
<DatasourcePreview
|
|
show={previewing}
|
|
done={() => setPreviewing(false)}
|
|
function={this.getDatasourceFunctionNode(stateDatasource.name, stateArgs)}
|
|
/>
|
|
) : null;
|
|
|
|
const datasourceRender = () =>
|
|
stateDatasource.render({
|
|
args: stateArgs,
|
|
updateArgs,
|
|
datasourceDef,
|
|
isInvalid,
|
|
setInvalid,
|
|
defaultIndex,
|
|
renderError,
|
|
});
|
|
|
|
const hasExpressionArgs = Object.values(stateArgs).some((a) => a && typeof a[0] === 'object');
|
|
|
|
return (
|
|
<Fragment>
|
|
<div className="canvasDataSource__section">
|
|
<EuiButtonEmpty
|
|
iconSide="right"
|
|
iconType="arrowRight"
|
|
onClick={() => setSelecting(!selecting)}
|
|
className="canvasDataSource__triggerButton"
|
|
flush="left"
|
|
size="s"
|
|
>
|
|
<EuiIcon type={stateDatasource.image} className="canvasDataSource__triggerButtonIcon" />
|
|
{stateDatasource.displayName}
|
|
</EuiButtonEmpty>
|
|
<EuiSpacer size="s" />
|
|
{!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>
|
|
</>
|
|
) : (
|
|
<EuiCallOut color="warning">
|
|
<p>{strings.getExpressionArgDescription()}</p>
|
|
</EuiCallOut>
|
|
)}
|
|
</div>
|
|
|
|
{datasourcePreview}
|
|
</Fragment>
|
|
);
|
|
}
|
|
}
|