feat: add generate schema button (#39751)
## Description Update JS and Plugin Action Toolbar to add new Schema generation CTA in them https://www.figma.com/design/mVEbXXryqv2oBxMcNg8yjC/Anvil-AI?node-id=3891-34025&t=AVP3gbWu07WzPfwc-0 Fixes #39726 ## Automation /ok-to-test tags="@tag.JS, @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/13920663021> > Commit: c0b76039714bf64155c0d41c6f72cda881bcd968 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=13920663021&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.JS, @tag.Datasource` > Spec: > <hr>Tue, 18 Mar 2025 11:30:10 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 real-time tracking of schema generation processes with clear UI indicators and error messaging. - Expanded actionable events to support improved feedback during schema creation for plugin actions and JavaScript functions. - **Refactor** - Streamlined component exports and updated import paths for enhanced organization and consistency in the editor toolbars. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Hetu Nandu <hetunandu@gmail.com>
This commit is contained in:
parent
2b703c9746
commit
d494ca4ee1
|
|
@ -3,7 +3,7 @@ export {
|
||||||
PluginActionContextProvider,
|
PluginActionContextProvider,
|
||||||
usePluginActionContext,
|
usePluginActionContext,
|
||||||
} from "./PluginActionContext";
|
} from "./PluginActionContext";
|
||||||
export { default as PluginActionToolbar } from "./components/PluginActionToolbar";
|
export { PluginActionToolbar } from "ee/PluginActionEditor/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 {
|
export type {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,16 @@ export const isActionDirty = (id: string) =>
|
||||||
const getActionRunningState = (state: AppState) =>
|
const getActionRunningState = (state: AppState) =>
|
||||||
state.ui.pluginActionEditor.isRunning;
|
state.ui.pluginActionEditor.isRunning;
|
||||||
|
|
||||||
|
const getActionSchemaGeneratingState = (state: AppState) =>
|
||||||
|
state.ui.pluginActionEditor.isSchemaGenerating;
|
||||||
|
|
||||||
|
export const isActionSchemaGenerating = (id: string) =>
|
||||||
|
createSelector(
|
||||||
|
[getActionSchemaGeneratingState],
|
||||||
|
(isSchemaGeneratingMap) =>
|
||||||
|
id in isSchemaGeneratingMap && isSchemaGeneratingMap[id],
|
||||||
|
);
|
||||||
|
|
||||||
export const isActionRunning = (id: string) =>
|
export const isActionRunning = (id: string) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
[getActionRunningState],
|
[getActionRunningState],
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ export interface PluginActionEditorState {
|
||||||
isCreating: boolean;
|
isCreating: boolean;
|
||||||
isRunning: Record<string, boolean>;
|
isRunning: Record<string, boolean>;
|
||||||
isSaving: Record<string, boolean>;
|
isSaving: Record<string, boolean>;
|
||||||
|
isSchemaGenerating: Record<string, boolean>;
|
||||||
isDeleting: Record<string, boolean>;
|
isDeleting: Record<string, boolean>;
|
||||||
isDirty: Record<string, boolean>;
|
isDirty: Record<string, boolean>;
|
||||||
runErrorMessage: Record<string, string>;
|
runErrorMessage: Record<string, string>;
|
||||||
|
|
@ -34,6 +35,7 @@ const initialState: PluginActionEditorState = {
|
||||||
isCreating: false,
|
isCreating: false,
|
||||||
isRunning: {},
|
isRunning: {},
|
||||||
isSaving: {},
|
isSaving: {},
|
||||||
|
isSchemaGenerating: {},
|
||||||
isDeleting: {},
|
isDeleting: {},
|
||||||
isDirty: {},
|
isDirty: {},
|
||||||
runErrorMessage: {},
|
runErrorMessage: {},
|
||||||
|
|
@ -141,6 +143,26 @@ export const handlers = {
|
||||||
set(state, ["isRunning", id], false);
|
set(state, ["isRunning", id], false);
|
||||||
set(state, ["runErrorMessage", id], error.message);
|
set(state, ["runErrorMessage", id], error.message);
|
||||||
},
|
},
|
||||||
|
[ReduxActionTypes.GENERATE_PLUGIN_ACTION_SCHEMA_REQUEST]: (
|
||||||
|
state: PluginActionEditorState,
|
||||||
|
action: ReduxAction<{
|
||||||
|
id: string;
|
||||||
|
}>,
|
||||||
|
) => {
|
||||||
|
set(state, ["isSchemaGenerating", action.payload.id], true);
|
||||||
|
},
|
||||||
|
[ReduxActionTypes.GENERATE_PLUGIN_ACTION_SCHEMA_SUCCESS]: (
|
||||||
|
state: PluginActionEditorState,
|
||||||
|
action: ReduxAction<{ id: string }>,
|
||||||
|
) => {
|
||||||
|
set(state, ["isSchemaGenerating", action.payload.id], false);
|
||||||
|
},
|
||||||
|
[ReduxActionErrorTypes.GENERATE_PLUGIN_ACTION_SCHEMA_ERROR]: (
|
||||||
|
state: PluginActionEditorState,
|
||||||
|
action: ReduxAction<{ id: string }>,
|
||||||
|
) => {
|
||||||
|
set(state, ["isSchemaGenerating", action.payload.id], false);
|
||||||
|
},
|
||||||
[ReduxActionTypes.SET_PLUGIN_ACTION_EDITOR_FORM_SELECTED_TAB]: (
|
[ReduxActionTypes.SET_PLUGIN_ACTION_EDITOR_FORM_SELECTED_TAB]: (
|
||||||
state: PluginActionEditorState,
|
state: PluginActionEditorState,
|
||||||
action: ReduxAction<{ selectedTab: string }>,
|
action: ReduxAction<{ selectedTab: string }>,
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@ import React, { useCallback } from "react";
|
||||||
import { IDEToolbar } from "IDE";
|
import { IDEToolbar } from "IDE";
|
||||||
import { Button, Tooltip } from "@appsmith/ads";
|
import { Button, Tooltip } from "@appsmith/ads";
|
||||||
import { modText } from "utils/helpers";
|
import { modText } from "utils/helpers";
|
||||||
import { usePluginActionContext } from "../PluginActionContext";
|
import { usePluginActionContext } from "PluginActionEditor/PluginActionContext";
|
||||||
import {
|
import {
|
||||||
useBlockExecution,
|
useBlockExecution,
|
||||||
useHandleRunClick,
|
useHandleRunClick,
|
||||||
useAnalyticsOnRunClick,
|
useAnalyticsOnRunClick,
|
||||||
} from "../hooks";
|
} from "PluginActionEditor/hooks";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { isActionRunning } from "../store";
|
import { isActionRunning } from "PluginActionEditor/store";
|
||||||
import PluginActionSettings from "./PluginActionSettings";
|
import PluginActionSettings from "PluginActionEditor/components/PluginActionSettings";
|
||||||
import { PluginActionContextMenu } from "./PluginActionContextMenu";
|
import { PluginActionContextMenu } from "PluginActionEditor/components/PluginActionContextMenu";
|
||||||
|
|
||||||
interface PluginActionToolbarProps {
|
interface PluginActionToolbarProps {
|
||||||
runOptions?: React.ReactNode;
|
runOptions?: React.ReactNode;
|
||||||
|
|
@ -19,7 +19,7 @@ interface PluginActionToolbarProps {
|
||||||
menuContent?: React.ReactNode[] | React.ReactNode;
|
menuContent?: React.ReactNode[] | React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PluginActionToolbar = (props: PluginActionToolbarProps) => {
|
export const PluginActionToolbar = (props: PluginActionToolbarProps) => {
|
||||||
const { action } = usePluginActionContext();
|
const { action } = usePluginActionContext();
|
||||||
const { handleRunClick } = useHandleRunClick();
|
const { handleRunClick } = useHandleRunClick();
|
||||||
const { callRunActionAnalytics } = useAnalyticsOnRunClick();
|
const { callRunActionAnalytics } = useAnalyticsOnRunClick();
|
||||||
|
|
@ -63,5 +63,3 @@ const PluginActionToolbar = (props: PluginActionToolbarProps) => {
|
||||||
</IDEToolbar>
|
</IDEToolbar>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PluginActionToolbar;
|
|
||||||
|
|
@ -710,6 +710,16 @@ const ActionExecutionTypes = {
|
||||||
RUN_ACTION_REQUEST: "RUN_ACTION_REQUEST",
|
RUN_ACTION_REQUEST: "RUN_ACTION_REQUEST",
|
||||||
RUN_ACTION_CANCELLED: "RUN_ACTION_CANCELLED",
|
RUN_ACTION_CANCELLED: "RUN_ACTION_CANCELLED",
|
||||||
RUN_ACTION_SUCCESS: "RUN_ACTION_SUCCESS",
|
RUN_ACTION_SUCCESS: "RUN_ACTION_SUCCESS",
|
||||||
|
GENERATE_JS_FUNCTION_SCHEMA_REQUEST: "GENERATE_JS_FUNCTION_SCHEMA_REQUEST",
|
||||||
|
GENERATE_JS_FUNCTION_SCHEMA_CANCELLED:
|
||||||
|
"GENERATE_JS_FUNCTION_SCHEMA_CANCELLED",
|
||||||
|
GENERATE_JS_FUNCTION_SCHEMA_SUCCESS: "GENERATE_JS_FUNCTION_SCHEMA_SUCCESS",
|
||||||
|
GENERATE_PLUGIN_ACTION_SCHEMA_REQUEST:
|
||||||
|
"GENERATE_PLUGIN_ACTION_SCHEMA_REQUEST",
|
||||||
|
GENERATE_PLUGIN_ACTION_SCHEMA_CANCELLED:
|
||||||
|
"GENERATE_PLUGIN_ACTION_SCHEMA_CANCELLED",
|
||||||
|
GENERATE_PLUGIN_ACTION_SCHEMA_SUCCESS:
|
||||||
|
"GENERATE_PLUGIN_ACTION_SCHEMA_SUCCESS",
|
||||||
CLEAR_ACTION_RESPONSE: "CLEAR_ACTION_RESPONSE",
|
CLEAR_ACTION_RESPONSE: "CLEAR_ACTION_RESPONSE",
|
||||||
SHOW_ACTION_MODAL: "SHOW_ACTION_MODAL",
|
SHOW_ACTION_MODAL: "SHOW_ACTION_MODAL",
|
||||||
CANCEL_ACTION_MODAL: "CANCEL_ACTION_MODAL",
|
CANCEL_ACTION_MODAL: "CANCEL_ACTION_MODAL",
|
||||||
|
|
@ -722,6 +732,8 @@ const ActionExecutionTypes = {
|
||||||
|
|
||||||
const ActionExecutionErrorTypes = {
|
const ActionExecutionErrorTypes = {
|
||||||
RUN_ACTION_ERROR: "RUN_ACTION_ERROR",
|
RUN_ACTION_ERROR: "RUN_ACTION_ERROR",
|
||||||
|
GENERATE_JS_FUNCTION_SCHEMA_ERROR: "GENERATE_JS_FUNCTION_SCHEMA_ERROR",
|
||||||
|
GENERATE_PLUGIN_ACTION_SCHEMA_ERROR: "GENERATE_PLUGIN_ACTION_SCHEMA_ERROR",
|
||||||
EXECUTE_PLUGIN_ACTION_ERROR: "EXECUTE_PLUGIN_ACTION_ERROR",
|
EXECUTE_PLUGIN_ACTION_ERROR: "EXECUTE_PLUGIN_ACTION_ERROR",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -647,6 +647,7 @@ export const EXPORT_DEFAULT_BEGINNING = () =>
|
||||||
`Start object with export default`;
|
`Start object with export default`;
|
||||||
export const ACTION_EXECUTION_FAILED = (actionName: string) =>
|
export const ACTION_EXECUTION_FAILED = (actionName: string) =>
|
||||||
`The action "${actionName}" has failed.`;
|
`The action "${actionName}" has failed.`;
|
||||||
|
export const CANNOT_GENERATE_SCHEMA = () => "Can't generate schema";
|
||||||
export const JS_EXECUTION_TRIGGERED = () => "Function triggered";
|
export const JS_EXECUTION_TRIGGERED = () => "Function triggered";
|
||||||
export const JS_EXECUTION_SUCCESS = () => "Function executed";
|
export const JS_EXECUTION_SUCCESS = () => "Function executed";
|
||||||
export const JS_EXECUTION_FAILURE = () => "Function execution failed";
|
export const JS_EXECUTION_FAILURE = () => "Function execution failed";
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { IDEToolbar, ToolbarSettingsPopover } from "IDE";
|
import { IDEToolbar, ToolbarSettingsPopover } from "IDE";
|
||||||
import { JSFunctionRun } from "./components/JSFunctionRun";
|
import { JSFunctionRun } from "pages/Editor/JSEditor/JSEditorToolbar/components/JSFunctionRun";
|
||||||
import type { JSActionDropdownOption, OnUpdateSettingsProps } from "./types";
|
import type {
|
||||||
|
JSActionDropdownOption,
|
||||||
|
OnUpdateSettingsProps,
|
||||||
|
} from "pages/Editor/JSEditor/JSEditorToolbar/types";
|
||||||
import type { SaveActionNameParams } from "PluginActionEditor";
|
import type { SaveActionNameParams } from "PluginActionEditor";
|
||||||
import type { ReduxAction } from "actions/ReduxActionTypes";
|
import type { ReduxAction } from "actions/ReduxActionTypes";
|
||||||
import type { JSAction, JSCollection } from "entities/JSCollection";
|
import type { JSAction, JSCollection } from "entities/JSCollection";
|
||||||
import type { DropdownOnSelect } from "@appsmith/ads-old";
|
import type { DropdownOnSelect } from "@appsmith/ads-old";
|
||||||
import { createMessage, JS_EDITOR_SETTINGS } from "ee/constants/messages";
|
import { createMessage, JS_EDITOR_SETTINGS } from "ee/constants/messages";
|
||||||
import { JSFunctionSettings } from "./components/JSFunctionSettings";
|
import { JSFunctionSettings } from "pages/Editor/JSEditor/JSEditorToolbar/components/JSFunctionSettings";
|
||||||
import { convertJSActionsToDropdownOptions } from "./utils";
|
import { convertJSActionsToDropdownOptions } from "pages/Editor/JSEditor/JSEditorToolbar/utils";
|
||||||
import { JSObjectNameEditor } from "./JSObjectNameEditor";
|
import { JSObjectNameEditor } from "pages/Editor/JSEditor/JSEditorToolbar/JSObjectNameEditor";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
changePermitted: boolean;
|
changePermitted: boolean;
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "ce/PluginActionEditor/components/PluginActionToolbar";
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "ce/pages/Editor/JSEditor/JSEditorToolbar/JSEditorToolbar";
|
||||||
|
|
@ -8,6 +8,7 @@ export const RUN_BUTTON_DEFAULTS = {
|
||||||
export const testLocators = {
|
export const testLocators = {
|
||||||
runJSAction: "run-js-action",
|
runJSAction: "run-js-action",
|
||||||
runJSActionTestID: "t--run-js-action",
|
runJSActionTestID: "t--run-js-action",
|
||||||
|
generateSchemaJSActionTestID: "t--generate-schema-js-action",
|
||||||
};
|
};
|
||||||
export const NO_FUNCTION_DROPDOWN_OPTION = {
|
export const NO_FUNCTION_DROPDOWN_OPTION = {
|
||||||
label: "No function available",
|
label: "No function available",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export { JSEditorToolbar } from "./JSEditorToolbar";
|
export { JSEditorToolbar } from "ee/pages/Editor/JSEditor/JSEditorToolbar/JSEditorToolbar";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
type OnUpdateSettingsProps,
|
type OnUpdateSettingsProps,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import {
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
ReduxActionErrorTypes,
|
ReduxActionErrorTypes,
|
||||||
} from "ee/constants/ReduxActionConstants";
|
} from "ee/constants/ReduxActionConstants";
|
||||||
import type { JSCollection } from "entities/JSCollection";
|
import type { JSAction, JSCollection } from "entities/JSCollection";
|
||||||
import { ActionExecutionResizerHeight } from "PluginActionEditor/components/PluginActionResponse/constants";
|
import { ActionExecutionResizerHeight } from "PluginActionEditor/components/PluginActionResponse/constants";
|
||||||
|
|
||||||
export enum JSEditorTab {
|
export enum JSEditorTab {
|
||||||
|
|
@ -23,6 +23,7 @@ export interface JsPaneReduxState {
|
||||||
isSaving: Record<string, boolean>;
|
isSaving: Record<string, boolean>;
|
||||||
isDeleting: Record<string, boolean>;
|
isDeleting: Record<string, boolean>;
|
||||||
isDirty: Record<string, boolean>;
|
isDirty: Record<string, boolean>;
|
||||||
|
isSchemaGenerating: Record<string, boolean>;
|
||||||
selectedConfigTab: JSEditorTab;
|
selectedConfigTab: JSEditorTab;
|
||||||
debugger: JSPaneDebuggerState;
|
debugger: JSPaneDebuggerState;
|
||||||
}
|
}
|
||||||
|
|
@ -32,6 +33,7 @@ const initialState: JsPaneReduxState = {
|
||||||
isSaving: {},
|
isSaving: {},
|
||||||
isDeleting: {},
|
isDeleting: {},
|
||||||
isDirty: {},
|
isDirty: {},
|
||||||
|
isSchemaGenerating: {},
|
||||||
selectedConfigTab: JSEditorTab.CODE,
|
selectedConfigTab: JSEditorTab.CODE,
|
||||||
debugger: {
|
debugger: {
|
||||||
open: false,
|
open: false,
|
||||||
|
|
@ -175,6 +177,50 @@ const jsPaneReducer = createReducer(initialState, {
|
||||||
isSaving: false,
|
isSaving: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
[ReduxActionTypes.GENERATE_JS_FUNCTION_SCHEMA_REQUEST]: (
|
||||||
|
state: JsPaneReduxState,
|
||||||
|
action: ReduxAction<{
|
||||||
|
action: JSAction;
|
||||||
|
}>,
|
||||||
|
) => {
|
||||||
|
if (!action.payload.action.collectionId) return state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isSchemaGenerating: {
|
||||||
|
...state.isSchemaGenerating,
|
||||||
|
[action.payload.action.collectionId]: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ReduxActionTypes.GENERATE_JS_FUNCTION_SCHEMA_SUCCESS]: (
|
||||||
|
state: JsPaneReduxState,
|
||||||
|
action: ReduxAction<{ action: JSAction }>,
|
||||||
|
) => {
|
||||||
|
if (!action.payload.action.collectionId) return state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isSchemaGenerating: {
|
||||||
|
...state.isSchemaGenerating,
|
||||||
|
[action.payload.action.collectionId]: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ReduxActionErrorTypes.GENERATE_JS_FUNCTION_SCHEMA_ERROR]: (
|
||||||
|
state: JsPaneReduxState,
|
||||||
|
action: ReduxAction<{ action: JSAction }>,
|
||||||
|
) => {
|
||||||
|
if (!action.payload.action.collectionId) return state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isSchemaGenerating: {
|
||||||
|
...state.isSchemaGenerating,
|
||||||
|
[action.payload.action.collectionId]: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default jsPaneReducer;
|
export default jsPaneReducer;
|
||||||
|
|
|
||||||
|
|
@ -22,3 +22,11 @@ export const getLastJSTab = (state: AppState): FocusEntityInfo | undefined => {
|
||||||
return identifyEntityFromPath(urlWithoutQueryParams);
|
return identifyEntityFromPath(urlWithoutQueryParams);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getIsGeneratingSchema = (state: AppState, collectionId: string) =>
|
||||||
|
state.ui.jsPane.isSchemaGenerating[collectionId];
|
||||||
|
|
||||||
|
export const getIsJSCollectionSaving = (
|
||||||
|
state: AppState,
|
||||||
|
collectionId: string,
|
||||||
|
) => state.ui.jsPane.isSaving[collectionId];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user