diff --git a/frontend/src/AppBuilder/RightSideBar/Inspector/EventManager.jsx b/frontend/src/AppBuilder/RightSideBar/Inspector/EventManager.jsx index 09c813fc7c..c3add3f1cc 100644 --- a/frontend/src/AppBuilder/RightSideBar/Inspector/EventManager.jsx +++ b/frontend/src/AppBuilder/RightSideBar/Inspector/EventManager.jsx @@ -352,6 +352,7 @@ export const EventManager = ({ actionId: 'show-alert', message: 'Hello world!', alertType: 'info', + component: eventMetaDefinition.name, ...customEventRefs, }, eventType: eventSourceType, diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/button.js b/frontend/src/AppBuilder/WidgetManager/widgets/button.js index 73b4a03bd4..67da105c55 100644 --- a/frontend/src/AppBuilder/WidgetManager/widgets/button.js +++ b/frontend/src/AppBuilder/WidgetManager/widgets/button.js @@ -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: { diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/image.js b/frontend/src/AppBuilder/WidgetManager/widgets/image.js index 7f15fbb6c5..8334267391 100644 --- a/frontend/src/AppBuilder/WidgetManager/widgets/image.js +++ b/frontend/src/AppBuilder/WidgetManager/widgets/image.js @@ -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', diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/numberinput.js b/frontend/src/AppBuilder/WidgetManager/widgets/numberinput.js index b0f72e6d81..fe3947e47b 100644 --- a/frontend/src/AppBuilder/WidgetManager/widgets/numberinput.js +++ b/frontend/src/AppBuilder/WidgetManager/widgets/numberinput.js @@ -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', diff --git a/frontend/src/AppBuilder/_stores/slices/debuggerSlice.js b/frontend/src/AppBuilder/_stores/slices/debuggerSlice.js index ac5b36c802..f4bab3d4ee 100644 --- a/frontend/src/AppBuilder/_stores/slices/debuggerSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/debuggerSlice.js @@ -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(), }); diff --git a/frontend/src/AppBuilder/_stores/slices/eventsSlice.js b/frontend/src/AppBuilder/_stores/slices/eventsSlice.js index 43b567732a..3eb143b5d7 100644 --- a/frontend/src/AppBuilder/_stores/slices/eventsSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/eventsSlice.js @@ -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(); } } } diff --git a/frontend/src/AppBuilder/_stores/slices/queryPanelSlice.js b/frontend/src/AppBuilder/_stores/slices/queryPanelSlice.js index c989df9051..cfc413aec5 100644 --- a/frontend/src/AppBuilder/_stores/slices/queryPanelSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/queryPanelSlice.js @@ -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; }, diff --git a/frontend/src/Editor/LeftSidebar/SidebarDebugger/Logs.jsx b/frontend/src/Editor/LeftSidebar/SidebarDebugger/Logs.jsx index 2af66fd6e7..ea7f0e298b 100644 --- a/frontend/src/Editor/LeftSidebar/SidebarDebugger/Logs.jsx +++ b/frontend/src/Editor/LeftSidebar/SidebarDebugger/Logs.jsx @@ -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' }} > - + {logProps.type === 'navToDisablePage' ? ( renderNavToDisabledPageMessage() ) : ( <> - - {title} +
+
{logProps?.errorTarget}
{moment(logProps?.timestamp).fromNow()} - +
+
+ + + +
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 ( + + [{firstWord} {secondWord}] + + ); + } + return segment; + }); + + return {processedText}; +}; diff --git a/frontend/src/_styles/left-sidebar.scss b/frontend/src/_styles/left-sidebar.scss index 0a5b441d66..5a9d022485 100644 --- a/frontend/src/_styles/left-sidebar.scss +++ b/frontend/src/_styles/left-sidebar.scss @@ -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) } } diff --git a/frontend/src/_styles/theme.scss b/frontend/src/_styles/theme.scss index 07895c1392..c0fda48ff7 100644 --- a/frontend/src/_styles/theme.scss +++ b/frontend/src/_styles/theme.scss @@ -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 {