diff --git a/app/client/cypress/e2e/Regression/ClientSide/Debugger/Api_pane_navigation_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Debugger/Api_pane_navigation_spec.ts index baea494db5..fe5229868f 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Debugger/Api_pane_navigation_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Debugger/Api_pane_navigation_spec.ts @@ -31,7 +31,6 @@ describe( debuggerHelper.ClicklogEntityLink(); agHelper.AssertElementVisibility(apiPage._nextCursorValue); - debuggerHelper.CloseBottomBar(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Api1", entityType: entityItems.Api, @@ -51,11 +50,9 @@ describe( apiPage.SelectPaneTab("Headers"); EditorNavigation.ShowCanvas(); debuggerHelper.AssertErrorCount(1); - debuggerHelper.ClickDebuggerIcon(); debuggerHelper.ClicklogEntityLink(); agHelper.AssertElementVisibility(apiPage._bodyValue(0)); - debuggerHelper.CloseBottomBar(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Api2", entityType: entityItems.Api, @@ -69,12 +66,11 @@ describe( apiPage.SelectPaneTab("Pagination"); EditorNavigation.ShowCanvas(); - debuggerHelper.ClickDebuggerIcon(); + // The Debugger should already be open here as it was opened before debuggerHelper.ClickLogsTab(); debuggerHelper.ClicklogEntityLink(true); agHelper.AssertElementVisibility(dataSources._queryTimeout); - debuggerHelper.CloseBottomBar(); entityExplorer.ActionContextMenuByEntityName({ entityNameinLeftSidebar: "Api3", entityType: entityItems.Api, diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/EntityBottomBar_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/EntityBottomBar_spec.ts index 377f4a0a4b..9eabb6ac94 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/EntityBottomBar_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/EntityBottomBar_spec.ts @@ -2,7 +2,7 @@ import * as _ from "../../../../support/Objects/ObjectsCore"; import { PageType } from "../../../../support/Pages/DebuggerHelper"; import EditorNavigation from "../../../../support/Pages/EditorNavigation"; -describe("Entity bottom bar", () => { +describe("Entity bottom bar", { tags: ["@tag.Debugger"] }, () => { it("1. Debugger should be closable", () => { //Verify if bottom bar is closed. _.debuggerHelper.AssertClosed(); @@ -32,17 +32,14 @@ describe("Entity bottom bar", () => { _.debuggerHelper.AssertSelectedTab("Response"); //verify if bottom bar is closed on switching to canvas page. EditorNavigation.ShowCanvas(); - _.debuggerHelper.AssertSelectedTab("Errors"); + _.debuggerHelper.AssertClosed(); }); it("3. Api bottom pane should be collapsable", () => { _.apiPage.CreateAndFillApi( _.dataManager.dsValues[_.dataManager.defaultEnviorment].mockApiUrl, ); - //Verify that the errors tab is still open. - _.debuggerHelper.AssertSelectedTab("Errors"); - //Verify if bottom bar is closed on clicking close icon in API page. - _.debuggerHelper.CloseBottomBar(); + //Verify that the errors tab is still closed. _.debuggerHelper.AssertClosed(); //Verify if bottom bar opens on clicking debugger icon in api page. _.debuggerHelper.ClickDebuggerIcon(); @@ -60,12 +57,11 @@ describe("Entity bottom bar", () => { it("4. Bottom bar in Datasource", () => { //Verify if bottom bar remain open on shifting to create new datasource page. _.dataSources.NavigateToDSCreateNew(); - //Expecting errors tab to be closed as previous selected tab was response. - //And response tab is not part of datasource page. + //Expecting errors tab to be closed as this is now a datasource _.debuggerHelper.AssertClosed(); //Verify if bottom bar opens on clicking debugger icon in datasource page. _.debuggerHelper.ClickDebuggerIcon(); - _.debuggerHelper.AssertClosed(); + _.debuggerHelper.AssertOpen(PageType.DataSources); }); it( diff --git a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs2_spec.js b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs2_spec.js index e0851d9a00..1c39aedda1 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs2_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/OtherUIFeatures/Logs2_spec.js @@ -14,7 +14,7 @@ const generateTestLogString = () => { return logString; }; -describe("Debugger logs", function () { +describe("Debugger logs", { tags: ["@tag.Debugger"] }, function () { this.beforeEach(() => { logString = generateTestLogString(); }); @@ -285,7 +285,8 @@ describe("Debugger logs", function () { }); EditorNavigation.SelectEntityByName("Page1", EntityType.Page); - _.agHelper.GetNClick(_.locators._errorTab); + _.agHelper.AssertElementVisibility(".t--debugger-count"); + _.debuggerHelper.ClickDebuggerIcon(); _.debuggerHelper.ClicklogEntityLink(); diff --git a/app/client/src/actions/apiPaneActions.ts b/app/client/src/actions/apiPaneActions.ts index 1c58a6864a..6d6a2dff92 100644 --- a/app/client/src/actions/apiPaneActions.ts +++ b/app/client/src/actions/apiPaneActions.ts @@ -2,6 +2,7 @@ import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; import type { EventLocation } from "@appsmith/utils/analyticsUtilTypes"; import type { SlashCommandPayload } from "entities/Action"; +import type { ApiPaneDebuggerState } from "@appsmith/reducers/uiReducers/apiPaneReducer"; export const changeApi = ( id: string, @@ -14,40 +15,6 @@ export const changeApi = ( }; }; -export const initApiPane = (urlId?: string): ReduxAction<{ id?: string }> => { - return { - type: ReduxActionTypes.INIT_API_PANE, - payload: { id: urlId }, - }; -}; - -export const setCurrentCategory = ( - category: string, -): ReduxAction<{ category: string }> => { - return { - type: ReduxActionTypes.SET_CURRENT_CATEGORY, - payload: { category }, - }; -}; - -export const setLastUsedEditorPage = ( - path: string, -): ReduxAction<{ path: string }> => { - return { - type: ReduxActionTypes.SET_LAST_USED_EDITOR_PAGE, - payload: { path }, - }; -}; - -export const setLastSelectedPage = ( - selectedPageId: string, -): ReduxAction<{ selectedPageId: string }> => { - return { - type: ReduxActionTypes.SET_LAST_SELECTED_PAGE_PAGE, - payload: { selectedPageId }, - }; -}; - export const createNewApiAction = ( pageId: string, from: EventLocation, @@ -109,3 +76,10 @@ export const setApiRightPaneSelectedTab: ( type: ReduxActionTypes.SET_API_RIGHT_PANE_SELECTED_TAB, payload: { selectedTab: payload }, }); + +export const setApiPaneDebuggerState = ( + payload: Partial, +) => ({ + type: ReduxActionTypes.SET_API_PANE_DEBUGGER_STATE, + payload, +}); diff --git a/app/client/src/actions/debuggerActions.ts b/app/client/src/actions/debuggerActions.ts index d34292ca60..3f58f4c476 100644 --- a/app/client/src/actions/debuggerActions.ts +++ b/app/client/src/actions/debuggerActions.ts @@ -1,7 +1,10 @@ import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; import type { Log, Message, SourceEntity } from "entities/AppsmithConsole"; import type { ENTITY_TYPE } from "@appsmith/entities/AppsmithConsole/utils"; -import type { DebuggerContext } from "reducers/uiReducers/debuggerReducer"; +import type { + CanvasDebuggerState, + DebuggerContext, +} from "reducers/uiReducers/debuggerReducer"; import type { EventName } from "@appsmith/utils/analyticsUtilTypes"; import type { APP_MODE } from "entities/App"; @@ -126,3 +129,12 @@ export const setDebuggerContext = (context: DebuggerContext) => { payload: { context }, }; }; + +export const setCanvasDebuggerState = ( + payload: Partial, +) => { + return { + type: ReduxActionTypes.SET_CANVAS_DEBUGGER_STATE, + payload, + }; +}; diff --git a/app/client/src/actions/jsPaneActions.ts b/app/client/src/actions/jsPaneActions.ts index f1eda98680..7ea2c9da47 100644 --- a/app/client/src/actions/jsPaneActions.ts +++ b/app/client/src/actions/jsPaneActions.ts @@ -6,7 +6,10 @@ import type { SetFunctionPropertyPayload, } from "@appsmith/api/JSActionAPI"; import type { EventLocation } from "@appsmith/utils/analyticsUtilTypes"; -import type { JSEditorTab } from "reducers/uiReducers/jsPaneReducer"; +import type { + JSEditorTab, + JSPaneDebuggerState, +} from "reducers/uiReducers/jsPaneReducer"; export const createNewJSCollection = ( pageId: string, @@ -111,3 +114,10 @@ export const setJsPaneConfigSelectedTab: ( type: ReduxActionTypes.SET_JS_PANE_CONFIG_SELECTED_TAB, payload: { selectedTab: payload }, }); + +export const setJsPaneDebuggerState = ( + payload: Partial, +) => ({ + type: ReduxActionTypes.SET_JS_PANE_DEBUGGER_STATE, + payload, +}); diff --git a/app/client/src/actions/queryPaneActions.ts b/app/client/src/actions/queryPaneActions.ts index 55f87e7724..7bfe58cc56 100644 --- a/app/client/src/actions/queryPaneActions.ts +++ b/app/client/src/actions/queryPaneActions.ts @@ -1,6 +1,7 @@ import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; import type { Action } from "entities/Action"; +import type { QueryPaneDebuggerState } from "@appsmith/reducers/uiReducers/queryPaneReducer"; export interface ChangeQueryPayload { id: string; @@ -26,3 +27,12 @@ export const setQueryPaneConfigSelectedTabIndex: ( type: ReduxActionTypes.SET_QUERY_PANE_CONFIG_SELECTED_TAB, payload: { selectedTabIndex: payload }, }); + +export const setQueryPaneDebuggerState = ( + payload: Partial, +) => { + return { + type: ReduxActionTypes.SET_QUERY_PANE_DEBUGGER_STATE, + payload, + }; +}; diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx index e8f201a29e..a626d4265b 100644 --- a/app/client/src/ce/constants/ReduxActionConstants.tsx +++ b/app/client/src/ce/constants/ReduxActionConstants.tsx @@ -463,7 +463,6 @@ const ActionTypes = { FETCH_ALL_PUBLISHED_PAGES: "FETCH_ALL_PUBLISHED_PAGES", CREATE_NEW_API_ACTION: "CREATE_NEW_API_ACTION", CREATE_NEW_QUERY_ACTION: "CREATE_NEW_QUERY_ACTION", - SET_CURRENT_CATEGORY: "SET_CURRENT_CATEGORY", SET_LAST_USED_EDITOR_PAGE: "SET_LAST_USED_EDITOR_PAGE", SET_LAST_SELECTED_PAGE_PAGE: "SET_LAST_SELECTED_PAGE_PAGE", FETCH_PROVIDER_DETAILS_BY_PROVIDER_ID_INIT: @@ -911,6 +910,10 @@ const ActionTypes = { END_CONSOLIDATED_PAGE_LOAD: "END_CONSOLIDATED_PAGE_LOAD", FETCH_ENVIRONMENT_SUCCESS: "FETCH_ENVIRONMENT_SUCCESS", SET_SHOW_CREATE_NEW_MODAL: "SET_SHOW_CREATE_NEW_MODAL", + SET_QUERY_PANE_DEBUGGER_STATE: "SET_QUERY_PANE_DEBUGGER_STATE", + SET_API_PANE_DEBUGGER_STATE: "SET_API_PANE_DEBUGGER_STATE", + SET_JS_PANE_DEBUGGER_STATE: "SET_JS_PANE_DEBUGGER_STATE", + SET_CANVAS_DEBUGGER_STATE: "SET_CANVAS_DEBUGGER_STATE", }; export const ReduxActionTypes = { diff --git a/app/client/src/ce/navigation/FocusElements/AppIDE.ts b/app/client/src/ce/navigation/FocusElements/AppIDE.ts index 87c8f1c1a5..e6b94fcf44 100644 --- a/app/client/src/ce/navigation/FocusElements/AppIDE.ts +++ b/app/client/src/ce/navigation/FocusElements/AppIDE.ts @@ -1,5 +1,6 @@ import { setApiPaneConfigSelectedTabIndex, + setApiPaneDebuggerState, setApiRightPaneSelectedTab, } from "actions/apiPaneActions"; import { @@ -13,6 +14,7 @@ import { } from "actions/editorContextActions"; import { getApiPaneConfigSelectedTabIndex, + getApiPaneDebuggerState, getApiRightPaneSelectedTab, } from "selectors/apiPaneSelectors"; import { @@ -33,14 +35,20 @@ import { import { setDatasourceViewMode } from "actions/datasourceActions"; import { updateExplorerWidthAction } from "actions/explorerActions"; -import { setJsPaneConfigSelectedTab } from "actions/jsPaneActions"; +import { + setJsPaneConfigSelectedTab, + setJsPaneDebuggerState, +} from "actions/jsPaneActions"; import { setAllPropertySectionState, setFocusablePropertyPaneField, setPropertyPaneWidthAction, setSelectedPropertyPanels, } from "actions/propertyPaneActions"; -import { setQueryPaneConfigSelectedTabIndex } from "actions/queryPaneActions"; +import { + setQueryPaneConfigSelectedTabIndex, + setQueryPaneDebuggerState, +} from "actions/queryPaneActions"; import { selectWidgetInitAction } from "actions/widgetSelectionActions"; import { DEFAULT_ENTITY_EXPLORER_WIDTH, @@ -53,6 +61,7 @@ import { getExplorerWidth } from "selectors/explorerSelector"; import { getFirstJSObject, getJSPaneConfigSelectedTab, + getJsPaneDebuggerState, } from "selectors/jsPaneSelectors"; import { getFocusablePropertyPaneField, @@ -62,6 +71,7 @@ import { import { getFirstQuery, getQueryPaneConfigSelectedTabIndex, + getQueryPaneDebuggerState, } from "selectors/queryPaneSelectors"; import { getDebuggerContext } from "selectors/debuggerSelectors"; import { setDebuggerContext } from "actions/debuggerActions"; @@ -83,6 +93,7 @@ import { FocusElement, FocusElementConfigType } from "navigation/FocusElements"; import type { FocusElementsConfigList } from "sagas/FocusRetentionSaga"; import { getJSTabs, getQueryTabs } from "selectors/ideSelectors"; import { setJSTabs, setQueryTabs } from "actions/ideActions"; +import { ActionExecutionResizerHeight } from "pages/Editor/APIEditor/constants"; export const AppIDEFocusElements: FocusElementsConfigList = { [FocusEntity.DATASOURCE_LIST]: [ @@ -117,6 +128,17 @@ export const AppIDEFocusElements: FocusElementsConfigList = { setter: setJsPaneConfigSelectedTab, defaultValue: JSEditorTab.CODE, }, + { + type: FocusElementConfigType.Redux, + name: FocusElement.JSDebugger, + selector: getJsPaneDebuggerState, + setter: setJsPaneDebuggerState, + defaultValue: { + open: false, + responseTabHeight: ActionExecutionResizerHeight, + selectedTab: undefined, + }, + }, ], [FocusEntity.QUERY]: [ { @@ -156,6 +178,28 @@ export const AppIDEFocusElements: FocusElementsConfigList = { selector: getApiRightPaneSelectedTab, setter: setApiRightPaneSelectedTab, }, + { + type: FocusElementConfigType.Redux, + name: FocusElement.QueryDebugger, + selector: getQueryPaneDebuggerState, + setter: setQueryPaneDebuggerState, + defaultValue: { + open: false, + responseTabHeight: ActionExecutionResizerHeight, + selectedTab: undefined, + }, + }, + { + type: FocusElementConfigType.Redux, + name: FocusElement.ApiDebugger, + selector: getApiPaneDebuggerState, + setter: setApiPaneDebuggerState, + defaultValue: { + open: false, + responseTabHeight: ActionExecutionResizerHeight, + selectedTab: undefined, + }, + }, ], [FocusEntity.PROPERTY_PANE]: [ { diff --git a/app/client/src/ce/reducers/uiReducers/apiPaneReducer.ts b/app/client/src/ce/reducers/uiReducers/apiPaneReducer.ts index 996da6dd11..f5d6afd19d 100644 --- a/app/client/src/ce/reducers/uiReducers/apiPaneReducer.ts +++ b/app/client/src/ce/reducers/uiReducers/apiPaneReducer.ts @@ -6,32 +6,38 @@ import { } from "@appsmith/constants/ReduxActionConstants"; import type { Action } from "entities/Action"; import type { UpdateActionPropertyActionPayload } from "actions/pluginActionActions"; +import { ActionExecutionResizerHeight } from "pages/Editor/APIEditor/constants"; export const initialState: ApiPaneReduxState = { isCreating: false, - isFetching: false, isRunning: {}, isSaving: {}, isDeleting: {}, isDirty: {}, - currentCategory: "", extraformData: {}, selectedConfigTabIndex: 0, - selectedResponseTab: "", + debugger: { + open: false, + responseTabHeight: ActionExecutionResizerHeight, + }, }; +export interface ApiPaneDebuggerState { + open: boolean; + responseTabHeight: number; + selectedTab?: string; +} + export interface ApiPaneReduxState { isCreating: boolean; // RR - isFetching: boolean; // RR isRunning: Record; isSaving: Record; // RN isDeleting: Record; isDirty: Record; - currentCategory: string; extraformData: Record; selectedConfigTabIndex: number; - selectedResponseTab: string; selectedRightPaneTab?: string; + debugger: ApiPaneDebuggerState; } export const handlers = { @@ -74,6 +80,10 @@ export const handlers = { ...state.isRunning, [action.payload.id]: true, }, + debugger: { + ...state.debugger, + open: true, + }, }), [ReduxActionTypes.RUN_ACTION_SUCCESS]: ( state: ApiPaneReduxState, @@ -183,14 +193,6 @@ export const handlers = { }, }), - [ReduxActionTypes.SET_CURRENT_CATEGORY]: ( - state: ApiPaneReduxState, - action: ReduxAction<{ category: string }>, - ) => ({ - ...state, - currentCategory: action.payload.category, - }), - /** * This redux action sets the extraformData field for an action. This is used to select the * appropriate body type tab selection in the Rest API plugin based on the content-type. @@ -233,6 +235,18 @@ export const handlers = { selectedRightPaneTab: selectedTab, }; }, + [ReduxActionTypes.SET_API_PANE_DEBUGGER_STATE]: ( + state: ApiPaneReduxState, + action: ReduxAction>, + ) => { + return { + ...state, + debugger: { + ...state.debugger, + ...action.payload, + }, + }; + }, }; const apiPaneReducer = createReducer(initialState, handlers); diff --git a/app/client/src/ce/reducers/uiReducers/queryPaneReducer.ts b/app/client/src/ce/reducers/uiReducers/queryPaneReducer.ts index 6d49fa9beb..8fc2dcaea4 100644 --- a/app/client/src/ce/reducers/uiReducers/queryPaneReducer.ts +++ b/app/client/src/ce/reducers/uiReducers/queryPaneReducer.ts @@ -8,29 +8,33 @@ import { omit } from "lodash"; import type { Action } from "entities/Action"; import type { ActionResponse } from "api/ActionAPI"; import { ActionExecutionResizerHeight } from "pages/Editor/APIEditor/constants"; +import { DEBUGGER_TAB_KEYS } from "../../../components/editorComponents/Debugger/helpers"; export const initialState: QueryPaneReduxState = { - isFetching: false, - isCreating: false, isRunning: {}, isSaving: {}, isDeleting: {}, runErrorMessage: {}, - lastUsed: "", // NR - responseTabHeight: ActionExecutionResizerHeight, + debugger: { + open: false, + responseTabHeight: ActionExecutionResizerHeight, + }, selectedConfigTabIndex: "0", }; +export interface QueryPaneDebuggerState { + open: boolean; + responseTabHeight: number; + selectedTab?: string; +} + export interface QueryPaneReduxState { - isFetching: boolean; // RR isRunning: Record; isSaving: Record; // RR isDeleting: Record; runErrorMessage: Record; - lastUsed: string; // NR - isCreating: boolean; // RR selectedConfigTabIndex: string; - responseTabHeight: number; + debugger: QueryPaneDebuggerState; } export const handlers = { @@ -122,13 +126,18 @@ export const handlers = { [ReduxActionTypes.RUN_ACTION_REQUEST]: ( state: any, action: ReduxAction<{ id: string }>, - ) => { + ): QueryPaneReduxState => { return { ...state, isRunning: { ...state.isRunning, [action.payload.id]: true, }, + debugger: { + ...state.debugger, + selectedTab: DEBUGGER_TAB_KEYS.RESPONSE_TAB, + open: true, + }, }; }, @@ -187,6 +196,18 @@ export const handlers = { selectedConfigTabIndex: selectedTabIndex, }; }, + [ReduxActionTypes.SET_QUERY_PANE_DEBUGGER_STATE]: ( + state: QueryPaneReduxState, + action: ReduxAction>, + ) => { + return { + ...state, + debugger: { + ...state.debugger, + ...action.payload, + }, + }; + }, }; const queryPaneReducer = createReducer(initialState, handlers); diff --git a/app/client/src/components/editorComponents/ApiResponseView.tsx b/app/client/src/components/editorComponents/ApiResponseView.tsx index 6d1f3d6697..be37c4aa7b 100644 --- a/app/client/src/components/editorComponents/ApiResponseView.tsx +++ b/app/client/src/components/editorComponents/ApiResponseView.tsx @@ -13,11 +13,10 @@ import { isArray, isEmpty, isString } from "lodash"; import { CHECK_REQUEST_BODY, createMessage, + DEBUGGER_ERRORS, DEBUGGER_LOGS, EMPTY_RESPONSE_FIRST_HALF, EMPTY_RESPONSE_LAST_HALF, - INSPECT_ENTITY, - DEBUGGER_ERRORS, } from "@appsmith/constants/messages"; import { Text as BlueprintText } from "@blueprintjs/core"; import { EditorTheme } from "./CodeEditor/EditorConfig"; @@ -26,26 +25,17 @@ import DebuggerLogs from "./Debugger/DebuggerLogs"; import ErrorLogs from "./Debugger/Errors"; import Resizer, { ResizerCSS } from "./Debugger/Resizer"; import AnalyticsUtil from "utils/AnalyticsUtil"; -import EntityDeps from "./Debugger/EntityDependecies"; import { Classes, TAB_MIN_HEIGHT, Text, TextType } from "design-system-old"; import { Button, Callout, Flex, SegmentedControl } from "design-system"; +import type { BottomTab } from "./EntityBottomTabs"; import EntityBottomTabs from "./EntityBottomTabs"; import { DEBUGGER_TAB_KEYS } from "./Debugger/helpers"; import Table from "pages/Editor/QueryEditor/Table"; import { API_RESPONSE_TYPE_OPTIONS } from "constants/ApiEditorConstants/CommonApiConstants"; import { setActionResponseDisplayFormat } from "actions/pluginActionActions"; import { isHtml } from "./utils"; -import { - getDebuggerSelectedTab, - getErrorCount, - getResponsePaneHeight, -} from "selectors/debuggerSelectors"; +import { getErrorCount } from "selectors/debuggerSelectors"; import { ActionExecutionResizerHeight } from "pages/Editor/APIEditor/constants"; -import { - setDebuggerSelectedTab, - setResponsePaneHeight, - showDebugger, -} from "actions/debuggerActions"; import LogAdditionalInfo from "./Debugger/ErrorLogs/components/LogAdditionalInfo"; import { JsonWrapper, @@ -59,6 +49,10 @@ import ActionExecutionInProgressView from "./ActionExecutionInProgressView"; import { CloseDebugger } from "./Debugger/DebuggerTabs"; import { EMPTY_RESPONSE } from "./emptyResponse"; import BindDataButton from "../../pages/Editor/QueryEditor/BindDataButton"; +import { setApiPaneDebuggerState } from "actions/apiPaneActions"; +import { getApiPaneDebuggerState } from "selectors/apiPaneSelectors"; +import { getIDEViewMode } from "selectors/ideSelectors"; +import { EditorViewMode } from "@appsmith/entities/IDE/constants"; interface TextStyleProps { accent: "primary" | "secondary" | "error"; @@ -312,12 +306,19 @@ function ApiResponseView(props: Props) { const panelRef: RefObject = useRef(null); const dispatch = useDispatch(); const errorCount = useSelector(getErrorCount); + const { open, responseTabHeight, selectedTab } = useSelector( + getApiPaneDebuggerState, + ); + + const ideViewMode = useSelector(getIDEViewMode); const onDebugClick = useCallback(() => { AnalyticsUtil.logEvent("OPEN_DEBUGGER", { source: "API", }); - dispatch(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.ERROR_TAB)); + dispatch( + setApiPaneDebuggerState({ selectedTab: DEBUGGER_TAB_KEYS.ERROR_TAB }), + ); }, []); const onRunClick = () => { @@ -380,7 +381,7 @@ function ApiResponseView(props: Props) { panelComponent: responseTabComponent( dataType.key, actionResponse?.body, - responsePaneHeight, + responseTabHeight, ), }; }); @@ -401,8 +402,6 @@ function ApiResponseView(props: Props) { (dataType) => dataType.title === responseDisplayFormat?.title, ); - // get the selected tab in the response pane. - const selectedResponseTab = useSelector(getDebuggerSelectedTab); // update the selected tab in the response pane. const updateSelectedResponseTab = useCallback((tabKey: string) => { if (tabKey === DEBUGGER_TAB_KEYS.ERROR_TAB) { @@ -410,13 +409,12 @@ function ApiResponseView(props: Props) { source: "API_PANE", }); } - dispatch(setDebuggerSelectedTab(tabKey)); + dispatch(setApiPaneDebuggerState({ selectedTab: tabKey })); }, []); - // get the height of the response pane. - const responsePaneHeight = useSelector(getResponsePaneHeight); + // update the height of the response pane on resize. const updateResponsePaneHeight = useCallback((height: number) => { - dispatch(setResponsePaneHeight(height)); + dispatch(setApiPaneDebuggerState({ responseTabHeight: height })); }, []); // get request timestamp formatted to human readable format. @@ -427,7 +425,7 @@ function ApiResponseView(props: Props) { name: currentActionConfig ? currentActionConfig.name : "API", id: currentActionConfig?.id || "", }; - const tabs = [ + const tabs: BottomTab[] = [ { key: "response", title: "Response", @@ -526,7 +524,7 @@ function ApiResponseView(props: Props) { {responseTabComponent( selectedControl || segmentedControlOptions[0]?.value, actionResponse?.body, - responsePaneHeight, + responseTabHeight, )} ) : null} @@ -579,32 +577,34 @@ function ApiResponseView(props: Props) { ), }, - { - key: DEBUGGER_TAB_KEYS.ERROR_TAB, - title: createMessage(DEBUGGER_ERRORS), - count: errorCount, - panelComponent: , - }, - { - key: DEBUGGER_TAB_KEYS.LOGS_TAB, - title: createMessage(DEBUGGER_LOGS), - panelComponent: , - }, - { - key: DEBUGGER_TAB_KEYS.INSPECT_TAB, - title: createMessage(INSPECT_ENTITY), - panelComponent: , - }, ]; + if (ideViewMode === EditorViewMode.FullScreen) { + tabs.push( + { + key: DEBUGGER_TAB_KEYS.ERROR_TAB, + title: createMessage(DEBUGGER_ERRORS), + count: errorCount, + panelComponent: , + }, + { + key: DEBUGGER_TAB_KEYS.LOGS_TAB, + title: createMessage(DEBUGGER_LOGS), + panelComponent: , + }, + ); + } + // close the debugger //TODO: move this to a common place - const onClose = () => dispatch(showDebugger(false)); + const onClose = () => dispatch(setApiPaneDebuggerState({ open: false })); + + if (!open) return null; return ( { updateResponsePaneHeight(height); }} @@ -659,7 +659,7 @@ function ApiResponseView(props: Props) { { const datasourceStructure = useSelector((state) => getDatasourceStructureById(state, props.datasourceId), ); - const responsePaneHeight = useSelector(getResponsePaneHeight); + const { responseTabHeight } = useSelector(getQueryPaneDebuggerState); const [selectedTable, setSelectedTable] = useState(); const selectedTableItems = find(datasourceStructure?.tables, [ @@ -69,7 +69,7 @@ const Schema = (props: Props) => { @@ -94,7 +94,7 @@ const Schema = (props: Props) => { borderLeft="1px solid var(--ads-v2-color-border)" flex="1" flexDirection="column" - height={`${responsePaneHeight - 45}px`} + height={`${responseTabHeight - 45}px`} justifyContent={ isLoading || columns.length === 0 ? "center" : "flex-start" } diff --git a/app/client/src/components/editorComponents/Debugger/hooks/useDebuggerTriggerClick.ts b/app/client/src/components/editorComponents/Debugger/hooks/useDebuggerTriggerClick.ts new file mode 100644 index 0000000000..f186805c33 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/hooks/useDebuggerTriggerClick.ts @@ -0,0 +1,96 @@ +import { useLocation } from "react-router"; +import { DEBUGGER_TAB_KEYS } from "../helpers"; +import { setCanvasDebuggerState } from "actions/debuggerActions"; +import AnalyticsUtil from "utils/AnalyticsUtil"; +import type { FocusEntityInfo } from "navigation/FocusEntity"; +import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity"; +import { setJsPaneDebuggerState } from "actions/jsPaneActions"; +import { setApiPaneDebuggerState } from "actions/apiPaneActions"; +import { setQueryPaneDebuggerState } from "actions/queryPaneActions"; +import { getJsPaneDebuggerState } from "selectors/jsPaneSelectors"; +import { getApiPaneDebuggerState } from "selectors/apiPaneSelectors"; +import { getQueryPaneDebuggerState } from "selectors/queryPaneSelectors"; +import { getCanvasDebuggerState } from "selectors/debuggerSelectors"; +import { getIDEViewMode } from "selectors/ideSelectors"; +import { useDispatch, useSelector } from "react-redux"; +import { EditorViewMode } from "@appsmith/entities/IDE/constants"; +import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants"; +import type { CanvasDebuggerState } from "reducers/uiReducers/debuggerReducer"; +import type { AppState } from "@appsmith/reducers"; + +interface Config { + set: ( + payload: Partial, + ) => ReduxAction>; + get: (state: AppState) => CanvasDebuggerState; +} + +const canvasDebuggerConfig: Config = { + set: setCanvasDebuggerState, + get: getCanvasDebuggerState, +}; + +const queryDebuggerConfig: Config = { + set: setQueryPaneDebuggerState, + get: getQueryPaneDebuggerState, +}; + +const getConfig = (focusInfo: FocusEntityInfo): Config => { + switch (focusInfo.entity) { + case FocusEntity.QUERY: + if (focusInfo.params.apiId) { + if (focusInfo.params.pluginPackageName) { + return queryDebuggerConfig; + } + return { + set: setApiPaneDebuggerState, + get: getApiPaneDebuggerState, + }; + } + return queryDebuggerConfig; + case FocusEntity.JS_OBJECT: + return { + set: setJsPaneDebuggerState, + get: getJsPaneDebuggerState, + }; + default: + return canvasDebuggerConfig; + } +}; + +const useDebuggerTriggerClick = () => { + const location = useLocation(); + const currentFocus = identifyEntityFromPath(location.pathname); + const ideState = useSelector(getIDEViewMode); + const dispatch = useDispatch(); + + const config = + ideState === EditorViewMode.FullScreen + ? getConfig(currentFocus) + : canvasDebuggerConfig; + + const state = useSelector(config.get); + return () => { + // If debugger is already open and selected tab is error tab then we will close debugger. + if (state.open && state.selectedTab === DEBUGGER_TAB_KEYS.ERROR_TAB) { + dispatch(config.set({ open: false })); + } else { + // If debugger is not open then we will open debugger and show error tab. + if (!state.open) { + dispatch( + config.set({ open: true, selectedTab: DEBUGGER_TAB_KEYS.ERROR_TAB }), + ); + } + // Select error tab if debugger is open and selected tab is not error tab. + // And also when we are opening debugger. + dispatch(config.set({ selectedTab: DEBUGGER_TAB_KEYS.ERROR_TAB })); + } + if (!state.open) { + AnalyticsUtil.logEvent("OPEN_DEBUGGER", { + source: "TRIGGER", + }); + } + }; +}; + +export default useDebuggerTriggerClick; diff --git a/app/client/src/components/editorComponents/Debugger/index.tsx b/app/client/src/components/editorComponents/Debugger/index.tsx index cc1d767861..2cf4fa833c 100644 --- a/app/client/src/components/editorComponents/Debugger/index.tsx +++ b/app/client/src/components/editorComponents/Debugger/index.tsx @@ -1,20 +1,10 @@ import React, { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import DebuggerTabs from "./DebuggerTabs"; -import { - setDebuggerSelectedTab, - setErrorCount, - showDebugger as showDebuggerAction, -} from "actions/debuggerActions"; -import AnalyticsUtil from "utils/AnalyticsUtil"; -import { stopEventPropagation } from "utils/AppsmithUtils"; -import { - getDebuggerSelectedTab, - getMessageCount, - showDebuggerFlag, -} from "selectors/debuggerSelectors"; -import { DEBUGGER_TAB_KEYS } from "./helpers"; +import { setErrorCount } from "actions/debuggerActions"; +import { getMessageCount, showDebuggerFlag } from "selectors/debuggerSelectors"; import { Button, Tooltip } from "design-system"; +import useDebuggerTriggerClick from "./hooks/useDebuggerTriggerClick"; function Debugger() { // Debugger render flag @@ -25,33 +15,13 @@ function Debugger() { export function DebuggerTrigger() { const dispatch = useDispatch(); - const showDebugger = useSelector(showDebuggerFlag); - const selectedTab = useSelector(getDebuggerSelectedTab); const messageCounters = useSelector(getMessageCount); useEffect(() => { dispatch(setErrorCount(messageCounters.errors)); }); - const onClick = (e: any) => { - // If debugger is already open and selected tab is error tab then we will close debugger. - if (showDebugger && selectedTab === DEBUGGER_TAB_KEYS.ERROR_TAB) { - dispatch(showDebuggerAction(false)); - } else { - // If debugger is not open then we will open debugger and show error tab. - if (!showDebugger) { - dispatch(showDebuggerAction(true)); - } - // Select error tab if debugger is open and selected tab is not error tab. - // And also when we are opening debugger. - dispatch(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.ERROR_TAB)); - } - if (!showDebugger) - AnalyticsUtil.logEvent("OPEN_DEBUGGER", { - source: "CANVAS", - }); - stopEventPropagation(e); - }; + const onClick = useDebuggerTriggerClick(); //tooltip will always show error count as we are opening error tab on click of debugger. const tooltipContent = diff --git a/app/client/src/components/editorComponents/JSResponseView.tsx b/app/client/src/components/editorComponents/JSResponseView.tsx index 915f218d29..8f82dd21d6 100644 --- a/app/client/src/components/editorComponents/JSResponseView.tsx +++ b/app/client/src/components/editorComponents/JSResponseView.tsx @@ -1,5 +1,5 @@ import type { RefObject } from "react"; -import React, { useEffect, useRef, useCallback, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import { connect, useDispatch, useSelector } from "react-redux"; import type { RouteComponentProps } from "react-router"; import { withRouter } from "react-router"; @@ -9,15 +9,14 @@ import type { AppState } from "@appsmith/reducers"; import type { JSEditorRouteParams } from "constants/routes"; import { createMessage, - DEBUGGER_LOGS, DEBUGGER_ERRORS, + DEBUGGER_LOGS, EXECUTING_FUNCTION, NO_JS_FUNCTION_RETURN_VALUE, UPDATING_JS_COLLECTION, } from "@appsmith/constants/messages"; import type { EditorTheme } from "./CodeEditor/EditorConfig"; import DebuggerLogs from "./Debugger/DebuggerLogs"; -import ErrorLogs from "./Debugger/Errors"; import Resizer, { ResizerCSS } from "./Debugger/Resizer"; import type { JSAction } from "entities/JSCollection"; import ReadOnlyEditor from "components/editorComponents/ReadOnlyEditor"; @@ -26,22 +25,14 @@ import LoadingOverlayScreen from "components/editorComponents/LoadingOverlayScre import type { JSCollectionData } from "@appsmith/reducers/entityReducers/jsActionsReducer"; import type { EvaluationError } from "utils/DynamicBindingUtils"; import { DEBUGGER_TAB_KEYS } from "./Debugger/helpers"; +import type { BottomTab } from "./EntityBottomTabs"; import EntityBottomTabs from "./EntityBottomTabs"; import { TAB_MIN_HEIGHT } from "design-system-old"; import { CodeEditorWithGutterStyles } from "pages/Editor/JSEditor/constants"; import { getIsSavingEntity } from "selectors/editorSelectors"; import { getJSResponseViewState } from "./utils"; -import { - getDebuggerSelectedTab, - getFilteredErrors, - getResponsePaneHeight, -} from "selectors/debuggerSelectors"; +import { getFilteredErrors } from "selectors/debuggerSelectors"; import { ActionExecutionResizerHeight } from "pages/Editor/APIEditor/constants"; -import { - setDebuggerSelectedTab, - setResponsePaneHeight, - showDebugger, -} from "actions/debuggerActions"; import { NoResponse, ResponseTabErrorContainer, @@ -52,6 +43,11 @@ import LOG_TYPE from "entities/AppsmithConsole/logtype"; import type { SourceEntity, Log } from "entities/AppsmithConsole"; import { ENTITY_TYPE } from "@appsmith/entities/AppsmithConsole/utils"; import { CloseDebugger } from "./Debugger/DebuggerTabs"; +import { getJsPaneDebuggerState } from "selectors/jsPaneSelectors"; +import { setJsPaneDebuggerState } from "actions/jsPaneActions"; +import { getIDEViewMode } from "selectors/ideSelectors"; +import { EditorViewMode } from "@appsmith/entities/IDE/constants"; +import ErrorLogs from "./Debugger/Errors"; const ResponseContainer = styled.div` ${ResizerCSS}; @@ -210,7 +206,10 @@ function JSResponseView(props: Props) { } } } catch (e) {} - const tabs = [ + + const ideViewMode = useSelector(getIDEViewMode); + + const tabs: BottomTab[] = [ { key: "response", title: "Response", @@ -279,12 +278,6 @@ function JSResponseView(props: Props) { ), }, - { - key: DEBUGGER_TAB_KEYS.ERROR_TAB, - title: createMessage(DEBUGGER_ERRORS), - count: errorCount, - panelComponent: , - }, { key: DEBUGGER_TAB_KEYS.LOGS_TAB, title: createMessage(DEBUGGER_LOGS), @@ -292,24 +285,34 @@ function JSResponseView(props: Props) { }, ]; + if (ideViewMode === EditorViewMode.FullScreen) { + tabs.push({ + key: DEBUGGER_TAB_KEYS.ERROR_TAB, + title: createMessage(DEBUGGER_ERRORS), + count: errorCount, + panelComponent: , + }); + } + // get the selected tab from the store. - const selectedResponseTab = useSelector(getDebuggerSelectedTab); + const { open, responseTabHeight, selectedTab } = useSelector( + getJsPaneDebuggerState, + ); + // set the selected tab in the store. const setSelectedResponseTab = useCallback((selectedTab: string) => { - dispatch(setDebuggerSelectedTab(selectedTab)); + dispatch(setJsPaneDebuggerState({ selectedTab })); }, []); - // get the height of the response pane. - const responseTabHeight = useSelector(getResponsePaneHeight); // set the height of the response pane on resize. const setResponseHeight = useCallback((height: number) => { - dispatch(setResponsePaneHeight(height)); + dispatch(setJsPaneDebuggerState({ responseTabHeight: height })); }, []); // close the debugger - const onClose = () => dispatch(showDebugger(false)); + const onClose = () => dispatch(setJsPaneDebuggerState({ open: false })); // Do not render if header tab is selected in the bottom bar. - return !(selectedResponseTab === DEBUGGER_TAB_KEYS.HEADER_TAB) ? ( + return open && selectedTab ? ( diff --git a/app/client/src/navigation/FocusElements.ts b/app/client/src/navigation/FocusElements.ts index c6356c5072..61441253c2 100644 --- a/app/client/src/navigation/FocusElements.ts +++ b/app/client/src/navigation/FocusElements.ts @@ -26,6 +26,9 @@ export enum FocusElement { SelectedJSObject = "SelectedJSObject", SelectedSegment = "SelectedSegment", IDETabs = "IDETabs", + QueryDebugger = "QueryDebugger", + ApiDebugger = "ApiDebugger", + JSDebugger = "JSDebugger", } export enum FocusElementConfigType { diff --git a/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx b/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx index ee25dfa67d..eacb7df5a0 100644 --- a/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx +++ b/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx @@ -50,7 +50,6 @@ import { replayHighlightClass } from "globalStyles/portals"; import { getPlugin } from "@appsmith/selectors/entitiesSelector"; import { setApiPaneConfigSelectedTabIndex } from "actions/apiPaneActions"; import type { AutoGeneratedHeader } from "./helpers"; -import { showDebuggerFlag } from "selectors/debuggerSelectors"; import { getApiPaneConfigSelectedTabIndex } from "selectors/apiPaneSelectors"; import { noop } from "lodash"; import { DEFAULT_DATASOURCE_NAME } from "constants/ApiEditorConstants/ApiEditorConstants"; @@ -573,9 +572,6 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { actionDatasourceName === DEFAULT_DATASOURCE_NAME) || !isExecutePermitted; - // Debugger render flag - const showDebugger = useSelector(showDebuggerFlag); - const isGraphql = isGraphqlPlugin(plugin); const theme = EditorTheme.LIGHT; @@ -732,19 +728,17 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { - {showDebugger && ( - - )} + { @@ -160,33 +160,6 @@ type DatasourceStructureProps = Partial & { }; const DatasourceStructure = (props: DatasourceStructureProps) => { - const [containerHeight, setContainerHeight] = useState(); - const containerRef = useRef(null); - - const updateContainerHeight = () => { - if (containerRef.current?.offsetHeight) { - setContainerHeight(containerRef.current?.offsetHeight); - } - }; - - const resizeObserver = useRef( - new ResizeObserver(() => { - updateContainerHeight(); - }), - ); - - useEffect(() => { - updateContainerHeight(); - if (containerRef.current) { - resizeObserver.current.observe(containerRef.current); - } - return () => { - if (containerRef.current) { - resizeObserver.current.unobserve(containerRef.current); - } - }; - }, []); - const Row = (index: number) => { const structure = props.tables[index]; @@ -201,15 +174,12 @@ const DatasourceStructure = (props: DatasourceStructureProps) => { }; return ( - - {containerHeight && ( - - )} + + ); }; diff --git a/app/client/src/pages/Editor/IDE/EditorPane/components/ActionDrawer.tsx b/app/client/src/pages/Editor/IDE/EditorPane/components/ActionDrawer.tsx index 28f67cafa6..af612152be 100644 --- a/app/client/src/pages/Editor/IDE/EditorPane/components/ActionDrawer.tsx +++ b/app/client/src/pages/Editor/IDE/EditorPane/components/ActionDrawer.tsx @@ -2,8 +2,6 @@ import React, { useEffect, useRef, useState } from "react"; import styled from "styled-components"; import { ResizerCSS } from "components/editorComponents/Debugger/Resizer"; import Resizable from "components/editorComponents/Debugger/Resizer"; -import { useSelector } from "react-redux"; -import { getResponsePaneHeight } from "selectors/debuggerSelectors"; import { ActionExecutionResizerHeight } from "pages/Editor/APIEditor/constants"; import type { BottomTab } from "components/editorComponents/EntityBottomTabs"; import EntityBottomTabs from "components/editorComponents/EntityBottomTabs"; @@ -23,11 +21,11 @@ interface Props { onResizeComplete: (height: number) => void; isRunning: boolean; tabs: BottomTab[]; + height?: number; } const ActionDrawer = (props: Props) => { const panelRef = useRef(null); - const responsePaneHeight = useSelector(getResponsePaneHeight); const [selectedTab, setSelectedTab] = useState(""); useEffect(() => { if (props.tabs.length) { @@ -38,7 +36,7 @@ const ActionDrawer = (props: Props) => { return ( void; } const ActionEditor = (props: Props) => { const dispatch = useDispatch(); const setDrawerHeight = useCallback((height: number) => { - dispatch(setResponsePaneHeight(height)); + if (props.onSetHeight) { + dispatch(props.onSetHeight(height)); + } }, []); const [settingsOpen, setSettingsOpen] = useState(false); @@ -42,6 +45,7 @@ const ActionEditor = (props: Props) => { /> ) : null; return ( - - {dataSources.length === 0 && } - {dataSources.length === 0 && this.props.mockDatasources.length > 0 && ( - <> - {mockDataSection} - - - )} - {isEnabledForCreateNew && ( - <> - - - - )} - - - - - - {dataSources.length > 0 && this.props.mockDatasources.length > 0 && ( - <> - - {mockDataSection} - - )} - + <> + + {dataSources.length === 0 && } + {dataSources.length === 0 && + this.props.mockDatasources.length > 0 && ( + <> + {mockDataSection} + + + )} + {isEnabledForCreateNew && ( + <> + + + + )} + + + + + + {dataSources.length > 0 && this.props.mockDatasources.length > 0 && ( + <> + + {mockDataSection} + + )} + + {showDebugger && } + ); } } diff --git a/app/client/src/pages/Editor/JSEditor/Form.tsx b/app/client/src/pages/Editor/JSEditor/Form.tsx index e6b5cb5281..1972b5a1b5 100644 --- a/app/client/src/pages/Editor/JSEditor/Form.tsx +++ b/app/client/src/pages/Editor/JSEditor/Form.tsx @@ -14,6 +14,7 @@ import JSObjectNameEditor from "./JSObjectNameEditor"; import { setActiveJSAction, setJsPaneConfigSelectedTab, + setJsPaneDebuggerState, startExecutingJSFunction, updateJSCollectionBody, } from "actions/jsPaneActions"; @@ -60,7 +61,6 @@ import history from "utils/history"; import { CursorPositionOrigin } from "@appsmith/reducers/uiReducers/editorContextReducer"; import LazyCodeEditor from "components/editorComponents/LazyCodeEditor"; import styled from "styled-components"; -import { showDebuggerFlag } from "selectors/debuggerSelectors"; import { Tab, TabPanel, Tabs, TabsList } from "design-system"; import { JSEditorTab } from "reducers/uiReducers/jsPaneReducer"; import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; @@ -70,6 +70,7 @@ import { getHasManageActionPermission, } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; import type { JSCollectionData } from "@appsmith/reducers/entityReducers/jsActionsReducer"; +import { DEBUGGER_TAB_KEYS } from "../../../components/editorComponents/Debugger/helpers"; interface JSFormProps { jsCollectionData: JSCollectionData; @@ -202,6 +203,12 @@ function JSEditorForm({ // Executes JS action const executeJSAction = (jsAction: JSAction, from: EventLocation) => { + dispatch( + setJsPaneDebuggerState({ + open: true, + selectedTab: DEBUGGER_TAB_KEYS.RESPONSE_TAB, + }), + ); setActiveResponse(jsAction); if (jsAction.id !== selectedJSActionOption.data?.id) setSelectedJSActionOption(convertJSActionToDropdownOption(jsAction)); @@ -303,9 +310,6 @@ function JSEditorForm({ const selectedConfigTab = useSelector(getJSPaneConfigSelectedTab); - // Debugger render flag - const showDebugger = useSelector(showDebuggerFlag); - const setSelectedConfigTab = useCallback((selectedTab: JSEditorTab) => { dispatch(setJsPaneConfigSelectedTab(selectedTab)); }, []); @@ -418,23 +422,21 @@ function JSEditorForm({ )} - {showDebugger ? ( - - | KeyboardEvent, - ) => { - handleRunAction(event, "JS_OBJECT_RESPONSE_RUN_BUTTON"); - }} - theme={theme} - /> - ) : null} + + | KeyboardEvent, + ) => { + handleRunAction(event, "JS_OBJECT_RESPONSE_RUN_BUTTON"); + }} + theme={theme} + /> diff --git a/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx b/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx index 717ec8c330..3434429581 100644 --- a/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx +++ b/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx @@ -1,4 +1,4 @@ -import { useContext, useEffect, useState } from "react"; +import { useContext } from "react"; import React, { useCallback } from "react"; import type { InjectedFormProps } from "redux-form"; import { noop } from "lodash"; @@ -15,7 +15,6 @@ import ActionSettings from "pages/Editor/ActionSettings"; import { Button, Tab, TabPanel, Tabs, TabsList, Tooltip } from "design-system"; import styled from "styled-components"; import FormRow from "components/editorComponents/FormRow"; -import { ResizerCSS } from "components/editorComponents/Debugger/Resizer"; import { createMessage, DOCUMENTATION, @@ -30,16 +29,10 @@ import ActionRightPane, { import type { ActionResponse } from "api/ActionAPI"; import type { Plugin } from "api/PluginApi"; import type { UIComponentTypes } from "api/PluginApi"; -import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/helpers"; import { EDITOR_TABS } from "constants/QueryEditorConstants"; import type { FormEvalOutput } from "reducers/evaluationReducers/formEvaluationReducer"; import { getQueryPaneConfigSelectedTabIndex } from "selectors/queryPaneSelectors"; import { setQueryPaneConfigSelectedTabIndex } from "actions/queryPaneActions"; -import { ActionExecutionResizerHeight } from "pages/Editor/APIEditor/constants"; -import { - getDebuggerSelectedTab, - showDebuggerFlag, -} from "selectors/debuggerSelectors"; import type { SourceEntity } from "entities/AppsmithConsole"; import { ENTITY_TYPE as SOURCE_ENTITY_TYPE } from "@appsmith/entities/AppsmithConsole/utils"; import { DocsLink, openDoc } from "../../../constants/DocumentationLinks"; @@ -47,7 +40,6 @@ import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; import { QueryEditorContext } from "./QueryEditorContext"; import QueryDebuggerTabs from "./QueryDebuggerTabs"; -import { setDebuggerSelectedTab, showDebugger } from "actions/debuggerActions"; import useShowSchema from "components/editorComponents/ActionRightPane/useShowSchema"; import { doesPluginRequireDatasource } from "@appsmith/entities/Engine/actionHelpers"; import FormRender from "./FormRender"; @@ -79,16 +71,6 @@ const QueryFormContainer = styled.form` } `; -export const TabbedViewContainer = styled.div` - ${ResizerCSS}; - height: ${ActionExecutionResizerHeight}px; - // Minimum height of bottom tabs as it can be resized - min-height: 36px; - width: 100%; - background-color: var(--ads-v2-color-bg); - border-top: 1px solid var(--ads-v2-color-border); -`; - const SettingsWrapper = styled.div` ${thinScrollbar}; height: 100%; @@ -221,7 +203,6 @@ export function EditorJSONtoForm(props: Props) { onCreateDatasourceClick, onRunClick, plugin, - responseDisplayFormat, runErrorMessage, settingConfig, uiComponent, @@ -242,8 +223,6 @@ export function EditorJSONtoForm(props: Props) { const currentActionConfig: Action | undefined = actions.find( (action) => action.id === params.apiId || action.id === params.queryId, ); - const [showResponseOnFirstLoad, setShowResponseOnFirstLoad] = - useState(false); const pluginRequireDatasource = doesPluginRequireDatasource(plugin); @@ -264,38 +243,6 @@ export function EditorJSONtoForm(props: Props) { const dispatch = useDispatch(); - // These useEffects are used to open the response tab by default for page load queries - // as for page load queries, query response is available and can be shown in response tab - useEffect(() => { - // actionResponse and responseDisplayFormat is present only when query has response available - if ( - responseDisplayFormat && - !!responseDisplayFormat?.title && - actionResponse && - actionResponse.isExecutionSuccess && - !showResponseOnFirstLoad - ) { - dispatch(showDebugger(true)); - dispatch(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.RESPONSE_TAB)); - setShowResponseOnFirstLoad(true); - } - }, [responseDisplayFormat, actionResponse, showResponseOnFirstLoad]); - - useEffect(() => { - if (showSchema) { - dispatch(showDebugger(true)); - dispatch(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.SCHEMA_TAB)); - } - }, [showSchema]); - - // When multiple page load queries exist, we want to response tab by default for all of them - // Hence this useEffect will reset showResponseOnFirstLoad flag used to track whether to show response tab or not - useEffect(() => { - if (!!currentActionConfig?.id) { - setShowResponseOnFirstLoad(false); - } - }, [currentActionConfig?.id]); - const handleDocumentationClick = () => { openDoc(DocsLink.QUERY, plugin?.documentationLink, plugin?.name); }; @@ -311,15 +258,10 @@ export function EditorJSONtoForm(props: Props) { const selectedConfigTab = useSelector(getQueryPaneConfigSelectedTabIndex); - // Debugger render flag - const renderDebugger = useSelector(showDebuggerFlag); - const setSelectedConfigTab = useCallback((selectedIndex: string) => { dispatch(setQueryPaneConfigSelectedTabIndex(selectedIndex)); }, []); - const selectedResponseTab = useSelector(getDebuggerSelectedTab); - // here we check for normal conditions for opening action pane // or if any of the flags are true, We should open the actionpane by default. const shouldOpenActionPaneByDefault = @@ -465,19 +407,16 @@ export function EditorJSONtoForm(props: Props) { )} - {renderDebugger && - selectedResponseTab !== DEBUGGER_TAB_KEYS.HEADER_TAB && ( - - )} + {showRightPane && ( diff --git a/app/client/src/pages/Editor/QueryEditor/QueryDebuggerTabs.tsx b/app/client/src/pages/Editor/QueryEditor/QueryDebuggerTabs.tsx index ea82cda35a..701584f8b4 100644 --- a/app/client/src/pages/Editor/QueryEditor/QueryDebuggerTabs.tsx +++ b/app/client/src/pages/Editor/QueryEditor/QueryDebuggerTabs.tsx @@ -1,20 +1,11 @@ -import { - setDebuggerSelectedTab, - setResponsePaneHeight, - showDebugger, -} from "actions/debuggerActions"; import { CloseDebugger } from "components/editorComponents/Debugger/DebuggerTabs"; import type { BottomTab } from "components/editorComponents/EntityBottomTabs"; import EntityBottomTabs from "components/editorComponents/EntityBottomTabs"; -import React, { useCallback, useEffect, useRef } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import styled from "styled-components"; import { ActionExecutionResizerHeight } from "pages/Editor/APIEditor/constants"; -import { - getDebuggerSelectedTab, - getErrorCount, - getResponsePaneHeight, -} from "selectors/debuggerSelectors"; +import { getErrorCount } from "selectors/debuggerSelectors"; import { Text, TextType } from "design-system-old"; import Resizable, { ResizerCSS, @@ -23,12 +14,10 @@ import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/helpers" import { DEBUGGER_ERRORS, DEBUGGER_LOGS, - INSPECT_ENTITY, createMessage, } from "@appsmith/constants/messages"; import DebuggerLogs from "components/editorComponents/Debugger/DebuggerLogs"; import ErrorLogs from "components/editorComponents/Debugger/Errors"; -import EntityDeps from "components/editorComponents/Debugger/EntityDependecies"; import Schema from "components/editorComponents/Debugger/Schema"; import type { ActionResponse } from "api/ActionAPI"; import { isString } from "lodash"; @@ -42,6 +31,11 @@ import { import { DatasourceComponentTypes } from "api/PluginApi"; import { fetchDatasourceStructure } from "actions/datasourceActions"; import { DatasourceStructureContext } from "entities/Datasource"; +import { getQueryPaneDebuggerState } from "selectors/queryPaneSelectors"; +import { setQueryPaneDebuggerState } from "actions/queryPaneActions"; +import { actionResponseDisplayDataFormats } from "../utils"; +import { getIDEViewMode } from "selectors/ideSelectors"; +import { EditorViewMode } from "@appsmith/entities/IDE/constants"; const ResultsCount = styled.div` position: absolute; @@ -86,8 +80,16 @@ function QueryDebuggerTabs({ const panelRef = useRef(null); const dispatch = useDispatch(); - const selectedResponseTab = useSelector(getDebuggerSelectedTab); - const responsePaneHeight = useSelector(getResponsePaneHeight); + const { open, responseTabHeight, selectedTab } = useSelector( + getQueryPaneDebuggerState, + ); + + const { responseDisplayFormat } = + actionResponseDisplayDataFormats(actionResponse); + + const [showResponseOnFirstLoad, setShowResponseOnFirstLoad] = + useState(false); + const errorCount = useSelector(getErrorCount); const pluginDatasourceForm = useSelector((state) => @@ -120,6 +122,46 @@ function QueryDebuggerTabs({ } }, []); + // These useEffects are used to open the response tab by default for page load queries + // as for page load queries, query response is available and can be shown in response tab + useEffect(() => { + // actionResponse and responseDisplayFormat is present only when query has response available + if ( + responseDisplayFormat && + !!responseDisplayFormat?.title && + actionResponse && + actionResponse.isExecutionSuccess && + !showResponseOnFirstLoad + ) { + dispatch( + setQueryPaneDebuggerState({ + open: true, + selectedTab: DEBUGGER_TAB_KEYS.RESPONSE_TAB, + }), + ); + setShowResponseOnFirstLoad(true); + } + }, [responseDisplayFormat, actionResponse, showResponseOnFirstLoad]); + + useEffect(() => { + if (showSchema && !selectedTab) { + dispatch( + setQueryPaneDebuggerState({ + open: true, + selectedTab: DEBUGGER_TAB_KEYS.SCHEMA_TAB, + }), + ); + } + }, [showSchema, currentActionConfig?.id, selectedTab]); + + // When multiple page load queries exist, we want to response tab by default for all of them + // Hence this useEffect will reset showResponseOnFirstLoad flag used to track whether to show response tab or not + useEffect(() => { + if (!!currentActionConfig?.id) { + setShowResponseOnFirstLoad(false); + } + }, [currentActionConfig?.id]); + // Query is executed even once during the session, show the response data. if (actionResponse) { if (isString(actionResponse.body)) { @@ -140,32 +182,36 @@ function QueryDebuggerTabs({ } const setQueryResponsePaneHeight = useCallback((height: number) => { - dispatch(setResponsePaneHeight(height)); + dispatch(setQueryPaneDebuggerState({ responseTabHeight: height })); + }, []); + + const onClose = useCallback(() => { + dispatch(setQueryPaneDebuggerState({ open: false })); }, []); - const onClose = () => dispatch(showDebugger(false)); const setSelectedResponseTab = useCallback((tabKey: string) => { - dispatch(setDebuggerSelectedTab(tabKey)); + dispatch(setQueryPaneDebuggerState({ selectedTab: tabKey })); }, []); - const responseTabs: BottomTab[] = [ - { - key: DEBUGGER_TAB_KEYS.ERROR_TAB, - title: createMessage(DEBUGGER_ERRORS), - count: errorCount, - panelComponent: , - }, - { - key: DEBUGGER_TAB_KEYS.LOGS_TAB, - title: createMessage(DEBUGGER_LOGS), - panelComponent: , - }, - { - key: DEBUGGER_TAB_KEYS.INSPECT_TAB, - title: createMessage(INSPECT_ENTITY), - panelComponent: , - }, - ]; + const ideViewMode = useSelector(getIDEViewMode); + + const responseTabs: BottomTab[] = []; + + if (ideViewMode === EditorViewMode.FullScreen) { + responseTabs.push( + { + key: DEBUGGER_TAB_KEYS.ERROR_TAB, + title: createMessage(DEBUGGER_ERRORS), + count: errorCount, + panelComponent: , + }, + { + key: DEBUGGER_TAB_KEYS.LOGS_TAB, + title: createMessage(DEBUGGER_LOGS), + panelComponent: , + }, + ); + } if (currentActionConfig) { responseTabs.unshift({ @@ -197,13 +243,15 @@ function QueryDebuggerTabs({ }); } + if (!open) return null; + return ( setQueryResponsePaneHeight(height) } @@ -226,7 +274,7 @@ function QueryDebuggerTabs({ { const actionResponse = useSelector((state) => getActionData(state, currentActionConfig.id), ); - const responsePaneHeight = useSelector(getResponsePaneHeight); + const { responseTabHeight } = useSelector(getQueryPaneDebuggerState); const { responseDataTypes, responseDisplayFormat } = actionResponseDisplayDataFormats(actionResponse); @@ -99,7 +99,7 @@ const QueryResponseTab = (props: Props) => { panelComponent: responseTabComponent( dataType.key, output, - responsePaneHeight, + responseTabHeight, ), }; }); @@ -278,7 +278,7 @@ const QueryResponseTab = (props: Props) => { {responseTabComponent( selectedControl || segmentedControlOptions[0]?.value, output, - responsePaneHeight, + responseTabHeight, )} )} diff --git a/app/client/src/reducers/uiReducers/debuggerReducer.ts b/app/client/src/reducers/uiReducers/debuggerReducer.ts index 9ac2c506ec..4b7eea94f8 100644 --- a/app/client/src/reducers/uiReducers/debuggerReducer.ts +++ b/app/client/src/reducers/uiReducers/debuggerReducer.ts @@ -160,6 +160,26 @@ const debuggerReducer = createImmerReducer(initialState, { ) => { state.context = action.context; }, + [ReduxActionTypes.SET_CANVAS_DEBUGGER_STATE]: ( + state: DebuggerReduxState, + action: { payload: Partial }, + ): DebuggerReduxState => { + return { + ...state, + isOpen: "open" in action.payload ? !!action.payload.open : state.isOpen, + context: { + ...state.context, + responseTabHeight: + "responseTabHeight" in action.payload + ? Number(action.payload.responseTabHeight) + : state.context.responseTabHeight, + selectedDebuggerTab: + "selectedTab" in action.payload + ? String(action.payload.selectedTab) + : state.context.selectedDebuggerTab, + }, + }; + }, // Resetting debugger state after env switch [ReduxActionTypes.SWITCH_ENVIRONMENT_SUCCESS]: () => { return klona(initialState); @@ -183,4 +203,10 @@ export interface DebuggerContext { selectedDebuggerFilter: string; } +export interface CanvasDebuggerState { + open: boolean; + responseTabHeight: number; + selectedTab?: string; +} + export default debuggerReducer; diff --git a/app/client/src/reducers/uiReducers/jsPaneReducer.ts b/app/client/src/reducers/uiReducers/jsPaneReducer.ts index 7553af7c5c..0403411d87 100644 --- a/app/client/src/reducers/uiReducers/jsPaneReducer.ts +++ b/app/client/src/reducers/uiReducers/jsPaneReducer.ts @@ -12,24 +12,31 @@ export enum JSEditorTab { SETTINGS = "SETTINGS", } +export interface JSPaneDebuggerState { + open: boolean; + responseTabHeight: number; + selectedTab?: string; +} + export interface JsPaneReduxState { isCreating: boolean; - isFetching: boolean; isSaving: Record; isDeleting: Record; isDirty: Record; selectedConfigTab: JSEditorTab; - responseTabHeight: number; + debugger: JSPaneDebuggerState; } const initialState: JsPaneReduxState = { isCreating: false, - isFetching: false, isSaving: {}, isDeleting: {}, isDirty: {}, - responseTabHeight: ActionExecutionResizerHeight, selectedConfigTab: JSEditorTab.CODE, + debugger: { + open: false, + responseTabHeight: ActionExecutionResizerHeight, + }, }; const jsPaneReducer = createReducer(initialState, { @@ -184,6 +191,18 @@ const jsPaneReducer = createReducer(initialState, { selectedConfigTab: selectedTab, }; }, + [ReduxActionTypes.SET_JS_PANE_DEBUGGER_STATE]: ( + state: JsPaneReduxState, + action: ReduxAction>, + ) => { + return { + ...state, + debugger: { + ...state.debugger, + ...action.payload, + }, + }; + }, }); export default jsPaneReducer; diff --git a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts index 5cfc7abbdd..83f4c7c43f 100644 --- a/app/client/src/sagas/ActionExecution/PluginActionSaga.ts +++ b/app/client/src/sagas/ActionExecution/PluginActionSaga.ts @@ -18,9 +18,11 @@ import { updateAction, updateActionData, } from "actions/pluginActionActions"; -import { makeUpdateJSCollection } from "sagas/JSPaneSagas"; +import { + handleExecuteJSFunctionSaga, + makeUpdateJSCollection, +} from "sagas/JSPaneSagas"; -import { setDebuggerSelectedTab, showDebugger } from "actions/debuggerActions"; import type { ApplicationPayload, ReduxAction, @@ -38,12 +40,13 @@ import type { import ActionAPI from "api/ActionAPI"; import { getAction, + getCurrentActions, getCurrentPageNameByActionId, + getDatasource, + getJSCollectionFromAllEntities, getPlugin, isActionDirty, isActionSaving, - getDatasource, - getJSCollectionFromAllEntities, } from "@appsmith/selectors/entitiesSelector"; import { getIsGitSyncModalOpen } from "selectors/gitSyncSelectors"; import { @@ -51,15 +54,15 @@ import { getCurrentApplication, } from "@appsmith/selectors/applicationSelectors"; import { + find, + flatten, get, isArray, - isString, - set, - find, - isNil, - flatten, isArrayBuffer, isEmpty, + isNil, + isString, + set, unset, } from "lodash"; import AppsmithConsole from "utils/AppsmithConsole"; @@ -77,12 +80,12 @@ import type { Action } from "entities/Action"; import { PluginType } from "entities/Action"; import LOG_TYPE from "entities/AppsmithConsole/logtype"; import { + ACTION_EXECUTION_CANCELLED, + ACTION_EXECUTION_FAILED, createMessage, ERROR_ACTION_EXECUTE_FAIL, ERROR_FAIL_ON_PAGE_LOAD_ACTIONS, ERROR_PLUGIN_ACTION_EXECUTE, - ACTION_EXECUTION_CANCELLED, - ACTION_EXECUTION_FAILED, SWITCH_ENVIRONMENT_SUCCESS, } from "@appsmith/constants/messages"; import type { @@ -107,7 +110,7 @@ import * as log from "loglevel"; import { EMPTY_RESPONSE } from "components/editorComponents/emptyResponse"; import type { AppState } from "@appsmith/reducers"; import { DEFAULT_EXECUTE_ACTION_TIMEOUT_MS } from "@appsmith/constants/ApiConstants"; -import { evalWorker, evaluateActionBindings } from "sagas/EvaluationsSaga"; +import { evaluateActionBindings, evalWorker } from "sagas/EvaluationsSaga"; import { isBlobUrl, parseBlobUrl } from "utils/AppsmithUtils"; import { getType, Types } from "utils/TypeHelpers"; import { matchPath } from "react-router"; @@ -115,11 +118,11 @@ import { API_EDITOR_BASE_PATH, API_EDITOR_ID_PATH, API_EDITOR_PATH_WITH_SELECTED_PAGE_ID, + CURL_IMPORT_PAGE_PATH, INTEGRATION_EDITOR_PATH, + matchQueryBuilderPath, QUERIES_EDITOR_BASE_PATH, QUERIES_EDITOR_ID_PATH, - CURL_IMPORT_PAGE_PATH, - matchQueryBuilderPath, } from "constants/routes"; import { SAAS_EDITOR_API_ID_PATH } from "pages/Editor/SaaSEditor/constants"; import { APP_MODE } from "entities/App"; @@ -141,10 +144,9 @@ import { submitCurlImportForm } from "actions/importActions"; import type { curlImportFormValues } from "pages/Editor/APIEditor/helpers"; import { matchBasePath } from "@appsmith/pages/Editor/Explorer/helpers"; import { - isTrueObject, findDatatype, + isTrueObject, } from "@appsmith/workers/Evaluation/evaluationUtils"; -import { handleExecuteJSFunctionSaga } from "sagas/JSPaneSagas"; import type { Plugin } from "api/PluginApi"; import { setDefaultActionDisplayFormat } from "./PluginActionSagaUtils"; import { checkAndLogErrorsIfCyclicDependency } from "sagas/helper"; @@ -152,13 +154,15 @@ import { toast } from "design-system"; import type { TRunDescription } from "workers/Evaluation/fns/actionFns"; import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/helpers"; import { FILE_SIZE_LIMIT_FOR_BLOBS } from "constants/WidgetConstants"; -import { getCurrentActions } from "@appsmith/selectors/entitiesSelector"; import type { ActionData } from "@appsmith/reducers/entityReducers/actionsReducer"; import { handleStoreOperations } from "./StoreActionSaga"; import { fetchPage } from "actions/pageActions"; import type { Datasource } from "entities/Datasource"; import { softRefreshDatasourceStructure } from "actions/datasourceActions"; -import { changeQuery } from "actions/queryPaneActions"; +import { + changeQuery, + setQueryPaneDebuggerState, +} from "actions/queryPaneActions"; import { getCurrentEnvironmentDetails, getCurrentEnvironmentName, @@ -179,6 +183,7 @@ import { } from "@appsmith/utils/actionExecutionUtils"; import type { JSAction, JSCollection } from "entities/JSCollection"; import { getAllowedActionAnalyticsKeys } from "constants/AppsmithActionConstants/formConfig/ActionAnalyticsConfig"; +import { setApiPaneDebuggerState } from "../../actions/apiPaneActions"; enum ActionResponseDataTypes { BINARY = "BINARY", @@ -792,7 +797,7 @@ export function* runActionSaga( const { paginationField } = reduxAction.payload; // open response tab in debugger on exection of action. if (!reduxAction.payload.skipOpeningDebugger) { - yield call(openDebugger); + yield call(openDebugger, plugin.type); } let payload = EMPTY_RESPONSE; @@ -1170,7 +1175,7 @@ function* executePageLoadAction(pageAction: PageAction, span?: OtlpSpan) { // open response tab in debugger on exection of action on page load. // Only if current page is the page on which the action is executed. if (window.location.pathname.includes(pageAction.id)) - yield call(openDebugger); + yield call(openDebugger, plugin.type); if (isError) { AppsmithConsole.addErrors([ @@ -1563,9 +1568,20 @@ function triggerFileUploadInstrumentation( } //Open debugger with response tab selected. -function* openDebugger() { - yield put(showDebugger(true)); - yield put(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.RESPONSE_TAB)); +function* openDebugger(pluginType: PluginType) { + if (pluginType === PluginType.API) { + yield put( + setApiPaneDebuggerState({ + open: true, + selectedTab: DEBUGGER_TAB_KEYS.RESPONSE_TAB, + }), + ); + } else { + setQueryPaneDebuggerState({ + open: true, + selectedTab: DEBUGGER_TAB_KEYS.RESPONSE_TAB, + }); + } } // Function to clear the action responses for the actions which are not executeOnLoad. diff --git a/app/client/src/sagas/JSPaneSagas.ts b/app/client/src/sagas/JSPaneSagas.ts index 79777228e2..b1c0a4de73 100644 --- a/app/client/src/sagas/JSPaneSagas.ts +++ b/app/client/src/sagas/JSPaneSagas.ts @@ -53,6 +53,7 @@ import { updateJSCollectionBodySuccess, updateJSFunction, executeJSFunctionInit, + setJsPaneDebuggerState, } from "actions/jsPaneActions"; import { getCurrentWorkspaceId } from "@appsmith/selectors/selectedWorkspaceSelectors"; import { getPluginIdOfPackageName } from "sagas/selectors"; @@ -91,14 +92,13 @@ import type { EventLocation } from "@appsmith/utils/analyticsUtilTypes"; import AnalyticsUtil from "utils/AnalyticsUtil"; import { checkAndLogErrorsIfCyclicDependency } from "./helper"; import { toast } from "design-system"; -import { setDebuggerSelectedTab, showDebugger } from "actions/debuggerActions"; import { DEBUGGER_TAB_KEYS } from "components/editorComponents/Debugger/helpers"; -import { getDebuggerSelectedTab } from "selectors/debuggerSelectors"; import { getIsServerDSLMigrationsEnabled } from "selectors/pageSelectors"; import { getJSActionNameToDisplay, getJSActionPathNameToDisplay, } from "@appsmith/utils/actionExecutionUtils"; +import { getJsPaneDebuggerState } from "selectors/jsPaneSelectors"; export interface GenerateDefaultJSObjectProps { name: string; @@ -434,15 +434,16 @@ export function* handleExecuteJSFunctionSaga(data: { // open response tab in debugger on runnning or page load js action. if (doesURLPathContainCollectionId || openDebugger) { - yield put(showDebugger(true)); + yield put(setJsPaneDebuggerState({ open: true })); - const debuggerSelectedTab: ReturnType = - yield select(getDebuggerSelectedTab); + const { selectedTab: debuggerSelectedTab } = yield select( + getJsPaneDebuggerState, + ); yield put( - setDebuggerSelectedTab( - debuggerSelectedTab || DEBUGGER_TAB_KEYS.RESPONSE_TAB, - ), + setJsPaneDebuggerState({ + selectedTab: debuggerSelectedTab || DEBUGGER_TAB_KEYS.RESPONSE_TAB, + }), ); } yield put({ @@ -481,8 +482,12 @@ export function* handleExecuteJSFunctionSaga(data: { } catch (error) { // open response tab in debugger on runnning js action. if (doesURLPathContainCollectionId) { - yield put(showDebugger(true)); - yield put(setDebuggerSelectedTab(DEBUGGER_TAB_KEYS.RESPONSE_TAB)); + yield put( + setJsPaneDebuggerState({ + open: true, + selectedTab: DEBUGGER_TAB_KEYS.RESPONSE_TAB, + }), + ); } AppsmithConsole.addErrors([ { diff --git a/app/client/src/selectors/apiPaneSelectors.ts b/app/client/src/selectors/apiPaneSelectors.ts index df0dd35505..9ec0ee0f5e 100644 --- a/app/client/src/selectors/apiPaneSelectors.ts +++ b/app/client/src/selectors/apiPaneSelectors.ts @@ -1,4 +1,6 @@ import type { AppState } from "@appsmith/reducers"; +import { createSelector } from "reselect"; +import { combinedPreviewModeSelector } from "./editorSelectors"; type GetFormData = ( state: AppState, @@ -18,3 +20,12 @@ export const getApiRightPaneSelectedTab = (state: AppState) => export const getIsRunning = (state: AppState, apiId: string) => state.ui.apiPane.isRunning[apiId]; + +export const getApiPaneDebuggerState = (state: AppState) => + state.ui.apiPane.debugger; + +export const showApiPaneDebugger = createSelector( + (state) => state.ui.apiPane.debugger.open, + combinedPreviewModeSelector, + (isOpen, isPreview) => isOpen && !isPreview, +); diff --git a/app/client/src/selectors/debuggerSelectors.tsx b/app/client/src/selectors/debuggerSelectors.tsx index 39ee035925..1fea171dd4 100644 --- a/app/client/src/selectors/debuggerSelectors.tsx +++ b/app/client/src/selectors/debuggerSelectors.tsx @@ -12,6 +12,7 @@ import { } from "@appsmith/workers/Evaluation/evaluationUtils"; import { getDataTree } from "./dataTreeSelectors"; import { combinedPreviewModeSelector } from "./editorSelectors"; +import type { CanvasDebuggerState } from "reducers/uiReducers/debuggerReducer"; interface ErrorObejct { [k: string]: Log; @@ -148,8 +149,22 @@ export const getScrollPosition = (state: AppState) => export const getDebuggerContext = (state: AppState) => state.ui.debugger.context; +export const getDebuggerOpen = (state: AppState) => state.ui.debugger.isOpen; + export const showDebuggerFlag = createSelector( - (state) => state.ui.debugger.isOpen, + getDebuggerOpen, combinedPreviewModeSelector, (isOpen, isPreview) => isOpen && !isPreview, ); + +export const getCanvasDebuggerState = createSelector( + showDebuggerFlag, + getDebuggerContext, + (openState, context): CanvasDebuggerState => { + return { + open: openState, + selectedTab: context.selectedDebuggerTab, + responseTabHeight: context.responseTabHeight, + }; + }, +); diff --git a/app/client/src/selectors/jsPaneSelectors.ts b/app/client/src/selectors/jsPaneSelectors.ts index 179cfecb3f..e425fe9c82 100644 --- a/app/client/src/selectors/jsPaneSelectors.ts +++ b/app/client/src/selectors/jsPaneSelectors.ts @@ -21,3 +21,6 @@ export const getFirstJSObject = ( return identifyEntityFromPath(urlWithoutQueryParams); } }; + +export const getJsPaneDebuggerState = (state: AppState) => + state.ui.jsPane.debugger; diff --git a/app/client/src/selectors/queryPaneSelectors.ts b/app/client/src/selectors/queryPaneSelectors.ts index 5ef7491c6e..651452bd59 100644 --- a/app/client/src/selectors/queryPaneSelectors.ts +++ b/app/client/src/selectors/queryPaneSelectors.ts @@ -18,6 +18,9 @@ export const getFirstQuery = (state: AppState): FocusEntityInfo | undefined => { } }; +export const getQueryPaneDebuggerState = (state: AppState) => + state.ui.queryPane.debugger; + export const getQueryRunErrorMessage = (state: AppState, id: string) => { const { runErrorMessage } = state.ui.queryPane; return runErrorMessage[id];