fix: query tab scrollbar padding gap fix (#38317)

## Description
Remove scrollbar gap in request config.


Fixes [#38135](https://github.com/appsmithorg/appsmith/issues/38135)

## Automation

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

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!IMPORTANT]
> 🟣 🟣 🟣 Your tests are running.
> Tests running at:
<https://github.com/appsmithorg/appsmith/actions/runs/12491071853>
> Commit: 85399dbbd44aef19ce3da06a8d6f190eed210de5
> Workflow: `PR Automation test suite`
> Tags: `@tag.IDE`
> Spec: ``
> <hr>Wed, 25 Dec 2024 08:14:00 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Introduced a tabbed interface in the `CommonEditorForm` for better
content organization.
- Enhanced usability of the `PluginActionForm` with scrollable content
areas.
  
- **Bug Fixes**
- Adjusted tooltip positioning to improve visibility in the
`EmbeddedDatasourcePathField`.

- **Style**
- Added new styled components for tabs and headers to enhance layout and
design.

- **Chores**
- Deprecated the `RequestTabs` component in preparation for its removal.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Alex 2024-12-25 14:09:07 +03:00 committed by GitHub
parent f078ec0b32
commit 0c1a1d8ee4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 127 additions and 42 deletions

View File

@ -12,7 +12,7 @@ const PluginActionForm = () => {
const { plugin } = usePluginActionContext(); const { plugin } = usePluginActionContext();
return ( return (
<Flex flex="1" overflow="hidden" p="spaces-4" w="100%"> <Flex flex="1" overflow="auto" p="spaces-4" w="100%">
{plugin.uiComponent === UIComponentTypes.ApiEditorForm && ( {plugin.uiComponent === UIComponentTypes.ApiEditorForm && (
<APIEditorForm /> <APIEditorForm />
)} )}

View File

@ -1,11 +1,19 @@
import React from "react"; import React from "react";
import { Tab, TabsList } from "@appsmith/ads";
import { type Action } from "entities/Action"; import { type Action } from "entities/Action";
import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig";
import { InfoFields } from "./InfoFields"; import { API_EDITOR_TABS } from "PluginActionEditor/constants/CommonApiConstants";
import { RequestTabs } from "./RequestTabs"; import { API_EDITOR_TAB_TITLES, createMessage } from "ee/constants/messages";
import { HintMessages } from "./HintMessages";
import { Flex } from "@appsmith/ads";
import useGetFormActionValues from "./hooks/useGetFormActionValues"; import useGetFormActionValues from "./hooks/useGetFormActionValues";
import { DatasourceConfig } from "./components/DatasourceConfig";
import { HintMessages } from "./HintMessages";
import { InfoFields } from "./InfoFields";
import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
import ApiAuthentication from "./components/ApiAuthentication";
import { useSelectedFormTab } from "./hooks/useSelectedFormTab";
import { getHeadersCount, getParamsCount } from "./utils";
import * as Styled from "./styles";
interface Props { interface Props {
httpMethodOptions: { value: string }[]; httpMethodOptions: { value: string }[];
@ -18,7 +26,13 @@ interface Props {
} }
const CommonEditorForm = (props: Props) => { const CommonEditorForm = (props: Props) => {
const { action } = props; const {
action,
bodyUIComponent,
formName,
isChangePermitted,
paginationUiComponent,
} = props;
const hintMessages = action.messages || []; const hintMessages = action.messages || [];
const theme = EditorTheme.LIGHT; const theme = EditorTheme.LIGHT;
const { const {
@ -29,39 +43,89 @@ const CommonEditorForm = (props: Props) => {
datasourceParams, datasourceParams,
} = useGetFormActionValues(); } = useGetFormActionValues();
const [currentTab, setCurrentTab] = useSelectedFormTab();
const headersCount = getHeadersCount(
actionHeaders,
datasourceHeaders,
autoGeneratedHeaders,
);
const paramsCount = getParamsCount(actionParams, datasourceHeaders);
return ( return (
<Flex <Styled.Tabs onValueChange={setCurrentTab} value={currentTab}>
data-testid={props.dataTestId} <Styled.FormHeader>
flex="1" <InfoFields
flexDirection="column" actionName={action.name}
gap="spaces-3" changePermitted={props.isChangePermitted}
overflow="hidden" formName={props.formName}
w="100%" options={props.httpMethodOptions}
> pluginId={action.pluginId}
<InfoFields theme={theme}
actionName={action.name} />
changePermitted={props.isChangePermitted} <HintMessages hintMessages={hintMessages} />
formName={props.formName} <TabsList>
options={props.httpMethodOptions} {Object.values(API_EDITOR_TABS)
pluginId={action.pluginId} .filter((tab) => {
theme={theme} return tab !== API_EDITOR_TABS.SETTINGS;
/> })
<HintMessages hintMessages={hintMessages} /> .map((tab) => (
<RequestTabs <Tab
actionConfigurationHeaders={actionHeaders} data-testid={`t--api-editor-${tab}`}
actionConfigurationParams={actionParams} key={tab}
actionName={action.name} notificationCount={
autogeneratedHeaders={autoGeneratedHeaders} tab == "HEADERS"
bodyUIComponent={props.bodyUIComponent} ? headersCount
datasourceHeaders={datasourceHeaders} : tab == "PARAMS"
datasourceParams={datasourceParams} ? paramsCount
formName={props.formName} : undefined
paginationUiComponent={props.paginationUiComponent} }
pushFields={props.isChangePermitted} value={tab}
showSettings={false} >
theme={theme} {createMessage(API_EDITOR_TAB_TITLES[tab])}
/> </Tab>
</Flex> ))}
</TabsList>
</Styled.FormHeader>
<Styled.TabPanel value={API_EDITOR_TABS.HEADERS}>
<DatasourceConfig
attributeName="header"
autogeneratedHeaders={autoGeneratedHeaders}
data={datasourceHeaders}
/>
<KeyValueFieldArray
actionConfig={actionHeaders}
dataTreePath={`${action.name}.config.headers`}
hideHeader
label="Headers"
name="actionConfiguration.headers"
placeholder="Value"
pushFields={isChangePermitted}
theme={theme}
/>
</Styled.TabPanel>
<Styled.TabPanel value={API_EDITOR_TABS.PARAMS}>
<DatasourceConfig attributeName={"param"} data={datasourceParams} />
<KeyValueFieldArray
actionConfig={actionParams}
dataTreePath={`${action.name}.config.queryParameters`}
hideHeader
label="Params"
name="actionConfiguration.queryParameters"
pushFields={isChangePermitted}
theme={theme}
/>
</Styled.TabPanel>
<Styled.TabPanel className="h-full" value={API_EDITOR_TABS.BODY}>
{bodyUIComponent}
</Styled.TabPanel>
<Styled.TabPanel value={API_EDITOR_TABS.PAGINATION}>
{paginationUiComponent}
</Styled.TabPanel>
<Styled.TabPanel value={API_EDITOR_TABS.AUTHENTICATION}>
<ApiAuthentication formName={formName} />
</Styled.TabPanel>
</Styled.Tabs>
); );
}; };

View File

@ -27,6 +27,9 @@ const StyledTabPanel = styled(TabPanel)`
overflow: auto; overflow: auto;
`; `;
/**
* @deprecated This component will be deleted along with APIEditor/CommonEditorForm.
*/
export function RequestTabs(props: { export function RequestTabs(props: {
autogeneratedHeaders: AutoGeneratedHeader[] | undefined; autogeneratedHeaders: AutoGeneratedHeader[] | undefined;
datasourceHeaders: Property[]; datasourceHeaders: Property[];

View File

@ -155,7 +155,7 @@ const StyledTooltip = styled.span<{ width?: number }>`
position: absolute; position: absolute;
z-index: 100000; z-index: 100000;
max-width: 300px; max-width: 300px;
bottom: 125%; top: 125%;
left: calc(-10px + ${(props) => (props.width ? props.width / 2 : 0)}px); left: calc(-10px + ${(props) => (props.width ? props.width / 2 : 0)}px);
margin-left: -60px; margin-left: -60px;
@ -165,14 +165,14 @@ const StyledTooltip = styled.span<{ width?: number }>`
&::after { &::after {
content: ""; content: "";
position: absolute; position: absolute;
top: 100%; bottom: 100%;
left: 50%; left: 50%;
height: 10px; height: 10px;
width: 10px; width: 10px;
margin-left: -5px; margin-left: -5px;
border-width: 5px; border-width: 5px;
border-style: solid; border-style: solid;
border-color: var(--ads-v2-color-bg-emphasis-max) transparent transparent border-color: transparent transparent var(--ads-v2-color-bg-emphasis-max)
transparent; transparent;
} }

View File

@ -1,4 +1,5 @@
import styled from "styled-components"; import styled from "styled-components";
import { Tabs as AdsTabs, TabPanel as AdsTabPanel } from "@appsmith/ads";
export const RequestMethodSelectContainer = styled.div` export const RequestMethodSelectContainer = styled.div`
width: 100px; width: 100px;
@ -10,3 +11,21 @@ export const RequestMethodSelectContainer = styled.div`
export const DatasourcePathFieldContainer = styled.div` export const DatasourcePathFieldContainer = styled.div`
width: 100%; width: 100%;
`; `;
export const FormHeader = styled.div`
position: sticky;
top: calc(-1 * var(--ads-v2-spaces-4));
padding-top: var(--ads-v2-spaces-4);
margin-top: calc(-1 * var(--ads-v2-spaces-4));
z-index: var(--ads-v2-z-index-21);
background-color: var(--ads-color-background);
height: 100px;
`;
export const Tabs = styled(AdsTabs)`
height: max-content;
`;
export const TabPanel = styled(AdsTabPanel)`
margin: 0 auto;
`;

View File

@ -23,7 +23,6 @@ const UQIEditorForm = () => {
alignItems="center" alignItems="center"
data-testid="t--uqi-editor-form" data-testid="t--uqi-editor-form"
flexDirection="column" flexDirection="column"
overflowY="scroll"
w="100%" w="100%"
> >
<FormRender <FormRender