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:
parent
b011680db7
commit
ab5b0c62e4
126
app/client/src/components/editorComponents/ApiResponseMeta.tsx
Normal file
126
app/client/src/components/editorComponents/ApiResponseMeta.tsx
Normal 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;
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user