diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/PluginActionForm.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/PluginActionForm.tsx index 66ab320a3048..759ea60f1b70 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionForm/PluginActionForm.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/PluginActionForm.tsx @@ -4,6 +4,7 @@ import { Flex } from "@appsmith/ads"; import { useChangeActionCall } from "./hooks/useChangeActionCall"; import { usePluginActionContext } from "../../PluginActionContext"; import { UIComponentTypes } from "api/PluginApi"; +import GraphQLEditorForm from "./components/GraphQLEditor/GraphQLEditorForm"; const PluginActionForm = () => { useChangeActionCall(); @@ -11,9 +12,12 @@ const PluginActionForm = () => { return ( - {plugin.uiComponent === UIComponentTypes.ApiEditorForm ? ( + {plugin.uiComponent === UIComponentTypes.ApiEditorForm && ( - ) : null} + )} + {plugin.uiComponent === UIComponentTypes.GraphQLEditorForm && ( + + )} ); }; diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/hooks/useGetFormActionValues.ts b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/hooks/useGetFormActionValues.ts index da75a1482a26..8b71a662e410 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/hooks/useGetFormActionValues.ts +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/CommonEditorForm/hooks/useGetFormActionValues.ts @@ -20,6 +20,7 @@ function useGetFormActionValues() { // return empty values to avoid form ui issues if (!formValues || !isAPIAction(formValues)) { return { + actionConfigurationBody: "", actionHeaders: [], actionParams: [], autoGeneratedHeaders: [], @@ -28,6 +29,12 @@ function useGetFormActionValues() { }; } + const actionConfigurationBody = get( + formValues, + "actionConfiguration.body", + "", + ) as string; + const actionHeaders = get( formValues, "actionConfiguration.headers", @@ -67,6 +74,7 @@ function useGetFormActionValues() { ) as Property[]; return { + actionConfigurationBody, actionHeaders, autoGeneratedHeaders, actionParams, diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/GraphQLEditor/GraphQLEditorForm.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/components/GraphQLEditor/GraphQLEditorForm.tsx new file mode 100644 index 000000000000..717781b5a382 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/GraphQLEditor/GraphQLEditorForm.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { reduxForm } from "redux-form"; +import { API_EDITOR_FORM_NAME } from "ee/constants/forms"; +import CommonEditorForm from "../CommonEditorForm"; +import Pagination from "pages/Editor/APIEditor/GraphQL/Pagination"; +import { GRAPHQL_HTTP_METHOD_OPTIONS } from "constants/ApiEditorConstants/GraphQLEditorConstants"; +import PostBodyData from "./PostBodyData"; +import { usePluginActionContext } from "PluginActionEditor"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; +import { getHasManageActionPermission } from "ee/utils/BusinessFeatures/permissionPageHelpers"; +import { noop } from "lodash"; +import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; +import useGetFormActionValues from "../CommonEditorForm/hooks/useGetFormActionValues"; + +const FORM_NAME = API_EDITOR_FORM_NAME; + +function GraphQLEditorForm() { + const { action } = usePluginActionContext(); + const theme = EditorTheme.LIGHT; + + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + const isChangePermitted = getHasManageActionPermission( + isFeatureEnabled, + action.userPermissions, + ); + + const { actionConfigurationBody } = useGetFormActionValues(); + + return ( + } + formName={FORM_NAME} + httpMethodOptions={GRAPHQL_HTTP_METHOD_OPTIONS} + isChangePermitted={isChangePermitted} + paginationUiComponent={ + + } + /> + ); +} + +export default reduxForm({ form: FORM_NAME, enableReinitialize: true })( + GraphQLEditorForm, +); diff --git a/app/client/src/PluginActionEditor/components/PluginActionForm/components/GraphQLEditor/PostBodyData.tsx b/app/client/src/PluginActionEditor/components/PluginActionForm/components/GraphQLEditor/PostBodyData.tsx new file mode 100644 index 000000000000..f897d38246e9 --- /dev/null +++ b/app/client/src/PluginActionEditor/components/PluginActionForm/components/GraphQLEditor/PostBodyData.tsx @@ -0,0 +1,109 @@ +import React, { useCallback, useRef } from "react"; +import styled from "styled-components"; +import QueryEditor from "pages/Editor/APIEditor/GraphQL/QueryEditor"; +import VariableEditor from "pages/Editor/APIEditor/GraphQL/VariableEditor"; +import useHorizontalResize from "utils/hooks/useHorizontalResize"; +import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; +import classNames from "classnames"; +import { tailwindLayers } from "constants/Layers"; + +const ResizableDiv = styled.div` + display: flex; + height: 100%; + flex-shrink: 0; +`; + +const PostBodyContainer = styled.div` + display: flex; + height: 100%; + overflow: hidden; + &&&& .CodeMirror { + height: 100%; + border-top: 1px solid var(--ads-v2-color-border); + border-bottom: 1px solid var(--ads-v2-color-border); + border-radius: 0; + padding: 0; + } + & .CodeMirror-scroll { + margin: 0px; + padding: 0px; + overflow: auto !important; + } +`; + +const ResizerHandler = styled.div<{ resizing: boolean }>` + width: 6px; + height: 100%; + margin-left: 2px; + border-right: 1px solid var(--ads-v2-color-border); + background: ${(props) => + props.resizing ? "var(--ads-v2-color-border)" : "transparent"}; + &:hover { + background: var(--ads-v2-color-border); + border-color: transparent; + } +`; + +const DEFAULT_GRAPHQL_VARIABLE_WIDTH = 300; + +interface Props { + actionName: string; +} + +function PostBodyData(props: Props) { + const { actionName } = props; + const theme = EditorTheme.LIGHT; + const resizeableRef = useRef(null); + const [variableEditorWidth, setVariableEditorWidth] = React.useState( + DEFAULT_GRAPHQL_VARIABLE_WIDTH, + ); + /** + * Variable Editor's resizeable handler for the changing of width + */ + const onVariableEditorWidthChange = useCallback((newWidth) => { + setVariableEditorWidth(newWidth); + }, []); + + const { onMouseDown, onMouseUp, onTouchStart, resizing } = + useHorizontalResize( + resizeableRef, + onVariableEditorWidthChange, + undefined, + true, + ); + + return ( + + +
+ +
+ + + +
+ ); +} + +export default PostBodyData; diff --git a/app/client/src/api/PluginApi.ts b/app/client/src/api/PluginApi.ts index ef8987b4208f..5bcc33486109 100644 --- a/app/client/src/api/PluginApi.ts +++ b/app/client/src/api/PluginApi.ts @@ -13,6 +13,7 @@ export enum UIComponentTypes { UQIDbEditorForm = "UQIDbEditorForm", ApiEditorForm = "ApiEditorForm", JsEditorForm = "JsEditorForm", + GraphQLEditorForm = "GraphQLEditorForm", } export enum DatasourceComponentTypes { diff --git a/app/client/src/pages/Editor/APIEditor/ApiEditorContext.tsx b/app/client/src/pages/Editor/APIEditor/ApiEditorContext.tsx index 1a2d9d517898..adca7c27f607 100644 --- a/app/client/src/pages/Editor/APIEditor/ApiEditorContext.tsx +++ b/app/client/src/pages/Editor/APIEditor/ApiEditorContext.tsx @@ -14,7 +14,6 @@ interface ApiEditorContextContextProps { saveActionName: ( params: SaveActionNameParams, ) => ReduxAction; - closeEditorLink?: React.ReactNode; showRightPaneTabbedSection?: boolean; actionRightPaneAdditionSections?: React.ReactNode; notification?: React.ReactNode | string; @@ -31,7 +30,6 @@ export function ApiEditorContextProvider({ actionRightPaneAdditionSections, actionRightPaneBackLink, children, - closeEditorLink, handleDeleteClick, handleRunClick, moreActionsMenu, @@ -44,7 +42,6 @@ export function ApiEditorContextProvider({ () => ({ actionRightPaneAdditionSections, actionRightPaneBackLink, - closeEditorLink, handleDeleteClick, showRightPaneTabbedSection, handleRunClick, @@ -56,7 +53,6 @@ export function ApiEditorContextProvider({ [ actionRightPaneBackLink, actionRightPaneAdditionSections, - closeEditorLink, handleDeleteClick, showRightPaneTabbedSection, handleRunClick, diff --git a/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx b/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx index 979c4edf1cb1..7c265e98b5c0 100644 --- a/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx +++ b/app/client/src/pages/Editor/APIEditor/CommonEditorForm.tsx @@ -3,11 +3,7 @@ import { useSelector } from "react-redux"; import styled from "styled-components"; import FormLabel from "components/editorComponents/FormLabel"; import FormRow from "components/editorComponents/FormRow"; -import type { - ActionResponse, - PaginationField, - SuggestedWidget, -} from "api/ActionAPI"; +import type { ActionResponse, PaginationField } from "api/ActionAPI"; import type { Action, PaginationType } from "entities/Action"; import ApiResponseView from "components/editorComponents/ApiResponseView"; import type { AppState } from "ee/reducers"; @@ -15,7 +11,6 @@ import ActionNameEditor from "components/editorComponents/ActionNameEditor"; import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig"; import { Button } from "@appsmith/ads"; import { useParams } from "react-router"; -import type { Datasource } from "entities/Datasource"; import equal from "fast-deep-equal/es6"; import { getPlugin } from "ee/selectors/entitiesSelector"; import type { AutoGeneratedHeader } from "./helpers"; @@ -148,23 +143,11 @@ export interface CommonFormProps { // eslint-disable-next-line @typescript-eslint/no-explicit-any datasourceParams?: any; actionName: string; - apiId: string; apiName: string; // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any settingsConfig: any; hintMessages?: Array; - // TODO: Fix this the next time the file is edited - // eslint-disable-next-line @typescript-eslint/no-explicit-any - datasources?: any; - currentPageId?: string; - applicationId?: string; - hasResponse: boolean; - responseDataTypes: { key: string; title: string }[]; - responseDisplayFormat: { title: string; value: string }; - suggestedWidgets?: SuggestedWidget[]; - updateDatasource: (datasource: Datasource) => void; - currentActionDatasourceId: string; autoGeneratedActionConfigHeaders?: AutoGeneratedHeader[]; } @@ -177,9 +160,6 @@ type CommonFormPropsWithExtraParams = CommonFormProps & { // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any handleSubmit: any; - // defaultSelectedTabIndex - defaultTabSelected?: number; - closeEditorLink?: React.ReactNode; httpsMethods: { value: string }[]; }; @@ -215,7 +195,6 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { actionConfigurationParams, actionResponse, autoGeneratedActionConfigHeaders, - closeEditorLink, formName, handleSubmit, hintMessages, @@ -287,7 +266,6 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) { return ( - {closeEditorLink}
` - width: 6px; - height: 100%; - margin-left: 2px; - border-right: 1px solid var(--ads-v2-color-border); - background: ${(props) => - props.resizing ? "var(--ads-v2-color-border)" : "transparent"}; - &:hover { - background: var(--ads-v2-color-border); - border-color: transparent; - } -`; +import PostBodyData from "PluginActionEditor/components/PluginActionForm/components/GraphQLEditor/PostBodyData"; type APIFormProps = { - httpMethodFromForm: string; actionConfigurationBody: string; } & CommonFormProps; type Props = APIFormProps & InjectedFormProps; -const DEFAULT_GRAPHQL_VARIABLE_WIDTH = 300; +const FORM_NAME = API_EDITOR_FORM_NAME; /** * Graphql Editor form which uses the Common Editor and pass on the differentiating components from the API Editor. @@ -79,72 +31,17 @@ const DEFAULT_GRAPHQL_VARIABLE_WIDTH = 300; */ function GraphQLEditorForm(props: Props) { const { actionName } = props; - const theme = EditorTheme.LIGHT; - const sizeableRef = useRef(null); - const [variableEditorWidth, setVariableEditorWidth] = React.useState( - DEFAULT_GRAPHQL_VARIABLE_WIDTH, - ); - - const { closeEditorLink } = useContext(ApiEditorContext); - - /** - * Variable Editor's resizeable handler for the changing of width - */ - const onVariableEditorWidthChange = useCallback((newWidth) => { - setVariableEditorWidth(newWidth); - }, []); - - const { onMouseDown, onMouseUp, onTouchStart, resizing } = - useHorizontalResize( - sizeableRef, - onVariableEditorWidthChange, - undefined, - true, - ); return ( - -
- -
- - - - - } - closeEditorLink={closeEditorLink} - defaultTabSelected={2} - formName={API_EDITOR_FORM_NAME} + bodyUIComponent={} + formName={FORM_NAME} httpsMethods={GRAPHQL_HTTP_METHOD_OPTIONS} paginationUIComponent={ void; -} - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const mapDispatchToProps = (dispatch: any): ReduxDispatchProps => ({ - updateDatasource: (datasource) => { - dispatch(change(API_EDITOR_FORM_NAME, "datasource", datasource)); - }, -}); +const selector = formValueSelector(FORM_NAME); export default connect( // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any (state: AppState, props: { pluginId: string; match?: any }) => { - const httpMethodFromForm = selector( - state, - "actionConfiguration.httpMethod", - ); const actionConfigurationHeaders = selector(state, "actionConfiguration.headers") || []; const actionConfigurationParams = @@ -201,55 +82,27 @@ export default connect( get(datasourceFromAction, "datasourceConfiguration.queryParameters") || []; - const currentActionDatasourceId = selector(state, "datasource.id"); - const actionConfigurationBody = selector(state, "actionConfiguration.body") || ""; - let hasResponse = false; - let suggestedWidgets; const actionResponse = getActionData(state, apiId); - if (actionResponse) { - hasResponse = - !isEmpty(actionResponse.statusCode) && - actionResponse.statusCode[0] === "2"; - suggestedWidgets = actionResponse.suggestedWidgets; - } - - const actionData = getActionData(state, apiId); - const { responseDataTypes, responseDisplayFormat } = - actionResponseDisplayDataFormats(actionData); - return { actionName, actionResponse, - apiId, - httpMethodFromForm, actionConfigurationHeaders, actionConfigurationParams, actionConfigurationBody, - currentActionDatasourceId, datasourceHeaders, datasourceParams, hintMessages, - datasources: state.entities.datasources.list.filter( - (d) => d.pluginId === props.pluginId, - ), - currentPageId: state.entities.pageList.currentPageId, - applicationId: state.entities.pageList.applicationId, - responseDataTypes, - responseDisplayFormat, - suggestedWidgets, - hasResponse, }; }, - mapDispatchToProps, )( // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any reduxForm({ - form: API_EDITOR_FORM_NAME, + form: FORM_NAME, enableReinitialize: true, })(GraphQLEditorForm), ); diff --git a/app/client/src/pages/Editor/APIEditor/GraphQL/QueryEditor.tsx b/app/client/src/pages/Editor/APIEditor/GraphQL/QueryEditor.tsx index 442d1669b085..53948e1520b4 100644 --- a/app/client/src/pages/Editor/APIEditor/GraphQL/QueryEditor.tsx +++ b/app/client/src/pages/Editor/APIEditor/GraphQL/QueryEditor.tsx @@ -18,9 +18,7 @@ import styled from "styled-components"; import { Text, TextType } from "@appsmith/ads-old"; import LazyCodeEditor from "components/editorComponents/LazyCodeEditor"; -const QueryHeader = styled.div` - display: flex; - width: 100%; +const QueryHeader = styled(Text)` background: var(--ads-v2-color-bg-subtle); padding: 8px 16px; `; @@ -51,10 +49,8 @@ function QueryEditor(props: QueryProps) { return ( - - - Query - + + Query - - - Query variables - + + Query variables ; +const FORM_NAME = API_EDITOR_FORM_NAME; + function ApiEditorForm(props: Props) { - const { closeEditorLink } = useContext(ApiEditorContext); const { actionName } = props; const theme = EditorTheme.LIGHT; @@ -41,8 +34,7 @@ function ApiEditorForm(props: Props) { bodyUIComponent={ } - closeEditorLink={closeEditorLink} - formName={API_EDITOR_FORM_NAME} + formName={FORM_NAME} httpsMethods={HTTP_METHOD_OPTIONS} paginationUIComponent={ void; -} - -// TODO: Fix this the next time the file is edited -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const mapDispatchToProps = (dispatch: any): ReduxDispatchProps => ({ - updateDatasource: (datasource) => { - dispatch(change(API_EDITOR_FORM_NAME, "datasource", datasource)); - }, -}); +const selector = formValueSelector(FORM_NAME); -export default connect((state: AppState, props: { pluginId: string }) => { +export default connect((state: AppState) => { const httpMethodFromForm = selector(state, "actionConfiguration.httpMethod"); const actionConfigurationHeaders = selector(state, "actionConfiguration.headers") || []; @@ -110,19 +90,6 @@ export default connect((state: AppState, props: { pluginId: string }) => { const responses = getActionResponses(state); const actionResponse = responses[apiId]; - let hasResponse = false; - let suggestedWidgets; - - if (actionResponse) { - hasResponse = - !isEmpty(actionResponse.statusCode) && - actionResponse.statusCode[0] === "2"; - suggestedWidgets = actionResponse.suggestedWidgets; - } - - const actionData = getActionData(state, apiId); - const { responseDataTypes, responseDisplayFormat } = - actionResponseDisplayDataFormats(actionData); return { actionName, @@ -136,19 +103,10 @@ export default connect((state: AppState, props: { pluginId: string }) => { datasourceHeaders, datasourceParams, hintMessages, - datasources: state.entities.datasources.list.filter( - (d) => d.pluginId === props.pluginId, - ), - currentPageId: state.entities.pageList.currentPageId, - applicationId: state.entities.pageList.applicationId, - responseDataTypes, - responseDisplayFormat, - suggestedWidgets, - hasResponse, }; -}, mapDispatchToProps)( +})( reduxForm({ - form: API_EDITOR_FORM_NAME, + form: FORM_NAME, enableReinitialize: true, })(ApiEditorForm), ); diff --git a/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx b/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx index 85b6d5651183..370964cc6dcc 100644 --- a/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx +++ b/app/client/src/pages/Editor/QueryEditor/EditorJSONtoForm.tsx @@ -197,7 +197,7 @@ export function EditorJSONtoForm(props: Props) { uiComponent, } = props; - const { actionRightPaneAdditionSections, closeEditorLink, notification } = + const { actionRightPaneAdditionSections, notification } = useContext(QueryEditorContext); const params = useParams<{ baseApiId?: string; baseQueryId?: string }>(); @@ -232,9 +232,12 @@ export function EditorJSONtoForm(props: Props) { const selectedConfigTab = useSelector(getQueryPaneConfigSelectedTabIndex); - const setSelectedConfigTab = useCallback((selectedIndex: string) => { - dispatch(setQueryPaneConfigSelectedTabIndex(selectedIndex)); - }, []); + const setSelectedConfigTab = useCallback( + (selectedIndex: string) => { + dispatch(setQueryPaneConfigSelectedTabIndex(selectedIndex)); + }, + [dispatch], + ); // when switching between different redux forms, make sure this redux form has been initialized before rendering anything. // the initialized prop below comes from redux-form. @@ -243,107 +246,102 @@ export function EditorJSONtoForm(props: Props) { } return ( - <> - {closeEditorLink} - - - {notification && ( - {notification} - )} - -
- - - + + {notification && ( + {notification} + )} + +
+ + + + + + + Query + + + Settings + + + + - - - - Query - - - Settings - - - - - - - - - - - - - - - {documentationLink && ( - + + + + + + + + + {documentationLink && ( + + { + e.stopPropagation(); + handleDocumentationClick(); + }} + size="sm" + startIcon="book-line" > - { - e.stopPropagation(); - handleDocumentationClick(); - }} - size="sm" - startIcon="book-line" - > - {createMessage(DOCUMENTATION)} - - - )} - - - - -
- -
- - + {createMessage(DOCUMENTATION)} + + + )} +
+ + +
+
+ +
+
); } diff --git a/app/client/src/pages/Editor/QueryEditor/QueryEditorContext.tsx b/app/client/src/pages/Editor/QueryEditor/QueryEditorContext.tsx index c5089fc6bdfc..88d21b626452 100644 --- a/app/client/src/pages/Editor/QueryEditor/QueryEditorContext.tsx +++ b/app/client/src/pages/Editor/QueryEditor/QueryEditorContext.tsx @@ -11,7 +11,6 @@ interface QueryEditorContextContextProps { saveActionName: ( params: SaveActionNameParams, ) => ReduxAction; - closeEditorLink?: React.ReactNode; actionRightPaneAdditionSections?: React.ReactNode; showSuggestedWidgets?: boolean; notification?: string | React.ReactNode; @@ -29,7 +28,6 @@ export function QueryEditorContextProvider({ actionRightPaneBackLink, changeQueryPage, children, - closeEditorLink, moreActionsMenu, notification, onCreateDatasourceClick, @@ -42,7 +40,6 @@ export function QueryEditorContextProvider({ actionRightPaneBackLink, actionRightPaneAdditionSections, changeQueryPage, - closeEditorLink, moreActionsMenu, onCreateDatasourceClick, onEntityNotFoundBackClick, @@ -54,7 +51,6 @@ export function QueryEditorContextProvider({ actionRightPaneBackLink, actionRightPaneAdditionSections, changeQueryPage, - closeEditorLink, moreActionsMenu, onCreateDatasourceClick, onEntityNotFoundBackClick,