fix: Api Pane IA (#32603)

## Description

Fixes the IA in API Response Pane by moving the meta information about
the API call inside the response tab

Fixes #32602

## Automation

/ok-to-test tags="@tag.Datasource"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/8645605363>
> Commit: 25936d836e9e230a2c87acc5248b23425db06488
> Cypress dashboard url: <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=8645605363&attempt=1"
target="_blank">Click here!</a>

<!-- end of auto-generated comment: Cypress test results  -->
This commit is contained in:
Hetu Nandu 2024-04-12 15:38:22 +05:30 committed by GitHub
parent b011680db7
commit ab5b0c62e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 133 additions and 106 deletions

View File

@ -0,0 +1,126 @@
import type { PropsWithChildren } from "react";
import React from "react";
import { Flex } from "design-system";
import { Text, TextType } from "design-system-old";
import { formatBytes } from "../../utils/helpers";
import { isEmpty } from "lodash";
import BindDataButton from "pages/Editor/QueryEditor/BindDataButton";
import styled from "styled-components";
import type { ActionResponse } from "api/ActionAPI";
import { Text as BlueprintText } from "@blueprintjs/core/lib/esm/components/text/text";
interface TextStyleProps {
accent: "primary" | "secondary" | "error";
}
const BaseText = styled(BlueprintText)<TextStyleProps>``;
const ResponseMetaInfo = styled.div`
display: flex;
${BaseText} {
color: var(--ads-v2-color-fg);
margin-left: ${(props) => props.theme.spaces[9]}px;
}
& [type="p3"] {
color: var(--ads-v2-color-fg-muted);
}
& [type="h5"] {
color: var(--ads-v2-color-fg);
}
`;
const ResponseMetaWrapper = styled.div`
align-items: center;
display: flex;
justify-content: space-between;
padding: var(--ads-v2-spaces-3);
border-bottom: 1px solid var(--ads-v2-color-border);
height: 40px;
`;
const FlexContainer = styled.div`
display: flex;
align-items: center;
margin-left: 20px;
span:first-child {
margin-right: ${(props) => props.theme.spaces[1] + 1}px;
}
`;
const StatusCodeText = styled(BaseText)<PropsWithChildren<{ code: string }>>`
color: ${(props) =>
props.code.startsWith("2")
? "var(--ads-v2-color-fg-success)"
: "var(--ads-v2-color-fg-error)"};
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&:hover {
width: 100%;
}
`;
interface Props {
actionResponse?: ActionResponse;
actionName?: string;
}
const ApiResponseMeta = (props: Props) => {
const { actionName, actionResponse } = props;
if (!actionResponse || !actionResponse.statusCode) return null;
return (
<ResponseMetaWrapper>
<Flex>
{actionResponse.statusCode && (
<FlexContainer>
<Text type={TextType.P3}>Status: </Text>
<StatusCodeText
accent="secondary"
className="t--response-status-code"
code={actionResponse.statusCode.toString()}
>
{actionResponse.statusCode}
</StatusCodeText>
</FlexContainer>
)}
<ResponseMetaInfo>
{actionResponse.duration && (
<FlexContainer>
<Text type={TextType.P3}>Time: </Text>
<Text type={TextType.H5}>{actionResponse.duration} ms</Text>
</FlexContainer>
)}
{actionResponse.size && (
<FlexContainer>
<Text type={TextType.P3}>Size: </Text>
<Text type={TextType.H5}>
{formatBytes(parseInt(actionResponse.size))}
</Text>
</FlexContainer>
)}
{!isEmpty(actionResponse?.body) &&
Array.isArray(actionResponse?.body) && (
<FlexContainer>
<Text type={TextType.P3}>Result: </Text>
<Text type={TextType.H5}>
{`${actionResponse?.body.length} Record${
actionResponse?.body.length > 1 ? "s" : ""
}`}
</Text>
</FlexContainer>
)}
</ResponseMetaInfo>
</Flex>
<BindDataButton
actionName={actionName || ""}
hasResponse={!!actionResponse}
suggestedWidgets={actionResponse.suggestedWidgets}
/>
</ResponseMetaWrapper>
);
};
export default ApiResponseMeta;

View File

@ -1,10 +1,9 @@
import type { PropsWithChildren, RefObject } from "react";
import type { RefObject } from "react";
import React, { useCallback, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import ReactJson from "react-json-view";
import styled from "styled-components";
import type { ActionResponse } from "api/ActionAPI";
import { formatBytes } from "utils/helpers";
import type { SourceEntity } from "entities/AppsmithConsole";
import LOG_TYPE from "entities/AppsmithConsole/logtype";
import { ENTITY_TYPE } from "@appsmith/entities/AppsmithConsole/utils";
@ -18,7 +17,6 @@ import {
EMPTY_RESPONSE_FIRST_HALF,
EMPTY_RESPONSE_LAST_HALF,
} from "@appsmith/constants/messages";
import { Text as BlueprintText } from "@blueprintjs/core";
import { EditorTheme } from "./CodeEditor/EditorConfig";
import NoResponseSVG from "assets/images/no-response.svg";
import DebuggerLogs from "./Debugger/DebuggerLogs";
@ -48,16 +46,11 @@ import { SegmentedControlContainer } from "../../pages/Editor/QueryEditor/Editor
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";
}
export const BaseText = styled(BlueprintText)<TextStyleProps>``;
import ApiResponseMeta from "./ApiResponseMeta";
const ResponseContainer = styled.div`
${ResizerCSS};
@ -70,30 +63,6 @@ const ResponseContainer = styled.div`
font-size: 12px;
}
`;
const ResponseMetaInfo = styled.div`
display: flex;
${BaseText} {
color: var(--ads-v2-color-fg);
margin-left: ${(props) => props.theme.spaces[9]}px;
}
& [type="p3"] {
color: var(--ads-v2-color-fg-muted);
}
& [type="h5"] {
color: var(--ads-v2-color-fg);
}
`;
const ResponseMetaWrapper = styled.div`
align-items: center;
display: flex;
position: absolute;
right: ${(props) => props.theme.spaces[17] + 1}px;
top: ${(props) => props.theme.spaces[2] + 3}px;
z-index: 6;
`;
const ResponseTabWrapper = styled.div`
display: flex;
@ -128,16 +97,6 @@ const TabbedViewWrapper = styled.div`
}
`;
const FlexContainer = styled.div`
display: flex;
align-items: center;
margin-left: 20px;
span:first-child {
margin-right: ${(props) => props.theme.spaces[1] + 1}px;
}
`;
const NoResponseContainer = styled.div`
flex: 1;
width: 100%;
@ -181,20 +140,6 @@ interface Props {
isRunning: boolean;
}
const StatusCodeText = styled(BaseText)<PropsWithChildren<{ code: string }>>`
color: ${(props) =>
props.code.startsWith("2")
? "var(--ads-v2-color-fg-success)"
: "var(--ads-v2-color-fg-error)"};
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&:hover {
width: 100%;
}
`;
const ResponseDataContainer = styled.div`
flex: 1;
overflow: auto;
@ -431,6 +376,10 @@ function ApiResponseView(props: Props) {
title: "Response",
panelComponent: (
<ResponseTabWrapper>
<ApiResponseMeta
actionName={currentActionConfig?.name}
actionResponse={actionResponse}
/>
{Array.isArray(messages) && messages.length > 0 && (
<HelpSection>
{messages.map((msg, i) => (
@ -503,7 +452,7 @@ function ApiResponseView(props: Props) {
responseTabs.length > 0 &&
selectedTabIndex !== -1 ? (
<SegmentedControlContainer>
<Flex justifyContent="space-between">
<Flex>
<SegmentedControl
data-testid="t--response-tab-segmented-control"
defaultValue={segmentedControlOptions[0]?.value}
@ -515,11 +464,6 @@ function ApiResponseView(props: Props) {
options={segmentedControlOptions}
value={selectedControl}
/>
<BindDataButton
actionName={currentActionConfig?.name || ""}
hasResponse={!!actionResponse}
suggestedWidgets={actionResponse.suggestedWidgets}
/>
</Flex>
{responseTabComponent(
selectedControl || segmentedControlOptions[0]?.value,
@ -613,49 +557,6 @@ function ApiResponseView(props: Props) {
snapToHeight={ActionExecutionResizerHeight}
/>
<TabbedViewWrapper>
{actionResponse.statusCode && (
<ResponseMetaWrapper>
{actionResponse.statusCode && (
<FlexContainer>
<Text type={TextType.P3}>Status: </Text>
<StatusCodeText
accent="secondary"
className="t--response-status-code"
code={actionResponse.statusCode.toString()}
>
{actionResponse.statusCode}
</StatusCodeText>
</FlexContainer>
)}
<ResponseMetaInfo>
{actionResponse.duration && (
<FlexContainer>
<Text type={TextType.P3}>Time: </Text>
<Text type={TextType.H5}>{actionResponse.duration} ms</Text>
</FlexContainer>
)}
{actionResponse.size && (
<FlexContainer>
<Text type={TextType.P3}>Size: </Text>
<Text type={TextType.H5}>
{formatBytes(parseInt(actionResponse.size))}
</Text>
</FlexContainer>
)}
{!isEmpty(actionResponse?.body) &&
Array.isArray(actionResponse?.body) && (
<FlexContainer>
<Text type={TextType.P3}>Result: </Text>
<Text type={TextType.H5}>
{`${actionResponse?.body.length} Record${
actionResponse?.body.length > 1 ? "s" : ""
}`}
</Text>
</FlexContainer>
)}
</ResponseMetaInfo>
</ResponseMetaWrapper>
)}
<EntityBottomTabs
expandedHeight={`${ActionExecutionResizerHeight}px`}
onSelect={updateSelectedResponseTab}