Skip to content

Commit

Permalink
chore: Plugin Action Editor Context (appsmithorg#36187)
Browse files Browse the repository at this point in the history
## Description

- Introduce the PluginActionEditor module structure
- Add basic handling and states in the PluginActionContext
- Update AppIDE to use the new Editor when the feature flag is active.
This will later be updated and the component will be used from the route
level itself


Fixes appsmithorg#36152

## 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/10805408539>
> Commit: 1b8259b
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10805408539&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Datasource`
> Spec:
> <hr>Wed, 11 Sep 2024 05:53:02 UTC
<!-- end of auto-generated comment: Cypress test results  -->


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


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


- **New Features**
- Introduced a `PluginActionEditor` component for managing plugin
actions.
- Added `PluginActionContext` for improved state management of plugin
actions.
- Implemented feature flag checks to conditionally render the redesigned
action editor interface in both the `ApiEditorWrapper` and `QueryEditor`
components.

- **Documentation**
- Added centralized export files for easier access to new components and
context providers.

- **Bug Fixes**
- Enhanced error handling for missing plugin settings and configurations
in the `PluginActionEditor`.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
hetunandu authored and Shivam-z committed Sep 26, 2024
1 parent 2fd8421 commit f390513
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 0 deletions.
62 changes: 62 additions & 0 deletions app/client/src/PluginActionEditor/PluginActionContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, {
type ReactNode,
createContext,
useContext,
useMemo,
} from "react";
import type { Action } from "entities/Action";
import type { Plugin } from "api/PluginApi";
import type { Datasource } from "entities/Datasource";

interface PluginActionContextType {
action: Action;
editorConfig: unknown[];
settingsConfig: unknown[];
plugin: Plugin;
datasource?: Datasource;
}

// No need to export this context to use it. Use the hook defined below instead
const PluginActionContext = createContext<PluginActionContextType | null>(null);

interface ChildrenProps {
children: ReactNode[];
}

export const PluginActionContextProvider = (
props: ChildrenProps & PluginActionContextType,
) => {
const { action, children, datasource, editorConfig, plugin, settingsConfig } =
props;

// using useMemo to avoid unnecessary renders
const contextValue = useMemo(
() => ({
action,
datasource,
editorConfig,
plugin,
settingsConfig,
}),
[action, datasource, editorConfig, plugin, settingsConfig],
);

return (
<PluginActionContext.Provider value={contextValue}>
{children}
</PluginActionContext.Provider>
);
};

// By using this hook, you are guaranteed that the states are correctly
// typed and set.
// Without this, consumers of the context would need to keep doing a null check
export const usePluginActionContext = () => {
const context = useContext(PluginActionContext);
if (!context) {
throw new Error(
"usePluginActionContext must be used within usePluginActionContextProvider",
);
}
return context;
};
89 changes: 89 additions & 0 deletions app/client/src/PluginActionEditor/PluginActionEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React from "react";
import { useLocation } from "react-router";
import { identifyEntityFromPath } from "../navigation/FocusEntity";
import { useSelector } from "react-redux";
import {
getActionByBaseId,
getDatasource,
getEditorConfig,
getPlugin,
getPluginSettingConfigs,
} from "ee/selectors/entitiesSelector";
import { PluginActionContextProvider } from "./PluginActionContext";
import { get } from "lodash";
import EntityNotFoundPane from "pages/Editor/EntityNotFoundPane";
import { getIsEditorInitialized } from "selectors/editorSelectors";
import Spinner from "components/editorComponents/Spinner";
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
import { Text } from "@appsmith/ads";

interface ChildrenProps {
children: React.ReactNode[];
}

const PluginActionEditor = (props: ChildrenProps) => {
const { pathname } = useLocation();

const isEditorInitialized = useSelector(getIsEditorInitialized);

const entity = identifyEntityFromPath(pathname);
const action = useSelector((state) => getActionByBaseId(state, entity.id));

const pluginId = get(action, "pluginId", "");
const plugin = useSelector((state) => getPlugin(state, pluginId));

const datasourceId = get(action, "datasource.id", "");
const datasource = useSelector((state) => getDatasource(state, datasourceId));

const settingsConfig = useSelector((state) =>
getPluginSettingConfigs(state, pluginId),
);

const editorConfig = useSelector((state) => getEditorConfig(state, pluginId));

if (!isEditorInitialized) {
return (
<CenteredWrapper>
<Spinner size={30} />
</CenteredWrapper>
);
}

if (!action) {
return <EntityNotFoundPane />;
}

if (!plugin) {
return (
<CenteredWrapper>
<Text color="var(--ads-v2-color-fg-error)" kind="heading-m">
Plugin not installed!
</Text>
</CenteredWrapper>
);
}

if (!settingsConfig || !editorConfig) {
return (
<CenteredWrapper>
<Text color="var(--ads-v2-color-fg-error)" kind="heading-m">
Editor config not found!
</Text>
</CenteredWrapper>
);
}

return (
<PluginActionContextProvider
action={action}
datasource={datasource}
editorConfig={editorConfig}
plugin={plugin}
settingsConfig={settingsConfig}
>
{props.children}
</PluginActionContextProvider>
);
};

export default PluginActionEditor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from "react";

const PluginActionForm = () => {
return <div />;
};

export default PluginActionForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./PluginActionForm";
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from "react";

const PluginActionResponsePane = () => {
return <div />;
};

export default PluginActionResponsePane;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from "react";

const PluginActionToolbar = () => {
return <div />;
};

export default PluginActionToolbar;
8 changes: 8 additions & 0 deletions app/client/src/PluginActionEditor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export { default as PluginActionEditor } from "./PluginActionEditor";
export {
PluginActionContextProvider,
usePluginActionContext,
} from "./PluginActionContext";
export { default as PluginActionToolbar } from "./components/PluginActionToolbar";
export { default as PluginActionForm } from "./components/PluginActionForm";
export { default as PluginActionResponsePane } from "./components/PluginActionResponsePane";
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import {
PluginActionEditor,
PluginActionToolbar,
PluginActionForm,
PluginActionResponsePane,
} from "PluginActionEditor";

const AppPluginActionEditor = () => {
return (
<PluginActionEditor>
<PluginActionToolbar />
<PluginActionForm />
<PluginActionResponsePane />
</PluginActionEditor>
);
};

export default AppPluginActionEditor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { default as CE_AppPluginActionEditor } from "ce/pages/Editor/AppPluginActionEditor/AppPluginActionEditor";

export default CE_AppPluginActionEditor;
9 changes: 9 additions & 0 deletions app/client/src/pages/Editor/APIEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { resolveIcon } from "../utils";
import { ENTITY_ICON_SIZE, EntityIcon } from "../Explorer/ExplorerIcons";
import { getIDEViewMode } from "selectors/ideSelectors";
import { EditorViewMode } from "ee/entities/IDE/constants";
import { AppPluginActionEditor } from "pages/Editor/AppPluginActionEditor";

type ApiEditorWrapperProps = RouteComponentProps<APIEditorRouteParams>;

Expand Down Expand Up @@ -177,6 +178,14 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) {
return <ConvertEntityNotification icon={icon} name={action?.name || ""} />;
}, [action?.name, isConverting]);

const isActionRedesignEnabled = useFeatureFlag(
FEATURE_FLAG.release_actions_redesign_enabled,
);

if (isActionRedesignEnabled) {
return <AppPluginActionEditor />;
}

return (
<ApiEditorContextProvider
actionRightPaneBackLink={actionRightPaneBackLink}
Expand Down
1 change: 1 addition & 0 deletions app/client/src/pages/Editor/AppPluginActionEditor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as AppPluginActionEditor } from "ee/pages/Editor/AppPluginActionEditor/AppPluginActionEditor";
9 changes: 9 additions & 0 deletions app/client/src/pages/Editor/QueryEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { resolveIcon } from "../utils";
import { ENTITY_ICON_SIZE, EntityIcon } from "../Explorer/ExplorerIcons";
import { getIDEViewMode } from "selectors/ideSelectors";
import { EditorViewMode } from "ee/entities/IDE/constants";
import { AppPluginActionEditor } from "../AppPluginActionEditor";

type QueryEditorProps = RouteComponentProps<QueryEditorRouteParams>;

Expand Down Expand Up @@ -188,6 +189,14 @@ function QueryEditor(props: QueryEditorProps) {
);
}, [action?.name, isConverting]);

const isActionRedesignEnabled = useFeatureFlag(
FEATURE_FLAG.release_actions_redesign_enabled,
);

if (isActionRedesignEnabled) {
return <AppPluginActionEditor />;
}

return (
<QueryEditorContextProvider
actionRightPaneBackLink={actionRightPaneBackLink}
Expand Down

0 comments on commit f390513

Please sign in to comment.