import React from 'react'; import { dataqueryService, authenticationService } from '@/_services'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import { Restapi } from './Restapi'; import { Mysql } from './Mysql'; import { Postgresql } from './Postgresql'; import { Stripe } from './Stripe'; import { Firestore } from './Firestore'; import { Redis } from './Redis'; import { Googlesheets } from './Googlesheets'; import SelectSearch, { fuzzySearch } from 'react-select-search'; import ReactTooltip from 'react-tooltip'; import { Elasticsearch } from './Elasticsearch'; const allSources = { Restapi, Mysql, Postgresql, Stripe, Firestore, Redis, Googlesheets, Elasticsearch } const queryNameRegex = new RegExp("^[A-Za-z0-9_-]*$"); const staticDataSources = [ { kind: 'restapi', id: 'restapi', name: 'REST API' }, ] const defaultOptions = { 'postgresql': { }, 'redis': { query: 'PING' }, 'mysql': { }, 'firestore': { path: '', }, 'elasticsearch': { query: '', }, 'restapi': { method: 'GET', url: null, url_params: [ ['', ''] ], headers: [ ['', ''] ], body: [ ['', ''] ], }, 'stripe': { }, 'googlesheets': { operation: 'read' } } class QueryManager extends React.Component { constructor(props) { super(props); this.state = { }; } setStateFromProps = (props) => { const selectedQuery = props.selectedQuery; 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, currentState: props.currentState }, () => { if(this.props.mode === 'edit') { const source = props.dataSources.find(source => source.id === selectedQuery.data_source_id) this.setState({ options: selectedQuery.options, selectedDataSource: source, selectedQuery, queryName: selectedQuery.name }) } else { this.setState({ options: {}, selectedDataSource: null, selectedQuery: null, }) } }); } componentWillReceiveProps(nextProps) { this.setStateFromProps(nextProps); } componentDidMount() { this.setStateFromProps(this.props); } changeDataSource = (sourceId) => { const source = [...this.state.dataSources, ...staticDataSources].find(source => source.id === sourceId); this.setState({ selectedDataSource: source, options: defaultOptions[source.kind], queryName: this.computeQueryName(source.kind) }); } switchCurrentTab = (tab) => { this.setState({ currentTab: tab }); } validateQueryName = () => { const { queryName, dataQueries, mode, selectedQuery} = this.state; if(mode === 'create') { return (dataQueries.find(query => query.name === queryName) === undefined) && queryNameRegex.test(queryName); } else { const existingQuery = dataQueries.find(query => query.name === queryName); if (existingQuery) { return (existingQuery.id === selectedQuery.id) && queryNameRegex.test(queryName); } else { queryNameRegex.test(queryName); } } } computeQueryName = (kind) => { const { dataQueries } = this.state; const currentQueriesForKind = dataQueries.filter(query => query.kind === kind); let found = false; let name = ''; let currentNumber = currentQueriesForKind.length + 1; while(!found) { name = `${kind}${currentNumber}`; if(dataQueries.find(query => query.name === name) === undefined) { found = true; } currentNumber = currentNumber + 1 } return name; } createOrUpdateDataQuery = () => { const { appId, options, selectedDataSource, mode, queryName } = this.state; const kind = selectedDataSource.kind; const dataSourceId = selectedDataSource.id; const isQueryNameValid = this.validateQueryName(); if(!isQueryNameValid) { toast.error('Invalid query name. Should be unique and only include letters, numbers and underscore.', { hideProgressBar: true, position: "bottom-center", }); return; } if ( mode === 'edit') { this.setState({ isUpdating: true }); dataqueryService.update(this.state.selectedQuery.id, queryName, options).then((data) => { toast.success('Query Updated', { hideProgressBar: true, position: "bottom-center", }); this.setState({ isUpdating: false }); this.props.dataQueriesChanged(); }); } else { this.setState({ isCreating: true }); dataqueryService.create(appId, queryName, kind, options, dataSourceId).then((data) => { toast.success('Query Added', { hideProgressBar: true, position: "bottom-center", }); this.setState({ isCreating: false }); this.props.dataQueriesChanged(); }); } } 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 ( ); } render() { const { dataSources, selectedDataSource, mode, currentTab, isUpdating, isCreating, addingQuery, editingQuery, selectedQuery, queryPaneHeight, currentState, queryName } = this.state; let ElementToRender = ''; if(selectedDataSource) { const sourcecomponentName = selectedDataSource.kind.charAt(0).toUpperCase() + selectedDataSource.kind.slice(1); ElementToRender = allSources[sourcecomponentName]; } let buttonText = mode === 'edit' ? 'Save' : 'Create'; const buttonDisabled = isUpdating || isCreating; if(isUpdating) { buttonText = 'Saving...'} if(isCreating) { buttonText = 'Creating...'} return (
{(addingQuery || editingQuery) &&
}
{(addingQuery || editingQuery) &&
this.setState({ queryName: e.target.value })} class="form-control-plaintext form-control-plaintext-sm mt-1" value={queryName} style={{width: '160px'}} autoFocus />
}
{((addingQuery || editingQuery) && selectedQuery) && this.props.runQuery(selectedQuery.id, selectedQuery.name)} className={`btn btn-secondary m-1 float-right1 ${currentState.queries[selectedQuery.name].isLoading === true ? ' btn-loading' : '' }`} > Run } {(addingQuery || editingQuery) && } {queryPaneHeight === '30%' ? : }
{(addingQuery || editingQuery) &&
{currentTab === 1 &&
{(dataSources && mode ==='create') &&
{ return { name: source.name, value: source.id } }), ...staticDataSources.map(source => { return {name: source.name, value: source.id} }), ]} value={selectedDataSource ? selectedDataSource.id : ''} search={true} onChange={(value) => this.changeDataSource(value) } filterOptions={fuzzySearch} renderOption={this.renderDataSourceOption} placeholder="Select a data source" />
} {selectedDataSource &&
}
} {currentTab === 2 &&

this.optionchanged('successMessage', e.target.value)} placeholder="Query ran successfully" class="form-control" value={this.state.options.successMessage} />

this.optionchanged('notificationDuration', e.target.value)} placeholder={5} class="form-control" value={this.state.options.notificationDuration} />
}
}
) } } export { QueryManager };