mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 08:58:26 +00:00
[Feature]: Push event errors from page, components and query to debugger (#11428)
This commit is contained in:
parent
3ebc1933cc
commit
00f4ee4370
10 changed files with 339 additions and 172 deletions
|
|
@ -352,6 +352,7 @@ export const EventManager = ({
|
|||
actionId: 'show-alert',
|
||||
message: 'Hello world!',
|
||||
alertType: 'info',
|
||||
component: eventMetaDefinition.name,
|
||||
...customEventRefs,
|
||||
},
|
||||
eventType: eventSourceType,
|
||||
|
|
|
|||
|
|
@ -132,10 +132,7 @@ export const buttonConfig = {
|
|||
borderRadius: {
|
||||
type: 'numberInput',
|
||||
displayName: 'Border radius',
|
||||
validation: {
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] } },
|
||||
defaultValue: false,
|
||||
},
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: false },
|
||||
accordian: 'button',
|
||||
},
|
||||
boxShadow: {
|
||||
|
|
|
|||
|
|
@ -82,10 +82,7 @@ export const imageConfig = {
|
|||
padding: {
|
||||
type: 'code',
|
||||
displayName: 'Padding',
|
||||
validation: {
|
||||
schema: { type: 'number' },
|
||||
defaultValue: 0,
|
||||
},
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 0 },
|
||||
},
|
||||
visibility: {
|
||||
type: 'toggle',
|
||||
|
|
|
|||
|
|
@ -20,10 +20,7 @@ export const numberinputConfig = {
|
|||
value: {
|
||||
type: 'code',
|
||||
displayName: 'Default value',
|
||||
validation: {
|
||||
schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] },
|
||||
defaultValue: 0,
|
||||
},
|
||||
validation: { schema: { type: 'union', schemas: [{ type: 'string' }, { type: 'number' }] }, defaultValue: 0 },
|
||||
},
|
||||
placeholder: {
|
||||
type: 'code',
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ export const createDebuggerSlice = (set, get) => ({
|
|||
componentId: id,
|
||||
},
|
||||
logLevel: 'error',
|
||||
errorTarget: 'Component Property',
|
||||
timestamp: moment().toISOString(),
|
||||
}));
|
||||
|
||||
|
|
@ -191,6 +192,7 @@ export const createDebuggerSlice = (set, get) => ({
|
|||
effectiveProperty: { [property]: defaultValue },
|
||||
componentId,
|
||||
},
|
||||
errorTarget: 'Component Property',
|
||||
logLevel: 'error',
|
||||
timestamp: moment().toISOString(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import generateFile from '@/_lib/generate-file';
|
|||
import urlJoin from 'url-join';
|
||||
import { useCallback } from 'react';
|
||||
import { navigate } from '@/AppBuilder/_utils/misc';
|
||||
import moment from 'moment';
|
||||
|
||||
// To unsubscribe from the changes when no longer needed
|
||||
// unsubscribe();
|
||||
|
|
@ -211,32 +212,46 @@ export const createEventsSlice = (set, get) => ({
|
|||
state.eventsSlice.module[moduleId].events = newEvents;
|
||||
});
|
||||
},
|
||||
setTablePageIndex: (tableId, index = 1) => {
|
||||
const { getExposedValueOfComponent } = get();
|
||||
if (_.isEmpty(tableId)) {
|
||||
console.log('No table is associated with this event.');
|
||||
setTablePageIndex: (tableId, index, eventObj) => {
|
||||
try {
|
||||
const { getExposedValueOfComponent } = get();
|
||||
if (typeof index !== 'number' && index !== undefined) {
|
||||
throw new Error('Invalid page index.');
|
||||
}
|
||||
const exposedValue = getExposedValueOfComponent(tableId);
|
||||
if (!exposedValue) {
|
||||
throw new Error('No table is associated with this event.');
|
||||
}
|
||||
exposedValue.setPage(index);
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('set_table_page_index', 'set-table-page-index', error, eventObj, {
|
||||
eventId: eventObj.eventType,
|
||||
});
|
||||
}
|
||||
const exposedValue = getExposedValueOfComponent(tableId);
|
||||
if (!exposedValue) {
|
||||
console.log('No table is associated with this event.');
|
||||
return Promise.resolve();
|
||||
}
|
||||
exposedValue.setPage(index);
|
||||
return Promise.resolve();
|
||||
},
|
||||
showModal: (modal, show) => {
|
||||
const { getExposedValueOfComponent } = get();
|
||||
const modalId = modal?.id ?? modal;
|
||||
console.log('modalId', modalId);
|
||||
if (_.isEmpty(modalId)) {
|
||||
console.log('No modal is associated with this event.');
|
||||
return Promise.resolve();
|
||||
}
|
||||
const exposedValue = getExposedValueOfComponent(modalId);
|
||||
show ? exposedValue.open() : exposedValue.close();
|
||||
showModal: (modal, show, eventObj) => {
|
||||
try {
|
||||
const { getExposedValueOfComponent } = get();
|
||||
const modalId = modal?.id ?? modal;
|
||||
if (_.isEmpty(modalId)) {
|
||||
throw new Error('No modal is associated with this event.');
|
||||
}
|
||||
const exposedValue = getExposedValueOfComponent(modalId);
|
||||
show ? exposedValue.open() : exposedValue.close();
|
||||
|
||||
return Promise.resolve();
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError(
|
||||
show ? 'show_modal' : 'close_modal',
|
||||
show ? 'show-modal' : 'close_modal',
|
||||
error,
|
||||
eventObj,
|
||||
{
|
||||
eventId: eventObj.eventType,
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
handleEvent: (eventName, events, options, moduleId = 'canvas') => {
|
||||
const latestEvents = get().eventsSlice.getModuleEvents(moduleId);
|
||||
|
|
@ -382,13 +397,84 @@ export const createEventsSlice = (set, get) => ({
|
|||
?.sort((a, b) => a.index - b.index);
|
||||
|
||||
for (const event of filteredEvents) {
|
||||
await get().eventsSlice.executeAction(event.event, mode, customVariables);
|
||||
await get().eventsSlice.executeAction(event, mode, customVariables);
|
||||
}
|
||||
},
|
||||
executeAction: debounce(async (event, mode, customVariables = {}) => {
|
||||
logError(errorType, errorKind, error, eventObj = '', options = {}, logLevel) {
|
||||
const { event = eventObj } = eventObj;
|
||||
const pages = get().modules.canvas.pages;
|
||||
const currentPageId = get().currentPageId;
|
||||
const currentPage = pages.find((page) => page.id === currentPageId);
|
||||
const componentIdMapping = get().modules['canvas'].componentNameIdMapping;
|
||||
const componentName = Object.keys(componentIdMapping).find(
|
||||
(key) => componentIdMapping[key] === eventObj?.sourceId
|
||||
);
|
||||
const componentId = eventObj?.sourceId;
|
||||
|
||||
const getSource = () => {
|
||||
if (eventObj.eventType) {
|
||||
return eventObj.eventType === 'data_query' ? 'query' : eventObj.eventType;
|
||||
}
|
||||
|
||||
const sourceMap = {
|
||||
onDataQueryFailure: 'query',
|
||||
onDataQuerySuccess: 'query',
|
||||
onPageLoad: 'page',
|
||||
};
|
||||
|
||||
return sourceMap[event.eventId] || 'component';
|
||||
};
|
||||
|
||||
const getQueryName = () => {
|
||||
const queries = get().dataQuery.queries.modules.canvas;
|
||||
return queries.find((query) => query.id === eventObj?.sourceId || '')?.name || '';
|
||||
};
|
||||
|
||||
const constructErrorHeader = () => {
|
||||
const source = getSource();
|
||||
const pageName = currentPage.name;
|
||||
|
||||
const headerMap = {
|
||||
component: `[Page ${pageName}] [Component ${componentName}] [Event ${event?.eventId}] [Action ${event.actionId}]`,
|
||||
page: `[Page ${pageName}] [Event ${event.eventId}] [Action ${event.actionId}]`,
|
||||
query: `[Query ${getQueryName()}] [Event ${event.eventId}] [Action ${event.actionId}]`,
|
||||
};
|
||||
|
||||
return headerMap[source] || '';
|
||||
};
|
||||
|
||||
const constructErrorTarget = () => {
|
||||
const source = getSource();
|
||||
|
||||
const errorTargetMap = {
|
||||
page: 'Event Errors with page',
|
||||
component: 'Component Event',
|
||||
query: 'Event Errors with query',
|
||||
};
|
||||
|
||||
return errorTargetMap[source];
|
||||
};
|
||||
useStore.getState().debugger.log({
|
||||
logLevel: logLevel ? logLevel : 'error',
|
||||
type: errorType ? errorType : 'event',
|
||||
kind: errorKind,
|
||||
key: constructErrorHeader(),
|
||||
error: {
|
||||
message: error.message,
|
||||
description: JSON.stringify(error.message, null, 2),
|
||||
...(event.component && componentId && { componentId: componentId }),
|
||||
},
|
||||
errorTarget: constructErrorTarget(),
|
||||
options: options,
|
||||
strace: 'app_level',
|
||||
timestamp: moment().toISOString(),
|
||||
});
|
||||
},
|
||||
executeAction: debounce(async (eventObj, mode, customVariables = {}) => {
|
||||
const { event = eventObj } = eventObj;
|
||||
const { getExposedValueOfComponent, getResolvedValue } = get();
|
||||
|
||||
if (event.runOnlyIf) {
|
||||
if (event?.runOnlyIf) {
|
||||
const shouldRun = getResolvedValue(event.runOnlyIf, customVariables);
|
||||
if (!shouldRun) {
|
||||
return false;
|
||||
|
|
@ -419,23 +505,37 @@ export const createEventsSlice = (set, get) => ({
|
|||
return Promise.resolve();
|
||||
}
|
||||
case 'run-query': {
|
||||
const { queryId, queryName } = event;
|
||||
const params = event['parameters'];
|
||||
const resolvedParams = {};
|
||||
if (params) {
|
||||
Object.keys(params).map((param) => (resolvedParams[param] = getResolvedValue(params[param], undefined)));
|
||||
try {
|
||||
const { queryId, queryName, component, eventId } = event;
|
||||
const params = event['parameters'];
|
||||
if (!queryId && !queryName) {
|
||||
throw new Error('No query selected');
|
||||
}
|
||||
const resolvedParams = {};
|
||||
if (params) {
|
||||
Object.keys(params).map(
|
||||
(param) => (resolvedParams[param] = getResolvedValue(params[param], undefined))
|
||||
);
|
||||
}
|
||||
// !Todo tackle confirm query part once done
|
||||
return get().queryPanel.runQuery(
|
||||
queryId,
|
||||
queryName,
|
||||
undefined,
|
||||
undefined,
|
||||
resolvedParams,
|
||||
component,
|
||||
eventId,
|
||||
false,
|
||||
false,
|
||||
'canvas'
|
||||
);
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('run_query', 'run-query', error, eventObj, {
|
||||
eventId: event.eventId,
|
||||
});
|
||||
return Promise.reject(error);
|
||||
}
|
||||
// !Todo tackle confirm query part once done
|
||||
return get().queryPanel.runQuery(
|
||||
queryId,
|
||||
queryName,
|
||||
undefined,
|
||||
undefined,
|
||||
resolvedParams,
|
||||
false,
|
||||
false,
|
||||
'canvas'
|
||||
);
|
||||
}
|
||||
case 'logout': {
|
||||
return logoutAction();
|
||||
|
|
@ -448,39 +548,47 @@ export const createEventsSlice = (set, get) => ({
|
|||
return Promise.resolve();
|
||||
}
|
||||
case 'go-to-app': {
|
||||
const resolvedValue = getResolvedValue(event.slug, customVariables);
|
||||
const slug = resolvedValue;
|
||||
const queryParams = event.queryParams?.reduce(
|
||||
(result, queryParam) => ({
|
||||
...result,
|
||||
...{
|
||||
[getResolvedValue(queryParam[0])]: getResolvedValue(queryParam[1], undefined, customVariables),
|
||||
},
|
||||
}),
|
||||
{}
|
||||
);
|
||||
let url = `/applications/${slug}`;
|
||||
|
||||
if (queryParams) {
|
||||
const queryPart = serializeNestedObjectToQueryParams(queryParams);
|
||||
|
||||
if (queryPart.length > 0) url = url + `?${queryPart}`;
|
||||
}
|
||||
if (mode === 'view') {
|
||||
navigate(url);
|
||||
} else {
|
||||
if (confirm('The app will be opened in a new tab as the action is triggered from the editor.')) {
|
||||
window.open(urlJoin(window.public_config?.TOOLJET_HOST, url));
|
||||
try {
|
||||
if (!event.slug) {
|
||||
throw new Error('No application slug provided');
|
||||
}
|
||||
const resolvedValue = getResolvedValue(event.slug, customVariables);
|
||||
const slug = resolvedValue;
|
||||
const queryParams = event.queryParams?.reduce(
|
||||
(result, queryParam) => ({
|
||||
...result,
|
||||
...{
|
||||
[getResolvedValue(queryParam[0])]: getResolvedValue(queryParam[1], undefined, customVariables),
|
||||
},
|
||||
}),
|
||||
{}
|
||||
);
|
||||
let url = `/applications/${slug}`;
|
||||
|
||||
if (queryParams) {
|
||||
const queryPart = serializeNestedObjectToQueryParams(queryParams);
|
||||
|
||||
if (queryPart.length > 0) url = url + `?${queryPart}`;
|
||||
}
|
||||
if (mode === 'view') {
|
||||
navigate(url);
|
||||
} else {
|
||||
if (confirm('The app will be opened in a new tab as the action is triggered from the editor.')) {
|
||||
window.open(urlJoin(window.public_config?.TOOLJET_HOST, url));
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('go_to_app', 'go-to-app', error, eventObj, { eventId: event.eventId });
|
||||
return Promise.reject();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
case 'show-modal':
|
||||
return get().eventsSlice.showModal(event.modal, true);
|
||||
return get().eventsSlice.showModal(event.modal, true, eventObj);
|
||||
|
||||
case 'close-modal':
|
||||
return get().eventsSlice.showModal(event.modal, false);
|
||||
return get().eventsSlice.showModal(event.modal, false, eventObj);
|
||||
case 'copy-to-clipboard': {
|
||||
const contentToCopy = getResolvedValue(event.contentToCopy, customVariables);
|
||||
copyToClipboard(contentToCopy);
|
||||
|
|
@ -509,7 +617,7 @@ export const createEventsSlice = (set, get) => ({
|
|||
}
|
||||
|
||||
case 'set-table-page': {
|
||||
get().eventsSlice.setTablePageIndex(event.table, getResolvedValue(event.pageIndex));
|
||||
get().eventsSlice.setTablePageIndex(event.table, getResolvedValue(event.pageIndex), eventObj);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -632,85 +740,110 @@ export const createEventsSlice = (set, get) => ({
|
|||
// return;
|
||||
}
|
||||
case 'control-component': {
|
||||
// let component = Object.values(getCurrentState()?.components ?? {}).filter(
|
||||
// (component) => component.id === event.componentId
|
||||
// )[0];
|
||||
const component = getExposedValueOfComponent(event.componentId);
|
||||
const action = component?.[event.componentSpecificActionHandle];
|
||||
// let action = '';
|
||||
// let actionArguments = '';
|
||||
// check if component id not found then try to find if its available as child widget else continue
|
||||
// with normal flow finding action
|
||||
// if (component == undefined) {
|
||||
// component = _ref.appDefinition.pages[getCurrentState()?.page?.id].components[event.componentId].component;
|
||||
// const parent = Object.values(getCurrentState()?.components ?? {}).find(
|
||||
// (item) => item.id === component.parent
|
||||
// );
|
||||
// const child = Object.values(parent?.children).find((item) => item.id === event.componentId);
|
||||
// if (child) {
|
||||
// action = child[event.componentSpecificActionHandle];
|
||||
// }
|
||||
// } else {
|
||||
// //normal component outside a container ex : form
|
||||
// action = component?.[event.componentSpecificActionHandle];
|
||||
// }
|
||||
// actionArguments = _.map(event.componentSpecificActionParams, (param) => ({
|
||||
// ...param,
|
||||
// value: resolveReferences(param.value, undefined, customVariables),
|
||||
// }));
|
||||
// console.log('actionArguments', event.componentSpecificActionParams);
|
||||
const actionArguments = event.componentSpecificActionParams.map((param) => {
|
||||
const value = getResolvedValue(param.value, customVariables);
|
||||
return {
|
||||
...param,
|
||||
value: value,
|
||||
// value: resolveCode(re.valueWithBrackets, getAllExposedValues()),
|
||||
};
|
||||
});
|
||||
// const actionArguments = _.map(event.componentSpecificActionParams, (param) => ({
|
||||
// ...param,
|
||||
// value: resolveReferences(param.value, getAllExposedValues(), customVariables),
|
||||
// }));
|
||||
try {
|
||||
// let component = Object.values(getCurrentState()?.components ?? {}).filter(
|
||||
// (component) => component.id === event.componentId
|
||||
// )[0];
|
||||
const { event } = eventObj;
|
||||
if (!event.componentSpecificActionHandle) {
|
||||
throw new Error('No component-specific action handle provided.');
|
||||
}
|
||||
const component = getExposedValueOfComponent(event.componentId);
|
||||
if (!event.componentId || !Object.keys(component).length) {
|
||||
throw new Error('No component ID provided for control-component action.');
|
||||
}
|
||||
const action = component?.[event.componentSpecificActionHandle];
|
||||
// let action = '';
|
||||
// let actionArguments = '';
|
||||
// check if component id not found then try to find if its available as child widget else continue
|
||||
// with normal flow finding action
|
||||
// if (component == undefined) {
|
||||
// component = _ref.appDefinition.pages[getCurrentState()?.page?.id].components[event.componentId].component;
|
||||
// const parent = Object.values(getCurrentState()?.components ?? {}).find(
|
||||
// (item) => item.id === component.parent
|
||||
// );
|
||||
// const child = Object.values(parent?.children).find((item) => item.id === event.componentId);
|
||||
// if (child) {
|
||||
// action = child[event.componentSpecificActionHandle];
|
||||
// }
|
||||
// } else {
|
||||
// //normal component outside a container ex : form
|
||||
// action = component?.[event.componentSpecificActionHandle];
|
||||
// }
|
||||
// actionArguments = _.map(event.componentSpecificActionParams, (param) => ({
|
||||
// ...param,
|
||||
// value: resolveReferences(param.value, undefined, customVariables),
|
||||
// }));
|
||||
// console.log('actionArguments', event.componentSpecificActionParams);
|
||||
const actionArguments = event.componentSpecificActionParams.map((param) => {
|
||||
const value = getResolvedValue(param.value, customVariables);
|
||||
return {
|
||||
...param,
|
||||
value: value,
|
||||
// value: resolveCode(re.valueWithBrackets, getAllExposedValues()),
|
||||
};
|
||||
});
|
||||
// const actionArguments = _.map(event.componentSpecificActionParams, (param) => ({
|
||||
// ...param,
|
||||
// value: resolveReferences(param.value, getAllExposedValues(), customVariables),
|
||||
// }));
|
||||
|
||||
const actionPromise = action && action(...actionArguments.map((argument) => argument.value));
|
||||
return actionPromise ?? Promise.resolve();
|
||||
const actionPromise = action && action(...actionArguments.map((argument) => argument.value));
|
||||
return actionPromise ?? Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('control_component', 'control-component', error, eventObj, {
|
||||
eventId: event.eventId,
|
||||
});
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
case 'switch-page': {
|
||||
const { switchPage } = get();
|
||||
const page = get().modules.canvas.pages.find((page) => page.id === event.pageId);
|
||||
const queryParams = event.queryParams || [];
|
||||
if (!page.disabled) {
|
||||
const resolvedQueryParams = [];
|
||||
queryParams.forEach((param) => {
|
||||
resolvedQueryParams.push([
|
||||
getResolvedValue(param[0], customVariables),
|
||||
getResolvedValue(param[1], customVariables),
|
||||
]);
|
||||
});
|
||||
const currentUrlParams = new URLSearchParams(window.location.search);
|
||||
currentUrlParams.forEach((value, key) => {
|
||||
if (key === 'version' || key === 'env') {
|
||||
// if version or env is in current url query param but not in resolved params then add it to resolvedQueryParams
|
||||
const exists = resolvedQueryParams.some(([resolvedKey]) => resolvedKey === key);
|
||||
if (!exists) {
|
||||
resolvedQueryParams.unshift([key, value]);
|
||||
try {
|
||||
const { pageId } = event;
|
||||
if (!pageId) {
|
||||
throw new Error('No page ID provided');
|
||||
}
|
||||
const { switchPage } = get();
|
||||
const page = get().modules.canvas.pages.find((page) => page.id === event.pageId);
|
||||
const queryParams = event.queryParams || [];
|
||||
if (!page.disabled) {
|
||||
const resolvedQueryParams = [];
|
||||
queryParams.forEach((param) => {
|
||||
resolvedQueryParams.push([
|
||||
getResolvedValue(param[0], customVariables),
|
||||
getResolvedValue(param[1], customVariables),
|
||||
]);
|
||||
});
|
||||
const currentUrlParams = new URLSearchParams(window.location.search);
|
||||
currentUrlParams.forEach((value, key) => {
|
||||
if (key === 'version' || key === 'env') {
|
||||
// if version or env is in current url query param but not in resolved params then add it to resolvedQueryParams
|
||||
const exists = resolvedQueryParams.some(([resolvedKey]) => resolvedKey === key);
|
||||
if (!exists) {
|
||||
resolvedQueryParams.unshift([key, value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
switchPage(page.id, page.handle, resolvedQueryParams);
|
||||
} else {
|
||||
toast.error('Page is disabled');
|
||||
//!TODO push to debugger
|
||||
get().debugger.log({
|
||||
logLevel: 'error',
|
||||
type: 'navToDisablePage',
|
||||
kind: 'page',
|
||||
message: `Attempt to switch to disabled page ${page.name} blocked.`,
|
||||
error: 'Page is disabled',
|
||||
});
|
||||
switchPage(page.id, page.handle, resolvedQueryParams);
|
||||
} else {
|
||||
toast.error('Page is disabled');
|
||||
//!TODO push to debugger
|
||||
get().debugger.log({
|
||||
logLevel: 'error',
|
||||
type: 'navToDisablePage',
|
||||
kind: 'page',
|
||||
message: `Attempt to switch to disabled page ${page.name} blocked.`,
|
||||
error: 'Page is disabled',
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
get().eventsSlice.logError('switch_page', 'switch-page', error, eventObj, {
|
||||
eventId: event.eventId,
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,6 +201,8 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
confirmed = undefined,
|
||||
mode = 'edit',
|
||||
userSuppliedParameters = {},
|
||||
component,
|
||||
eventId,
|
||||
shouldSetPreviewData = false,
|
||||
isOnLoad = false,
|
||||
moduleId = 'canvas'
|
||||
|
|
@ -247,8 +249,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
if (query) {
|
||||
dataQuery = JSON.parse(JSON.stringify(query));
|
||||
} else {
|
||||
toast.error('No query has been associated with the action.');
|
||||
return;
|
||||
throw new Error('No query selected');
|
||||
}
|
||||
|
||||
if (_.isEmpty(parameters)) {
|
||||
|
|
@ -298,6 +299,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
isLoading: true,
|
||||
data: [],
|
||||
rawData: [],
|
||||
id: queryId,
|
||||
});
|
||||
|
||||
let queryExecutionPromise = null;
|
||||
|
|
@ -367,6 +369,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
kind: query.kind,
|
||||
key: query.name,
|
||||
message: errorData?.description,
|
||||
errorTarget: 'Queries',
|
||||
error:
|
||||
query.kind === 'restapi'
|
||||
? {
|
||||
|
|
@ -435,6 +438,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
key: query.name,
|
||||
message: 'Query executed successfully',
|
||||
isQuerySuccessLog: true,
|
||||
errorTarget: 'Queries',
|
||||
});
|
||||
|
||||
setResolvedQuery(queryId, {
|
||||
|
|
@ -760,6 +764,7 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
error: result,
|
||||
isTransformation: true,
|
||||
isQuerySuccessLog: result?.status === 'failed' ? false : true,
|
||||
errorTarget: 'Queries',
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,12 +8,11 @@ import { useEditorActions, useEditorStore } from '@/_stores/editorStore';
|
|||
|
||||
function Logs({ logProps, idx }) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
let titleLogType = logProps?.type;
|
||||
// need to change the titleLogType to query for transformations because if transformation fails, it is eventually a query failure
|
||||
let titleLogType = logProps?.type !== 'event' ? logProps?.type : '';
|
||||
if (titleLogType === 'transformations') {
|
||||
titleLogType = 'query';
|
||||
}
|
||||
const title = ` [${capitalize(titleLogType)} ${logProps?.key}]`;
|
||||
const title = logProps?.key;
|
||||
const message =
|
||||
logProps?.type === 'navToDisablePage'
|
||||
? logProps?.message
|
||||
|
|
@ -21,19 +20,21 @@ function Logs({ logProps, idx }) {
|
|||
? 'Completed'
|
||||
: logProps?.type === 'component'
|
||||
? `Invalid property detected: ${logProps?.message}.`
|
||||
: logProps?.type === 'Custom Log'
|
||||
? logProps?.description
|
||||
: `${startCase(logProps?.type)} failed: ${
|
||||
logProps?.description ||
|
||||
logProps?.message ||
|
||||
(isString(logProps?.message) && logProps?.message) ||
|
||||
(isString(logProps?.error?.description) && logProps?.error?.description) || //added string check since description can be an object. eg: runpy
|
||||
logProps?.error?.message
|
||||
logProps?.error?.message.trim()
|
||||
}`;
|
||||
|
||||
const defaultStyles = {
|
||||
transform: open ? 'rotate(90deg)' : 'rotate(0deg)',
|
||||
transform: open ? 'rotate(0deg)' : 'rotate(-90deg)',
|
||||
transition: '0.2s all',
|
||||
display: logProps?.isQuerySuccessLog || logProps.type === 'navToDisablePage' ? 'none' : 'inline-block',
|
||||
cursor: 'pointer',
|
||||
paddingTop: '8px',
|
||||
top: '8px',
|
||||
pointerEvents: logProps?.isQuerySuccessLog || logProps.type === 'navToDisablePage' ? 'none' : 'default',
|
||||
};
|
||||
|
||||
|
|
@ -85,20 +86,25 @@ function Logs({ logProps, idx }) {
|
|||
onClick={(e) => {
|
||||
setOpen((prev) => !prev);
|
||||
}}
|
||||
style={{ pointerEvents: logProps?.isQuerySuccessLog ? 'none' : 'default' }}
|
||||
style={{ pointerEvents: logProps?.isQuerySuccessLog ? 'none' : 'default', position: 'relative' }}
|
||||
>
|
||||
<span className={cx('position-absolute')} style={defaultStyles}>
|
||||
<SolidIcon name="cheveronright" width="16" />
|
||||
<SolidIcon name="rightarrrow" fill={`var(--icons-strong)`} width="16" />
|
||||
</span>
|
||||
<span className="w-100" style={{ paddingTop: '8px', paddingBottom: '8px', paddingLeft: '20px' }}>
|
||||
{logProps.type === 'navToDisablePage' ? (
|
||||
renderNavToDisabledPageMessage()
|
||||
) : (
|
||||
<>
|
||||
<span className="d-flex justify-content-between align-items-center text-truncate">
|
||||
<span className="text-truncate text-slate-12">{title}</span>
|
||||
<div className="d-flex align-items-center justify-content-between">
|
||||
<div className="error-target cursor-pointer">{logProps?.errorTarget}</div>
|
||||
<small className="text-slate-10 text-right ">{moment(logProps?.timestamp).fromNow()}</small>
|
||||
</span>
|
||||
</div>
|
||||
<div className={`d-flex justify-content-between align-items-center ${!open && 'text-truncate'}`}>
|
||||
<span className={` cursor-pointer debugger-error-title ${!open && 'text-truncate'}`}>
|
||||
<HighlightSecondWord text={title} />
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
className={cx('mx-1', {
|
||||
'text-tomato-9': !logProps?.isQuerySuccessLog,
|
||||
|
|
@ -134,3 +140,22 @@ function Logs({ logProps, idx }) {
|
|||
let isString = (value) => typeof value === 'string' || value instanceof String;
|
||||
|
||||
export default Logs;
|
||||
|
||||
const HighlightSecondWord = ({ text }) => {
|
||||
const processedText = text.split(/(\[.*?\])/).map((segment, index) => {
|
||||
if (segment.startsWith('[') && segment.endsWith(']')) {
|
||||
const content = segment.slice(1, -1).split(' ');
|
||||
const firstWord = content[0];
|
||||
const secondWord = content[1];
|
||||
|
||||
return (
|
||||
<span key={index}>
|
||||
[{firstWord} <b>{secondWord}</b>]
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return segment;
|
||||
});
|
||||
|
||||
return <span>{processedText}</span>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -232,11 +232,24 @@
|
|||
}
|
||||
|
||||
.debugger-content {
|
||||
padding: 0px 16px;
|
||||
background-color: var(--base);
|
||||
cursor: pointer;
|
||||
|
||||
hr {
|
||||
margin-top: 0px !important;
|
||||
margin-bottom: 16px !important;
|
||||
margin: 0px !important;
|
||||
margin-top: 16px !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--slate3);
|
||||
}
|
||||
|
||||
.error-target {
|
||||
background-color: var(--interactive-overlays-fill-hover) !important;
|
||||
padding: 4px 7px;
|
||||
border-radius: 7px;
|
||||
color: var(--slate10)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14328,7 +14328,6 @@ color: var(--text-default);
|
|||
.debugger-card-body {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
|
||||
.left-sidebar-header-btn {
|
||||
|
|
@ -14671,7 +14670,6 @@ color: var(--text-default);
|
|||
.debugger-card-body {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
|
||||
.left-sidebar-header-btn {
|
||||
|
|
@ -15031,7 +15029,6 @@ color: var(--text-default);
|
|||
.debugger-card-body {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 16px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
|
||||
.left-sidebar-header-btn {
|
||||
|
|
|
|||
Loading…
Reference in a new issue