Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(AI Transform Node): UX improvements #11280

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5141326
fixes
michael-radency Oct 16, 2024
05877f5
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 16, 2024
18e40d4
code generated for last prompt warning
michael-radency Oct 16, 2024
c3aa292
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 16, 2024
d98a4fc
generate code on test button click if missed
michael-radency Oct 17, 2024
f3f8df9
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 17, 2024
483352f
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 17, 2024
7f0efc1
improvements
michael-radency Oct 17, 2024
8aef298
test update
michael-radency Oct 17, 2024
78fa618
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 18, 2024
ac0407a
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 18, 2024
2f571e2
review update
michael-radency Oct 18, 2024
3b0bbb5
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 21, 2024
a2c5cab
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 21, 2024
5450c7a
counter/warning backdrop
michael-radency Oct 21, 2024
d820454
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 21, 2024
ef616ba
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 24, 2024
80fee44
test fix
michael-radency Oct 24, 2024
0efbc95
Update packages/editor-ui/src/components/NodeExecuteButton.vue
michael-radency Oct 31, 2024
2cc5dc0
review update
michael-radency Oct 31, 2024
71bb10e
Merge branch 'node-1864-improve-ux-in-ai-transform-node' of https://g…
michael-radency Oct 31, 2024
fce8905
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 31, 2024
7c04556
review update
michael-radency Oct 31, 2024
a6569cb
tests fix
michael-radency Oct 31, 2024
ab1506a
tests fix
michael-radency Oct 31, 2024
8575c00
tests fix
michael-radency Oct 31, 2024
c52727e
tests fix
michael-radency Oct 31, 2024
0bb5bdc
tests fix
michael-radency Oct 31, 2024
c75619c
tests fix
michael-radency Oct 31, 2024
b23024d
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 31, 2024
0ea2798
tooltip and icon update
michael-radency Oct 31, 2024
76d8a3d
Merge branch 'master' of https://github.com/n8n-io/n8n into node-1864…
michael-radency Oct 31, 2024
392f8b6
trim strings before comaprison
michael-radency Oct 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/design-system/src/components/N8nInput/Input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const props = withDefaults(defineProps<InputProps>(), {
readonly: false,
clearable: false,
rows: 2,
maxlength: Infinity,
maxlength: undefined,
title: '',
name: () => uid('input'),
autocomplete: 'off',
Expand Down Expand Up @@ -81,6 +81,7 @@ defineExpose({ focus, blur, select });
:clearable="clearable"
:rows="rows"
:title="title"
:maxlength="maxlength"
v-bind="$attrs"
>
<template v-if="$slots.prepend" #prepend>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
<script setup lang="ts">
import { ApplicationError, type INodeProperties, type NodePropertyAction } from 'n8n-workflow';
import { type INodeProperties, type NodePropertyAction } from 'n8n-workflow';
import type { INodeUi, IUpdateInformation } from '@/Interface';
import { ref, computed, onMounted } from 'vue';
import { N8nButton, N8nInput, N8nTooltip } from 'n8n-design-system/components';
import { useI18n } from '@/composables/useI18n';
import { useToast } from '@/composables/useToast';
import { useNDVStore } from '@/stores/ndv.store';
import { getSchemas, getParentNodes } from './utils';
import { useRootStore } from '@/stores/root.store';
import { getParentNodes, generateCodeForAiTransform } from './utils';
import { useTelemetry } from '@/composables/useTelemetry';
import { generateCodeForPrompt } from '@/api/ai';
import { useUIStore } from '@/stores/ui.store';

import { format } from 'prettier';
import jsParser from 'prettier/plugins/babel';
import * as estree from 'prettier/plugins/estree';
import { useSettingsStore } from '@/stores/settings.store';
import type { AskAiRequest } from '@/types/assistant.types';
const AI_TRANSFORM_CODE_GENERATED_FOR_PROMPT = 'codeGeneratedForPrompt';

const emit = defineEmits<{
valueChanged: [value: IUpdateInformation];
Expand All @@ -27,8 +22,7 @@ const props = defineProps<{
path: string;
}>();

const rootStore = useRootStore();
const settingsStore = useSettingsStore();
const { activeNode } = useNDVStore();

const i18n = useI18n();

Expand All @@ -53,6 +47,11 @@ const isSubmitEnabled = computed(() => {

return true;
});
const promptUpdated = computed(() => {
const lastPrompt = activeNode?.parameters[AI_TRANSFORM_CODE_GENERATED_FOR_PROMPT] as string;
if (!lastPrompt) return false;
return lastPrompt.trim() !== prompt.value.trim();
});

function startLoading() {
isLoading.value = true;
Expand All @@ -69,7 +68,6 @@ function getPath(parameter: string) {
}

async function onSubmit() {
const { activeNode } = useNDVStore();
const { showMessage } = useToast();
const action: string | NodePropertyAction | undefined =
props.parameter.typeOptions?.buttonConfig?.action;
Expand All @@ -93,46 +91,26 @@ async function onSubmit() {
startLoading();

try {
const schemas = getSchemas();

const payload: AskAiRequest.RequestPayload = {
question: prompt.value,
context: {
schema: schemas.parentNodesSchemas,
inputSchema: schemas.inputSchema!,
ndvPushRef: useNDVStore().pushRef,
pushRef: rootStore.pushRef,
},
forNode: 'transform',
};
switch (type) {
case 'askAiCodeGeneration':
let value;
if (settingsStore.isAskAiEnabled) {
const { restApiContext } = useRootStore();
const { code } = await generateCodeForPrompt(restApiContext, payload);
value = code;
} else {
throw new ApplicationError('AI code generation is not enabled');
}
const updateInformation = await generateCodeForAiTransform(
prompt.value,
getPath(target as string),
);
if (!updateInformation) return;

if (value === undefined) return;
//updade code parameter
emit('valueChanged', updateInformation);

const formattedCode = await format(String(value), {
parser: 'babel',
plugins: [jsParser, estree],
//update code generated for prompt parameter
emit('valueChanged', {
name: getPath(AI_TRANSFORM_CODE_GENERATED_FOR_PROMPT),
value: prompt.value,
});

const updateInformation = {
name: getPath(target as string),
value: formattedCode,
};

emit('valueChanged', updateInformation);

useTelemetry().trackAiTransform('generationFinished', {
prompt: prompt.value,
code: formattedCode,
code: updateInformation.value,
});
break;
default:
Expand Down Expand Up @@ -168,6 +146,16 @@ function onPromptInput(inputValue: string) {
});
}

function useDarkBackdrop(): string {
const theme = useUIStore().appliedTheme;

if (theme === 'light') {
return 'background-color: var(--color-background-xlight);';
} else {
return 'background-color: var(--color-background-light);';
}
}

onMounted(() => {
parentNodes.value = getParentNodes();
});
Expand All @@ -185,13 +173,18 @@ onMounted(() => {
>
</n8n-input-label>
<div :class="$style.inputContainer" :hidden="!hasInputField">
<div :class="$style.meta">
<div :class="$style.meta" :style="useDarkBackdrop()">
<span
v-if="inputFieldMaxLength"
v-show="prompt.length > 1"
:class="$style.counter"
v-text="`${prompt.length} / ${inputFieldMaxLength}`"
/>
<span
v-if="promptUpdated"
:class="$style['warning-text']"
v-text="'Instructions changed. Click \'Generate code\' before running this node again'"
/>
</div>
<N8nInput
v-model="prompt"
Expand Down Expand Up @@ -255,9 +248,15 @@ onMounted(() => {
display: flex;
justify-content: space-between;
position: absolute;
bottom: var(--spacing-2xs);
padding-bottom: var(--spacing-2xs);
padding-top: var(--spacing-2xs);
margin: 1px;
margin-right: var(--spacing-s);
bottom: 0;
left: var(--spacing-xs);
right: var(--spacing-xs);
gap: 10px;
align-items: end;
z-index: 1;

* {
Expand All @@ -267,10 +266,15 @@ onMounted(() => {
}
.counter {
color: var(--color-text-light);
flex-shrink: 0;
}
.controls {
padding: var(--spacing-2xs) 0;
display: flex;
justify-content: flex-end;
}
.warning-text {
color: var(--color-warning);
line-height: 1.2;
}
</style>
47 changes: 46 additions & 1 deletion packages/editor-ui/src/components/ButtonParameter/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import type { Schema } from '@/Interface';
import type { INodeExecutionData } from 'n8n-workflow';
import { ApplicationError, type INodeExecutionData } from 'n8n-workflow';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { useNDVStore } from '@/stores/ndv.store';
import { useDataSchema } from '@/composables/useDataSchema';
import { executionDataToJson } from '@/utils/nodeTypesUtils';
import { generateCodeForPrompt } from '../../api/ai';
import { useRootStore } from '../../stores/root.store';
import { type AskAiRequest } from '../../types/assistant.types';
import { useSettingsStore } from '../../stores/settings.store';
import { format } from 'prettier';
import jsParser from 'prettier/plugins/babel';
import * as estree from 'prettier/plugins/estree';

export function getParentNodes() {
const activeNode = useNDVStore().activeNode;
Expand Down Expand Up @@ -44,3 +51,41 @@ export function getSchemas() {
parentNodesSchemas,
};
}

export async function generateCodeForAiTransform(prompt: string, path: string) {
const schemas = getSchemas();

const payload: AskAiRequest.RequestPayload = {
question: prompt,
context: {
schema: schemas.parentNodesSchemas,
inputSchema: schemas.inputSchema!,
ndvPushRef: useNDVStore().pushRef,
pushRef: useRootStore().pushRef,
},
forNode: 'transform',
};

let value;
if (useSettingsStore().isAskAiEnabled) {
const { restApiContext } = useRootStore();
const { code } = await generateCodeForPrompt(restApiContext, payload);
value = code;
} else {
throw new ApplicationError('AI code generation is not enabled');
}

if (value === undefined) return;

const formattedCode = await format(String(value), {
parser: 'babel',
plugins: [jsParser, estree],
});

const updateInformation = {
name: path,
value: formattedCode,
};

return updateInformation;
}
Loading