2021-04-03 11:14:15 +00:00
|
|
|
import React from 'react';
|
2021-04-30 08:10:57 +00:00
|
|
|
import { dataqueryService } from '@/_services';
|
|
|
|
|
import { toast } from 'react-toastify';
|
2021-04-03 11:14:15 +00:00
|
|
|
import 'react-toastify/dist/ReactToastify.css';
|
2021-04-08 13:57:24 +00:00
|
|
|
import SelectSearch, { fuzzySearch } from 'react-select-search';
|
2021-04-26 07:13:20 +00:00
|
|
|
import ReactTooltip from 'react-tooltip';
|
2021-04-30 16:15:42 +00:00
|
|
|
import { allSources } from './QueryEditors';
|
|
|
|
|
import { Transformation } from './Transformation';
|
2021-05-13 13:31:55 +00:00
|
|
|
import { defaultOptions } from './constants';
|
2021-05-22 11:29:27 +00:00
|
|
|
import ReactJson from 'react-json-view';
|
2021-06-17 05:56:53 +00:00
|
|
|
import { previewQuery } from '@/_helpers/appUtils';
|
2021-09-06 14:40:51 +00:00
|
|
|
import { EventManager } from '../Inspector/EventManager';
|
2021-11-15 06:18:09 +00:00
|
|
|
import { CodeHinter } from '../CodeBuilder/CodeHinter';
|
2021-04-30 06:31:32 +00:00
|
|
|
const queryNameRegex = new RegExp('^[A-Za-z0-9_-]*$');
|
2021-04-29 16:39:09 +00:00
|
|
|
|
2021-07-24 06:13:21 +00:00
|
|
|
const staticDataSources = [{ kind: 'restapi', id: 'null', name: 'REST API' }];
|
2021-04-04 17:07:03 +00:00
|
|
|
|
2021-09-29 09:30:27 +00:00
|
|
|
let QueryManager = class QueryManager extends React.Component {
|
2021-04-30 06:31:32 +00:00
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
|
|
this.state = {};
|
2021-05-22 12:57:36 +00:00
|
|
|
|
|
|
|
|
this.previewPanelRef = React.createRef();
|
2021-04-30 06:31:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setStateFromProps = (props) => {
|
|
|
|
|
const selectedQuery = props.selectedQuery;
|
2021-06-17 05:56:53 +00:00
|
|
|
const dataSourceId = selectedQuery?.data_source_id;
|
|
|
|
|
const source = props.dataSources.find((datasource) => datasource.id === dataSourceId);
|
2021-08-29 16:03:40 +00:00
|
|
|
const paneHeightChanged = this.state.queryPaneHeight !== props.queryPaneHeight;
|
2021-04-30 06:31:32 +00:00
|
|
|
|
|
|
|
|
this.setState(
|
|
|
|
|
{
|
|
|
|
|
appId: props.appId,
|
|
|
|
|
dataSources: props.dataSources,
|
|
|
|
|
dataQueries: props.dataQueries,
|
|
|
|
|
mode: props.mode,
|
|
|
|
|
currentTab: 1,
|
|
|
|
|
addingQuery: props.addingQuery,
|
|
|
|
|
editingQuery: props.editingQuery,
|
|
|
|
|
queryPaneHeight: props.queryPaneHeight,
|
2021-05-22 11:29:27 +00:00
|
|
|
currentState: props.currentState,
|
2021-06-17 05:56:53 +00:00
|
|
|
selectedSource: source,
|
2021-04-30 06:31:32 +00:00
|
|
|
},
|
|
|
|
|
() => {
|
|
|
|
|
if (this.props.mode === 'edit') {
|
2021-05-02 09:27:26 +00:00
|
|
|
let source = props.dataSources.find((datasource) => datasource.id === selectedQuery.data_source_id);
|
2021-09-06 14:40:51 +00:00
|
|
|
if (selectedQuery.kind === 'restapi') {
|
|
|
|
|
if (!selectedQuery.data_source_id) {
|
2021-07-25 17:20:19 +00:00
|
|
|
source = { kind: 'restapi' };
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-30 06:31:32 +00:00
|
|
|
this.setState({
|
|
|
|
|
options: selectedQuery.options,
|
|
|
|
|
selectedDataSource: source,
|
|
|
|
|
selectedQuery,
|
2021-06-17 05:56:53 +00:00
|
|
|
queryName: selectedQuery.name,
|
2021-04-30 06:31:32 +00:00
|
|
|
});
|
2021-04-29 16:39:09 +00:00
|
|
|
} else {
|
2021-04-30 06:31:32 +00:00
|
|
|
this.setState({
|
2021-06-17 05:56:53 +00:00
|
|
|
options: {},
|
|
|
|
|
selectedQuery: null,
|
2021-09-06 14:40:51 +00:00
|
|
|
selectedDataSource: paneHeightChanged ? this.state.selectedDataSource : props.selectedDataSource,
|
2021-04-30 06:31:32 +00:00
|
|
|
});
|
2021-04-29 16:39:09 +00:00
|
|
|
}
|
2021-04-30 06:31:32 +00:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
|
this.setStateFromProps(nextProps);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
|
this.setStateFromProps(this.props);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
changeDataSource = (sourceId) => {
|
2021-04-30 08:10:57 +00:00
|
|
|
const source = [...this.state.dataSources, ...staticDataSources].find((datasource) => datasource.id === sourceId);
|
2021-06-17 05:56:53 +00:00
|
|
|
|
2021-04-30 06:31:32 +00:00
|
|
|
this.setState({
|
|
|
|
|
selectedDataSource: source,
|
2021-06-17 05:56:53 +00:00
|
|
|
selectedSource: source,
|
2021-04-30 06:31:32 +00:00
|
|
|
options: defaultOptions[source.kind],
|
2021-06-17 05:56:53 +00:00
|
|
|
queryName: this.computeQueryName(source.kind),
|
2021-04-30 06:31:32 +00:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switchCurrentTab = (tab) => {
|
|
|
|
|
this.setState({
|
2021-06-17 05:56:53 +00:00
|
|
|
currentTab: tab,
|
2021-04-30 06:31:32 +00:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
validateQueryName = () => {
|
2021-06-17 05:56:53 +00:00
|
|
|
const { queryName, dataQueries, mode, selectedQuery } = this.state;
|
2021-04-30 06:31:32 +00:00
|
|
|
|
|
|
|
|
if (mode === 'create') {
|
|
|
|
|
return dataQueries.find((query) => query.name === queryName) === undefined && queryNameRegex.test(queryName);
|
2021-04-29 16:39:09 +00:00
|
|
|
}
|
2021-04-30 08:10:57 +00:00
|
|
|
const existingQuery = dataQueries.find((query) => query.name === queryName);
|
|
|
|
|
if (existingQuery) {
|
|
|
|
|
return existingQuery.id === selectedQuery.id && queryNameRegex.test(queryName);
|
|
|
|
|
}
|
|
|
|
|
return queryNameRegex.test(queryName);
|
2021-04-30 06:31:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
computeQueryName = (kind) => {
|
|
|
|
|
const { dataQueries } = this.state;
|
|
|
|
|
const currentQueriesForKind = dataQueries.filter((query) => query.kind === kind);
|
|
|
|
|
let found = false;
|
2021-04-30 12:43:29 +00:00
|
|
|
let newName = '';
|
2021-04-30 06:31:32 +00:00
|
|
|
let currentNumber = currentQueriesForKind.length + 1;
|
|
|
|
|
|
|
|
|
|
while (!found) {
|
2021-04-30 12:43:29 +00:00
|
|
|
newName = `${kind}${currentNumber}`;
|
|
|
|
|
if (dataQueries.find((query) => query.name === newName) === undefined) {
|
2021-04-30 06:31:32 +00:00
|
|
|
found = true;
|
|
|
|
|
}
|
2021-04-30 08:10:57 +00:00
|
|
|
currentNumber += 1;
|
2021-04-04 06:26:23 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-30 12:43:29 +00:00
|
|
|
return newName;
|
2021-04-30 06:31:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
createOrUpdateDataQuery = () => {
|
2021-06-17 05:56:53 +00:00
|
|
|
const { appId, options, selectedDataSource, mode, queryName } = this.state;
|
2021-04-30 06:31:32 +00:00
|
|
|
const kind = selectedDataSource.kind;
|
2021-07-24 06:13:21 +00:00
|
|
|
const dataSourceId = selectedDataSource.id === 'null' ? null : selectedDataSource.id;
|
2021-04-30 06:31:32 +00:00
|
|
|
|
|
|
|
|
const isQueryNameValid = this.validateQueryName();
|
|
|
|
|
if (!isQueryNameValid) {
|
|
|
|
|
toast.error('Invalid query name. Should be unique and only include letters, numbers and underscore.', {
|
|
|
|
|
hideProgressBar: true,
|
2021-06-17 05:56:53 +00:00
|
|
|
position: 'bottom-center',
|
2021-04-30 06:31:32 +00:00
|
|
|
});
|
|
|
|
|
return;
|
2021-04-03 11:14:15 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-30 06:31:32 +00:00
|
|
|
if (mode === 'edit') {
|
|
|
|
|
this.setState({ isUpdating: true });
|
2021-06-17 05:56:53 +00:00
|
|
|
dataqueryService
|
|
|
|
|
.update(this.state.selectedQuery.id, queryName, options)
|
|
|
|
|
.then(() => {
|
|
|
|
|
toast.success('Query Updated', { hideProgressBar: true, position: 'bottom-center' });
|
|
|
|
|
this.setState({ isUpdating: false });
|
|
|
|
|
this.props.dataQueriesChanged();
|
|
|
|
|
})
|
|
|
|
|
.catch(({ error }) => {
|
|
|
|
|
this.setState({ isUpdating: false });
|
|
|
|
|
toast.error(error, { hideProgressBar: true, position: 'bottom-center' });
|
|
|
|
|
});
|
2021-04-30 06:31:32 +00:00
|
|
|
} else {
|
|
|
|
|
this.setState({ isCreating: true });
|
2021-06-17 05:56:53 +00:00
|
|
|
dataqueryService
|
|
|
|
|
.create(appId, queryName, kind, options, dataSourceId)
|
|
|
|
|
.then(() => {
|
|
|
|
|
toast.success('Query Added', { hideProgressBar: true, position: 'bottom-center' });
|
|
|
|
|
this.setState({ isCreating: false });
|
|
|
|
|
this.props.dataQueriesChanged();
|
|
|
|
|
})
|
|
|
|
|
.catch(({ error }) => {
|
|
|
|
|
this.setState({ isCreating: false });
|
|
|
|
|
toast.error(error, { hideProgressBar: true, position: 'bottom-center' });
|
|
|
|
|
});
|
2021-04-03 11:14:15 +00:00
|
|
|
}
|
2021-04-30 06:31:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
optionchanged = (option, value) => {
|
|
|
|
|
this.setState({ options: { ...this.state.options, [option]: value } });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
optionsChanged = (newOptions) => {
|
|
|
|
|
this.setState({ options: newOptions });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
toggleOption = (option) => {
|
|
|
|
|
const currentValue = this.state.options[option] ? this.state.options[option] : false;
|
|
|
|
|
this.optionchanged(option, !currentValue);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
renderDataSourceOption = (props, option, snapshot, className) => {
|
|
|
|
|
return (
|
|
|
|
|
<button {...props} className={className} type="button">
|
|
|
|
|
<div className="row">
|
|
|
|
|
<div className="col-md-9">
|
|
|
|
|
<span className="text-muted mx-2">{option.name}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2021-09-06 14:40:51 +00:00
|
|
|
// Here we have mocked data query in format of a component to be usable by event manager
|
|
|
|
|
// TODO: Refactor EventManager to be generic
|
|
|
|
|
mockDataQueryAsComponent = () => {
|
|
|
|
|
const dataQueryEvents = this.state.options?.events || [];
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
component: { component: { definition: { events: dataQueryEvents } } },
|
|
|
|
|
componentMeta: {
|
|
|
|
|
events: {
|
|
|
|
|
onDataQuerySuccess: { displayName: 'Query Success' },
|
|
|
|
|
onDataQueryFailure: { displayName: 'Query Failure' },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
eventsChanged = (events) => {
|
|
|
|
|
this.optionchanged('events', events);
|
|
|
|
|
};
|
|
|
|
|
|
2021-04-30 06:31:32 +00:00
|
|
|
render() {
|
|
|
|
|
const {
|
|
|
|
|
dataSources,
|
|
|
|
|
selectedDataSource,
|
|
|
|
|
mode,
|
2021-05-22 11:50:55 +00:00
|
|
|
options,
|
2021-04-30 06:31:32 +00:00
|
|
|
currentTab,
|
|
|
|
|
isUpdating,
|
|
|
|
|
isCreating,
|
|
|
|
|
addingQuery,
|
|
|
|
|
editingQuery,
|
|
|
|
|
selectedQuery,
|
|
|
|
|
queryPaneHeight,
|
|
|
|
|
currentState,
|
2021-05-22 11:29:27 +00:00
|
|
|
queryName,
|
|
|
|
|
previewLoading,
|
2021-06-17 05:56:53 +00:00
|
|
|
queryPreviewData,
|
2021-04-30 06:31:32 +00:00
|
|
|
} = this.state;
|
|
|
|
|
|
|
|
|
|
let ElementToRender = '';
|
|
|
|
|
|
|
|
|
|
if (selectedDataSource) {
|
|
|
|
|
const sourcecomponentName = selectedDataSource.kind.charAt(0).toUpperCase() + selectedDataSource.kind.slice(1);
|
|
|
|
|
ElementToRender = allSources[sourcecomponentName];
|
2021-04-04 17:07:03 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-30 06:31:32 +00:00
|
|
|
let buttonText = mode === 'edit' ? 'Save' : 'Create';
|
|
|
|
|
const buttonDisabled = isUpdating || isCreating;
|
2021-09-06 14:40:51 +00:00
|
|
|
const mockDataQueryComponent = this.mockDataQueryAsComponent();
|
2021-04-07 07:03:03 +00:00
|
|
|
|
2021-04-30 06:31:32 +00:00
|
|
|
return (
|
|
|
|
|
<div className="query-manager" key={selectedQuery ? selectedQuery.id : ''}>
|
|
|
|
|
<ReactTooltip type="dark" effect="solid" delayShow={250} />
|
|
|
|
|
<div className="row header">
|
|
|
|
|
<div className="col">
|
|
|
|
|
{(addingQuery || editingQuery) && (
|
|
|
|
|
<div className="nav-header">
|
2021-05-22 07:29:44 +00:00
|
|
|
<ul className="nav nav-tabs query-manager-header" data-bs-toggle="tabs">
|
2021-04-30 06:31:32 +00:00
|
|
|
<li className="nav-item">
|
|
|
|
|
<a
|
|
|
|
|
onClick={() => this.switchCurrentTab(1)}
|
|
|
|
|
className={currentTab === 1 ? 'nav-link active' : 'nav-link'}
|
|
|
|
|
>
|
|
|
|
|
General
|
|
|
|
|
</a>
|
|
|
|
|
</li>
|
|
|
|
|
<li className="nav-item">
|
|
|
|
|
<a
|
|
|
|
|
onClick={() => this.switchCurrentTab(2)}
|
|
|
|
|
className={currentTab === 2 ? 'nav-link active' : 'nav-link'}
|
|
|
|
|
>
|
|
|
|
|
Advanced
|
|
|
|
|
</a>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2021-06-17 05:56:53 +00:00
|
|
|
{(addingQuery || editingQuery) && selectedDataSource && (
|
2021-04-30 06:31:32 +00:00
|
|
|
<div className="col query-name-field">
|
|
|
|
|
<div className="input-icon" style={{ width: '160px' }}>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
onChange={(e) => this.setState({ queryName: e.target.value })}
|
2021-04-30 08:10:57 +00:00
|
|
|
className="form-control-plaintext form-control-plaintext-sm mt-1"
|
2021-04-30 06:31:32 +00:00
|
|
|
value={queryName}
|
|
|
|
|
style={{ width: '160px' }}
|
2021-05-02 06:17:22 +00:00
|
|
|
autoFocus={false}
|
2021-04-30 06:31:32 +00:00
|
|
|
/>
|
2021-04-30 08:10:57 +00:00
|
|
|
<span className="input-icon-addon">
|
2021-07-03 17:07:50 +00:00
|
|
|
<img className="svg-icon" src="/assets/images/icons/edit.svg" width="12" height="12" />
|
2021-04-30 06:31:32 +00:00
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2021-09-03 05:01:01 +00:00
|
|
|
<div className="col-auto px-1">
|
2021-05-22 11:50:55 +00:00
|
|
|
{(addingQuery || editingQuery) && (
|
2021-05-22 11:29:27 +00:00
|
|
|
<span
|
2021-06-17 05:56:53 +00:00
|
|
|
onClick={() => {
|
2021-09-06 14:40:51 +00:00
|
|
|
const _options = { ...options };
|
|
|
|
|
|
2021-06-17 05:56:53 +00:00
|
|
|
const query = {
|
2021-09-06 14:40:51 +00:00
|
|
|
data_source_id: selectedDataSource.id === 'null' ? null : selectedDataSource.id,
|
2021-08-30 11:25:27 +00:00
|
|
|
options: _options,
|
2021-06-17 05:56:53 +00:00
|
|
|
kind: selectedDataSource.kind,
|
|
|
|
|
};
|
|
|
|
|
previewQuery(this, query)
|
|
|
|
|
.then(() => {
|
|
|
|
|
this.previewPanelRef.current.scrollIntoView();
|
|
|
|
|
})
|
|
|
|
|
.catch(({ error, data }) => {
|
2021-09-21 13:48:28 +00:00
|
|
|
console.log(error, data);
|
2021-05-22 12:57:36 +00:00
|
|
|
});
|
|
|
|
|
}}
|
2021-06-17 05:56:53 +00:00
|
|
|
className={`btn btn-secondary m-1 float-right1 ${previewLoading ? ' btn-loading' : ''}`}
|
2021-05-22 11:29:27 +00:00
|
|
|
>
|
|
|
|
|
Preview
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
2021-04-30 06:31:32 +00:00
|
|
|
{(addingQuery || editingQuery) && (
|
|
|
|
|
<button
|
|
|
|
|
onClick={this.createOrUpdateDataQuery}
|
|
|
|
|
disabled={buttonDisabled}
|
2021-05-22 15:02:26 +00:00
|
|
|
className={`btn btn-primary m-1 float-right ${isUpdating || isCreating ? 'btn-loading' : ''}`}
|
2021-04-30 06:31:32 +00:00
|
|
|
>
|
|
|
|
|
{buttonText}
|
|
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
{queryPaneHeight === '30%' ? (
|
|
|
|
|
<span
|
|
|
|
|
className="btn btn-light m-1"
|
|
|
|
|
onClick={this.props.toggleQueryPaneHeight}
|
|
|
|
|
data-tip="Maximize query editor"
|
|
|
|
|
>
|
2021-05-31 10:38:18 +00:00
|
|
|
<img src="/assets/images/icons/maximize.svg" width="12" height="12" />
|
2021-04-30 06:31:32 +00:00
|
|
|
</span>
|
|
|
|
|
) : (
|
|
|
|
|
<span
|
|
|
|
|
className="btn btn-light m-1"
|
|
|
|
|
onClick={this.props.toggleQueryPaneHeight}
|
|
|
|
|
data-tip="Minimize query editor"
|
|
|
|
|
>
|
2021-05-31 10:38:18 +00:00
|
|
|
<img src="/assets/images/icons/minimize.svg" width="12" height="12" />
|
2021-04-30 06:31:32 +00:00
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{(addingQuery || editingQuery) && (
|
2021-05-13 16:38:13 +00:00
|
|
|
<div className="py-2">
|
2021-04-30 06:31:32 +00:00
|
|
|
{currentTab === 1 && (
|
2021-05-24 13:09:00 +00:00
|
|
|
<div className="row row-deck px-2 pt-1 query-details">
|
2021-04-30 06:31:32 +00:00
|
|
|
{dataSources && mode === 'create' && (
|
|
|
|
|
<div className="datasource-picker mb-2">
|
|
|
|
|
<label className="form-label col-md-2">Datasource</label>
|
|
|
|
|
<SelectSearch
|
|
|
|
|
options={[
|
|
|
|
|
...dataSources.map((source) => {
|
|
|
|
|
return { name: source.name, value: source.id };
|
|
|
|
|
}),
|
|
|
|
|
...staticDataSources.map((source) => {
|
|
|
|
|
return { name: source.name, value: source.id };
|
2021-06-17 05:56:53 +00:00
|
|
|
}),
|
2021-04-30 06:31:32 +00:00
|
|
|
]}
|
|
|
|
|
value={selectedDataSource ? selectedDataSource.id : ''}
|
|
|
|
|
search={true}
|
|
|
|
|
onChange={(value) => this.changeDataSource(value)}
|
|
|
|
|
filterOptions={fuzzySearch}
|
|
|
|
|
renderOption={this.renderDataSourceOption}
|
|
|
|
|
placeholder="Select a data source"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{selectedDataSource && (
|
|
|
|
|
<div>
|
2021-06-17 05:56:53 +00:00
|
|
|
<ElementToRender
|
|
|
|
|
selectedDataSource={this.state.selectedSource}
|
|
|
|
|
options={this.state.options}
|
|
|
|
|
optionsChanged={this.optionsChanged}
|
2021-11-17 17:59:00 +00:00
|
|
|
optionchanged={this.optionchanged}
|
2021-06-17 05:56:53 +00:00
|
|
|
currentState={currentState}
|
2021-07-03 14:17:47 +00:00
|
|
|
darkMode={this.props.darkMode}
|
2021-08-30 11:25:27 +00:00
|
|
|
isEditMode={this.props.mode === 'edit'}
|
2021-06-17 05:56:53 +00:00
|
|
|
/>
|
2021-04-30 16:15:42 +00:00
|
|
|
<hr></hr>
|
|
|
|
|
<div className="mb-3 mt-2">
|
2021-06-17 05:56:53 +00:00
|
|
|
<Transformation
|
|
|
|
|
changeOption={this.optionchanged}
|
|
|
|
|
options={this.state.options}
|
|
|
|
|
currentState={currentState}
|
2021-07-03 14:17:47 +00:00
|
|
|
darkMode={this.props.darkMode}
|
2021-06-17 05:56:53 +00:00
|
|
|
/>
|
2021-04-30 16:15:42 +00:00
|
|
|
</div>
|
2021-05-24 16:13:02 +00:00
|
|
|
<div className="row preview-header border-top" ref={this.previewPanelRef}>
|
2021-06-17 05:56:53 +00:00
|
|
|
<div className="py-2">Preview</div>
|
2021-05-22 11:29:27 +00:00
|
|
|
</div>
|
|
|
|
|
<div className="mb-3 mt-2">
|
2021-06-17 05:56:53 +00:00
|
|
|
{previewLoading && (
|
|
|
|
|
<center>
|
2021-06-28 07:40:14 +00:00
|
|
|
<div className="spinner-border text-azure mt-5" role="status"></div>
|
2021-06-17 05:56:53 +00:00
|
|
|
</center>
|
|
|
|
|
)}
|
|
|
|
|
{previewLoading === false && (
|
2021-05-22 11:29:27 +00:00
|
|
|
<div>
|
|
|
|
|
<ReactJson
|
|
|
|
|
name={false}
|
|
|
|
|
style={{ fontSize: '0.7rem' }}
|
|
|
|
|
enableClipboard={false}
|
|
|
|
|
src={queryPreviewData}
|
2021-07-03 19:40:57 +00:00
|
|
|
theme={this.props.darkMode ? 'shapeshifter' : 'rjv-default'}
|
2021-05-22 13:04:24 +00:00
|
|
|
displayDataTypes={true}
|
|
|
|
|
collapsed={false}
|
|
|
|
|
displayObjectSize={true}
|
2021-05-22 11:29:27 +00:00
|
|
|
quotesOnKeys={false}
|
|
|
|
|
sortKeys={true}
|
|
|
|
|
indentWidth={1}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2021-06-17 05:56:53 +00:00
|
|
|
)}
|
2021-05-22 11:29:27 +00:00
|
|
|
</div>
|
2021-04-30 06:31:32 +00:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{currentTab === 2 && (
|
2021-05-13 16:38:13 +00:00
|
|
|
<div className="advanced-options-container m-2">
|
2021-04-30 06:31:32 +00:00
|
|
|
<label className="form-check form-switch">
|
|
|
|
|
<input
|
|
|
|
|
className="form-check-input"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
onClick={() => this.toggleOption('runOnPageLoad')}
|
|
|
|
|
checked={this.state.options.runOnPageLoad}
|
|
|
|
|
/>
|
|
|
|
|
<span className="form-check-label">Run this query on page load?</span>
|
|
|
|
|
</label>
|
|
|
|
|
<label className="form-check form-switch">
|
|
|
|
|
<input
|
|
|
|
|
className="form-check-input"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
onClick={() => this.toggleOption('requestConfirmation')}
|
|
|
|
|
checked={this.state.options.requestConfirmation}
|
|
|
|
|
/>
|
|
|
|
|
<span className="form-check-label">Request confirmation before running query?</span>
|
|
|
|
|
</label>
|
|
|
|
|
|
|
|
|
|
<label className="form-check form-switch">
|
|
|
|
|
<input
|
|
|
|
|
className="form-check-input"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
onClick={() => this.toggleOption('showSuccessNotification')}
|
|
|
|
|
checked={this.state.options.showSuccessNotification}
|
|
|
|
|
/>
|
|
|
|
|
<span className="form-check-label">Show notification on success?</span>
|
|
|
|
|
</label>
|
2021-09-15 15:40:59 +00:00
|
|
|
{this.state.options.showSuccessNotification && (
|
2021-09-06 14:40:51 +00:00
|
|
|
<div>
|
|
|
|
|
<div className="row mt-3">
|
|
|
|
|
<div className="col-auto">
|
|
|
|
|
<label className="form-label p-2">Success Message</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="col">
|
2021-11-15 06:18:09 +00:00
|
|
|
<CodeHinter
|
|
|
|
|
currentState={this.props.currentState}
|
|
|
|
|
initialValue={this.state.options.successMessage}
|
|
|
|
|
height="36px"
|
2021-09-06 14:40:51 +00:00
|
|
|
className="form-control"
|
2021-11-15 06:18:09 +00:00
|
|
|
theme={'default'}
|
|
|
|
|
onChange={(value) => this.optionchanged('successMessage', value)}
|
|
|
|
|
placeholder="Query ran successfully"
|
2021-09-06 14:40:51 +00:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2021-04-30 06:31:32 +00:00
|
|
|
|
2021-09-06 14:40:51 +00:00
|
|
|
<div className="row mt-3">
|
|
|
|
|
<div className="col-auto">
|
|
|
|
|
<label className="form-label p-2">Notification duration (s)</label>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="col">
|
|
|
|
|
<input
|
|
|
|
|
type="number"
|
|
|
|
|
disabled={!this.state.options.showSuccessNotification}
|
|
|
|
|
onChange={(e) => this.optionchanged('notificationDuration', e.target.value)}
|
|
|
|
|
placeholder={5}
|
|
|
|
|
className="form-control"
|
|
|
|
|
value={this.state.options.notificationDuration}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2021-04-30 06:31:32 +00:00
|
|
|
</div>
|
2021-09-15 15:40:59 +00:00
|
|
|
)}
|
2021-09-06 14:40:51 +00:00
|
|
|
|
|
|
|
|
<div className="hr-text hr-text-left">Events</div>
|
|
|
|
|
|
|
|
|
|
<div className="query-manager-events">
|
|
|
|
|
<EventManager
|
|
|
|
|
eventsChanged={this.eventsChanged}
|
|
|
|
|
component={mockDataQueryComponent.component}
|
|
|
|
|
componentMeta={mockDataQueryComponent.componentMeta}
|
|
|
|
|
currentState={this.props.currentState}
|
|
|
|
|
dataQueries={this.props.dataQueries}
|
|
|
|
|
components={this.props.allComponents}
|
|
|
|
|
apps={this.props.apps}
|
|
|
|
|
popoverPlacement="top"
|
|
|
|
|
/>
|
2021-04-26 07:13:20 +00:00
|
|
|
</div>
|
2021-04-30 06:31:32 +00:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-09-29 09:30:27 +00:00
|
|
|
};
|
2021-04-03 11:14:15 +00:00
|
|
|
|
2021-09-28 17:03:40 +00:00
|
|
|
QueryManager = React.memo(QueryManager);
|
2021-04-04 06:46:53 +00:00
|
|
|
export { QueryManager };
|