chore: Handling the updation of action name in the plugin action toolbar (#36560)
## Description Handling the updation of action name in the plugin action toolbar in the new modularised flow. Fixes [#36498](https://github.com/appsmithorg/appsmith/issues/36498) ## Automation /ok-to-test tags="@tag.All" ### 🔍 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/11071023786> > Commit: 73647e50cfeb6919b30c674f8f3a3a219f6f98c8 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11071023786&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.All` > Spec: > <hr>Fri, 27 Sep 2024 14:15:24 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 new component for editing plugin action names, enhancing user experience in managing plugin actions. - Added optional icon size property to the editable text component for improved customization. - Enhanced the `CommonEditorForm` and `QueryEditorHeader` components to display plugin-specific information and saving status. - **Bug Fixes** - Streamlined action dispatching logic, improving reliability in saving actions. - **Documentation** - Updated interfaces and prop types for better clarity and type safety in the codebase. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
b1ed82dbcf
commit
5995e4292a
|
|
@ -0,0 +1,81 @@
|
||||||
|
import React from "react";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
|
||||||
|
import { usePluginActionContext } from "PluginActionEditor/PluginActionContext";
|
||||||
|
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||||
|
import { getHasManageActionPermission } from "ee/utils/BusinessFeatures/permissionPageHelpers";
|
||||||
|
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
||||||
|
import { PluginType } from "entities/Action";
|
||||||
|
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { getSavingStatusForActionName } from "selectors/actionSelectors";
|
||||||
|
import { getAssetUrl } from "ee/utils/airgapHelpers";
|
||||||
|
import { ActionUrlIcon } from "pages/Editor/Explorer/ExplorerIcons";
|
||||||
|
|
||||||
|
export interface SaveActionNameParams {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PluginActionNameEditorProps {
|
||||||
|
saveActionName: (
|
||||||
|
params: SaveActionNameParams,
|
||||||
|
) => ReduxAction<SaveActionNameParams>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ActionNameEditorWrapper = styled.div`
|
||||||
|
& .ads-v2-box {
|
||||||
|
gap: var(--ads-v2-spaces-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&& .t--action-name-edit-field {
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
.bp3-editable-text-content {
|
||||||
|
height: unset !important;
|
||||||
|
line-height: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .t--plugin-icon-box {
|
||||||
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 12px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const PluginActionNameEditor = (props: PluginActionNameEditorProps) => {
|
||||||
|
const { action, plugin } = usePluginActionContext();
|
||||||
|
|
||||||
|
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
|
||||||
|
const isChangePermitted = getHasManageActionPermission(
|
||||||
|
isFeatureEnabled,
|
||||||
|
action?.userPermissions,
|
||||||
|
);
|
||||||
|
|
||||||
|
const saveStatus = useSelector((state) =>
|
||||||
|
getSavingStatusForActionName(state, action?.id || ""),
|
||||||
|
);
|
||||||
|
|
||||||
|
const iconUrl = getAssetUrl(plugin?.iconLocation) || "";
|
||||||
|
const icon = ActionUrlIcon(iconUrl);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ActionNameEditorWrapper>
|
||||||
|
<ActionNameEditor
|
||||||
|
actionConfig={action}
|
||||||
|
disabled={!isChangePermitted}
|
||||||
|
enableFontStyling={plugin?.type === PluginType.API}
|
||||||
|
icon={icon}
|
||||||
|
saveActionName={props.saveActionName}
|
||||||
|
saveStatus={saveStatus}
|
||||||
|
/>
|
||||||
|
</ActionNameEditorWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PluginActionNameEditor;
|
||||||
|
|
@ -6,3 +6,8 @@ export {
|
||||||
export { default as PluginActionToolbar } from "./components/PluginActionToolbar";
|
export { default as PluginActionToolbar } from "./components/PluginActionToolbar";
|
||||||
export { default as PluginActionForm } from "./components/PluginActionForm";
|
export { default as PluginActionForm } from "./components/PluginActionForm";
|
||||||
export { default as PluginActionResponse } from "./components/PluginActionResponse";
|
export { default as PluginActionResponse } from "./components/PluginActionResponse";
|
||||||
|
export type {
|
||||||
|
SaveActionNameParams,
|
||||||
|
PluginActionNameEditorProps,
|
||||||
|
} from "./components/PluginActionNameEditor";
|
||||||
|
export { default as PluginActionNameEditor } from "./components/PluginActionNameEditor";
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,13 @@
|
||||||
import React, { memo } from "react";
|
import React, { memo } from "react";
|
||||||
import { useSelector } from "react-redux";
|
|
||||||
|
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
import EditableText, {
|
import EditableText, {
|
||||||
EditInteractionKind,
|
EditInteractionKind,
|
||||||
} from "components/editorComponents/EditableText";
|
} from "components/editorComponents/EditableText";
|
||||||
import { removeSpecialChars } from "utils/helpers";
|
import { removeSpecialChars } from "utils/helpers";
|
||||||
import type { AppState } from "ee/reducers";
|
|
||||||
|
|
||||||
import { saveActionName } from "actions/pluginActionActions";
|
|
||||||
import { Flex } from "@appsmith/ads";
|
import { Flex } from "@appsmith/ads";
|
||||||
import { getActionByBaseId, getPlugin } from "ee/selectors/entitiesSelector";
|
|
||||||
import NameEditorComponent, {
|
import NameEditorComponent, {
|
||||||
IconBox,
|
IconBox,
|
||||||
IconWrapper,
|
|
||||||
NameWrapper,
|
NameWrapper,
|
||||||
} from "components/utils/NameEditorComponent";
|
} from "components/utils/NameEditorComponent";
|
||||||
import {
|
import {
|
||||||
|
|
@ -21,14 +15,13 @@ import {
|
||||||
ACTION_NAME_PLACEHOLDER,
|
ACTION_NAME_PLACEHOLDER,
|
||||||
createMessage,
|
createMessage,
|
||||||
} from "ee/constants/messages";
|
} from "ee/constants/messages";
|
||||||
import { getAssetUrl } from "ee/utils/airgapHelpers";
|
|
||||||
import { getSavingStatusForActionName } from "selectors/actionSelectors";
|
|
||||||
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
||||||
|
import type { SaveActionNameParams } from "PluginActionEditor";
|
||||||
|
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||||
|
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
||||||
|
import type { Action } from "entities/Action";
|
||||||
|
import type { ModuleInstance } from "ee/constants/ModuleInstanceConstants";
|
||||||
|
|
||||||
interface SaveActionNameParams {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
interface ActionNameEditorProps {
|
interface ActionNameEditorProps {
|
||||||
/*
|
/*
|
||||||
This prop checks if page is API Pane or Query Pane or Curl Pane
|
This prop checks if page is API Pane or Query Pane or Curl Pane
|
||||||
|
|
@ -38,38 +31,34 @@ interface ActionNameEditorProps {
|
||||||
*/
|
*/
|
||||||
enableFontStyling?: boolean;
|
enableFontStyling?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
saveActionName?: (
|
saveActionName: (
|
||||||
params: SaveActionNameParams,
|
params: SaveActionNameParams,
|
||||||
) => ReduxAction<SaveActionNameParams>;
|
) => ReduxAction<SaveActionNameParams>;
|
||||||
|
actionConfig?: Action | ModuleInstance;
|
||||||
|
icon?: JSX.Element;
|
||||||
|
saveStatus: { isSaving: boolean; error: boolean };
|
||||||
}
|
}
|
||||||
|
|
||||||
function ActionNameEditor(props: ActionNameEditorProps) {
|
function ActionNameEditor(props: ActionNameEditorProps) {
|
||||||
const params = useParams<{ baseApiId?: string; baseQueryId?: string }>();
|
const {
|
||||||
|
actionConfig,
|
||||||
|
disabled = false,
|
||||||
|
enableFontStyling = false,
|
||||||
|
icon = "",
|
||||||
|
saveActionName,
|
||||||
|
saveStatus,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const currentActionConfig = useSelector((state: AppState) =>
|
const isActionRedesignEnabled = useFeatureFlag(
|
||||||
getActionByBaseId(state, params.baseApiId || params.baseQueryId || ""),
|
FEATURE_FLAG.release_actions_redesign_enabled,
|
||||||
);
|
|
||||||
|
|
||||||
const currentPlugin = useSelector((state: AppState) =>
|
|
||||||
getPlugin(state, currentActionConfig?.pluginId || ""),
|
|
||||||
);
|
|
||||||
|
|
||||||
const saveStatus = useSelector((state) =>
|
|
||||||
getSavingStatusForActionName(state, currentActionConfig?.id || ""),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NameEditorComponent
|
<NameEditorComponent
|
||||||
/**
|
id={actionConfig?.id}
|
||||||
* This component is used by module editor in EE which uses a different
|
|
||||||
* action to save the name of an action. The current callers of this component
|
|
||||||
* pass the existing saveAction action but as fallback the saveActionName is used here
|
|
||||||
* as a guard.
|
|
||||||
*/
|
|
||||||
dispatchAction={props.saveActionName || saveActionName}
|
|
||||||
id={currentActionConfig?.id}
|
|
||||||
idUndefinedErrorMessage={ACTION_ID_NOT_FOUND_IN_URL}
|
idUndefinedErrorMessage={ACTION_ID_NOT_FOUND_IN_URL}
|
||||||
name={currentActionConfig?.name}
|
name={actionConfig?.name}
|
||||||
|
onSaveName={saveActionName}
|
||||||
saveStatus={saveStatus}
|
saveStatus={saveStatus}
|
||||||
>
|
>
|
||||||
{({
|
{({
|
||||||
|
|
@ -85,28 +74,22 @@ function ActionNameEditor(props: ActionNameEditorProps) {
|
||||||
isNew: boolean;
|
isNew: boolean;
|
||||||
saveStatus: { isSaving: boolean; error: boolean };
|
saveStatus: { isSaving: boolean; error: boolean };
|
||||||
}) => (
|
}) => (
|
||||||
<NameWrapper enableFontStyling={props.enableFontStyling}>
|
<NameWrapper enableFontStyling={enableFontStyling}>
|
||||||
<Flex
|
<Flex
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
gap="spaces-3"
|
gap="spaces-3"
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
width="100%"
|
width="100%"
|
||||||
>
|
>
|
||||||
{currentPlugin && (
|
{icon && <IconBox className="t--plugin-icon-box">{icon}</IconBox>}
|
||||||
<IconBox>
|
|
||||||
<IconWrapper
|
|
||||||
alt={currentPlugin.name}
|
|
||||||
src={getAssetUrl(currentPlugin?.iconLocation)}
|
|
||||||
/>
|
|
||||||
</IconBox>
|
|
||||||
)}
|
|
||||||
<EditableText
|
<EditableText
|
||||||
className="t--action-name-edit-field"
|
className="t--action-name-edit-field"
|
||||||
defaultValue={currentActionConfig ? currentActionConfig.name : ""}
|
defaultValue={actionConfig ? actionConfig.name : ""}
|
||||||
disabled={props.disabled}
|
disabled={disabled}
|
||||||
editInteractionKind={EditInteractionKind.SINGLE}
|
editInteractionKind={EditInteractionKind.SINGLE}
|
||||||
errorTooltipClass="t--action-name-edit-error"
|
errorTooltipClass="t--action-name-edit-error"
|
||||||
forceDefault={forceUpdate}
|
forceDefault={forceUpdate}
|
||||||
|
iconSize={isActionRedesignEnabled ? "sm" : "md"}
|
||||||
isEditingDefault={isNew}
|
isEditingDefault={isNew}
|
||||||
isInvalid={isInvalidNameForEntity}
|
isInvalid={isInvalidNameForEntity}
|
||||||
onTextChanged={handleNameChange}
|
onTextChanged={handleNameChange}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,13 @@ import {
|
||||||
} from "@blueprintjs/core";
|
} from "@blueprintjs/core";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { Button, Spinner, toast, Tooltip } from "@appsmith/ads";
|
import {
|
||||||
|
Button,
|
||||||
|
Spinner,
|
||||||
|
toast,
|
||||||
|
Tooltip,
|
||||||
|
type ButtonSizes,
|
||||||
|
} from "@appsmith/ads";
|
||||||
import { INVALID_NAME_ERROR, createMessage } from "ee/constants/messages";
|
import { INVALID_NAME_ERROR, createMessage } from "ee/constants/messages";
|
||||||
|
|
||||||
export enum EditInteractionKind {
|
export enum EditInteractionKind {
|
||||||
|
|
@ -39,6 +45,7 @@ interface EditableTextProps {
|
||||||
minLines?: number;
|
minLines?: number;
|
||||||
customErrorTooltip?: string;
|
customErrorTooltip?: string;
|
||||||
useFullWidth?: boolean;
|
useFullWidth?: boolean;
|
||||||
|
iconSize?: ButtonSizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// using the !important keyword here is mandatory because a style is being applied to that element using the style attribute
|
// using the !important keyword here is mandatory because a style is being applied to that element using the style attribute
|
||||||
|
|
@ -129,6 +136,7 @@ export function EditableText(props: EditableTextProps) {
|
||||||
errorTooltipClass,
|
errorTooltipClass,
|
||||||
forceDefault,
|
forceDefault,
|
||||||
hideEditIcon,
|
hideEditIcon,
|
||||||
|
iconSize = "md",
|
||||||
isEditingDefault,
|
isEditingDefault,
|
||||||
isInvalid,
|
isInvalid,
|
||||||
maxLength,
|
maxLength,
|
||||||
|
|
@ -275,7 +283,7 @@ export function EditableText(props: EditableTextProps) {
|
||||||
className="t--action-name-edit-icon"
|
className="t--action-name-edit-icon"
|
||||||
isIconButton
|
isIconButton
|
||||||
kind="tertiary"
|
kind="tertiary"
|
||||||
size="md"
|
size={iconSize}
|
||||||
startIcon="pencil-line"
|
startIcon="pencil-line"
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import {
|
||||||
} from "ee/constants/messages";
|
} from "ee/constants/messages";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Classes } from "@blueprintjs/core";
|
import { Classes } from "@blueprintjs/core";
|
||||||
|
import type { SaveActionNameParams } from "PluginActionEditor";
|
||||||
|
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
||||||
|
|
||||||
export const NameWrapper = styled.div<{ enableFontStyling?: boolean }>`
|
export const NameWrapper = styled.div<{ enableFontStyling?: boolean }>`
|
||||||
min-width: 50%;
|
min-width: 50%;
|
||||||
|
|
@ -71,9 +73,9 @@ interface NameEditorProps {
|
||||||
children: (params: any) => JSX.Element;
|
children: (params: any) => JSX.Element;
|
||||||
id?: string;
|
id?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
// TODO: Fix this the next time the file is edited
|
onSaveName: (
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
params: SaveActionNameParams,
|
||||||
dispatchAction: (a: any) => any;
|
) => ReduxAction<SaveActionNameParams>;
|
||||||
// TODO: Fix this the next time the file is edited
|
// TODO: Fix this the next time the file is edited
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
suffixErrorMessage?: (params?: any) => string;
|
suffixErrorMessage?: (params?: any) => string;
|
||||||
|
|
@ -90,10 +92,10 @@ interface NameEditorProps {
|
||||||
|
|
||||||
function NameEditor(props: NameEditorProps) {
|
function NameEditor(props: NameEditorProps) {
|
||||||
const {
|
const {
|
||||||
dispatchAction,
|
|
||||||
id: entityId,
|
id: entityId,
|
||||||
idUndefinedErrorMessage,
|
idUndefinedErrorMessage,
|
||||||
name: entityName,
|
name: entityName,
|
||||||
|
onSaveName,
|
||||||
saveStatus,
|
saveStatus,
|
||||||
suffixErrorMessage = ACTION_NAME_CONFLICT_ERROR,
|
suffixErrorMessage = ACTION_NAME_CONFLICT_ERROR,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
@ -131,8 +133,8 @@ function NameEditor(props: NameEditorProps) {
|
||||||
|
|
||||||
const handleNameChange = useCallback(
|
const handleNameChange = useCallback(
|
||||||
(name: string) => {
|
(name: string) => {
|
||||||
if (name !== entityName && !isInvalidNameForEntity(name)) {
|
if (name !== entityName && !isInvalidNameForEntity(name) && entityId) {
|
||||||
dispatch(dispatchAction({ id: entityId, name }));
|
dispatch(onSaveName({ id: entityId, name }));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[dispatch, isInvalidNameForEntity, entityId, entityName],
|
[dispatch, isInvalidNameForEntity, entityId, entityName],
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
||||||
import type { PaginationField } from "api/ActionAPI";
|
import type { PaginationField } from "api/ActionAPI";
|
||||||
import React, { createContext, useMemo } from "react";
|
import React, { createContext, useMemo } from "react";
|
||||||
|
import type { SaveActionNameParams } from "PluginActionEditor";
|
||||||
interface SaveActionNameParams {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApiEditorContextContextProps {
|
interface ApiEditorContextContextProps {
|
||||||
moreActionsMenu?: React.ReactNode;
|
moreActionsMenu?: React.ReactNode;
|
||||||
|
|
@ -15,7 +11,7 @@ interface ApiEditorContextContextProps {
|
||||||
// TODO: Fix this the next time the file is edited
|
// TODO: Fix this the next time the file is edited
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
settingsConfig: any;
|
settingsConfig: any;
|
||||||
saveActionName?: (
|
saveActionName: (
|
||||||
params: SaveActionNameParams,
|
params: SaveActionNameParams,
|
||||||
) => ReduxAction<SaveActionNameParams>;
|
) => ReduxAction<SaveActionNameParams>;
|
||||||
closeEditorLink?: React.ReactNode;
|
closeEditorLink?: React.ReactNode;
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@ import {
|
||||||
InfoFields,
|
InfoFields,
|
||||||
RequestTabs,
|
RequestTabs,
|
||||||
} from "PluginActionEditor/components/PluginActionForm/components/CommonEditorForm";
|
} from "PluginActionEditor/components/PluginActionForm/components/CommonEditorForm";
|
||||||
|
import { getSavingStatusForActionName } from "selectors/actionSelectors";
|
||||||
|
import { getAssetUrl } from "ee/utils/airgapHelpers";
|
||||||
|
import { ActionUrlIcon } from "../Explorer/ExplorerIcons";
|
||||||
|
|
||||||
const Form = styled.form`
|
const Form = styled.form`
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -245,6 +248,18 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) {
|
||||||
currentActionConfig?.userPermissions,
|
currentActionConfig?.userPermissions,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const currentPlugin = useSelector((state: AppState) =>
|
||||||
|
getPlugin(state, currentActionConfig?.pluginId || ""),
|
||||||
|
);
|
||||||
|
|
||||||
|
const saveStatus = useSelector((state) =>
|
||||||
|
getSavingStatusForActionName(state, currentActionConfig?.id || ""),
|
||||||
|
);
|
||||||
|
|
||||||
|
const iconUrl = getAssetUrl(currentPlugin?.iconLocation) || "";
|
||||||
|
|
||||||
|
const icon = ActionUrlIcon(iconUrl);
|
||||||
|
|
||||||
const plugin = useSelector((state: AppState) =>
|
const plugin = useSelector((state: AppState) =>
|
||||||
getPlugin(state, pluginId ?? ""),
|
getPlugin(state, pluginId ?? ""),
|
||||||
);
|
);
|
||||||
|
|
@ -281,9 +296,12 @@ function CommonEditorForm(props: CommonFormPropsWithExtraParams) {
|
||||||
<FormRow className="form-row-header">
|
<FormRow className="form-row-header">
|
||||||
<NameWrapper className="t--nameOfApi">
|
<NameWrapper className="t--nameOfApi">
|
||||||
<ActionNameEditor
|
<ActionNameEditor
|
||||||
|
actionConfig={currentActionConfig}
|
||||||
disabled={!isChangePermitted}
|
disabled={!isChangePermitted}
|
||||||
enableFontStyling
|
enableFontStyling
|
||||||
|
icon={icon}
|
||||||
saveActionName={saveActionName}
|
saveActionName={saveActionName}
|
||||||
|
saveStatus={saveStatus}
|
||||||
/>
|
/>
|
||||||
</NameWrapper>
|
</NameWrapper>
|
||||||
<ActionButtons className="t--formActionButtons">
|
<ActionButtons className="t--formActionButtons">
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,11 @@ import {
|
||||||
getPluginSettingConfigs,
|
getPluginSettingConfigs,
|
||||||
getPlugins,
|
getPlugins,
|
||||||
} from "ee/selectors/entitiesSelector";
|
} from "ee/selectors/entitiesSelector";
|
||||||
import { deleteAction, runAction } from "actions/pluginActionActions";
|
import {
|
||||||
|
deleteAction,
|
||||||
|
runAction,
|
||||||
|
saveActionName,
|
||||||
|
} from "actions/pluginActionActions";
|
||||||
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
||||||
import Editor from "./Editor";
|
import Editor from "./Editor";
|
||||||
import BackToCanvas from "components/common/BackToCanvas";
|
import BackToCanvas from "components/common/BackToCanvas";
|
||||||
|
|
@ -151,15 +155,7 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) {
|
||||||
});
|
});
|
||||||
dispatch(runAction(action?.id ?? "", paginationField));
|
dispatch(runAction(action?.id ?? "", paginationField));
|
||||||
},
|
},
|
||||||
[
|
[action?.id, apiName, pageName, plugins, pluginId, datasourceId, dispatch],
|
||||||
action?.id,
|
|
||||||
apiName,
|
|
||||||
pageName,
|
|
||||||
getPageName,
|
|
||||||
plugins,
|
|
||||||
pluginId,
|
|
||||||
datasourceId,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const actionRightPaneBackLink = useMemo(() => {
|
const actionRightPaneBackLink = useMemo(() => {
|
||||||
|
|
@ -173,13 +169,13 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) {
|
||||||
pageName,
|
pageName,
|
||||||
});
|
});
|
||||||
dispatch(deleteAction({ id: action?.id ?? "", name: apiName }));
|
dispatch(deleteAction({ id: action?.id ?? "", name: apiName }));
|
||||||
}, [getPageName, pages, basePageId, apiName]);
|
}, [pages, basePageId, apiName, action?.id, dispatch, pageName]);
|
||||||
|
|
||||||
const notification = useMemo(() => {
|
const notification = useMemo(() => {
|
||||||
if (!isConverting) return null;
|
if (!isConverting) return null;
|
||||||
|
|
||||||
return <ConvertEntityNotification icon={icon} name={action?.name || ""} />;
|
return <ConvertEntityNotification icon={icon} name={action?.name || ""} />;
|
||||||
}, [action?.name, isConverting]);
|
}, [action?.name, isConverting, icon]);
|
||||||
|
|
||||||
const isActionRedesignEnabled = useFeatureFlag(
|
const isActionRedesignEnabled = useFeatureFlag(
|
||||||
FEATURE_FLAG.release_actions_redesign_enabled,
|
FEATURE_FLAG.release_actions_redesign_enabled,
|
||||||
|
|
@ -196,6 +192,7 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) {
|
||||||
handleRunClick={handleRunClick}
|
handleRunClick={handleRunClick}
|
||||||
moreActionsMenu={moreActionsMenu}
|
moreActionsMenu={moreActionsMenu}
|
||||||
notification={notification}
|
notification={notification}
|
||||||
|
saveActionName={saveActionName}
|
||||||
settingsConfig={settingsConfig}
|
settingsConfig={settingsConfig}
|
||||||
>
|
>
|
||||||
<Disabler isDisabled={isConverting}>
|
<Disabler isDisabled={isConverting}>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import {
|
||||||
import { Tooltip } from "@appsmith/ads";
|
import { Tooltip } from "@appsmith/ads";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { getSavingStatusForActionName } from "selectors/actionSelectors";
|
import { getSavingStatusForActionName } from "selectors/actionSelectors";
|
||||||
|
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
||||||
|
import type { SaveActionNameParams } from "PluginActionEditor";
|
||||||
|
|
||||||
export const searchHighlightSpanClassName = "token";
|
export const searchHighlightSpanClassName = "token";
|
||||||
export const searchTokenizationDelimiter = "!!";
|
export const searchTokenizationDelimiter = "!!";
|
||||||
|
|
@ -84,7 +86,7 @@ export interface EntityNameProps {
|
||||||
name: string;
|
name: string;
|
||||||
isEditing?: boolean;
|
isEditing?: boolean;
|
||||||
onChange?: (name: string) => void;
|
onChange?: (name: string) => void;
|
||||||
updateEntityName: (name: string) => void;
|
updateEntityName: (name: string) => ReduxAction<SaveActionNameParams>;
|
||||||
entityId: string;
|
entityId: string;
|
||||||
searchKeyword?: string;
|
searchKeyword?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
|
@ -164,10 +166,10 @@ export const EntityName = React.memo(
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NameEditorComponent
|
<NameEditorComponent
|
||||||
dispatchAction={handleUpdateName}
|
|
||||||
id={props.entityId}
|
id={props.entityId}
|
||||||
idUndefinedErrorMessage={ACTION_ID_NOT_FOUND_IN_URL}
|
idUndefinedErrorMessage={ACTION_ID_NOT_FOUND_IN_URL}
|
||||||
name={updatedName}
|
name={updatedName}
|
||||||
|
onSaveName={handleUpdateName}
|
||||||
saveStatus={saveStatus}
|
saveStatus={saveStatus}
|
||||||
suffixErrorMessage={ENTITY_EXPLORER_ACTION_NAME_CONFLICT_ERROR}
|
suffixErrorMessage={ENTITY_EXPLORER_ACTION_NAME_CONFLICT_ERROR}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,8 @@ import NameEditorComponent, {
|
||||||
} from "components/utils/NameEditorComponent";
|
} from "components/utils/NameEditorComponent";
|
||||||
import { getSavingStatusForJSObjectName } from "selectors/actionSelectors";
|
import { getSavingStatusForJSObjectName } from "selectors/actionSelectors";
|
||||||
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
||||||
|
import type { SaveActionNameParams } from "PluginActionEditor";
|
||||||
|
|
||||||
export interface SaveActionNameParams {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
export interface JSObjectNameEditorProps {
|
export interface JSObjectNameEditorProps {
|
||||||
/*
|
/*
|
||||||
This prop checks if page is API Pane or Query Pane or Curl Pane
|
This prop checks if page is API Pane or Query Pane or Curl Pane
|
||||||
|
|
@ -64,10 +61,10 @@ export function JSObjectNameEditor(props: JSObjectNameEditorProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NameEditorComponent
|
<NameEditorComponent
|
||||||
dispatchAction={props.saveJSObjectName}
|
|
||||||
id={currentJSObjectConfig?.id}
|
id={currentJSObjectConfig?.id}
|
||||||
idUndefinedErrorMessage={JSOBJECT_ID_NOT_FOUND_IN_URL}
|
idUndefinedErrorMessage={JSOBJECT_ID_NOT_FOUND_IN_URL}
|
||||||
name={currentJSObjectConfig?.name}
|
name={currentJSObjectConfig?.name}
|
||||||
|
onSaveName={props.saveJSObjectName}
|
||||||
saveStatus={saveStatus}
|
saveStatus={saveStatus}
|
||||||
>
|
>
|
||||||
{({
|
{({
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,14 @@
|
||||||
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
||||||
|
import type { SaveActionNameParams } from "PluginActionEditor";
|
||||||
import React, { createContext, useMemo } from "react";
|
import React, { createContext, useMemo } from "react";
|
||||||
|
|
||||||
interface SaveActionNameParams {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface QueryEditorContextContextProps {
|
interface QueryEditorContextContextProps {
|
||||||
moreActionsMenu?: React.ReactNode;
|
moreActionsMenu?: React.ReactNode;
|
||||||
onCreateDatasourceClick?: () => void;
|
onCreateDatasourceClick?: () => void;
|
||||||
onEntityNotFoundBackClick?: () => void;
|
onEntityNotFoundBackClick?: () => void;
|
||||||
changeQueryPage?: (baseQueryId: string) => void;
|
changeQueryPage?: (baseQueryId: string) => void;
|
||||||
actionRightPaneBackLink?: React.ReactNode;
|
actionRightPaneBackLink?: React.ReactNode;
|
||||||
saveActionName?: (
|
saveActionName: (
|
||||||
params: SaveActionNameParams,
|
params: SaveActionNameParams,
|
||||||
) => ReduxAction<SaveActionNameParams>;
|
) => ReduxAction<SaveActionNameParams>;
|
||||||
closeEditorLink?: React.ReactNode;
|
closeEditorLink?: React.ReactNode;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import { useActiveActionBaseId } from "ee/pages/Editor/Explorer/hooks";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import {
|
import {
|
||||||
getActionByBaseId,
|
getActionByBaseId,
|
||||||
|
getPlugin,
|
||||||
getPluginNameFromId,
|
getPluginNameFromId,
|
||||||
} from "ee/selectors/entitiesSelector";
|
} from "ee/selectors/entitiesSelector";
|
||||||
import { QueryEditorContext } from "./QueryEditorContext";
|
import { QueryEditorContext } from "./QueryEditorContext";
|
||||||
|
|
@ -21,6 +22,9 @@ import type { Datasource } from "entities/Datasource";
|
||||||
import type { AppState } from "ee/reducers";
|
import type { AppState } from "ee/reducers";
|
||||||
import { SQL_DATASOURCES } from "constants/QueryEditorConstants";
|
import { SQL_DATASOURCES } from "constants/QueryEditorConstants";
|
||||||
import DatasourceSelector from "./DatasourceSelector";
|
import DatasourceSelector from "./DatasourceSelector";
|
||||||
|
import { getSavingStatusForActionName } from "selectors/actionSelectors";
|
||||||
|
import { getAssetUrl } from "ee/utils/airgapHelpers";
|
||||||
|
import { ActionUrlIcon } from "../Explorer/ExplorerIcons";
|
||||||
|
|
||||||
const NameWrapper = styled.div`
|
const NameWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -79,6 +83,18 @@ const QueryEditorHeader = (props: Props) => {
|
||||||
currentActionConfig?.userPermissions,
|
currentActionConfig?.userPermissions,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const currentPlugin = useSelector((state: AppState) =>
|
||||||
|
getPlugin(state, currentActionConfig?.pluginId || ""),
|
||||||
|
);
|
||||||
|
|
||||||
|
const saveStatus = useSelector((state) =>
|
||||||
|
getSavingStatusForActionName(state, currentActionConfig?.id || ""),
|
||||||
|
);
|
||||||
|
|
||||||
|
const iconUrl = getAssetUrl(currentPlugin?.iconLocation) || "";
|
||||||
|
|
||||||
|
const icon = ActionUrlIcon(iconUrl);
|
||||||
|
|
||||||
// get the current action's plugin name
|
// get the current action's plugin name
|
||||||
const currentActionPluginName = useSelector((state: AppState) =>
|
const currentActionPluginName = useSelector((state: AppState) =>
|
||||||
getPluginNameFromId(state, currentActionConfig?.pluginId || ""),
|
getPluginNameFromId(state, currentActionConfig?.pluginId || ""),
|
||||||
|
|
@ -106,8 +122,11 @@ const QueryEditorHeader = (props: Props) => {
|
||||||
<StyledFormRow>
|
<StyledFormRow>
|
||||||
<NameWrapper>
|
<NameWrapper>
|
||||||
<ActionNameEditor
|
<ActionNameEditor
|
||||||
|
actionConfig={currentActionConfig}
|
||||||
disabled={!isChangePermitted}
|
disabled={!isChangePermitted}
|
||||||
|
icon={icon}
|
||||||
saveActionName={saveActionName}
|
saveActionName={saveActionName}
|
||||||
|
saveStatus={saveStatus}
|
||||||
/>
|
/>
|
||||||
</NameWrapper>
|
</NameWrapper>
|
||||||
<ActionsWrapper>
|
<ActionsWrapper>
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import { ENTITY_ICON_SIZE, EntityIcon } from "../Explorer/ExplorerIcons";
|
||||||
import { getIDEViewMode } from "selectors/ideSelectors";
|
import { getIDEViewMode } from "selectors/ideSelectors";
|
||||||
import { EditorViewMode } from "ee/entities/IDE/constants";
|
import { EditorViewMode } from "ee/entities/IDE/constants";
|
||||||
import { AppPluginActionEditor } from "../AppPluginActionEditor";
|
import { AppPluginActionEditor } from "../AppPluginActionEditor";
|
||||||
|
import { saveActionName } from "actions/pluginActionActions";
|
||||||
|
|
||||||
type QueryEditorProps = RouteComponentProps<QueryEditorRouteParams>;
|
type QueryEditorProps = RouteComponentProps<QueryEditorRouteParams>;
|
||||||
|
|
||||||
|
|
@ -126,6 +127,7 @@ function QueryEditor(props: QueryEditorProps) {
|
||||||
}, [
|
}, [
|
||||||
action?.id,
|
action?.id,
|
||||||
action?.name,
|
action?.name,
|
||||||
|
action?.pluginType,
|
||||||
isChangePermitted,
|
isChangePermitted,
|
||||||
isDeletePermitted,
|
isDeletePermitted,
|
||||||
basePageId,
|
basePageId,
|
||||||
|
|
@ -143,7 +145,7 @@ function QueryEditor(props: QueryEditorProps) {
|
||||||
changeQuery({ baseQueryId: baseQueryId, basePageId, applicationId }),
|
changeQuery({ baseQueryId: baseQueryId, basePageId, applicationId }),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[basePageId, applicationId],
|
[basePageId, applicationId, dispatch],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onCreateDatasourceClick = useCallback(() => {
|
const onCreateDatasourceClick = useCallback(() => {
|
||||||
|
|
@ -159,13 +161,7 @@ function QueryEditor(props: QueryEditorProps) {
|
||||||
AnalyticsUtil.logEvent("NAVIGATE_TO_CREATE_NEW_DATASOURCE_PAGE", {
|
AnalyticsUtil.logEvent("NAVIGATE_TO_CREATE_NEW_DATASOURCE_PAGE", {
|
||||||
entryPoint,
|
entryPoint,
|
||||||
});
|
});
|
||||||
}, [
|
}, [basePageId]);
|
||||||
basePageId,
|
|
||||||
history,
|
|
||||||
integrationEditorURL,
|
|
||||||
DatasourceCreateEntryPoints,
|
|
||||||
AnalyticsUtil,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// custom function to return user to integrations page if action is not found
|
// custom function to return user to integrations page if action is not found
|
||||||
const onEntityNotFoundBackClick = useCallback(
|
const onEntityNotFoundBackClick = useCallback(
|
||||||
|
|
@ -176,7 +172,7 @@ function QueryEditor(props: QueryEditorProps) {
|
||||||
selectedTab: INTEGRATION_TABS.ACTIVE,
|
selectedTab: INTEGRATION_TABS.ACTIVE,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
[basePageId, history, integrationEditorURL],
|
[basePageId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const notification = useMemo(() => {
|
const notification = useMemo(() => {
|
||||||
|
|
@ -189,7 +185,7 @@ function QueryEditor(props: QueryEditorProps) {
|
||||||
withPadding
|
withPadding
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}, [action?.name, isConverting]);
|
}, [action?.name, isConverting, icon]);
|
||||||
|
|
||||||
const isActionRedesignEnabled = useFeatureFlag(
|
const isActionRedesignEnabled = useFeatureFlag(
|
||||||
FEATURE_FLAG.release_actions_redesign_enabled,
|
FEATURE_FLAG.release_actions_redesign_enabled,
|
||||||
|
|
@ -207,6 +203,7 @@ function QueryEditor(props: QueryEditorProps) {
|
||||||
notification={notification}
|
notification={notification}
|
||||||
onCreateDatasourceClick={onCreateDatasourceClick}
|
onCreateDatasourceClick={onCreateDatasourceClick}
|
||||||
onEntityNotFoundBackClick={onEntityNotFoundBackClick}
|
onEntityNotFoundBackClick={onEntityNotFoundBackClick}
|
||||||
|
saveActionName={saveActionName}
|
||||||
>
|
>
|
||||||
<Disabler isDisabled={isConverting}>
|
<Disabler isDisabled={isConverting}>
|
||||||
<Editor
|
<Editor
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user