Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from "react";
import { useSelector } from "react-redux";
import ActionNameEditor from "components/editorComponents/ActionNameEditor";
import { usePluginActionContext } from "PluginActionEditor/PluginActionContext";
import { getActionByBaseId } from "ee/selectors/entitiesSelector";
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";

export interface SaveActionNameParams {
id: string;
name: string;
}

export interface PluginActionNameEditorProps {
saveActionName: (
params: SaveActionNameParams,
) => ReduxAction<SaveActionNameParams>;
}

const PluginActionNameEditor = (props: PluginActionNameEditorProps) => {
const { action, plugin } = usePluginActionContext();
const currentActionConfig = useSelector((state) =>
action.baseId ? getActionByBaseId(state, action.baseId) : undefined,
);
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
const isChangePermitted = getHasManageActionPermission(
isFeatureEnabled,
currentActionConfig?.userPermissions,
);

return (
<div>
<ActionNameEditor
disabled={!isChangePermitted}
enableFontStyling={plugin?.type === PluginType.API}
saveActionName={props.saveActionName}
/>
</div>
);
};

export default PluginActionNameEditor;
5 changes: 5 additions & 0 deletions app/client/src/PluginActionEditor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ export {
export { default as PluginActionToolbar } from "./components/PluginActionToolbar";
export { default as PluginActionForm } from "./components/PluginActionForm";
export { default as PluginActionResponse } from "./components/PluginActionResponse";
export type {
SaveActionNameParams,
PluginActionNameEditorProps,
} from "./components/PluginActionNameEditor";
export { default as PluginActionNameEditor } from "./components/PluginActionNameEditor";
22 changes: 8 additions & 14 deletions app/client/src/components/editorComponents/ActionNameEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import EditableText, {
import { removeSpecialChars } from "utils/helpers";
import type { AppState } from "ee/reducers";

import { saveActionName } from "actions/pluginActionActions";
import { Flex } from "@appsmith/ads";
import { getActionByBaseId, getPlugin } from "ee/selectors/entitiesSelector";
import NameEditorComponent, {
Expand All @@ -24,11 +23,8 @@ import {
import { getAssetUrl } from "ee/utils/airgapHelpers";
import { getSavingStatusForActionName } from "selectors/actionSelectors";
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
import type { SaveActionNameParams } from "PluginActionEditor";

interface SaveActionNameParams {
id: string;
name: string;
}
interface ActionNameEditorProps {
/*
This prop checks if page is API Pane or Query Pane or Curl Pane
Expand All @@ -38,13 +34,17 @@ interface ActionNameEditorProps {
*/
enableFontStyling?: boolean;
disabled?: boolean;
saveActionName?: (
saveActionName: (
params: SaveActionNameParams,
) => ReduxAction<SaveActionNameParams>;
}

function ActionNameEditor(props: ActionNameEditorProps) {
const params = useParams<{ baseApiId?: string; baseQueryId?: string }>();
const params = useParams<{
baseApiId?: string;
baseQueryId?: string;
moduleInstanceId?: string;
}>();

const currentActionConfig = useSelector((state: AppState) =>
getActionByBaseId(state, params.baseApiId || params.baseQueryId || ""),
Expand All @@ -60,16 +60,10 @@ function ActionNameEditor(props: ActionNameEditorProps) {

return (
<NameEditorComponent
/**
* 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}
name={currentActionConfig?.name}
onSaveName={props.saveActionName}
saveStatus={saveStatus}
>
{({
Expand Down
13 changes: 8 additions & 5 deletions app/client/src/components/utils/NameEditorComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
} from "ee/constants/messages";
import styled from "styled-components";
import { Classes } from "@blueprintjs/core";
import type { SaveActionNameParams } from "PluginActionEditor";
import type { ReduxAction } from "ee/constants/ReduxActionConstants";

export const NameWrapper = styled.div<{ enableFontStyling?: boolean }>`
min-width: 50%;
Expand Down Expand Up @@ -71,9 +73,10 @@ interface NameEditorProps {
children: (params: any) => JSX.Element;
id?: string;
name?: string;
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
dispatchAction: (a: any) => any;
onSaveName: (
params: SaveActionNameParams,
) => ReduxAction<SaveActionNameParams>;
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
suffixErrorMessage?: (params?: any) => string;
Expand All @@ -90,10 +93,10 @@ interface NameEditorProps {

function NameEditor(props: NameEditorProps) {
const {
dispatchAction,
id: entityId,
idUndefinedErrorMessage,
name: entityName,
onSaveName,
saveStatus,
suffixErrorMessage = ACTION_NAME_CONFLICT_ERROR,
} = props;
Expand Down Expand Up @@ -131,8 +134,8 @@ function NameEditor(props: NameEditorProps) {

const handleNameChange = useCallback(
(name: string) => {
if (name !== entityName && !isInvalidNameForEntity(name)) {
dispatch(dispatchAction({ id: entityId, name }));
if (name !== entityName && !isInvalidNameForEntity(name) && entityId) {
dispatch(onSaveName({ id: entityId, name }));
}
},
[dispatch, isInvalidNameForEntity, entityId, entityName],
Expand Down
8 changes: 2 additions & 6 deletions app/client/src/pages/Editor/APIEditor/ApiEditorContext.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
import type { PaginationField } from "api/ActionAPI";
import React, { createContext, useMemo } from "react";

interface SaveActionNameParams {
id: string;
name: string;
}
import type { SaveActionNameParams } from "PluginActionEditor";

interface ApiEditorContextContextProps {
moreActionsMenu?: React.ReactNode;
Expand All @@ -15,7 +11,7 @@ interface ApiEditorContextContextProps {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
settingsConfig: any;
saveActionName?: (
saveActionName: (
params: SaveActionNameParams,
) => ReduxAction<SaveActionNameParams>;
closeEditorLink?: React.ReactNode;
Expand Down
21 changes: 9 additions & 12 deletions app/client/src/pages/Editor/APIEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import {
getPluginSettingConfigs,
getPlugins,
} from "ee/selectors/entitiesSelector";
import { deleteAction, runAction } from "actions/pluginActionActions";
import {
deleteAction,
runAction,
saveActionName,
} from "actions/pluginActionActions";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import Editor from "./Editor";
import BackToCanvas from "components/common/BackToCanvas";
Expand Down Expand Up @@ -151,15 +155,7 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) {
});
dispatch(runAction(action?.id ?? "", paginationField));
},
[
action?.id,
apiName,
pageName,
getPageName,
plugins,
pluginId,
datasourceId,
],
[action?.id, apiName, pageName, plugins, pluginId, datasourceId, dispatch],
);

const actionRightPaneBackLink = useMemo(() => {
Expand All @@ -173,13 +169,13 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) {
pageName,
});
dispatch(deleteAction({ id: action?.id ?? "", name: apiName }));
}, [getPageName, pages, basePageId, apiName]);
}, [pages, basePageId, apiName, action?.id, dispatch, pageName]);

const notification = useMemo(() => {
if (!isConverting) return null;

return <ConvertEntityNotification icon={icon} name={action?.name || ""} />;
}, [action?.name, isConverting]);
}, [action?.name, isConverting, icon]);

const isActionRedesignEnabled = useFeatureFlag(
FEATURE_FLAG.release_actions_redesign_enabled,
Expand All @@ -196,6 +192,7 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) {
handleRunClick={handleRunClick}
moreActionsMenu={moreActionsMenu}
notification={notification}
saveActionName={saveActionName}
settingsConfig={settingsConfig}
>
<Disabler isDisabled={isConverting}>
Expand Down
6 changes: 4 additions & 2 deletions app/client/src/pages/Editor/Explorer/Entity/Name.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
import { Tooltip } from "@appsmith/ads";
import { useSelector } from "react-redux";
import { getSavingStatusForActionName } from "selectors/actionSelectors";
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
import type { SaveActionNameParams } from "PluginActionEditor";

export const searchHighlightSpanClassName = "token";
export const searchTokenizationDelimiter = "!!";
Expand Down Expand Up @@ -84,7 +86,7 @@ export interface EntityNameProps {
name: string;
isEditing?: boolean;
onChange?: (name: string) => void;
updateEntityName: (name: string) => void;
updateEntityName: (name: string) => ReduxAction<SaveActionNameParams>;
entityId: string;
searchKeyword?: string;
className?: string;
Expand Down Expand Up @@ -164,10 +166,10 @@ export const EntityName = React.memo(

return (
<NameEditorComponent
dispatchAction={handleUpdateName}
id={props.entityId}
idUndefinedErrorMessage={ACTION_ID_NOT_FOUND_IN_URL}
name={updatedName}
onSaveName={handleUpdateName}
saveStatus={saveStatus}
suffixErrorMessage={ENTITY_EXPLORER_ACTION_NAME_CONFLICT_ERROR}
>
Expand Down
7 changes: 2 additions & 5 deletions app/client/src/pages/Editor/JSEditor/JSObjectNameEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,8 @@ import NameEditorComponent, {
} from "components/utils/NameEditorComponent";
import { getSavingStatusForJSObjectName } from "selectors/actionSelectors";
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
import type { SaveActionNameParams } from "PluginActionEditor";
Comment thread
ankitakinger marked this conversation as resolved.

export interface SaveActionNameParams {
id: string;
name: string;
}
export interface JSObjectNameEditorProps {
/*
This prop checks if page is API Pane or Query Pane or Curl Pane
Expand Down Expand Up @@ -64,10 +61,10 @@ export function JSObjectNameEditor(props: JSObjectNameEditorProps) {

return (
<NameEditorComponent
dispatchAction={props.saveJSObjectName}
id={currentJSObjectConfig?.id}
idUndefinedErrorMessage={JSOBJECT_ID_NOT_FOUND_IN_URL}
name={currentJSObjectConfig?.name}
onSaveName={props.saveJSObjectName}
saveStatus={saveStatus}
>
{({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
import type { SaveActionNameParams } from "PluginActionEditor";
import React, { createContext, useMemo } from "react";

interface SaveActionNameParams {
id: string;
name: string;
}

interface QueryEditorContextContextProps {
moreActionsMenu?: React.ReactNode;
onCreateDatasourceClick?: () => void;
onEntityNotFoundBackClick?: () => void;
changeQueryPage?: (baseQueryId: string) => void;
actionRightPaneBackLink?: React.ReactNode;
saveActionName?: (
saveActionName: (
params: SaveActionNameParams,
) => ReduxAction<SaveActionNameParams>;
closeEditorLink?: React.ReactNode;
Expand Down
17 changes: 7 additions & 10 deletions app/client/src/pages/Editor/QueryEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { ENTITY_ICON_SIZE, EntityIcon } from "../Explorer/ExplorerIcons";
import { getIDEViewMode } from "selectors/ideSelectors";
import { EditorViewMode } from "ee/entities/IDE/constants";
import { AppPluginActionEditor } from "../AppPluginActionEditor";
import { saveActionName } from "actions/pluginActionActions";

type QueryEditorProps = RouteComponentProps<QueryEditorRouteParams>;

Expand Down Expand Up @@ -126,6 +127,7 @@ function QueryEditor(props: QueryEditorProps) {
}, [
action?.id,
action?.name,
action?.pluginType,
isChangePermitted,
isDeletePermitted,
basePageId,
Expand All @@ -143,7 +145,7 @@ function QueryEditor(props: QueryEditorProps) {
changeQuery({ baseQueryId: baseQueryId, basePageId, applicationId }),
);
},
[basePageId, applicationId],
[basePageId, applicationId, dispatch],
);

const onCreateDatasourceClick = useCallback(() => {
Expand All @@ -159,13 +161,7 @@ function QueryEditor(props: QueryEditorProps) {
AnalyticsUtil.logEvent("NAVIGATE_TO_CREATE_NEW_DATASOURCE_PAGE", {
entryPoint,
});
}, [
basePageId,
history,
integrationEditorURL,
DatasourceCreateEntryPoints,
AnalyticsUtil,
]);
}, [basePageId]);

// custom function to return user to integrations page if action is not found
const onEntityNotFoundBackClick = useCallback(
Expand All @@ -176,7 +172,7 @@ function QueryEditor(props: QueryEditorProps) {
selectedTab: INTEGRATION_TABS.ACTIVE,
}),
),
[basePageId, history, integrationEditorURL],
[basePageId],
);

const notification = useMemo(() => {
Expand All @@ -189,7 +185,7 @@ function QueryEditor(props: QueryEditorProps) {
withPadding
/>
);
}, [action?.name, isConverting]);
}, [action?.name, isConverting, icon]);

const isActionRedesignEnabled = useFeatureFlag(
FEATURE_FLAG.release_actions_redesign_enabled,
Expand All @@ -207,6 +203,7 @@ function QueryEditor(props: QueryEditorProps) {
notification={notification}
onCreateDatasourceClick={onCreateDatasourceClick}
onEntityNotFoundBackClick={onEntityNotFoundBackClick}
saveActionName={saveActionName}
>
<Disabler isDisabled={isConverting}>
<Editor
Expand Down