chore: add workflows setting for agents CE (#40988)
/ok-to-test tags="@tag.Sanity"
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added a "Trigger Settings" sidebar button and editor pane for AI Agent
apps.
- Introduced a "Run History" tab in the debugger and a corresponding
trigger in the bottom bar for AI Agent apps.
- New SVG icon ("lightning-line") added for sidebar and UI elements.
- Support for importing agent templates and associating workflows with
applications.
- **Enhancements**
- Sidebar and bottom bar now adapt to AI Agent app context.
- Layout and header updated to accommodate the new "Trigger Settings"
editor state.
- **Bug Fixes**
- No bug fixes included in this release.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- This is an auto-generated comment: Cypress test results -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/15753160141>
> Commit: d0e477ce71479ac091957566c5bba05e0f215e60
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=15753160141&attempt=2"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Sanity`
> Spec:
> <hr>Thu, 19 Jun 2025 09:22:45 UTC
<!-- end of auto-generated comment: Cypress test results -->
This commit is contained in:
parent
bb1c055126
commit
f2b76c5577
|
|
@ -1213,6 +1213,10 @@ const AIChatIcon = importSvg(
|
|||
async () => import("../__assets__/icons/ads/ai-chat.svg"),
|
||||
);
|
||||
|
||||
const LightningLineIcon = importSvg(
|
||||
async () => import("../__assets__/icons/ads/lightning-line.svg"),
|
||||
);
|
||||
|
||||
import PlayIconPNG from "../__assets__/icons/control/play-icon.png";
|
||||
|
||||
function PlayIconPNGWrapper() {
|
||||
|
|
@ -1636,6 +1640,7 @@ const ICON_LOOKUP = {
|
|||
intercom: IntercomIcon,
|
||||
onedrive: OnedriveIcon,
|
||||
sharepoint: SharepointIcon,
|
||||
"lightning-line": LightningLineIcon,
|
||||
};
|
||||
|
||||
export const IconCollection = Object.keys(ICON_LOOKUP);
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||
readOnly={isReadOnly}
|
||||
ref={inputRef}
|
||||
renderer={renderAs}
|
||||
size="1"
|
||||
value={value}
|
||||
{...rest}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13 9H21L11 24V15H4L13 0V9ZM11 11V7.22L7.532 13H13V17.394L17.263 11H11Z" fill="#4C5664"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 201 B |
|
|
@ -6,6 +6,7 @@ const SidebarButtonTitles = {
|
|||
DATA: "Datasources",
|
||||
SETTINGS: "Settings",
|
||||
LIBRARIES: "Libraries",
|
||||
TRIGGER_SETTINGS: "Trigger Settings",
|
||||
};
|
||||
|
||||
export const EditorButton = (urlSuffix: string): IDESidebarButton => ({
|
||||
|
|
@ -39,3 +40,11 @@ export const SettingsButton = (urlSuffix: string): IDESidebarButton => ({
|
|||
testId: SidebarButtonTitles.SETTINGS,
|
||||
urlSuffix,
|
||||
});
|
||||
|
||||
export const TriggerSettingsButton = (urlSuffix: string): IDESidebarButton => ({
|
||||
state: EditorState.TRIGGER_SETTINGS,
|
||||
icon: "lightning-line",
|
||||
tooltip: SidebarButtonTitles.TRIGGER_SETTINGS,
|
||||
testId: SidebarButtonTitles.TRIGGER_SETTINGS,
|
||||
urlSuffix,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,4 +9,5 @@ export enum EditorState {
|
|||
EDITOR = "EDITOR",
|
||||
SETTINGS = "SETTINGS",
|
||||
LIBRARIES = "LIBRARIES",
|
||||
TRIGGER_SETTINGS = "TRIGGER_SETTINGS",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,18 @@ class TemplatesAPI extends Api {
|
|||
body,
|
||||
);
|
||||
}
|
||||
|
||||
// This endpoint imports the application from a template and creates a workflow,
|
||||
// and attaches the workflow to the application.
|
||||
static async importAgentTemplate(
|
||||
templateId: string,
|
||||
workspaceId: string,
|
||||
): Promise<AxiosPromise<ImportTemplateResponse>> {
|
||||
return Api.post(TemplatesAPI.baseUrl + `/applications/agents`, {
|
||||
templateId,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default TemplatesAPI;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ export interface ApplicationResponsePayload {
|
|||
slug: string;
|
||||
applicationVersion: ApplicationVersion;
|
||||
isPublic?: boolean;
|
||||
connectedWorkflowId?: string;
|
||||
}
|
||||
|
||||
export interface FetchApplicationPayload {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export interface Workflow {
|
|||
// PR for reference: https://github.com/appsmithorg/appsmith/pull/8796
|
||||
evaluationVersion: EvaluationVersion;
|
||||
token?: string;
|
||||
connectedApplicationId?: string;
|
||||
}
|
||||
|
||||
export type WorkflowMetadata = Workflow;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ export const DATA_SOURCES_EDITOR_ID_PATH = `/datasource/:datasourceId`;
|
|||
export const APP_LIBRARIES_EDITOR_PATH = `/libraries`;
|
||||
export const APP_PACKAGES_EDITOR_PATH = `/packages`;
|
||||
export const APP_SETTINGS_EDITOR_PATH = `/settings`;
|
||||
export const APP_TRIGGER_SETTINGS_EDITOR_PATH = `/trigger-settings`;
|
||||
export const SAAS_GSHEET_EDITOR_ID_PATH = `/saas/google-sheets-plugin/datasources/:datasourceId`;
|
||||
export const BUILDER_CHECKLIST_PATH = `/checklist`;
|
||||
export const ADMIN_SETTINGS_PATH = "/settings";
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
EditorButton,
|
||||
LibrariesButton,
|
||||
SettingsButton,
|
||||
TriggerSettingsButton,
|
||||
} from "IDE/constants/SidebarButtons";
|
||||
import { Condition, type IDESidebarButton } from "@appsmith/ads";
|
||||
import {
|
||||
|
|
@ -18,9 +19,20 @@ const DataButtonWithWarning: IDESidebarButton = {
|
|||
|
||||
const DataButtonWithoutWarning = DataButton("datasource");
|
||||
|
||||
export const BottomButtons = (datasourcesExist: boolean) => [
|
||||
datasourcesExist ? DataButtonWithoutWarning : DataButtonWithWarning,
|
||||
LibrariesButton("libraries"),
|
||||
SettingsButton("settings"),
|
||||
];
|
||||
export const BottomButtons = (
|
||||
datasourcesExist: boolean,
|
||||
isAgentApp: boolean,
|
||||
) => {
|
||||
const buttons = [
|
||||
datasourcesExist ? DataButtonWithoutWarning : DataButtonWithWarning,
|
||||
LibrariesButton("libraries"),
|
||||
SettingsButton("settings"),
|
||||
];
|
||||
|
||||
if (isAgentApp) {
|
||||
buttons.splice(1, 0, TriggerSettingsButton("trigger-settings"));
|
||||
}
|
||||
|
||||
return buttons;
|
||||
};
|
||||
export const TopButtons = [EditorButton("")];
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
APP_LIBRARIES_EDITOR_PATH,
|
||||
APP_PACKAGES_EDITOR_PATH,
|
||||
APP_SETTINGS_EDITOR_PATH,
|
||||
APP_TRIGGER_SETTINGS_EDITOR_PATH,
|
||||
BUILDER_CHECKLIST_PATH,
|
||||
BUILDER_CUSTOM_PATH,
|
||||
BUILDER_PATH,
|
||||
|
|
@ -71,6 +72,7 @@ export const MainPaneRoutes = (
|
|||
`${path}${APP_LIBRARIES_EDITOR_PATH}`,
|
||||
`${path}${APP_PACKAGES_EDITOR_PATH}`,
|
||||
`${path}${APP_SETTINGS_EDITOR_PATH}`,
|
||||
`${path}${APP_TRIGGER_SETTINGS_EDITOR_PATH}`,
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import OldGitQuickActions from "pages/Editor/gitSync/QuickGitActions";
|
|||
import { GitQuickActions } from "git";
|
||||
import { useGitModEnabled } from "pages/Editor/gitSync/hooks/modHooks";
|
||||
import { AIAgentSupportTrigger } from "ee/components/BottomBar/AIAgentSupportTrigger";
|
||||
import { RunHistoryTrigger } from "ee/pages/WorkflowIDE/layouts/components/BottomBar/WorkflowRunHistory/RunHistoryTrigger";
|
||||
import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors";
|
||||
|
||||
function GitActions() {
|
||||
const isGitModEnabled = useGitModEnabled();
|
||||
|
|
@ -34,6 +36,7 @@ export default function BottomBar() {
|
|||
const isAnvilEnabled = useSelector(getIsAnvilEnabledInCurrentApplication);
|
||||
const isPreviewMode = useSelector(previewModeSelector);
|
||||
const isGitEnabled = !isAnvilEnabled && !isPreviewMode;
|
||||
const isAiAgentApp = useSelector(getIsAiAgentApp);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
|
@ -67,6 +70,7 @@ export default function BottomBar() {
|
|||
/>
|
||||
</ManualUpgrades>
|
||||
<AIAgentSupportTrigger />
|
||||
{isAiAgentApp && <RunHistoryTrigger />}
|
||||
<DebuggerTrigger />
|
||||
<HelpButton />
|
||||
</Wrapper>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ import { StateInspector } from "./StateInspector";
|
|||
import { getIDETypeByUrl } from "ee/entities/IDE/utils";
|
||||
import { useLocation } from "react-router";
|
||||
import { IDE_TYPE } from "ee/IDE/Interfaces/IDETypes";
|
||||
import { RunHistoryTab } from "ee/pages/WorkflowIDE/layouts/components/BottomBar/WorkflowRunHistory/RunHistoryTab";
|
||||
import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors";
|
||||
|
||||
function DebuggerTabs() {
|
||||
const dispatch = useDispatch();
|
||||
|
|
@ -42,6 +44,7 @@ function DebuggerTabs() {
|
|||
},
|
||||
[dispatch],
|
||||
);
|
||||
const isAiAgentApp = useSelector(getIsAiAgentApp);
|
||||
|
||||
const setSelectedTab = useCallback(
|
||||
(tabKey: string) => {
|
||||
|
|
@ -87,8 +90,16 @@ function DebuggerTabs() {
|
|||
});
|
||||
}
|
||||
|
||||
if (isAiAgentApp) {
|
||||
tabs.push({
|
||||
key: DEBUGGER_TAB_KEYS.RUN_HISTORY_TAB,
|
||||
title: "Run History",
|
||||
panelComponent: <RunHistoryTab />,
|
||||
});
|
||||
}
|
||||
|
||||
return tabs;
|
||||
}, [errorCount, ideType]);
|
||||
}, [errorCount, ideType, isAiAgentApp]);
|
||||
|
||||
// Do not render if response, header or schema tab is selected in the bottom bar.
|
||||
const shouldRender = !(
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ export enum DEBUGGER_TAB_KEYS {
|
|||
LOGS_TAB = "LOGS_TAB",
|
||||
STATE_TAB = "STATE_TAB",
|
||||
VISUALIZATION_TAB = "VISUALIZATION_TAB",
|
||||
RUN_HISTORY_TAB = "RUN_HISTORY_TAB",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
export const TriggerSettingsPane = () => {
|
||||
return null;
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { TriggerSettingsPane } from "./TriggerSettingsPane";
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export const RunHistoryTab = () => {
|
||||
return null;
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export const RunHistoryTrigger = () => {
|
||||
return null;
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { RunHistoryTab } from "./RunHistoryTab";
|
||||
|
|
@ -0,0 +1 @@
|
|||
export * from "./WorkflowRunHistory";
|
||||
|
|
@ -45,4 +45,5 @@ export interface ApplicationPayload {
|
|||
isCommunityTemplate?: boolean;
|
||||
publishedAppToCommunityTemplate?: boolean;
|
||||
forkedFromTemplateTitle?: string;
|
||||
connectedWorkflowId?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export enum FocusEntity {
|
|||
JS_MODULE_INSTANCE = "JS_MODULE_INSTANCE",
|
||||
JS_OBJECT_ADD = "JS_OBJECT_ADD",
|
||||
PAGE = "PAGE",
|
||||
TRIGGER_SETTINGS = "TRIGGER_SETTINGS",
|
||||
}
|
||||
|
||||
export const FocusStoreHierarchy: Partial<Record<FocusEntity, FocusEntity>> = {
|
||||
|
|
@ -300,6 +301,15 @@ export function identifyEntityFromPath(path: string): FocusEntityInfo {
|
|||
params: match.params,
|
||||
};
|
||||
}
|
||||
|
||||
if (match.params.entity === "trigger-settings") {
|
||||
return {
|
||||
entity: FocusEntity.TRIGGER_SETTINGS,
|
||||
id: "",
|
||||
appState: EditorState.TRIGGER_SETTINGS,
|
||||
params: match.params,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ const HeaderTitleComponent = ({ appState }: HeaderTitleProps) => {
|
|||
);
|
||||
case EditorState.LIBRARIES:
|
||||
return <IDEHeaderTitle key={appState} title={libraryHeaderTitle} />;
|
||||
case EditorState.TRIGGER_SETTINGS:
|
||||
return <IDEHeaderTitle key={appState} title="Trigger Settings" />;
|
||||
default:
|
||||
return <EditorTitle key={appState} />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ function useGridLayoutTemplate(): ReturnValue {
|
|||
|
||||
break;
|
||||
case EditorState.SETTINGS:
|
||||
case EditorState.TRIGGER_SETTINGS:
|
||||
if (isPreviewMode || isProtectedMode) {
|
||||
setColumns(["0px", "0px", `${windowWidth}px`, "0px"]);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
APP_LIBRARIES_EDITOR_PATH,
|
||||
APP_PACKAGES_EDITOR_PATH,
|
||||
APP_SETTINGS_EDITOR_PATH,
|
||||
APP_TRIGGER_SETTINGS_EDITOR_PATH,
|
||||
DATA_SOURCES_EDITOR_ID_PATH,
|
||||
DATA_SOURCES_EDITOR_LIST_PATH,
|
||||
INTEGRATION_EDITOR_PATH,
|
||||
|
|
@ -13,6 +14,7 @@ import {
|
|||
import AppSettingsPane from "../../components/AppSettings";
|
||||
import { DataSidePane } from "pages/Editor/DataSidePane";
|
||||
import EditorPane from "../components/EditorPane";
|
||||
import { TriggerSettingsPane } from "ee/pages/AppIDE/components/TriggerSettingsPane";
|
||||
import LibrarySidePane from "ee/pages/AppIDE/components/LibrariesList/LibrarySidePane";
|
||||
import { getDatasourceUsageCountForApp } from "ee/selectors/entitiesSelector";
|
||||
import { IDE_TYPE } from "ee/IDE/Interfaces/IDETypes";
|
||||
|
|
@ -65,6 +67,11 @@ const LeftPane = () => {
|
|||
exact
|
||||
path={librarySidePanePaths}
|
||||
/>
|
||||
<SentryRoute
|
||||
component={TriggerSettingsPane}
|
||||
exact
|
||||
path={`${path}${APP_TRIGGER_SETTINGS_EDITOR_PATH}`}
|
||||
/>
|
||||
<SentryRoute
|
||||
component={AppSettingsPane}
|
||||
exact
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
BottomButtons,
|
||||
TopButtons,
|
||||
} from "ee/pages/AppIDE/constants/SidebarButtons";
|
||||
import { getIsAiAgentApp } from "ee/selectors/aiAgentSelectors";
|
||||
|
||||
function Sidebar() {
|
||||
const dispatch = useDispatch();
|
||||
|
|
@ -20,11 +21,12 @@ function Sidebar() {
|
|||
const currentWorkspaceId = useSelector(getCurrentWorkspaceId);
|
||||
const datasources = useSelector(getDatasources);
|
||||
const datasourcesExist = datasources.length > 0;
|
||||
const isAgentApp = useSelector(getIsAiAgentApp);
|
||||
|
||||
// Updates the bottom button config based on datasource existence
|
||||
const bottomButtons = React.useMemo(() => {
|
||||
return BottomButtons(datasourcesExist);
|
||||
}, [datasourcesExist]);
|
||||
return BottomButtons(datasourcesExist, isAgentApp);
|
||||
}, [datasourcesExist, isAgentApp]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchWorkspace(currentWorkspaceId));
|
||||
|
|
|
|||
|
|
@ -89,7 +89,9 @@ function* importTemplateToWorkspaceSaga(
|
|||
|
||||
try {
|
||||
const response: ImportTemplateResponse = yield call(
|
||||
TemplatesAPI.importTemplate,
|
||||
isAgentTemplate
|
||||
? TemplatesAPI.importAgentTemplate
|
||||
: TemplatesAPI.importTemplate,
|
||||
action.payload.templateId,
|
||||
action.payload.workspaceId,
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user