From 23c9374e4ceb7933511ae753a7b1b9dbef24bd99 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Fri, 14 Feb 2025 21:57:08 +0530 Subject: [PATCH] feat: Inspect State CTA for discovery (#39100) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Adds various discovery points for State Inspector Fixes #38934 ## Automation /ok-to-test tags="@tag.All" ### :mag: Cypress test results > [!TIP] > ๐ŸŸข ๐ŸŸข ๐ŸŸข All cypress tests have passed! ๐ŸŽ‰ ๐ŸŽ‰ ๐ŸŽ‰ > Workflow run: > Commit: e9dc2398262b8cd2bbb69b45bd7089e9fd029e56 > Cypress dashboard. > Tags: `@tag.All` > Spec: >
Fri, 14 Feb 2025 15:47:53 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Introduced an โ€œInspect Stateโ€ option across various parts of the interface, enabling users to directly review state details for widgets, actions, and collections via context menus, toolbars, and property pane actions. - Added a new `InspectStateHeaderButton` and `InspectStateMenuItem` for enhanced state inspection capabilities. - **Style** - Refined layout and typography in popups and menus for a cleaner, more consistent user experience. - **Bug Fixes** - Enhanced type safety in property pane actions by enforcing stricter type checks. - **Chores** - Updated imports and refactored related logic to streamline the configuration handling for the debugger interface. --- .../PeekOverlay/PeekOverlay_Spec.ts | 272 +++++++++--------- .../cypress/support/Pages/PeekOverlay.ts | 4 +- .../ads/src/Icon/Icon.provider.tsx | 5 + .../__assets__/icons/ads/state-inspector.svg | 11 + app/client/src/actions/debuggerActions.ts | 7 - .../src/actions/debuggerStateInspector.ts | 8 + app/client/src/ce/constants/messages.ts | 1 + .../PeekOverlayPopup/PeekOverlayPopup.tsx | 28 +- .../CodeEditor/PeekOverlayPopup/styles.ts | 16 +- .../CTAs/InspectStateHeaderButton.tsx | 36 +++ .../CTAs/InspectStateMenuItem.tsx | 34 +++ .../CTAs/InspectStateToolbarButton.tsx | 36 +++ .../Debugger/StateInspector/CTAs/index.ts | 3 + .../StateInspector/hooks/useGetDisplayData.ts | 2 +- .../hooks/useStateInspectorState.ts | 4 +- .../Debugger/hooks/useDebuggerConfig.ts | 17 ++ .../Debugger/hooks/useDebuggerTriggerClick.ts | 63 +--- .../Debugger/utils/getDebuggerPaneConfig.ts | 50 ++++ .../components/ToolbarMenu/ToolbarMenu.tsx | 4 + .../JS/EntityItem/AppJSContextMenuItems.tsx | 6 +- .../EntityItem/AppQueryContextMenuItems.tsx | 6 +- .../UI/UIEntityListTree/WidgetContextMenu.tsx | 5 + .../JSEditor/AppJSEditorContextMenu.tsx | 4 + .../Editor/PropertyPane/PropertyPaneTitle.tsx | 10 +- .../Editor/PropertyPane/PropertyPaneView.tsx | 16 +- app/client/src/sagas/DebuggerSagas.ts | 2 +- .../src/selectors/debuggerSelectors.tsx | 5 +- .../src/selectors/debuggerStateInspector.ts | 4 + 28 files changed, 427 insertions(+), 232 deletions(-) create mode 100644 app/client/packages/design-system/ads/src/__assets__/icons/ads/state-inspector.svg create mode 100644 app/client/src/actions/debuggerStateInspector.ts create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateHeaderButton.tsx create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateMenuItem.tsx create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateToolbarButton.tsx create mode 100644 app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/index.ts create mode 100644 app/client/src/components/editorComponents/Debugger/hooks/useDebuggerConfig.ts create mode 100644 app/client/src/components/editorComponents/Debugger/utils/getDebuggerPaneConfig.ts create mode 100644 app/client/src/selectors/debuggerStateInspector.ts diff --git a/app/client/cypress/e2e/Regression/ClientSide/PeekOverlay/PeekOverlay_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/PeekOverlay/PeekOverlay_Spec.ts index 8208f09385a4..efba23656cb6 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/PeekOverlay/PeekOverlay_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/PeekOverlay/PeekOverlay_Spec.ts @@ -9,141 +9,145 @@ import { dataManager, } from "../../../../support/Objects/ObjectsCore"; -describe("Peek overlay", { tags: ["@tag.JS", "@tag.Binding"] }, () => { - it("1. Main test", () => { - entityExplorer.DragDropWidgetNVerify("tablewidgetv2", 500, 100); - table.AddSampleTableData(); - apiPage.CreateAndFillApi( - dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl, - ); - agHelper.Sleep(2000); - apiPage.RunAPI(); - apiPage.CreateAndFillApi( - dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl, - ); - agHelper.Sleep(2000); - - jsEditor.CreateJSObject(JsObjectContent, { - paste: true, - completeReplace: true, - toRun: false, - shouldCreateNewJSObj: true, - lineNumber: 0, - prettify: true, +describe( + "Peek overlay", + { tags: ["@tag.JS", "@tag.Binding", "@tag.IDE"] }, + () => { + it("1. Main test", () => { + entityExplorer.DragDropWidgetNVerify("tablewidgetv2", 500, 100); + table.AddSampleTableData(); + apiPage.CreateAndFillApi( + dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl, + ); + agHelper.Sleep(2000); + apiPage.RunAPI(); + apiPage.CreateAndFillApi( + dataManager.dsValues[dataManager.defaultEnviorment].mockApiUrl, + ); + agHelper.Sleep(2000); + + jsEditor.CreateJSObject(JsObjectContent, { + paste: true, + completeReplace: true, + toRun: false, + shouldCreateNewJSObj: true, + lineNumber: 0, + prettify: true, + }); + jsEditor.SelectFunctionDropdown("myFun2"); + jsEditor.RunJSObj(); + agHelper.Sleep(); + debuggerHelper.CloseBottomBar(); + + // check number array + peekOverlay.HoverCode(8, 3, "numArray"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("array"); + peekOverlay.CheckPrimitveArrayInOverlay([1, 2, 3]); + peekOverlay.ResetHover(); + + // check basic object + peekOverlay.HoverCode(9, 3, "objectData"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("object"); + peekOverlay.CheckBasicObjectInOverlay({ x: 123, y: "123" }); + peekOverlay.ResetHover(); + + // check null - with this keyword + peekOverlay.HoverCode(10, 3, "nullData"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("null"); + peekOverlay.CheckPrimitiveValue("null"); + peekOverlay.ResetHover(); + + // check number + peekOverlay.HoverCode(11, 3, "numberData"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("number"); + peekOverlay.CheckPrimitiveValue("1"); + peekOverlay.ResetHover(); + + // check boolean + peekOverlay.HoverCode(12, 3, "isLoading"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("boolean"); + peekOverlay.CheckPrimitiveValue("false"); + peekOverlay.ResetHover(); + + // TODO: handle this function failure on CI tests -> "function(){}" + // check function + // peekOverlay.HoverCode(13, 3, "run"); + // peekOverlay.IsOverlayOpen(); + // peekOverlay.VerifyDataType("function"); + // peekOverlay.CheckPrimitiveValue("function () {}"); + // peekOverlay.ResetHover(); + + // check undefined + peekOverlay.HoverCode(14, 3, "data"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("undefined"); + peekOverlay.CheckPrimitiveValue("undefined"); + peekOverlay.ResetHover(); + + // check string + peekOverlay.HoverCode(15, 3, "mode"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("string"); + peekOverlay.CheckPrimitiveValue("EDIT"); + peekOverlay.ResetHover(); + + // check if overlay closes + peekOverlay.HoverCode(16, 3, "store"); + peekOverlay.IsOverlayOpen(); + peekOverlay.ResetHover(); + peekOverlay.IsOverlayOpen(false); + + // widget object + peekOverlay.HoverCode(17, 1, "Table1"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("object"); + peekOverlay.ResetHover(); + + // widget property + peekOverlay.HoverCode(18, 3, "pageNo"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("number"); + peekOverlay.CheckPrimitiveValue("1"); + peekOverlay.ResetHover(); + + // widget property + peekOverlay.HoverCode(19, 3, "tableData"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("array"); + peekOverlay.CheckObjectArrayInOverlay([{}, {}, {}]); + peekOverlay.ResetHover(); + + // basic nested property + peekOverlay.HoverCode(20, 7, "id"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("number"); + peekOverlay.CheckPrimitiveValue("1"); + peekOverlay.ResetHover(); + + // undefined object + peekOverlay.HoverCode(21, 1, "aljshdlja"); + peekOverlay.IsOverlayOpen(false); + peekOverlay.ResetHover(); + + // this keyword + peekOverlay.HoverCode(22, 3, "numArray"); + peekOverlay.IsOverlayOpen(); + peekOverlay.VerifyDataType("array"); + peekOverlay.CheckPrimitveArrayInOverlay([1, 2, 3]); + peekOverlay.ResetHover(); + + // pageList is an internal property - peek overlay shouldn't work + peekOverlay.HoverCode(23, 1, "pageList"); + peekOverlay.IsOverlayOpen(false); + peekOverlay.ResetHover(); }); - jsEditor.SelectFunctionDropdown("myFun2"); - jsEditor.RunJSObj(); - agHelper.Sleep(); - debuggerHelper.CloseBottomBar(); - - // check number array - peekOverlay.HoverCode(8, 3, "numArray"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("array"); - peekOverlay.CheckPrimitveArrayInOverlay([1, 2, 3]); - peekOverlay.ResetHover(); - - // check basic object - peekOverlay.HoverCode(9, 3, "objectData"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("object"); - peekOverlay.CheckBasicObjectInOverlay({ x: 123, y: "123" }); - peekOverlay.ResetHover(); - - // check null - with this keyword - peekOverlay.HoverCode(10, 3, "nullData"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("null"); - peekOverlay.CheckPrimitiveValue("null"); - peekOverlay.ResetHover(); - - // check number - peekOverlay.HoverCode(11, 3, "numberData"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("number"); - peekOverlay.CheckPrimitiveValue("1"); - peekOverlay.ResetHover(); - - // check boolean - peekOverlay.HoverCode(12, 3, "isLoading"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("boolean"); - peekOverlay.CheckPrimitiveValue("false"); - peekOverlay.ResetHover(); - - // TODO: handle this function failure on CI tests -> "function(){}" - // check function - // peekOverlay.HoverCode(13, 3, "run"); - // peekOverlay.IsOverlayOpen(); - // peekOverlay.VerifyDataType("function"); - // peekOverlay.CheckPrimitiveValue("function () {}"); - // peekOverlay.ResetHover(); - - // check undefined - peekOverlay.HoverCode(14, 3, "data"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("undefined"); - peekOverlay.CheckPrimitiveValue("undefined"); - peekOverlay.ResetHover(); - - // check string - peekOverlay.HoverCode(15, 3, "mode"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("string"); - peekOverlay.CheckPrimitiveValue("EDIT"); - peekOverlay.ResetHover(); - - // check if overlay closes - peekOverlay.HoverCode(16, 3, "store"); - peekOverlay.IsOverlayOpen(); - peekOverlay.ResetHover(); - peekOverlay.IsOverlayOpen(false); - - // widget object - peekOverlay.HoverCode(17, 1, "Table1"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("object"); - peekOverlay.ResetHover(); - - // widget property - peekOverlay.HoverCode(18, 3, "pageNo"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("number"); - peekOverlay.CheckPrimitiveValue("1"); - peekOverlay.ResetHover(); - - // widget property - peekOverlay.HoverCode(19, 3, "tableData"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("array"); - peekOverlay.CheckObjectArrayInOverlay([{}, {}, {}]); - peekOverlay.ResetHover(); - - // basic nested property - peekOverlay.HoverCode(20, 7, "id"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("number"); - peekOverlay.CheckPrimitiveValue("1"); - peekOverlay.ResetHover(); - - // undefined object - peekOverlay.HoverCode(21, 1, "aljshdlja"); - peekOverlay.IsOverlayOpen(false); - peekOverlay.ResetHover(); - - // this keyword - peekOverlay.HoverCode(22, 3, "numArray"); - peekOverlay.IsOverlayOpen(); - peekOverlay.VerifyDataType("array"); - peekOverlay.CheckPrimitveArrayInOverlay([1, 2, 3]); - peekOverlay.ResetHover(); - - // pageList is an internal property - peek overlay shouldn't work - peekOverlay.HoverCode(23, 1, "pageList"); - peekOverlay.IsOverlayOpen(false); - peekOverlay.ResetHover(); - }); -}); + }, +); const JsObjectContent = `export default { numArray: [1, 2, 3], diff --git a/app/client/cypress/support/Pages/PeekOverlay.ts b/app/client/cypress/support/Pages/PeekOverlay.ts index b369bac11465..80e42fbdf038 100644 --- a/app/client/cypress/support/Pages/PeekOverlay.ts +++ b/app/client/cypress/support/Pages/PeekOverlay.ts @@ -4,6 +4,7 @@ export class PeekOverlay { private readonly locators = { _overlayContainer: "#t--peek-overlay-container", _dataContainer: "#t--peek-overlay-data", + _dataTypeContainer: '[data-testid="t--peek-overlay-data-type"]', // react json viewer selectors _rjv_variableValue: ".variable-value", @@ -108,8 +109,7 @@ export class PeekOverlay { VerifyDataType(type: string) { this.agHelper - .GetElement(this.locators._overlayContainer) - .children("div") + .GetElement(this.locators._dataTypeContainer) .eq(0) .should("have.text", type); } diff --git a/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx b/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx index 30170ae254ec..1bdf87646d6a 100644 --- a/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx +++ b/app/client/packages/design-system/ads/src/Icon/Icon.provider.tsx @@ -1123,6 +1123,10 @@ const SalesforceIcon = importSvg( async () => import("../__assets__/icons/ads/salesforce.svg"), ); +const StateInspectorIcon = importSvg( + async () => import("../__assets__/icons/ads/state-inspector.svg"), +); + const MdFileIcon = importSvg( async () => import("../__assets__/icons/ads/md-file.svg"), ); @@ -1560,6 +1564,7 @@ const ICON_LOOKUP = { zendesk: ZendeskIcon, "google-drive": GoogleDriveIcon, salesforce: SalesforceIcon, + "state-inspector": StateInspectorIcon, }; export const IconCollection = Object.keys(ICON_LOOKUP); diff --git a/app/client/packages/design-system/ads/src/__assets__/icons/ads/state-inspector.svg b/app/client/packages/design-system/ads/src/__assets__/icons/ads/state-inspector.svg new file mode 100644 index 000000000000..091f9fd272bc --- /dev/null +++ b/app/client/packages/design-system/ads/src/__assets__/icons/ads/state-inspector.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/app/client/src/actions/debuggerActions.ts b/app/client/src/actions/debuggerActions.ts index 356fc6492698..be2052a4e16f 100644 --- a/app/client/src/actions/debuggerActions.ts +++ b/app/client/src/actions/debuggerActions.ts @@ -147,10 +147,3 @@ export const showDebuggerLogs = () => { type: ReduxActionTypes.SHOW_DEBUGGER_LOGS, }; }; - -export const setDebuggerStateInspectorSelectedItem = (payload: string) => { - return { - type: ReduxActionTypes.SET_DEBUGGER_STATE_INSPECTOR_SELECTED_ITEM, - payload, - }; -}; diff --git a/app/client/src/actions/debuggerStateInspector.ts b/app/client/src/actions/debuggerStateInspector.ts new file mode 100644 index 000000000000..d71cf645243b --- /dev/null +++ b/app/client/src/actions/debuggerStateInspector.ts @@ -0,0 +1,8 @@ +import { ReduxActionTypes } from "ee/constants/ReduxActionConstants"; + +export const setDebuggerStateInspectorSelectedItem = (payload: string) => { + return { + type: ReduxActionTypes.SET_DEBUGGER_STATE_INSPECTOR_SELECTED_ITEM, + payload, + }; +}; diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index c6f5dbfd9afb..290161943e6a 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -1775,6 +1775,7 @@ export const CONTEXT_SETTINGS = () => "Settings"; export const CONTEXT_PARTIAL_EXPORT = () => "Export"; export const CONTEXT_PARTIAL_IMPORT = () => "Import"; export const CONTEXT_SET_AS_HOME_PAGE = () => "Set as home page"; +export const CONTEXT_INSPECT_STATE = () => "Inspect state"; export const PAGE = () => "Page"; export const PAGES = () => "Pages"; diff --git a/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/PeekOverlayPopup.tsx b/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/PeekOverlayPopup.tsx index 9b40c04b8ea8..906b6779a66b 100644 --- a/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/PeekOverlayPopup.tsx +++ b/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/PeekOverlayPopup.tsx @@ -6,7 +6,7 @@ import React, { } from "react"; import { useEventCallback } from "usehooks-ts"; import { componentWillAppendToBody } from "react-append-to-body"; -import { debounce } from "lodash"; +import { debounce, get } from "lodash"; import { zIndexLayers } from "constants/CanvasEditorConstants"; import { useSelector } from "react-redux"; import { getConfigTree, getDataTree } from "selectors/dataTreeSelectors"; @@ -16,6 +16,8 @@ import * as Styled from "./styles"; import { CONTAINER_MAX_HEIGHT_PX, PEEK_OVERLAY_DELAY } from "./constants"; import { getDataTypeHeader, getPropertyData } from "./utils"; import { JSONViewer, Size } from "../../JSONViewer"; +import { InspectStateHeaderButton } from "components/editorComponents/Debugger/StateInspector/CTAs"; +import { getEntityPayloadInfo } from "ee/utils/getEntityPayloadInfo"; export interface PeekOverlayStateProps { objectName: string; @@ -54,6 +56,15 @@ export function PeekOverlayPopUpContent( configTree, ); + let id: string | undefined; + const entityType = get(dataTree, [objectName, "ENTITY_TYPE"]); + + if (entityType && objectName in configTree) { + const entityInfo = getEntityPayloadInfo[entityType](configTree[objectName]); + + if (entityInfo) id = entityInfo.id; + } + const [jsData, dataType] = useMemo( // Because getPropertyData can return a function // And we don't want to execute it. @@ -98,9 +109,18 @@ export function PeekOverlayPopUpContent( onWheel={onWheel} {...getPositionValues()} > - - {dataType} - + + + {dataType} + + {propertyPath.length === 0 && id ? ( + + ) : null} + + {(dataType === "object" || dataType === "array") && jsData !== null && ( diff --git a/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/styles.ts b/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/styles.ts index 0117cb1a161b..570e8dcf393d 100644 --- a/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/styles.ts +++ b/app/client/src/components/editorComponents/CodeEditor/PeekOverlayPopup/styles.ts @@ -1,5 +1,5 @@ import styled from "styled-components"; -import { Divider } from "@appsmith/ads"; +import { Divider, Flex } from "@appsmith/ads"; export const PeekOverlayContainer = styled.div<{ $left: string; @@ -17,12 +17,18 @@ export const PeekOverlayContainer = styled.div<{ bottom: ${({ $bottom }) => $bottom}; `; +export const Header = styled(Flex)` + padding: var(--ads-v2-spaces-2) var(--ads-v2-spaces-2) var(--ads-v2-spaces-2) + var(--ads-v2-spaces-4); + justify-content: space-between; + align-items: center; + gap: var(--ads-v2-spaces-3); + height: 32px; +`; + export const DataType = styled.div` - height: 24px; color: var(--appsmith-color-black-700); - padding: var(--ads-v2-spaces-2) 0 var(--ads-v2-spaces-2) - var(--ads-v2-spaces-4); - font-size: 10px; + font-size: 12px; `; export const BlockDivider = styled(Divider)` diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateHeaderButton.tsx b/app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateHeaderButton.tsx new file mode 100644 index 000000000000..53a382c6ee20 --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateHeaderButton.tsx @@ -0,0 +1,36 @@ +import React, { useCallback } from "react"; +import { Button } from "@appsmith/ads"; +import { setDebuggerStateInspectorSelectedItem } from "actions/debuggerStateInspector"; +import { useDispatch } from "react-redux"; +import { DEBUGGER_TAB_KEYS } from "../../constants"; +import { useDebuggerConfig } from "../../hooks/useDebuggerConfig"; +import { CONTEXT_INSPECT_STATE, createMessage } from "ee/constants/messages"; + +interface Props { + entityId: string; + disabled?: boolean; +} + +export function InspectStateHeaderButton({ disabled, entityId }: Props) { + const dispatch = useDispatch(); + const config = useDebuggerConfig(); + + const handleSelect = useCallback(() => { + dispatch(setDebuggerStateInspectorSelectedItem(entityId)); + dispatch( + config.set({ open: true, selectedTab: DEBUGGER_TAB_KEYS.STATE_TAB }), + ); + }, [config, dispatch, entityId]); + + return ( + + ); +} diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateMenuItem.tsx b/app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateMenuItem.tsx new file mode 100644 index 000000000000..6c63fbc38acb --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateMenuItem.tsx @@ -0,0 +1,34 @@ +import React, { useCallback } from "react"; +import { MenuItem } from "@appsmith/ads"; +import { CONTEXT_INSPECT_STATE, createMessage } from "ee/constants/messages"; +import { setDebuggerStateInspectorSelectedItem } from "actions/debuggerStateInspector"; +import { useDispatch } from "react-redux"; +import { DEBUGGER_TAB_KEYS } from "../../constants"; +import { useDebuggerConfig } from "../../hooks/useDebuggerConfig"; + +interface Props { + entityId: string; + disabled?: boolean; +} + +export function InspectStateMenuItem({ disabled, entityId }: Props) { + const dispatch = useDispatch(); + const config = useDebuggerConfig(); + + const handleSelect = useCallback(() => { + dispatch(setDebuggerStateInspectorSelectedItem(entityId)); + dispatch( + config.set({ open: true, selectedTab: DEBUGGER_TAB_KEYS.STATE_TAB }), + ); + }, [config, dispatch, entityId]); + + return ( + + {createMessage(CONTEXT_INSPECT_STATE)} + + ); +} diff --git a/app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateToolbarButton.tsx b/app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateToolbarButton.tsx new file mode 100644 index 000000000000..19af4ae8a3fb --- /dev/null +++ b/app/client/src/components/editorComponents/Debugger/StateInspector/CTAs/InspectStateToolbarButton.tsx @@ -0,0 +1,36 @@ +import React, { useCallback } from "react"; +import { Button, Tooltip } from "@appsmith/ads"; +import { setDebuggerStateInspectorSelectedItem } from "actions/debuggerStateInspector"; +import { useDispatch } from "react-redux"; +import { DEBUGGER_TAB_KEYS } from "../../constants"; +import { useDebuggerConfig } from "../../hooks/useDebuggerConfig"; +import { CONTEXT_INSPECT_STATE, createMessage } from "ee/constants/messages"; + +interface Props { + entityId: string; + disabled?: boolean; +} + +export function InspectStateToolbarButton({ disabled, entityId }: Props) { + const dispatch = useDispatch(); + const config = useDebuggerConfig(); + + const handleSelect = useCallback(() => { + dispatch(setDebuggerStateInspectorSelectedItem(entityId)); + dispatch( + config.set({ open: true, selectedTab: DEBUGGER_TAB_KEYS.STATE_TAB }), + ); + }, [config, dispatch, entityId]); + + return ( + +