2021-05-28 12:31:13 +00:00
|
|
|
import React from 'react';
|
2021-12-30 11:57:02 +00:00
|
|
|
import { toast } from 'react-hot-toast';
|
2021-12-10 03:13:05 +00:00
|
|
|
import {
|
|
|
|
|
getDynamicVariables,
|
|
|
|
|
resolveReferences,
|
|
|
|
|
executeMultilineJS,
|
|
|
|
|
serializeNestedObjectToQueryParams,
|
2022-07-12 11:09:02 +00:00
|
|
|
computeComponentName,
|
2022-12-27 14:40:33 +00:00
|
|
|
generateAppActions,
|
|
|
|
|
loadPyodide,
|
2021-12-10 03:13:05 +00:00
|
|
|
} from '@/_helpers/utils';
|
2021-04-26 05:32:02 +00:00
|
|
|
import { dataqueryService } from '@/_services';
|
2021-05-13 09:54:58 +00:00
|
|
|
import _ from 'lodash';
|
|
|
|
|
import moment from 'moment';
|
2021-05-28 12:31:13 +00:00
|
|
|
import Tooltip from 'react-bootstrap/Tooltip';
|
2022-06-02 06:21:52 +00:00
|
|
|
import { componentTypes } from '@/Editor/WidgetManager/components';
|
2021-11-24 09:33:28 +00:00
|
|
|
import generateCSV from '@/_lib/generate-csv';
|
|
|
|
|
import generateFile from '@/_lib/generate-file';
|
2022-10-27 11:29:43 +00:00
|
|
|
import RunjsIcon from '@/Editor/Icons/runjs.svg';
|
2022-12-22 20:39:57 +00:00
|
|
|
import RunTooljetDbIcon from '@/Editor/Icons/tooljetdb.svg';
|
2022-12-27 14:40:33 +00:00
|
|
|
import RunPyIcon from '@/Editor/Icons/runpy.svg';
|
2022-07-12 11:09:02 +00:00
|
|
|
import { v4 as uuidv4 } from 'uuid';
|
2022-08-06 04:04:07 +00:00
|
|
|
// eslint-disable-next-line import/no-unresolved
|
|
|
|
|
import { allSvgs } from '@tooljet/plugins/client';
|
2022-08-27 16:28:24 +00:00
|
|
|
import urlJoin from 'url-join';
|
2022-12-22 20:39:57 +00:00
|
|
|
import { tooljetDbOperations } from '@/Editor/QueryManager/QueryEditors/TooljetDatabase/operations';
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2022-08-11 12:07:18 +00:00
|
|
|
const ERROR_TYPES = Object.freeze({
|
|
|
|
|
ReferenceError: 'ReferenceError',
|
|
|
|
|
SyntaxError: 'SyntaxError',
|
|
|
|
|
TypeError: 'TypeError',
|
|
|
|
|
URIError: 'URIError',
|
|
|
|
|
RangeError: 'RangeError',
|
|
|
|
|
EvalError: 'EvalError',
|
|
|
|
|
});
|
|
|
|
|
|
2021-06-04 14:51:36 +00:00
|
|
|
export function setStateAsync(_ref, state) {
|
2021-04-30 08:10:57 +00:00
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
_ref.setState(state, resolve);
|
|
|
|
|
});
|
2021-04-26 17:40:43 +00:00
|
|
|
}
|
|
|
|
|
|
2022-01-21 11:12:33 +00:00
|
|
|
export function setCurrentStateAsync(_ref, changes) {
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
_ref.setState((prevState) => {
|
|
|
|
|
return {
|
|
|
|
|
currentState: prevState.currentState,
|
|
|
|
|
...changes,
|
|
|
|
|
};
|
|
|
|
|
}, resolve);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-30 08:10:57 +00:00
|
|
|
export function onComponentOptionsChanged(_ref, component, options) {
|
|
|
|
|
const componentName = component.name;
|
|
|
|
|
const components = _ref.state.currentState.components;
|
|
|
|
|
let componentData = components[componentName];
|
2021-09-21 13:48:28 +00:00
|
|
|
componentData = componentData || {};
|
2021-04-26 17:40:43 +00:00
|
|
|
|
2021-04-30 08:10:57 +00:00
|
|
|
for (const option of options) {
|
|
|
|
|
componentData[option[0]] = option[1];
|
|
|
|
|
}
|
2021-04-26 17:40:43 +00:00
|
|
|
|
2022-03-09 08:21:44 +00:00
|
|
|
return setCurrentStateAsync(_ref, {
|
|
|
|
|
components: { ...components, [componentName]: componentData },
|
2021-04-30 08:10:57 +00:00
|
|
|
});
|
2021-04-26 17:40:43 +00:00
|
|
|
}
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2021-04-30 08:10:57 +00:00
|
|
|
export function onComponentOptionChanged(_ref, component, option_name, value) {
|
|
|
|
|
const componentName = component.name;
|
|
|
|
|
const components = _ref.state.currentState.components;
|
|
|
|
|
let componentData = components[componentName];
|
2021-09-21 13:48:28 +00:00
|
|
|
componentData = componentData || {};
|
2021-04-30 08:10:57 +00:00
|
|
|
componentData[option_name] = value;
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2022-12-22 20:39:57 +00:00
|
|
|
return setCurrentStateAsync(_ref, {
|
|
|
|
|
components: { ...components, [componentName]: componentData },
|
|
|
|
|
});
|
2021-04-26 05:32:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function fetchOAuthToken(authUrl, dataSourceId) {
|
2021-04-30 08:10:57 +00:00
|
|
|
localStorage.setItem('sourceWaitingForOAuth', dataSourceId);
|
|
|
|
|
window.open(authUrl);
|
2021-04-26 05:32:02 +00:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 02:04:02 +00:00
|
|
|
export function addToLocalStorage(object) {
|
|
|
|
|
localStorage.setItem(object['key'], object['value']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getDataFromLocalStorage(key) {
|
|
|
|
|
return localStorage.getItem(key);
|
|
|
|
|
}
|
2022-12-27 14:40:33 +00:00
|
|
|
|
|
|
|
|
async function executeRunPycode(_ref, code, query, editorState, isPreview, mode) {
|
|
|
|
|
const pyodide = await loadPyodide();
|
|
|
|
|
|
|
|
|
|
const evaluatePythonCode = async (pyodide) => {
|
|
|
|
|
let result = {};
|
|
|
|
|
const { currentState } = _ref.state;
|
|
|
|
|
try {
|
|
|
|
|
const appStateVars = currentState['variables'] ?? {};
|
|
|
|
|
|
|
|
|
|
const actions = generateAppActions(_ref, query.id, mode, editorState, isPreview);
|
|
|
|
|
|
|
|
|
|
for (const key of Object.keys(currentState.queries)) {
|
|
|
|
|
currentState.queries[key] = {
|
|
|
|
|
...currentState.queries[key],
|
|
|
|
|
run: () => actions.runQuery(key),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await pyodide.globals.set('components', currentState['components']);
|
|
|
|
|
await pyodide.globals.set('queries', currentState['queries']);
|
|
|
|
|
await pyodide.globals.set('tj_globals', currentState['globals']);
|
|
|
|
|
await pyodide.globals.set('client', currentState['client']);
|
|
|
|
|
await pyodide.globals.set('server', currentState['server']);
|
|
|
|
|
await pyodide.globals.set('variables', appStateVars);
|
|
|
|
|
await pyodide.globals.set('actions', actions);
|
|
|
|
|
|
|
|
|
|
let pyresult = await pyodide.runPythonAsync(code);
|
|
|
|
|
result = await pyresult;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error(err);
|
|
|
|
|
|
|
|
|
|
const errorType = err.message.includes('SyntaxError') ? 'SyntaxError' : 'NameError';
|
|
|
|
|
const error = err.message.split(errorType + ': ')[1];
|
|
|
|
|
const errorMessage = `${errorType} : ${error}`;
|
|
|
|
|
|
|
|
|
|
result = {};
|
|
|
|
|
|
|
|
|
|
result = {
|
|
|
|
|
status: 'failed',
|
|
|
|
|
message: errorMessage,
|
|
|
|
|
description: {
|
|
|
|
|
code: query?.options?.code,
|
|
|
|
|
error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))),
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pyodide.isPyProxy(result) ? result.toJs() : result;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return { data: await evaluatePythonCode(pyodide, code) };
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 08:41:26 +00:00
|
|
|
async function exceutePycode(payload, code, currentState, query, mode) {
|
2022-12-27 14:40:33 +00:00
|
|
|
const pyodide = await loadPyodide();
|
2022-10-27 08:41:26 +00:00
|
|
|
|
|
|
|
|
const evaluatePython = async (pyodide) => {
|
|
|
|
|
let result = {};
|
|
|
|
|
try {
|
2022-10-28 08:20:57 +00:00
|
|
|
//remove the comments from the code
|
|
|
|
|
let codeWithoutComments = code.replace(/#.*$/gm, '');
|
|
|
|
|
codeWithoutComments = codeWithoutComments.replace(/^\s+/g, '');
|
|
|
|
|
const _code = codeWithoutComments.replace('return ', '');
|
|
|
|
|
currentState['variables'] = currentState['variables'] ?? {};
|
2022-10-27 08:41:26 +00:00
|
|
|
const _currentState = JSON.stringify(currentState);
|
2022-10-28 08:20:57 +00:00
|
|
|
|
2022-10-27 08:41:26 +00:00
|
|
|
let execFunction = await pyodide.runPython(`
|
|
|
|
|
from pyodide.ffi import to_js
|
|
|
|
|
import json
|
2022-10-28 08:20:57 +00:00
|
|
|
def exec_code(payload, _currentState):
|
2022-10-27 08:41:26 +00:00
|
|
|
data = json.loads(payload)
|
2022-10-28 08:20:57 +00:00
|
|
|
currentState = json.loads(_currentState)
|
2022-10-27 08:41:26 +00:00
|
|
|
components = currentState['components']
|
|
|
|
|
queries = currentState['queries']
|
|
|
|
|
globals = currentState['globals']
|
|
|
|
|
variables = currentState['variables']
|
|
|
|
|
client = currentState['client']
|
|
|
|
|
server = currentState['server']
|
2022-12-08 12:21:09 +00:00
|
|
|
page = currentState['page']
|
2022-10-27 08:41:26 +00:00
|
|
|
code_to_execute = ${_code}
|
2022-10-28 08:20:57 +00:00
|
|
|
|
2022-10-27 08:41:26 +00:00
|
|
|
try:
|
|
|
|
|
res = to_js(json.dumps(code_to_execute))
|
2022-12-27 14:40:33 +00:00
|
|
|
# convert dictionary to js object
|
2022-10-27 08:41:26 +00:00
|
|
|
return res
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(e)
|
|
|
|
|
return {"error": str(e)}
|
2022-12-22 20:39:57 +00:00
|
|
|
|
2022-10-27 08:41:26 +00:00
|
|
|
exec_code
|
|
|
|
|
`);
|
|
|
|
|
const _data = JSON.stringify(payload);
|
2022-10-28 08:20:57 +00:00
|
|
|
result = execFunction(_data, _currentState);
|
2022-10-27 08:41:26 +00:00
|
|
|
return JSON.parse(result);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error(err);
|
|
|
|
|
|
|
|
|
|
const errorType = err.message.includes('SyntaxError') ? 'SyntaxError' : 'NameError';
|
|
|
|
|
const error = err.message.split(errorType + ': ')[1];
|
|
|
|
|
const errorMessage = `${errorType} : ${error}`;
|
|
|
|
|
result = {};
|
|
|
|
|
if (mode === 'edit') toast.error(errorMessage);
|
|
|
|
|
|
|
|
|
|
result = {
|
|
|
|
|
status: 'failed',
|
2022-12-27 14:40:33 +00:00
|
|
|
message: errorMessage,
|
|
|
|
|
description: {
|
|
|
|
|
error: JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))),
|
2022-10-27 08:41:26 +00:00
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
2022-02-05 02:04:02 +00:00
|
|
|
|
2022-10-27 08:41:26 +00:00
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return await evaluatePython(pyodide, code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function runPythonTransformation(currentState, rawData, transformation, query, mode) {
|
|
|
|
|
const data = rawData;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return await exceutePycode(data, transformation, currentState, query, mode);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.log(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function runTransformation(
|
|
|
|
|
_ref,
|
|
|
|
|
rawData,
|
|
|
|
|
transformation,
|
|
|
|
|
transformationLanguage = 'javascript',
|
|
|
|
|
query,
|
|
|
|
|
mode = 'edit'
|
|
|
|
|
) {
|
2021-04-30 08:10:57 +00:00
|
|
|
const data = rawData;
|
2022-08-11 12:07:18 +00:00
|
|
|
|
2021-04-30 08:10:57 +00:00
|
|
|
let result = [];
|
|
|
|
|
|
2021-09-08 07:00:06 +00:00
|
|
|
const currentState = _ref.state.currentState || {};
|
|
|
|
|
|
2022-10-27 08:41:26 +00:00
|
|
|
if (transformationLanguage === 'python') {
|
|
|
|
|
result = await runPythonTransformation(currentState, data, transformation, query, mode);
|
2022-08-11 12:07:18 +00:00
|
|
|
|
2022-10-27 08:41:26 +00:00
|
|
|
return result;
|
2021-04-30 08:10:57 +00:00
|
|
|
}
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2022-10-27 08:41:26 +00:00
|
|
|
if (transformationLanguage === 'javascript') {
|
|
|
|
|
try {
|
|
|
|
|
const evalFunction = Function(
|
2022-12-08 12:21:09 +00:00
|
|
|
['data', 'moment', '_', 'components', 'queries', 'globals', 'variables', 'page'],
|
2022-10-27 08:41:26 +00:00
|
|
|
transformation
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
result = evalFunction(
|
|
|
|
|
data,
|
|
|
|
|
moment,
|
|
|
|
|
_,
|
|
|
|
|
currentState.components,
|
|
|
|
|
currentState.queries,
|
|
|
|
|
currentState.globals,
|
2022-12-08 12:21:09 +00:00
|
|
|
currentState.variables,
|
|
|
|
|
currentState.page
|
2022-10-27 08:41:26 +00:00
|
|
|
);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
const $error = err.name;
|
|
|
|
|
const $errorMessage = _.has(ERROR_TYPES, $error) ? `${$error} : ${err.message}` : err || 'Unknown error';
|
|
|
|
|
if (mode === 'edit') toast.error($errorMessage);
|
2022-12-22 20:39:57 +00:00
|
|
|
result = {
|
|
|
|
|
message: err.stack.split('\n')[0],
|
|
|
|
|
status: 'failed',
|
|
|
|
|
data: data,
|
|
|
|
|
};
|
2022-10-27 08:41:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2021-04-26 05:32:02 +00:00
|
|
|
}
|
|
|
|
|
|
2022-02-17 07:40:20 +00:00
|
|
|
export async function executeActionsForEventId(_ref, eventId, component, mode, customVariables) {
|
2022-12-08 12:21:09 +00:00
|
|
|
const events = component?.definition?.events || [];
|
2021-09-21 13:48:28 +00:00
|
|
|
const filteredEvents = events.filter((event) => event.eventId === eventId);
|
2021-08-24 06:51:09 +00:00
|
|
|
|
2021-09-21 13:48:28 +00:00
|
|
|
for (const event of filteredEvents) {
|
2022-02-17 07:40:20 +00:00
|
|
|
await executeAction(_ref, event, mode, customVariables); // skipcq: JS-0032
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
2021-08-24 06:51:09 +00:00
|
|
|
}
|
|
|
|
|
|
2021-06-28 06:36:23 +00:00
|
|
|
export function onComponentClick(_ref, id, component, mode = 'edit') {
|
2021-08-24 06:51:09 +00:00
|
|
|
executeActionsForEventId(_ref, 'onClick', component, mode);
|
2021-04-26 05:32:02 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-27 05:33:30 +00:00
|
|
|
export function onQueryConfirmOrCancel(_ref, queryConfirmationData, isConfirm = false, mode = 'edit') {
|
|
|
|
|
const filtertedQueryConfirmation = _ref.state?.queryConfirmationList.filter(
|
|
|
|
|
(query) => query.queryId !== queryConfirmationData.queryId
|
|
|
|
|
);
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2021-04-30 08:10:57 +00:00
|
|
|
_ref.setState({
|
2022-09-27 05:33:30 +00:00
|
|
|
queryConfirmationList: filtertedQueryConfirmation,
|
2021-04-30 08:10:57 +00:00
|
|
|
});
|
2022-09-27 05:33:30 +00:00
|
|
|
isConfirm && runQuery(_ref, queryConfirmationData.queryId, queryConfirmationData.queryName, true, mode);
|
2021-04-26 05:32:02 +00:00
|
|
|
}
|
|
|
|
|
|
2022-07-12 07:38:36 +00:00
|
|
|
export async function copyToClipboard(text) {
|
2021-06-11 13:21:55 +00:00
|
|
|
try {
|
|
|
|
|
await navigator.clipboard.writeText(text);
|
2021-12-10 23:11:24 +00:00
|
|
|
toast.success('Copied to clipboard!');
|
2021-06-11 13:21:55 +00:00
|
|
|
} catch (err) {
|
|
|
|
|
console.log('Failed to copy!', err);
|
|
|
|
|
}
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
2021-06-11 13:21:55 +00:00
|
|
|
|
2022-01-20 13:35:34 +00:00
|
|
|
function showModal(_ref, modal, show) {
|
2022-01-28 14:53:28 +00:00
|
|
|
const modalId = modal?.id ?? modal;
|
2021-10-12 09:44:42 +00:00
|
|
|
if (_.isEmpty(modalId)) {
|
|
|
|
|
console.log('No modal is associated with this event.');
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 12:21:09 +00:00
|
|
|
const modalMeta = _ref.state.appDefinition.pages[_ref.state.currentPageId].components[modalId];
|
2021-08-25 07:53:52 +00:00
|
|
|
const newState = {
|
|
|
|
|
currentState: {
|
|
|
|
|
..._ref.state.currentState,
|
|
|
|
|
components: {
|
|
|
|
|
..._ref.state.currentState.components,
|
|
|
|
|
[modalMeta.component.name]: {
|
|
|
|
|
..._ref.state.currentState.components[modalMeta.component.name],
|
2021-09-21 13:48:28 +00:00
|
|
|
show: show,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
_ref.setState(newState);
|
2021-08-25 07:53:52 +00:00
|
|
|
|
2021-10-12 09:44:42 +00:00
|
|
|
return Promise.resolve();
|
2021-08-25 07:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
2022-03-31 13:20:33 +00:00
|
|
|
function logoutAction(_ref) {
|
|
|
|
|
localStorage.clear();
|
|
|
|
|
_ref.props.history.push('/login');
|
|
|
|
|
window.location.href = '/login';
|
|
|
|
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
2022-06-16 09:39:26 +00:00
|
|
|
export const executeAction = (_ref, event, mode, customVariables) => {
|
2022-02-17 07:40:20 +00:00
|
|
|
console.log('nopski', customVariables);
|
2021-04-30 08:10:57 +00:00
|
|
|
if (event) {
|
2021-09-22 05:13:54 +00:00
|
|
|
switch (event.actionId) {
|
|
|
|
|
case 'show-alert': {
|
2022-02-17 07:40:20 +00:00
|
|
|
const message = resolveReferences(event.message, _ref.state.currentState, undefined, customVariables);
|
2021-12-10 23:11:24 +00:00
|
|
|
switch (event.alertType) {
|
|
|
|
|
case 'success':
|
|
|
|
|
case 'error':
|
|
|
|
|
toast[event.alertType](message);
|
|
|
|
|
break;
|
|
|
|
|
case 'info':
|
|
|
|
|
toast(message);
|
|
|
|
|
break;
|
|
|
|
|
case 'warning':
|
|
|
|
|
toast(message, {
|
|
|
|
|
icon: '⚠️',
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-10-12 09:44:42 +00:00
|
|
|
return Promise.resolve();
|
2021-09-22 05:13:54 +00:00
|
|
|
}
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
case 'run-query': {
|
|
|
|
|
const { queryId, queryName } = event;
|
2022-09-27 05:33:30 +00:00
|
|
|
return runQuery(_ref, queryId, queryName, undefined, mode);
|
2021-09-22 05:13:54 +00:00
|
|
|
}
|
2022-03-31 13:20:33 +00:00
|
|
|
case 'logout': {
|
|
|
|
|
return logoutAction(_ref);
|
|
|
|
|
}
|
2021-08-30 15:39:12 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
case 'open-webpage': {
|
2022-02-17 07:40:20 +00:00
|
|
|
const url = resolveReferences(event.url, _ref.state.currentState, undefined, customVariables);
|
2021-09-22 05:13:54 +00:00
|
|
|
window.open(url, '_blank');
|
2021-10-12 09:44:42 +00:00
|
|
|
return Promise.resolve();
|
2021-09-22 05:13:54 +00:00
|
|
|
}
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
case 'go-to-app': {
|
2022-02-17 07:40:20 +00:00
|
|
|
const slug = resolveReferences(event.slug, _ref.state.currentState, undefined, customVariables);
|
2021-09-22 05:13:54 +00:00
|
|
|
const queryParams = event.queryParams?.reduce(
|
|
|
|
|
(result, queryParam) => ({
|
|
|
|
|
...result,
|
|
|
|
|
...{
|
|
|
|
|
[resolveReferences(queryParam[0], _ref.state.currentState)]: resolveReferences(
|
|
|
|
|
queryParam[1],
|
2022-02-17 07:40:20 +00:00
|
|
|
_ref.state.currentState,
|
|
|
|
|
undefined,
|
|
|
|
|
customVariables
|
2021-09-22 05:13:54 +00:00
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
{}
|
|
|
|
|
);
|
2021-09-21 13:48:28 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
let url = `/applications/${slug}`;
|
2021-08-26 15:03:59 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
if (queryParams) {
|
|
|
|
|
const queryPart = serializeNestedObjectToQueryParams(queryParams);
|
2021-06-28 06:36:23 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
if (queryPart.length > 0) url = url + `?${queryPart}`;
|
|
|
|
|
}
|
2021-06-28 06:36:23 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
if (mode === 'view') {
|
|
|
|
|
_ref.props.history.push(url);
|
2021-12-30 14:24:06 +00:00
|
|
|
_ref.props.history.go();
|
2021-09-22 05:13:54 +00:00
|
|
|
} else {
|
|
|
|
|
if (confirm('The app will be opened in a new tab as the action is triggered from the editor.')) {
|
2022-09-26 13:27:45 +00:00
|
|
|
window.open(urlJoin(window.public_config?.TOOLJET_HOST, url));
|
2021-09-22 05:13:54 +00:00
|
|
|
}
|
2021-06-28 06:36:23 +00:00
|
|
|
}
|
2021-10-12 09:44:42 +00:00
|
|
|
return Promise.resolve();
|
2021-06-28 06:36:23 +00:00
|
|
|
}
|
|
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
case 'show-modal':
|
|
|
|
|
return showModal(_ref, event.modal, true);
|
2021-05-09 18:06:11 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
case 'close-modal':
|
|
|
|
|
return showModal(_ref, event.modal, false);
|
2021-06-11 13:21:55 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
case 'copy-to-clipboard': {
|
2022-02-17 07:40:20 +00:00
|
|
|
const contentToCopy = resolveReferences(
|
|
|
|
|
event.contentToCopy,
|
|
|
|
|
_ref.state.currentState,
|
|
|
|
|
undefined,
|
|
|
|
|
customVariables
|
|
|
|
|
);
|
2021-09-22 05:13:54 +00:00
|
|
|
copyToClipboard(contentToCopy);
|
2021-08-24 06:51:09 +00:00
|
|
|
|
2021-10-12 09:44:42 +00:00
|
|
|
return Promise.resolve();
|
2021-09-22 05:13:54 +00:00
|
|
|
}
|
2021-10-25 16:54:21 +00:00
|
|
|
|
|
|
|
|
case 'set-localstorage-value': {
|
2022-02-17 07:40:20 +00:00
|
|
|
const key = resolveReferences(event.key, _ref.state.currentState, undefined, customVariables);
|
|
|
|
|
const value = resolveReferences(event.value, _ref.state.currentState, undefined, customVariables);
|
2021-10-25 16:54:21 +00:00
|
|
|
localStorage.setItem(key, value);
|
2021-11-24 09:33:28 +00:00
|
|
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'generate-file': {
|
|
|
|
|
// const fileType = event.fileType;
|
2022-02-17 07:40:20 +00:00
|
|
|
const data = resolveReferences(event.data, _ref.state.currentState, undefined, customVariables) ?? [];
|
|
|
|
|
const fileName =
|
|
|
|
|
resolveReferences(event.fileName, _ref.state.currentState, undefined, customVariables) ?? 'data.txt';
|
2022-04-04 16:57:35 +00:00
|
|
|
const fileType =
|
|
|
|
|
resolveReferences(event.fileType, _ref.state.currentState, undefined, customVariables) ?? 'csv';
|
|
|
|
|
const fileData = {
|
|
|
|
|
csv: generateCSV,
|
|
|
|
|
plaintext: (plaintext) => plaintext,
|
|
|
|
|
}[fileType](data);
|
2022-10-31 08:49:34 +00:00
|
|
|
generateFile(fileName, fileData, fileType);
|
2021-11-24 09:33:28 +00:00
|
|
|
return Promise.resolve();
|
2021-10-25 16:54:21 +00:00
|
|
|
}
|
2022-01-20 13:35:34 +00:00
|
|
|
|
|
|
|
|
case 'set-table-page': {
|
|
|
|
|
setTablePageIndex(_ref, event.table, event.pageIndex);
|
2022-01-31 03:36:34 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'set-custom-variable': {
|
2022-02-17 07:40:20 +00:00
|
|
|
const key = resolveReferences(event.key, _ref.state.currentState, undefined, customVariables);
|
|
|
|
|
const value = resolveReferences(event.value, _ref.state.currentState, undefined, customVariables);
|
2022-04-13 10:12:00 +00:00
|
|
|
const customAppVariables = { ..._ref.state.currentState.variables };
|
|
|
|
|
customAppVariables[key] = value;
|
2022-01-31 03:36:34 +00:00
|
|
|
|
|
|
|
|
return _ref.setState({
|
|
|
|
|
currentState: {
|
|
|
|
|
..._ref.state.currentState,
|
2022-04-13 10:12:00 +00:00
|
|
|
variables: customAppVariables,
|
2022-01-31 03:36:34 +00:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'unset-custom-variable': {
|
2022-02-17 07:40:20 +00:00
|
|
|
const key = resolveReferences(event.key, _ref.state.currentState, undefined, customVariables);
|
2022-04-13 10:12:00 +00:00
|
|
|
const customAppVariables = { ..._ref.state.currentState.variables };
|
|
|
|
|
delete customAppVariables[key];
|
2022-01-31 03:36:34 +00:00
|
|
|
|
|
|
|
|
return _ref.setState({
|
|
|
|
|
currentState: {
|
|
|
|
|
..._ref.state.currentState,
|
2022-04-13 10:12:00 +00:00
|
|
|
variables: customAppVariables,
|
2022-01-31 03:36:34 +00:00
|
|
|
},
|
|
|
|
|
});
|
2022-01-20 13:35:34 +00:00
|
|
|
}
|
2022-07-01 11:24:34 +00:00
|
|
|
|
2022-12-08 12:21:09 +00:00
|
|
|
case 'set-page-variable': {
|
|
|
|
|
const key = resolveReferences(event.key, _ref.state.currentState, undefined, customVariables);
|
|
|
|
|
const value = resolveReferences(event.value, _ref.state.currentState, undefined, customVariables);
|
2022-12-22 20:39:57 +00:00
|
|
|
const customPageVariables = {
|
|
|
|
|
..._ref.state.currentState.page.variables,
|
|
|
|
|
[key]: value,
|
|
|
|
|
};
|
2022-12-08 12:21:09 +00:00
|
|
|
|
|
|
|
|
return _ref.setState({
|
|
|
|
|
currentState: {
|
|
|
|
|
..._ref.state.currentState,
|
|
|
|
|
page: {
|
|
|
|
|
..._ref.state.currentState.page,
|
|
|
|
|
variables: customPageVariables,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'unset-page-variable': {
|
|
|
|
|
const key = resolveReferences(event.key, _ref.state.currentState, undefined, customVariables);
|
|
|
|
|
const customPageVariables = _.omit(_ref.state.currentState.page.variables, key);
|
|
|
|
|
|
|
|
|
|
return _ref.setState({
|
|
|
|
|
currentState: {
|
|
|
|
|
..._ref.state.currentState,
|
|
|
|
|
page: {
|
|
|
|
|
..._ref.state.currentState.page,
|
|
|
|
|
variables: customPageVariables,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-01 11:24:34 +00:00
|
|
|
case 'control-component': {
|
|
|
|
|
const component = Object.values(_ref.state.currentState?.components ?? {}).filter(
|
|
|
|
|
(component) => component.id === event.componentId
|
|
|
|
|
)[0];
|
|
|
|
|
const action = component[event.componentSpecificActionHandle];
|
|
|
|
|
const actionArguments = _.map(event.componentSpecificActionParams, (param) => ({
|
|
|
|
|
...param,
|
|
|
|
|
value: resolveReferences(param.value, _ref.state.currentState, undefined, customVariables),
|
|
|
|
|
}));
|
|
|
|
|
const actionPromise = action(...actionArguments.map((argument) => argument.value));
|
|
|
|
|
return actionPromise ?? Promise.resolve();
|
|
|
|
|
}
|
2022-12-08 12:21:09 +00:00
|
|
|
|
|
|
|
|
case 'switch-page': {
|
|
|
|
|
_ref.switchPage(
|
|
|
|
|
event.pageId,
|
|
|
|
|
resolveReferences(event.queryParams, _ref.state.currentState, [], customVariables)
|
|
|
|
|
);
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
2021-06-11 13:21:55 +00:00
|
|
|
}
|
2021-04-30 08:10:57 +00:00
|
|
|
}
|
2022-06-16 09:39:26 +00:00
|
|
|
};
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2021-08-24 06:51:09 +00:00
|
|
|
export async function onEvent(_ref, eventName, options, mode = 'edit') {
|
2021-04-30 08:10:57 +00:00
|
|
|
let _self = _ref;
|
2021-05-02 13:45:13 +00:00
|
|
|
console.log('Event: ', eventName);
|
2021-04-30 08:10:57 +00:00
|
|
|
|
2022-02-17 07:40:20 +00:00
|
|
|
const { customVariables } = options;
|
|
|
|
|
|
2022-12-08 12:21:09 +00:00
|
|
|
if (eventName === 'onPageLoad') {
|
|
|
|
|
await executeActionsForEventId(_ref, 'onPageLoad', { definition: { events: [options] } }, mode, customVariables);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 09:39:09 +00:00
|
|
|
if (eventName === 'onTrigger') {
|
|
|
|
|
const { component, queryId, queryName } = options;
|
|
|
|
|
_self.setState(
|
|
|
|
|
{
|
|
|
|
|
currentState: {
|
|
|
|
|
..._self.state.currentState,
|
|
|
|
|
components: {
|
|
|
|
|
..._self.state.currentState.components,
|
|
|
|
|
[component.name]: {
|
|
|
|
|
..._self.state.currentState.components[component.name],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
() => {
|
|
|
|
|
runQuery(_ref, queryId, queryName, true, mode);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-04 08:53:50 +00:00
|
|
|
if (eventName === 'onCalendarEventSelect') {
|
|
|
|
|
const { component, calendarEvent } = options;
|
|
|
|
|
_self.setState(
|
|
|
|
|
{
|
|
|
|
|
currentState: {
|
|
|
|
|
..._self.state.currentState,
|
|
|
|
|
components: {
|
|
|
|
|
..._self.state.currentState.components,
|
|
|
|
|
[component.name]: {
|
|
|
|
|
..._self.state.currentState.components[component.name],
|
|
|
|
|
selectedEvent: { ...calendarEvent },
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
() => {
|
2022-02-17 07:40:20 +00:00
|
|
|
executeActionsForEventId(_ref, 'onCalendarEventSelect', component, mode, customVariables);
|
2021-11-04 08:53:50 +00:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eventName === 'onCalendarSlotSelect') {
|
|
|
|
|
const { component, selectedSlots } = options;
|
|
|
|
|
_self.setState(
|
|
|
|
|
{
|
|
|
|
|
currentState: {
|
|
|
|
|
..._self.state.currentState,
|
|
|
|
|
components: {
|
|
|
|
|
..._self.state.currentState.components,
|
|
|
|
|
[component.name]: {
|
|
|
|
|
..._self.state.currentState.components[component.name],
|
|
|
|
|
selectedSlots,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
() => {
|
2022-02-17 07:40:20 +00:00
|
|
|
executeActionsForEventId(_ref, 'onCalendarSlotSelect', component, mode, customVariables);
|
2021-11-04 08:53:50 +00:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-30 08:10:57 +00:00
|
|
|
if (eventName === 'onTableActionButtonClicked') {
|
2021-10-05 14:06:30 +00:00
|
|
|
const { component, data, action, rowId } = options;
|
2021-09-21 13:48:28 +00:00
|
|
|
_self.setState(
|
|
|
|
|
{
|
|
|
|
|
currentState: {
|
|
|
|
|
..._self.state.currentState,
|
|
|
|
|
components: {
|
|
|
|
|
..._self.state.currentState.components,
|
|
|
|
|
[component.name]: {
|
|
|
|
|
..._self.state.currentState.components[component.name],
|
|
|
|
|
selectedRow: data,
|
2021-10-05 14:06:30 +00:00
|
|
|
selectedRowId: rowId,
|
2021-09-21 13:48:28 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2021-11-08 07:28:05 +00:00
|
|
|
async () => {
|
|
|
|
|
if (action && action.events) {
|
|
|
|
|
for (const event of action.events) {
|
|
|
|
|
if (event.actionId) {
|
|
|
|
|
// the event param uses a hacky workaround for using same format used by event manager ( multiple handlers )
|
2022-02-17 07:40:20 +00:00
|
|
|
await executeAction(_self, { ...event, ...event.options }, mode, customVariables);
|
2021-11-08 07:28:05 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
console.log('No action is associated with this event');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (eventName === 'OnTableToggleCellChanged') {
|
|
|
|
|
const { component, column, rowId, row } = options;
|
|
|
|
|
_self.setState(
|
|
|
|
|
{
|
|
|
|
|
currentState: {
|
|
|
|
|
..._self.state.currentState,
|
|
|
|
|
components: {
|
|
|
|
|
..._self.state.currentState.components,
|
|
|
|
|
[component.name]: {
|
|
|
|
|
..._self.state.currentState.components[component.name],
|
|
|
|
|
selectedRow: row,
|
|
|
|
|
selectedRowId: rowId,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
async () => {
|
|
|
|
|
if (column && column.events) {
|
|
|
|
|
for (const event of column.events) {
|
2021-09-21 13:48:28 +00:00
|
|
|
if (event.actionId) {
|
|
|
|
|
// the event param uses a hacky workaround for using same format used by event manager ( multiple handlers )
|
2022-02-17 07:40:20 +00:00
|
|
|
await executeAction(_self, { ...event, ...event.options }, mode, customVariables);
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
2021-11-08 07:28:05 +00:00
|
|
|
}
|
2021-09-21 13:48:28 +00:00
|
|
|
} else {
|
|
|
|
|
console.log('No action is associated with this event');
|
2021-04-30 08:10:57 +00:00
|
|
|
}
|
|
|
|
|
}
|
2021-09-21 13:48:28 +00:00
|
|
|
);
|
2021-04-30 08:10:57 +00:00
|
|
|
}
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2021-09-21 13:48:28 +00:00
|
|
|
if (
|
|
|
|
|
[
|
|
|
|
|
'onDetect',
|
|
|
|
|
'onCheck',
|
|
|
|
|
'onUnCheck',
|
|
|
|
|
'onBoundsChange',
|
|
|
|
|
'onCreateMarker',
|
|
|
|
|
'onMarkerClick',
|
|
|
|
|
'onPageChanged',
|
|
|
|
|
'onSearch',
|
|
|
|
|
'onChange',
|
2022-08-08 11:07:12 +00:00
|
|
|
'onEnterPressed',
|
2021-09-21 13:48:28 +00:00
|
|
|
'onSelectionChange',
|
|
|
|
|
'onSelect',
|
2021-10-20 02:20:45 +00:00
|
|
|
'onClick',
|
2022-09-27 05:42:14 +00:00
|
|
|
'onHover',
|
2021-11-04 05:41:10 +00:00
|
|
|
'onFileSelected',
|
2022-08-03 12:41:20 +00:00
|
|
|
'onFileLoaded',
|
|
|
|
|
'onFileDeselected',
|
2022-01-03 03:48:56 +00:00
|
|
|
'onStart',
|
|
|
|
|
'onResume',
|
|
|
|
|
'onReset',
|
|
|
|
|
'onPause',
|
|
|
|
|
'onCountDownFinish',
|
2021-12-29 17:09:27 +00:00
|
|
|
'onCalendarNavigate',
|
|
|
|
|
'onCalendarViewChange',
|
2021-12-29 13:32:41 +00:00
|
|
|
'onSearchTextChanged',
|
2022-01-18 05:49:55 +00:00
|
|
|
'onPageChange',
|
2022-06-14 05:36:36 +00:00
|
|
|
'onCardAdded',
|
|
|
|
|
'onCardRemoved',
|
|
|
|
|
'onCardMoved',
|
|
|
|
|
'onCardSelected',
|
|
|
|
|
'onCardUpdated',
|
2022-06-08 06:50:51 +00:00
|
|
|
'onTabSwitch',
|
2022-09-28 12:21:09 +00:00
|
|
|
'onFocus',
|
|
|
|
|
'onBlur',
|
2022-09-26 10:16:21 +00:00
|
|
|
'onOpen',
|
|
|
|
|
'onClose',
|
2022-09-21 10:53:02 +00:00
|
|
|
'onRowClicked',
|
2022-10-13 08:55:47 +00:00
|
|
|
'onCancelChanges',
|
2022-10-06 06:20:53 +00:00
|
|
|
'onSort',
|
2022-10-06 06:17:33 +00:00
|
|
|
'onCellValueChanged',
|
2022-10-06 06:12:18 +00:00
|
|
|
'onFilterChanged',
|
2022-10-13 09:46:37 +00:00
|
|
|
'onRowHovered',
|
2022-12-08 09:11:02 +00:00
|
|
|
'onSubmit',
|
|
|
|
|
'onInvalid',
|
2021-09-21 13:48:28 +00:00
|
|
|
].includes(eventName)
|
|
|
|
|
) {
|
2021-04-30 08:10:57 +00:00
|
|
|
const { component } = options;
|
2022-02-17 07:40:20 +00:00
|
|
|
executeActionsForEventId(_ref, eventName, component, mode, customVariables);
|
2021-08-18 16:45:43 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-30 08:10:57 +00:00
|
|
|
if (eventName === 'onBulkUpdate') {
|
2021-08-24 06:51:09 +00:00
|
|
|
onComponentOptionChanged(_self, options.component, 'isSavingChanges', true);
|
2022-02-17 07:40:20 +00:00
|
|
|
await executeActionsForEventId(_self, eventName, options.component, mode, customVariables);
|
2021-08-24 06:51:09 +00:00
|
|
|
onComponentOptionChanged(_self, options.component, 'isSavingChanges', false);
|
2021-04-30 08:10:57 +00:00
|
|
|
}
|
2021-09-06 14:40:51 +00:00
|
|
|
|
|
|
|
|
if (['onDataQuerySuccess', 'onDataQueryFailure'].includes(eventName)) {
|
2022-02-17 07:40:20 +00:00
|
|
|
await executeActionsForEventId(_self, eventName, options, mode, customVariables);
|
2021-09-06 14:40:51 +00:00
|
|
|
}
|
2021-04-30 08:10:57 +00:00
|
|
|
}
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2022-02-23 04:18:05 +00:00
|
|
|
export function getQueryVariables(options, state) {
|
2021-05-18 13:57:54 +00:00
|
|
|
let queryVariables = {};
|
2021-09-22 05:13:54 +00:00
|
|
|
const optionsType = typeof options;
|
|
|
|
|
switch (optionsType) {
|
|
|
|
|
case 'string': {
|
2022-02-25 14:34:05 +00:00
|
|
|
options = options.replace(/\n/g, ' ');
|
2021-09-22 05:13:54 +00:00
|
|
|
const dynamicVariables = getDynamicVariables(options) || [];
|
|
|
|
|
dynamicVariables.forEach((variable) => {
|
|
|
|
|
queryVariables[variable] = resolveReferences(variable, state);
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-05-18 13:57:54 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
case 'object': {
|
|
|
|
|
if (Array.isArray(options)) {
|
|
|
|
|
options.forEach((element) => {
|
|
|
|
|
_.merge(queryVariables, getQueryVariables(element, state));
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
Object.keys(options || {}).forEach((key) => {
|
|
|
|
|
_.merge(queryVariables, getQueryVariables(options[key], state));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-05-18 13:57:54 +00:00
|
|
|
|
2021-09-22 05:13:54 +00:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-05-18 13:57:54 +00:00
|
|
|
return queryVariables;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-08 13:08:55 +00:00
|
|
|
export function previewQuery(_ref, query, editorState, calledFromQuery = false) {
|
2021-05-30 14:05:10 +00:00
|
|
|
const options = getQueryVariables(query.options, _ref.props.currentState);
|
2021-05-22 11:29:27 +00:00
|
|
|
|
|
|
|
|
_ref.setState({ previewLoading: true });
|
|
|
|
|
|
|
|
|
|
return new Promise(function (resolve, reject) {
|
2021-12-08 07:33:08 +00:00
|
|
|
let queryExecutionPromise = null;
|
|
|
|
|
if (query.kind === 'runjs') {
|
2022-12-29 07:49:04 +00:00
|
|
|
queryExecutionPromise = executeMultilineJS(_ref, query.options.code, editorState, query?.id, true);
|
2022-12-22 20:39:57 +00:00
|
|
|
} else if (query.kind === 'tooljetdb') {
|
|
|
|
|
const { organization_id } = JSON.parse(localStorage.getItem('currentUser'));
|
|
|
|
|
queryExecutionPromise = tooljetDbOperations.perform(query.options, organization_id, _ref.state.currentState);
|
2022-12-27 14:40:33 +00:00
|
|
|
} else if (query.kind === 'runpy') {
|
|
|
|
|
queryExecutionPromise = executeRunPycode(_ref, query.options.code, query, editorState, true, 'edit');
|
2021-12-08 07:33:08 +00:00
|
|
|
} else {
|
2022-12-15 10:31:10 +00:00
|
|
|
queryExecutionPromise = dataqueryService.preview(query, options, editorState?.state?.editingVersion?.id);
|
2021-12-08 07:33:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
queryExecutionPromise
|
2022-10-27 08:41:26 +00:00
|
|
|
.then(async (data) => {
|
2021-09-21 13:48:28 +00:00
|
|
|
let finalData = data.data;
|
2021-05-31 17:04:45 +00:00
|
|
|
|
2021-09-21 13:48:28 +00:00
|
|
|
if (query.options.enableTransformation) {
|
2022-10-27 08:41:26 +00:00
|
|
|
finalData = await runTransformation(
|
|
|
|
|
_ref,
|
|
|
|
|
finalData,
|
|
|
|
|
query.options.transformation,
|
|
|
|
|
query.options.transformationLanguage,
|
|
|
|
|
query,
|
|
|
|
|
'edit'
|
|
|
|
|
);
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
2021-05-31 17:04:45 +00:00
|
|
|
|
2022-06-16 09:39:26 +00:00
|
|
|
if (calledFromQuery) {
|
|
|
|
|
_ref.setState({ previewLoading: false });
|
|
|
|
|
} else {
|
|
|
|
|
_ref.setState({ previewLoading: false, queryPreviewData: finalData });
|
|
|
|
|
}
|
2023-01-09 13:25:51 +00:00
|
|
|
|
2022-12-27 14:40:33 +00:00
|
|
|
const queryStatus =
|
|
|
|
|
query.kind === 'tooljetdb'
|
|
|
|
|
? data.statusText
|
|
|
|
|
: query.kind === 'runpy'
|
2023-01-03 03:01:47 +00:00
|
|
|
? data?.data?.status ?? 'ok'
|
|
|
|
|
: data.status;
|
2022-12-22 20:39:57 +00:00
|
|
|
switch (queryStatus) {
|
2023-01-09 13:25:51 +00:00
|
|
|
case 'Bad Request':
|
2021-09-22 05:13:54 +00:00
|
|
|
case 'failed': {
|
2023-01-19 16:17:20 +00:00
|
|
|
const err = query.kind == 'tooljetdb' ? data?.error || data : _.isEmpty(data.data) ? data : data.data;
|
2022-12-27 14:40:33 +00:00
|
|
|
toast.error(`${err.message}`);
|
2021-09-22 05:13:54 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'needs_oauth': {
|
2021-09-21 13:48:28 +00:00
|
|
|
const url = data.data.auth_url; // Backend generates and return sthe auth url
|
|
|
|
|
fetchOAuthToken(url, query.data_source_id);
|
2021-09-22 05:13:54 +00:00
|
|
|
break;
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
2022-12-22 20:39:57 +00:00
|
|
|
case 'ok':
|
|
|
|
|
case 'OK':
|
|
|
|
|
case 'Created':
|
|
|
|
|
case 'Accepted':
|
|
|
|
|
case 'No Content': {
|
2021-12-10 23:11:24 +00:00
|
|
|
toast(`Query completed.`, {
|
|
|
|
|
icon: '🚀',
|
2021-09-21 13:48:28 +00:00
|
|
|
});
|
2021-09-22 05:13:54 +00:00
|
|
|
break;
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
2021-07-25 17:32:36 +00:00
|
|
|
}
|
2021-07-17 07:36:21 +00:00
|
|
|
|
2022-06-16 09:39:26 +00:00
|
|
|
resolve({ status: data.status, data: finalData });
|
2021-09-21 13:48:28 +00:00
|
|
|
})
|
|
|
|
|
.catch(({ error, data }) => {
|
|
|
|
|
_ref.setState({ previewLoading: false, queryPreviewData: data });
|
2021-12-10 23:11:24 +00:00
|
|
|
toast.error(error);
|
2021-09-21 13:48:28 +00:00
|
|
|
reject({ error, data });
|
|
|
|
|
});
|
2021-05-22 11:29:27 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-16 10:38:36 +00:00
|
|
|
export function runQuery(_ref, queryId, queryName, confirmed = undefined, mode = 'edit') {
|
2021-09-21 13:48:28 +00:00
|
|
|
const query = _ref.state.app.data_queries.find((query) => query.id === queryId);
|
2021-04-30 08:10:57 +00:00
|
|
|
let dataQuery = {};
|
|
|
|
|
|
|
|
|
|
if (query) {
|
|
|
|
|
dataQuery = JSON.parse(JSON.stringify(query));
|
|
|
|
|
} else {
|
2021-12-10 23:11:24 +00:00
|
|
|
toast.error('No query has been associated with the action.');
|
2021-04-30 08:10:57 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-18 13:57:54 +00:00
|
|
|
const options = getQueryVariables(dataQuery.options, _ref.state.currentState);
|
2021-04-30 08:10:57 +00:00
|
|
|
|
2021-09-29 09:30:27 +00:00
|
|
|
if (dataQuery.options.requestConfirmation) {
|
2022-09-27 05:33:30 +00:00
|
|
|
const queryConfirmationList = _ref.state?.queryConfirmationList ? [..._ref.state?.queryConfirmationList] : [];
|
|
|
|
|
const queryConfirmation = {
|
|
|
|
|
queryId,
|
|
|
|
|
queryName,
|
|
|
|
|
};
|
|
|
|
|
if (!queryConfirmationList.some((query) => queryId === query.queryId)) {
|
|
|
|
|
queryConfirmationList.push(queryConfirmation);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-30 08:10:57 +00:00
|
|
|
if (confirmed === undefined) {
|
|
|
|
|
_ref.setState({
|
2022-09-27 05:33:30 +00:00
|
|
|
queryConfirmationList,
|
2021-04-30 08:10:57 +00:00
|
|
|
});
|
|
|
|
|
return;
|
2021-04-26 05:32:02 +00:00
|
|
|
}
|
2021-04-30 08:10:57 +00:00
|
|
|
}
|
|
|
|
|
const newState = {
|
|
|
|
|
..._ref.state.currentState,
|
|
|
|
|
queries: {
|
|
|
|
|
..._ref.state.currentState.queries,
|
|
|
|
|
[queryName]: {
|
|
|
|
|
..._ref.state.currentState.queries[queryName],
|
2021-05-02 13:45:13 +00:00
|
|
|
isLoading: true,
|
|
|
|
|
data: [],
|
2021-09-21 13:48:28 +00:00
|
|
|
rawData: [],
|
|
|
|
|
},
|
2021-08-27 06:35:53 +00:00
|
|
|
},
|
2021-09-21 13:48:28 +00:00
|
|
|
errors: {},
|
2021-04-30 08:10:57 +00:00
|
|
|
};
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2021-04-30 08:10:57 +00:00
|
|
|
let _self = _ref;
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2021-12-30 11:57:02 +00:00
|
|
|
// eslint-disable-next-line no-unused-vars
|
2021-04-30 08:10:57 +00:00
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
|
|
_self.setState({ currentState: newState }, () => {
|
2021-12-08 07:33:08 +00:00
|
|
|
let queryExecutionPromise = null;
|
|
|
|
|
if (query.kind === 'runjs') {
|
2022-12-29 07:49:04 +00:00
|
|
|
queryExecutionPromise = executeMultilineJS(_self, query.options.code, _ref, query?.id, false, confirmed, mode);
|
2022-12-27 14:40:33 +00:00
|
|
|
} else if (query.kind === 'runpy') {
|
|
|
|
|
queryExecutionPromise = executeRunPycode(_self, query.options.code, query, _ref, false, mode);
|
2022-12-22 20:39:57 +00:00
|
|
|
} else if (query.kind === 'tooljetdb') {
|
|
|
|
|
const { organization_id } = JSON.parse(localStorage.getItem('currentUser'));
|
|
|
|
|
queryExecutionPromise = tooljetDbOperations.perform(query.options, organization_id, _self.state.currentState);
|
2021-12-08 07:33:08 +00:00
|
|
|
} else {
|
2021-12-10 03:13:05 +00:00
|
|
|
queryExecutionPromise = dataqueryService.run(queryId, options);
|
2021-12-08 07:33:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
queryExecutionPromise
|
2022-10-27 08:41:26 +00:00
|
|
|
.then(async (data) => {
|
2021-09-21 13:48:28 +00:00
|
|
|
if (data.status === 'needs_oauth') {
|
|
|
|
|
const url = data.data.auth_url; // Backend generates and return sthe auth url
|
2022-09-19 14:57:37 +00:00
|
|
|
fetchOAuthToken(url, dataQuery['data_source_id'] || dataQuery['dataSourceId']);
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2023-01-09 13:25:51 +00:00
|
|
|
const promiseStatus =
|
|
|
|
|
query.kind === 'tooljetdb'
|
|
|
|
|
? data.statusText
|
|
|
|
|
: query.kind === 'runpy'
|
|
|
|
|
? data?.data?.status ?? 'ok'
|
|
|
|
|
: data.status;
|
|
|
|
|
|
|
|
|
|
if (promiseStatus === 'failed' || promiseStatus === 'Bad Request') {
|
2022-12-27 14:40:33 +00:00
|
|
|
const errorData = query.kind === 'runpy' ? data.data : data;
|
2021-09-21 13:48:28 +00:00
|
|
|
return _self.setState(
|
|
|
|
|
{
|
|
|
|
|
currentState: {
|
|
|
|
|
..._self.state.currentState,
|
|
|
|
|
queries: {
|
|
|
|
|
..._self.state.currentState.queries,
|
2021-12-28 10:39:38 +00:00
|
|
|
[queryName]: _.assign(
|
|
|
|
|
{
|
|
|
|
|
..._self.state.currentState.queries[queryName],
|
|
|
|
|
isLoading: false,
|
|
|
|
|
},
|
|
|
|
|
query.kind === 'restapi'
|
2022-03-08 06:39:53 +00:00
|
|
|
? {
|
2023-01-03 03:01:47 +00:00
|
|
|
request: data.data.requestObject,
|
|
|
|
|
response: data.data.responseObject,
|
|
|
|
|
responseHeaders: data.data.responseHeaders,
|
|
|
|
|
}
|
2021-12-28 10:39:38 +00:00
|
|
|
: {}
|
|
|
|
|
),
|
2021-09-21 13:48:28 +00:00
|
|
|
},
|
|
|
|
|
errors: {
|
|
|
|
|
..._self.state.currentState.errors,
|
|
|
|
|
[queryName]: {
|
|
|
|
|
type: 'query',
|
2021-12-28 10:39:38 +00:00
|
|
|
kind: query.kind,
|
2022-12-27 14:40:33 +00:00
|
|
|
data: errorData,
|
2021-09-21 13:48:28 +00:00
|
|
|
options: options,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
() => {
|
2022-06-16 09:39:26 +00:00
|
|
|
resolve(data);
|
2022-12-22 20:39:57 +00:00
|
|
|
onEvent(_self, 'onDataQueryFailure', {
|
|
|
|
|
definition: { events: dataQuery.options.events },
|
|
|
|
|
});
|
2022-08-26 02:55:00 +00:00
|
|
|
if (mode !== 'view') {
|
2023-01-19 16:17:20 +00:00
|
|
|
const err = query.kind == 'tooljetdb' ? data?.error || data : _.isEmpty(data.data) ? data : data.data;
|
|
|
|
|
toast.error(err?.message);
|
2022-08-26 02:55:00 +00:00
|
|
|
}
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-26 05:32:02 +00:00
|
|
|
|
2021-09-21 13:48:28 +00:00
|
|
|
let rawData = data.data;
|
|
|
|
|
let finalData = data.data;
|
2021-09-06 14:40:51 +00:00
|
|
|
|
2021-09-21 13:48:28 +00:00
|
|
|
if (dataQuery.options.enableTransformation) {
|
2022-10-27 08:41:26 +00:00
|
|
|
finalData = await runTransformation(
|
|
|
|
|
_ref,
|
|
|
|
|
finalData,
|
|
|
|
|
query.options.transformation,
|
|
|
|
|
query.options.transformationLanguage,
|
|
|
|
|
query,
|
|
|
|
|
'edit'
|
|
|
|
|
);
|
2021-10-11 03:00:26 +00:00
|
|
|
if (finalData.status === 'failed') {
|
2022-12-27 14:40:33 +00:00
|
|
|
console.log('runPythonTransformation', finalData);
|
2021-10-11 03:00:26 +00:00
|
|
|
return _self.setState(
|
|
|
|
|
{
|
|
|
|
|
currentState: {
|
|
|
|
|
..._self.state.currentState,
|
|
|
|
|
queries: {
|
|
|
|
|
..._self.state.currentState.queries,
|
|
|
|
|
[queryName]: {
|
|
|
|
|
..._self.state.currentState.queries[queryName],
|
|
|
|
|
isLoading: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
errors: {
|
|
|
|
|
..._self.state.currentState.errors,
|
|
|
|
|
[queryName]: {
|
|
|
|
|
type: 'transformations',
|
|
|
|
|
data: finalData,
|
|
|
|
|
options: options,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
() => {
|
2022-06-16 09:39:26 +00:00
|
|
|
resolve(finalData);
|
2022-12-22 20:39:57 +00:00
|
|
|
onEvent(_self, 'onDataQueryFailure', {
|
|
|
|
|
definition: { events: dataQuery.options.events },
|
|
|
|
|
});
|
2021-10-11 03:00:26 +00:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dataQuery.options.showSuccessNotification) {
|
2022-07-30 06:29:07 +00:00
|
|
|
const notificationDuration = dataQuery.options.notificationDuration * 1000 || 5000;
|
2021-09-21 13:48:28 +00:00
|
|
|
toast.success(dataQuery.options.successMessage, {
|
2021-12-10 23:11:24 +00:00
|
|
|
duration: notificationDuration,
|
2021-09-21 13:48:28 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_self.setState(
|
|
|
|
|
{
|
2021-08-27 06:35:53 +00:00
|
|
|
currentState: {
|
|
|
|
|
..._self.state.currentState,
|
|
|
|
|
queries: {
|
|
|
|
|
..._self.state.currentState.queries,
|
2021-12-28 10:39:38 +00:00
|
|
|
[queryName]: _.assign(
|
|
|
|
|
{
|
|
|
|
|
..._self.state.currentState.queries[queryName],
|
|
|
|
|
isLoading: false,
|
|
|
|
|
data: finalData,
|
|
|
|
|
rawData,
|
|
|
|
|
},
|
2022-03-08 06:39:53 +00:00
|
|
|
query.kind === 'restapi'
|
2022-12-22 20:39:57 +00:00
|
|
|
? {
|
2023-01-03 03:01:47 +00:00
|
|
|
request: data.request,
|
|
|
|
|
response: data.response,
|
|
|
|
|
responseHeaders: data.responseHeaders,
|
|
|
|
|
}
|
2022-03-08 06:39:53 +00:00
|
|
|
: {}
|
2021-12-28 10:39:38 +00:00
|
|
|
),
|
2021-08-27 06:35:53 +00:00
|
|
|
},
|
2021-09-21 13:48:28 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
() => {
|
2022-06-16 09:39:26 +00:00
|
|
|
resolve({ status: 'ok', data: finalData });
|
2021-11-03 08:03:29 +00:00
|
|
|
onEvent(_self, 'onDataQuerySuccess', { definition: { events: dataQuery.options.events } }, mode);
|
2022-08-16 10:38:36 +00:00
|
|
|
|
|
|
|
|
if (mode !== 'view') {
|
|
|
|
|
toast(`Query (${queryName}) completed.`, {
|
|
|
|
|
icon: '🚀',
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-04-30 08:10:57 +00:00
|
|
|
}
|
2021-09-21 13:48:28 +00:00
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
.catch(({ error }) => {
|
2022-12-27 14:40:33 +00:00
|
|
|
if (mode !== 'view') toast.error(error ?? 'Unknown error');
|
2021-09-21 13:48:28 +00:00
|
|
|
_self.setState(
|
|
|
|
|
{
|
|
|
|
|
currentState: {
|
|
|
|
|
..._self.state.currentState,
|
|
|
|
|
queries: {
|
|
|
|
|
..._self.state.currentState.queries,
|
|
|
|
|
[queryName]: {
|
|
|
|
|
isLoading: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
() => {
|
2022-06-16 09:39:26 +00:00
|
|
|
resolve({ status: 'failed', message: error });
|
2021-05-02 06:23:56 +00:00
|
|
|
}
|
2021-09-21 13:48:28 +00:00
|
|
|
);
|
2021-05-02 06:23:56 +00:00
|
|
|
});
|
2021-04-26 05:32:02 +00:00
|
|
|
});
|
2021-04-30 08:10:57 +00:00
|
|
|
});
|
2021-04-26 05:32:02 +00:00
|
|
|
}
|
2021-05-28 12:31:13 +00:00
|
|
|
|
2022-02-23 04:18:05 +00:00
|
|
|
export function setTablePageIndex(_ref, tableId, index) {
|
2022-01-28 14:53:28 +00:00
|
|
|
if (_.isEmpty(tableId)) {
|
2022-01-20 13:35:34 +00:00
|
|
|
console.log('No table is associated with this event.');
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-28 14:53:28 +00:00
|
|
|
const table = Object.entries(_ref.state.currentState.components).filter((entry) => entry[1].id === tableId)[0][1];
|
2022-01-20 13:35:34 +00:00
|
|
|
const newPageIndex = resolveReferences(index, _ref.state.currentState);
|
2022-01-28 14:53:28 +00:00
|
|
|
table.setPage(newPageIndex ?? 1);
|
2022-01-20 13:35:34 +00:00
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-21 13:48:28 +00:00
|
|
|
export function renderTooltip({ props, text }) {
|
2022-07-27 04:26:09 +00:00
|
|
|
if (text === '') return <></>;
|
2021-09-21 13:48:28 +00:00
|
|
|
return (
|
|
|
|
|
<Tooltip id="button-tooltip" {...props}>
|
|
|
|
|
{text}
|
|
|
|
|
</Tooltip>
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-09-13 07:17:45 +00:00
|
|
|
|
2022-02-23 04:18:05 +00:00
|
|
|
export function computeComponentState(_ref, components = {}) {
|
2021-09-13 07:17:45 +00:00
|
|
|
let componentState = {};
|
|
|
|
|
const currentComponents = _ref.state.currentState.components;
|
|
|
|
|
Object.keys(components).forEach((key) => {
|
|
|
|
|
const component = components[key];
|
|
|
|
|
const componentMeta = componentTypes.find((comp) => component.component.component === comp.component);
|
|
|
|
|
|
|
|
|
|
const existingComponentName = Object.keys(currentComponents).find((comp) => currentComponents[comp].id === key);
|
|
|
|
|
const existingValues = currentComponents[existingComponentName];
|
|
|
|
|
|
2022-01-14 08:27:31 +00:00
|
|
|
if (component.parent) {
|
|
|
|
|
const parentComponent = components[component.parent];
|
2022-12-08 09:11:02 +00:00
|
|
|
let isListView = false,
|
|
|
|
|
isForm = false;
|
2022-01-14 08:27:31 +00:00
|
|
|
try {
|
|
|
|
|
isListView = parentComponent.component.component === 'Listview';
|
2022-12-08 09:11:02 +00:00
|
|
|
isForm = parentComponent.component.component === 'Form';
|
2022-01-14 08:27:31 +00:00
|
|
|
} catch {
|
|
|
|
|
console.log('error');
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 09:11:02 +00:00
|
|
|
if (!isListView && !isForm) {
|
2022-12-22 20:39:57 +00:00
|
|
|
componentState[component.component.name] = {
|
|
|
|
|
...componentMeta.exposedVariables,
|
|
|
|
|
id: key,
|
|
|
|
|
...existingValues,
|
|
|
|
|
};
|
2022-01-14 08:27:31 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
2022-12-22 20:39:57 +00:00
|
|
|
componentState[component.component.name] = {
|
|
|
|
|
...componentMeta.exposedVariables,
|
|
|
|
|
id: key,
|
|
|
|
|
...existingValues,
|
|
|
|
|
};
|
2022-01-14 08:27:31 +00:00
|
|
|
}
|
2021-09-13 07:17:45 +00:00
|
|
|
});
|
|
|
|
|
|
2021-10-06 13:17:56 +00:00
|
|
|
return setStateAsync(_ref, {
|
|
|
|
|
currentState: {
|
|
|
|
|
..._ref.state.currentState,
|
|
|
|
|
components: {
|
|
|
|
|
...componentState,
|
2021-09-13 07:17:45 +00:00
|
|
|
},
|
|
|
|
|
},
|
2021-10-06 13:17:56 +00:00
|
|
|
defaultComponentStateComputed: true,
|
|
|
|
|
});
|
2021-09-21 13:48:28 +00:00
|
|
|
}
|
2022-01-18 14:41:20 +00:00
|
|
|
|
2022-11-07 09:03:39 +00:00
|
|
|
export const getSvgIcon = (key, height = 50, width = 50, iconFile = undefined, styles = {}) => {
|
2022-10-27 11:29:43 +00:00
|
|
|
if (iconFile) return <img src={`data:image/svg+xml;base64,${iconFile}`} style={{ height, width }} />;
|
|
|
|
|
if (key === 'runjs') return <RunjsIcon style={{ height, width }} />;
|
2022-12-22 20:39:57 +00:00
|
|
|
if (key === 'tooljetdb') return <RunTooljetDbIcon />;
|
2022-12-27 14:40:33 +00:00
|
|
|
if (key === 'runpy') return <RunPyIcon />;
|
2022-01-18 14:41:20 +00:00
|
|
|
const Icon = allSvgs[key];
|
|
|
|
|
|
2022-11-10 10:21:45 +00:00
|
|
|
if (!Icon) return <></>;
|
|
|
|
|
|
2022-11-07 09:03:39 +00:00
|
|
|
return <Icon style={{ height, width, ...styles }} />;
|
2022-01-18 14:41:20 +00:00
|
|
|
};
|
2022-07-12 11:09:02 +00:00
|
|
|
|
2022-07-19 13:21:45 +00:00
|
|
|
export const debuggerActions = {
|
|
|
|
|
error: (_self, errors) => {
|
|
|
|
|
_self.setState((prevState) => ({
|
|
|
|
|
...prevState,
|
|
|
|
|
currentState: {
|
|
|
|
|
...prevState.currentState,
|
|
|
|
|
errors: {
|
|
|
|
|
...prevState.currentState.errors,
|
|
|
|
|
...errors,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
flush: (_self) => {
|
|
|
|
|
_self.setState((prevState) => ({
|
|
|
|
|
...prevState,
|
|
|
|
|
currentState: {
|
|
|
|
|
...prevState.currentState,
|
|
|
|
|
errors: {},
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
},
|
2022-08-24 21:35:03 +00:00
|
|
|
|
|
|
|
|
//* @params: errors - Object
|
|
|
|
|
generateErrorLogs: (errors) => {
|
|
|
|
|
const errorsArr = [];
|
|
|
|
|
Object.entries(errors).forEach(([key, value]) => {
|
|
|
|
|
const errorType =
|
2022-12-22 20:39:57 +00:00
|
|
|
value.type === 'query' && (value.kind === 'restapi' || value.kind === 'tooljetdb' || value.kind === 'runjs')
|
|
|
|
|
? value.kind
|
|
|
|
|
: value.type;
|
2022-08-24 21:35:03 +00:00
|
|
|
|
|
|
|
|
const error = {};
|
|
|
|
|
const generalProps = {
|
|
|
|
|
key,
|
|
|
|
|
type: value.type,
|
|
|
|
|
kind: errorType !== 'transformations' ? value.kind : 'transformations',
|
2022-12-08 12:21:09 +00:00
|
|
|
page: value.page,
|
2022-08-24 21:35:03 +00:00
|
|
|
timestamp: moment(),
|
2022-12-08 12:21:09 +00:00
|
|
|
strace: value.strace ?? 'app_level',
|
2022-08-24 21:35:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (errorType) {
|
|
|
|
|
case 'restapi':
|
|
|
|
|
generalProps.message = value.data.message;
|
|
|
|
|
generalProps.description = value.data.description;
|
|
|
|
|
error.substitutedVariables = value.options;
|
|
|
|
|
error.request = value.data.data.requestObject;
|
|
|
|
|
error.response = value.data.data.responseObject;
|
2022-12-22 20:39:57 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'tooljetdb':
|
|
|
|
|
generalProps.message = value.data.message;
|
|
|
|
|
generalProps.description = value.data.description;
|
|
|
|
|
error.substitutedVariables = value.options;
|
|
|
|
|
error.request = value.data.data.requestObject;
|
|
|
|
|
error.response = value.data.data.responseObject;
|
2022-08-24 21:35:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'runjs':
|
|
|
|
|
error.message = value.data.data.message;
|
|
|
|
|
error.description = value.data.data.description;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'query':
|
|
|
|
|
error.message = value.data.message;
|
|
|
|
|
error.description = value.data.description;
|
|
|
|
|
error.substitutedVariables = value.options;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'transformations':
|
|
|
|
|
generalProps.message = value.data.message;
|
2022-12-27 14:40:33 +00:00
|
|
|
error.data = value.data.data ?? value.data;
|
2022-08-24 21:35:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'component':
|
|
|
|
|
generalProps.message = value.data.message;
|
|
|
|
|
generalProps.property = key.split('- ')[1];
|
|
|
|
|
error.resolvedProperties = value.resolvedProperties;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
errorsArr.push({
|
|
|
|
|
error,
|
|
|
|
|
...generalProps,
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return errorsArr;
|
|
|
|
|
},
|
2022-07-19 13:21:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const getComponentName = (currentState, id) => {
|
|
|
|
|
try {
|
|
|
|
|
const name = Object.entries(currentState?.components).filter(([_, component]) => component.id === id)[0][0];
|
|
|
|
|
return name;
|
|
|
|
|
} catch {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-08 12:21:09 +00:00
|
|
|
const updateNewComponents = (pageId, appDefinition, newComponents, updateAppDefinition) => {
|
2022-07-12 11:09:02 +00:00
|
|
|
const newAppDefinition = JSON.parse(JSON.stringify(appDefinition));
|
|
|
|
|
newComponents.forEach((newComponent) => {
|
2022-12-08 12:21:09 +00:00
|
|
|
newComponent.component.name = computeComponentName(
|
|
|
|
|
newComponent.component.component,
|
|
|
|
|
newAppDefinition.pages[pageId].components
|
|
|
|
|
);
|
|
|
|
|
newAppDefinition.pages[pageId].components[newComponent.id] = newComponent;
|
2022-07-12 11:09:02 +00:00
|
|
|
});
|
|
|
|
|
updateAppDefinition(newAppDefinition);
|
|
|
|
|
};
|
|
|
|
|
|
2022-08-24 21:26:08 +00:00
|
|
|
export const cloneComponents = (_ref, updateAppDefinition, isCloning = true, isCut = false) => {
|
2022-12-08 12:21:09 +00:00
|
|
|
const { selectedComponents, appDefinition, currentPageId } = _ref.state;
|
2022-08-24 21:26:08 +00:00
|
|
|
if (selectedComponents.length < 1) return getSelectedText();
|
2022-12-08 12:21:09 +00:00
|
|
|
const { components: allComponents } = appDefinition.pages[currentPageId];
|
2022-08-24 21:26:08 +00:00
|
|
|
let newDefinition = _.cloneDeep(appDefinition);
|
|
|
|
|
let newComponents = [],
|
|
|
|
|
newComponentObj = {},
|
|
|
|
|
addedComponentId = new Set();
|
2022-07-12 11:09:02 +00:00
|
|
|
for (let selectedComponent of selectedComponents) {
|
2022-08-24 21:26:08 +00:00
|
|
|
if (addedComponentId.has(selectedComponent.id)) continue;
|
2022-07-12 11:09:02 +00:00
|
|
|
const component = {
|
|
|
|
|
id: selectedComponent.id,
|
|
|
|
|
component: allComponents[selectedComponent.id]?.component,
|
|
|
|
|
layouts: allComponents[selectedComponent.id]?.layouts,
|
|
|
|
|
parent: allComponents[selectedComponent.id]?.parent,
|
|
|
|
|
};
|
2022-08-24 21:26:08 +00:00
|
|
|
addedComponentId.add(selectedComponent.id);
|
2022-07-12 11:09:02 +00:00
|
|
|
let clonedComponent = JSON.parse(JSON.stringify(component));
|
|
|
|
|
clonedComponent.parent = undefined;
|
|
|
|
|
clonedComponent.children = [];
|
2022-08-24 21:26:08 +00:00
|
|
|
clonedComponent.children = [...getChildComponents(allComponents, component, clonedComponent, addedComponentId)];
|
2022-07-12 11:09:02 +00:00
|
|
|
newComponents = [...newComponents, clonedComponent];
|
2022-08-24 21:26:08 +00:00
|
|
|
newComponentObj = {
|
|
|
|
|
newComponents,
|
|
|
|
|
isCloning,
|
|
|
|
|
isCut,
|
|
|
|
|
};
|
2022-07-12 11:09:02 +00:00
|
|
|
}
|
|
|
|
|
if (isCloning) {
|
2022-12-08 12:21:09 +00:00
|
|
|
addComponents(currentPageId, appDefinition, updateAppDefinition, undefined, newComponentObj);
|
2022-07-12 11:09:02 +00:00
|
|
|
toast.success('Component cloned succesfully');
|
2022-08-24 21:26:08 +00:00
|
|
|
} else if (isCut) {
|
|
|
|
|
navigator.clipboard.writeText(JSON.stringify(newComponentObj));
|
2022-12-08 12:21:09 +00:00
|
|
|
removeSelectedComponent(currentPageId, newDefinition, selectedComponents);
|
2022-08-24 21:26:08 +00:00
|
|
|
updateAppDefinition(newDefinition);
|
2022-07-12 11:09:02 +00:00
|
|
|
} else {
|
2022-08-24 21:26:08 +00:00
|
|
|
navigator.clipboard.writeText(JSON.stringify(newComponentObj));
|
2022-07-12 11:09:02 +00:00
|
|
|
toast.success('Component copied succesfully');
|
|
|
|
|
}
|
|
|
|
|
_ref.setState({ currentSidebarTab: 2 });
|
|
|
|
|
};
|
|
|
|
|
|
2022-08-24 21:26:08 +00:00
|
|
|
const getChildComponents = (allComponents, component, parentComponent, addedComponentId) => {
|
2022-07-12 11:09:02 +00:00
|
|
|
let childComponents = [],
|
|
|
|
|
selectedChildComponents = [];
|
|
|
|
|
|
|
|
|
|
if (component.component.component === 'Tabs' || component.component.component === 'Calendar') {
|
|
|
|
|
childComponents = Object.keys(allComponents).filter((key) => allComponents[key].parent?.startsWith(component.id));
|
|
|
|
|
} else {
|
|
|
|
|
childComponents = Object.keys(allComponents).filter((key) => allComponents[key].parent === component.id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
childComponents.forEach((componentId) => {
|
|
|
|
|
let childComponent = JSON.parse(JSON.stringify(allComponents[componentId]));
|
|
|
|
|
childComponent.id = componentId;
|
|
|
|
|
const newComponent = JSON.parse(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
id: componentId,
|
|
|
|
|
component: allComponents[componentId]?.component,
|
|
|
|
|
layouts: allComponents[componentId]?.layouts,
|
|
|
|
|
parent: allComponents[componentId]?.parent,
|
|
|
|
|
})
|
|
|
|
|
);
|
2022-08-24 21:26:08 +00:00
|
|
|
addedComponentId.add(componentId);
|
2022-07-12 11:09:02 +00:00
|
|
|
|
|
|
|
|
if ((component.component.component === 'Tabs') | (component.component.component === 'Calendar')) {
|
|
|
|
|
const childTabId = childComponent.parent.split('-').at(-1);
|
|
|
|
|
childComponent.parent = `${parentComponent.id}-${childTabId}`;
|
|
|
|
|
} else {
|
|
|
|
|
childComponent.parent = parentComponent.id;
|
|
|
|
|
}
|
|
|
|
|
parentComponent.children = [...(parentComponent.children || []), childComponent];
|
2022-08-24 21:26:08 +00:00
|
|
|
childComponent.children = [...getChildComponents(allComponents, newComponent, childComponent, addedComponentId)];
|
2022-07-12 11:09:02 +00:00
|
|
|
selectedChildComponents.push(childComponent);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return selectedChildComponents;
|
|
|
|
|
};
|
|
|
|
|
|
2022-08-24 21:26:08 +00:00
|
|
|
const updateComponentLayout = (components, parentId, isCut = false) => {
|
2022-07-12 11:09:02 +00:00
|
|
|
let prevComponent;
|
|
|
|
|
components.forEach((component, index) => {
|
|
|
|
|
Object.keys(component.layouts).map((layout) => {
|
|
|
|
|
if (parentId !== undefined) {
|
|
|
|
|
if (index > 0) {
|
|
|
|
|
component.layouts[layout].top = prevComponent.layouts[layout].top + prevComponent.layouts[layout].height;
|
|
|
|
|
component.layouts[layout].left = 0;
|
|
|
|
|
} else {
|
|
|
|
|
component.layouts[layout].top = 0;
|
|
|
|
|
component.layouts[layout].left = 0;
|
|
|
|
|
}
|
|
|
|
|
prevComponent = component;
|
2022-08-24 21:26:08 +00:00
|
|
|
} else if (!isCut) {
|
2022-07-12 11:09:02 +00:00
|
|
|
component.layouts[layout].top = component.layouts[layout].top + component.layouts[layout].height;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-08 12:21:09 +00:00
|
|
|
export const addComponents = (pageId, appDefinition, appDefinitionChanged, parentId = undefined, newComponentObj) => {
|
|
|
|
|
console.log({ pageId, newComponentObj });
|
2022-07-12 11:09:02 +00:00
|
|
|
const finalComponents = [];
|
|
|
|
|
let parentComponent = undefined;
|
2022-08-24 21:26:08 +00:00
|
|
|
const { isCloning, isCut, newComponents: pastedComponent = [] } = newComponentObj;
|
2022-07-12 11:09:02 +00:00
|
|
|
|
|
|
|
|
if (parentId) {
|
2022-12-08 12:21:09 +00:00
|
|
|
const id = Object.keys(appDefinition.pages[pageId].components).filter((key) => parentId.startsWith(key));
|
|
|
|
|
parentComponent = JSON.parse(JSON.stringify(appDefinition.pages[pageId].components[id[0]]));
|
2022-07-12 11:09:02 +00:00
|
|
|
parentComponent.id = parentId;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 21:26:08 +00:00
|
|
|
!isCloning && updateComponentLayout(pastedComponent, parentId, isCut);
|
2022-07-12 11:09:02 +00:00
|
|
|
|
|
|
|
|
const buildComponents = (components, parentComponent = undefined, skipTabCalendarCheck = false) => {
|
|
|
|
|
if (Array.isArray(components) && components.length > 0) {
|
|
|
|
|
components.forEach((component) => {
|
|
|
|
|
const newComponent = {
|
|
|
|
|
id: uuidv4(),
|
|
|
|
|
component: component?.component,
|
|
|
|
|
layouts: component?.layouts,
|
|
|
|
|
};
|
|
|
|
|
if (parentComponent) {
|
|
|
|
|
if (
|
|
|
|
|
!skipTabCalendarCheck &&
|
|
|
|
|
(parentComponent.component.component === 'Tabs' || parentComponent.component.component === 'Calendar')
|
|
|
|
|
) {
|
|
|
|
|
const childTabId = component.parent.split('-').at(-1);
|
|
|
|
|
newComponent.parent = `${parentComponent.id}-${childTabId}`;
|
|
|
|
|
} else {
|
|
|
|
|
newComponent.parent = parentComponent.id;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finalComponents.push(newComponent);
|
|
|
|
|
if (component.children.length > 0) {
|
|
|
|
|
buildComponents(component.children, newComponent);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
buildComponents(pastedComponent, parentComponent, true);
|
|
|
|
|
|
2022-12-08 12:21:09 +00:00
|
|
|
updateNewComponents(pageId, appDefinition, finalComponents, appDefinitionChanged);
|
2022-07-12 11:09:02 +00:00
|
|
|
!isCloning && toast.success('Component pasted succesfully');
|
|
|
|
|
};
|
2022-08-09 10:15:19 +00:00
|
|
|
|
|
|
|
|
export const addNewWidgetToTheEditor = (
|
|
|
|
|
componentMeta,
|
|
|
|
|
eventMonitorObject,
|
|
|
|
|
currentComponents,
|
|
|
|
|
canvasBoundingRect,
|
|
|
|
|
currentLayout,
|
|
|
|
|
shouldSnapToGrid,
|
|
|
|
|
zoomLevel,
|
2022-08-11 11:52:06 +00:00
|
|
|
isInSubContainer = false,
|
|
|
|
|
addingDefault = false
|
2022-08-09 10:15:19 +00:00
|
|
|
) => {
|
|
|
|
|
const componentMetaData = _.cloneDeep(componentMeta);
|
|
|
|
|
const componentData = _.cloneDeep(componentMetaData);
|
|
|
|
|
|
|
|
|
|
const defaultWidth = isInSubContainer
|
|
|
|
|
? (componentMetaData.defaultSize.width * 100) / 43
|
|
|
|
|
: componentMetaData.defaultSize.width;
|
|
|
|
|
const defaultHeight = componentMetaData.defaultSize.height;
|
|
|
|
|
|
|
|
|
|
componentData.name = computeComponentName(componentData.component, currentComponents);
|
|
|
|
|
|
|
|
|
|
let left = 0;
|
|
|
|
|
let top = 0;
|
|
|
|
|
|
2022-08-11 11:52:06 +00:00
|
|
|
if (isInSubContainer && addingDefault) {
|
|
|
|
|
const newComponent = {
|
|
|
|
|
id: uuidv4(),
|
|
|
|
|
component: componentData,
|
|
|
|
|
layout: {
|
|
|
|
|
[currentLayout]: {
|
|
|
|
|
top: top,
|
|
|
|
|
left: left,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return newComponent;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-09 10:15:19 +00:00
|
|
|
const offsetFromTopOfWindow = canvasBoundingRect.top;
|
|
|
|
|
const offsetFromLeftOfWindow = canvasBoundingRect.left;
|
|
|
|
|
const currentOffset = eventMonitorObject.getSourceClientOffset();
|
|
|
|
|
const initialClientOffset = eventMonitorObject.getInitialClientOffset();
|
|
|
|
|
const delta = eventMonitorObject.getDifferenceFromInitialOffset();
|
|
|
|
|
const subContainerWidth = canvasBoundingRect.width;
|
|
|
|
|
|
|
|
|
|
left = Math.round(currentOffset?.x + currentOffset?.x * (1 - zoomLevel) - offsetFromLeftOfWindow);
|
|
|
|
|
top = Math.round(
|
|
|
|
|
initialClientOffset?.y - 10 + delta.y + initialClientOffset?.y * (1 - zoomLevel) - offsetFromTopOfWindow
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (shouldSnapToGrid) {
|
|
|
|
|
[left, top] = snapToGrid(subContainerWidth, left, top);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
left = (left * 100) / subContainerWidth;
|
|
|
|
|
|
|
|
|
|
if (currentLayout === 'mobile') {
|
|
|
|
|
componentData.definition.others.showOnDesktop.value = false;
|
|
|
|
|
componentData.definition.others.showOnMobile.value = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 09:11:02 +00:00
|
|
|
const widgetsWithDefaultComponents = ['Listview', 'Tabs', 'Form'];
|
2022-08-19 04:48:18 +00:00
|
|
|
|
2022-08-09 10:15:19 +00:00
|
|
|
const newComponent = {
|
|
|
|
|
id: uuidv4(),
|
|
|
|
|
component: componentData,
|
|
|
|
|
layout: {
|
|
|
|
|
[currentLayout]: {
|
|
|
|
|
top: top,
|
|
|
|
|
left: left,
|
|
|
|
|
width: defaultWidth,
|
|
|
|
|
height: defaultHeight,
|
|
|
|
|
},
|
|
|
|
|
},
|
2022-08-11 11:52:06 +00:00
|
|
|
|
2022-08-19 04:48:18 +00:00
|
|
|
withDefaultChildren: widgetsWithDefaultComponents.includes(componentData.component),
|
2022-08-09 10:15:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return newComponent;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function snapToGrid(canvasWidth, x, y) {
|
|
|
|
|
const gridX = canvasWidth / 43;
|
|
|
|
|
|
|
|
|
|
const snappedX = Math.round(x / gridX) * gridX;
|
|
|
|
|
const snappedY = Math.round(y / 10) * 10;
|
|
|
|
|
return [snappedX, snappedY];
|
|
|
|
|
}
|
2022-12-08 12:21:09 +00:00
|
|
|
export const removeSelectedComponent = (pageId, newDefinition, selectedComponents) => {
|
2022-08-24 21:26:08 +00:00
|
|
|
selectedComponents.forEach((component) => {
|
|
|
|
|
let childComponents = [];
|
|
|
|
|
|
2022-12-08 12:21:09 +00:00
|
|
|
if (newDefinition.pages[pageId].components[component.id]?.component?.component === 'Tabs') {
|
|
|
|
|
childComponents = Object.keys(newDefinition.pages[pageId].components).filter((key) =>
|
|
|
|
|
newDefinition.pages[pageId].components[key].parent?.startsWith(component.id)
|
2022-08-24 21:26:08 +00:00
|
|
|
);
|
|
|
|
|
} else {
|
2022-12-08 12:21:09 +00:00
|
|
|
childComponents = Object.keys(newDefinition.pages[pageId].components).filter(
|
|
|
|
|
(key) => newDefinition.pages[pageId].components[key].parent === component.id
|
2022-08-24 21:26:08 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
childComponents.forEach((componentId) => {
|
2022-12-08 12:21:09 +00:00
|
|
|
delete newDefinition.pages[pageId].components[componentId];
|
2022-08-24 21:26:08 +00:00
|
|
|
});
|
|
|
|
|
|
2022-12-08 12:21:09 +00:00
|
|
|
delete newDefinition.pages[pageId].components[component.id];
|
2022-08-24 21:26:08 +00:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getSelectedText = () => {
|
|
|
|
|
if (window.getSelection) {
|
|
|
|
|
navigator.clipboard.writeText(window.getSelection());
|
|
|
|
|
}
|
|
|
|
|
if (window.document.getSelection) {
|
|
|
|
|
navigator.clipboard.writeText(window.document.getSelection());
|
|
|
|
|
}
|
|
|
|
|
if (window.document.selection) {
|
|
|
|
|
navigator.clipboard.writeText(window.document.selection.createRange().text);
|
|
|
|
|
}
|
|
|
|
|
};
|