feat(editor): Pre built agents experiment v2 (no-changelog) (#18842)

This commit is contained in:
Jaakko Husso
2025-08-28 09:40:52 +03:00
committed by GitHub
parent 07915c6b25
commit 883e887666
23 changed files with 3991 additions and 70 deletions

View File

@@ -37,6 +37,7 @@ import { TemplateClickSource, trackTemplatesClick } from '@/utils/experiments';
import { I18nT } from 'vue-i18n';
import { usePersonalizedTemplatesV2Store } from '@/experiments/templateRecoV2/stores/templateRecoV2.store';
import { useKeybindings } from '@/composables/useKeybindings';
import { useCalloutHelpers } from '@/composables/useCalloutHelpers';
const becomeTemplateCreatorStore = useBecomeTemplateCreatorStore();
const cloudPlanStore = useCloudPlanStore();
@@ -58,6 +59,7 @@ const router = useRouter();
const telemetry = useTelemetry();
const pageRedirectionHelper = usePageRedirectionHelper();
const { getReportingURL } = useBugReporting();
const calloutHelpers = useCalloutHelpers();
useKeybindings({
ctrl_alt_o: () => handleSelect('about'),
@@ -97,13 +99,28 @@ const mainMenuItems = computed<IMenuItem[]>(() => [
icon: 'cloud',
available: settingsStore.isCloudDeployment && hasPermission(['instanceOwner']),
},
{
// Link to in-app pre-built agent templates, available experiment is enabled
id: 'templates',
icon: 'package-open',
label: i18n.baseText('mainSidebar.templates'),
position: 'bottom',
available:
settingsStore.isTemplatesEnabled &&
calloutHelpers.isPreBuiltAgentsCalloutVisible.value &&
!personalizedTemplatesV2Store.isFeatureEnabled(),
route: { to: { name: VIEWS.PRE_BUILT_AGENT_TEMPLATES } },
},
{
// Link to templateRecoV2 modal, available when experiment is enabled
id: 'templates',
icon: 'package-open',
label: i18n.baseText('mainSidebar.templates'),
position: 'bottom',
available: settingsStore.isTemplatesEnabled && personalizedTemplatesV2Store.isFeatureEnabled(),
available:
settingsStore.isTemplatesEnabled &&
!calloutHelpers.isPreBuiltAgentsCalloutVisible.value &&
personalizedTemplatesV2Store.isFeatureEnabled(),
},
{
// Link to in-app templates, available if custom templates are enabled and experiment is disabled
@@ -113,6 +130,7 @@ const mainMenuItems = computed<IMenuItem[]>(() => [
position: 'bottom',
available:
settingsStore.isTemplatesEnabled &&
!calloutHelpers.isPreBuiltAgentsCalloutVisible.value &&
templatesStore.hasCustomTemplatesHost &&
!personalizedTemplatesV2Store.isFeatureEnabled(),
route: { to: { name: VIEWS.TEMPLATES } },
@@ -125,6 +143,7 @@ const mainMenuItems = computed<IMenuItem[]>(() => [
position: 'bottom',
available:
settingsStore.isTemplatesEnabled &&
!calloutHelpers.isPreBuiltAgentsCalloutVisible.value &&
!templatesStore.hasCustomTemplatesHost &&
!personalizedTemplatesV2Store.isFeatureEnabled(),
link: {

View File

@@ -34,6 +34,7 @@ import {
TAGS_MANAGER_MODAL_KEY,
VERSIONS_MODAL_KEY,
WHATS_NEW_MODAL_KEY,
PRE_BUILT_AGENTS_MODAL_KEY,
WORKFLOW_ACTIVATION_CONFLICTING_WEBHOOK_MODAL_KEY,
WORKFLOW_ACTIVE_MODAL_KEY,
WORKFLOW_DIFF_MODAL_KEY,
@@ -350,6 +351,12 @@ import NodeRecommendationModal from '@/experiments/templateRecoV2/components/Nod
</template>
</ModalRoot>
<ModalRoot :name="PRE_BUILT_AGENTS_MODAL_KEY">
<template #default="{ modalName, data }">
<PreBuiltAgentsModal :modal-name="modalName" :data="data" />
</template>
</ModalRoot>
<!-- Dynamic modals from modules -->
<DynamicModalLoader />
</div>

View File

@@ -424,7 +424,12 @@ export function getActiveViewCallouts(
results.push(getPreBuiltAgentsCalloutWithDivider());
} else if ([AI_CATEGORY_MEMORY, AI_CATEGORY_TOOLS].includes(title)) {
results.push(getPreBuiltAgentsCallout());
} else if (title === 'Google Calendar' || title === 'Telegram') {
} else if (title === 'Google Calendar') {
const templateLink = getTemplateLink(PrebuiltAgentTemplates.CalendarAgent, templates);
if (templateLink) {
results.push(templateLink);
}
} else if (title === 'Telegram') {
const templateLink = getTemplateLink(PrebuiltAgentTemplates.VoiceAssistantAgent, templates);
if (templateLink) {
results.push(templateLink);

View File

@@ -0,0 +1,79 @@
<script setup lang="ts">
import { useI18n } from '@n8n/i18n';
import { PRE_BUILT_AGENTS_MODAL_KEY } from '@/constants';
import { N8nHeading } from '@n8n/design-system';
import { createEventBus } from '@n8n/utils/event-bus';
import { computed } from 'vue';
import { useCalloutHelpers } from '@/composables/useCalloutHelpers';
import type { INodeCreateElement } from '@/Interface';
const i18n = useI18n();
const modalBus = createEventBus();
const calloutHelpers = useCalloutHelpers();
const preBuiltAgents = computed<INodeCreateElement[]>(() =>
calloutHelpers.getPreBuiltAgentNodeCreatorItems(),
);
function onSelected(actionCreateElement: INodeCreateElement) {
if (actionCreateElement.type === 'openTemplate') {
calloutHelpers.openSampleWorkflowTemplate(actionCreateElement.properties.templateId, {
telemetry: {
source: 'modal',
},
});
}
}
</script>
<template>
<Modal
max-width="500px"
max-height="85vh"
:event-bus="modalBus"
:name="PRE_BUILT_AGENTS_MODAL_KEY"
:center="true"
:show-close="true"
:class="$style.modal"
>
<template #header>
<div :class="$style.header">
<N8nHeading size="xlarge">{{ i18n.baseText('workflows.empty.preBuiltAgents') }}</N8nHeading>
</div>
</template>
<template #content>
<div :class="$style.container">
<ItemsRenderer :elements="preBuiltAgents" :class="$style.items" @selected="onSelected" />
</div>
</template>
</Modal>
</template>
<style lang="scss" module>
.modal {
:global(.el-dialog__body) {
padding: 0;
padding-bottom: var(--spacing-s);
}
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: var(--spacing-s);
}
.container {
display: flex;
flex-direction: column;
min-height: 100%;
}
.item {
margin-left: 0;
margin-right: 0;
padding-right: 0;
}
</style>