Skip to content

Commit

Permalink
fix(editor): Condition to show the warning after workflow activation …
Browse files Browse the repository at this point in the history
…for free AI credits (no-changelog) (n8n-io#12518)
  • Loading branch information
RicardoE105 authored Jan 9, 2025
1 parent 8fab98f commit 46f13cf
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 11 deletions.
126 changes: 122 additions & 4 deletions packages/editor-ui/src/components/WorkflowActivator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,17 @@ describe('WorkflowActivator', () => {
expect(getByTestId('workflow-activator-status')).toHaveTextContent('Inactive');
});

it('Should show warning toast if the workflow to be activated has free OpenAI credentials', async () => {
it('Should show warning toast if the workflow to be activated has non-disabled node using free OpenAI credentials', async () => {
const toast = useToast();

mockWorkflowsStore.workflow.usedCredentials = [
{
mockWorkflowsStore.usedCredentials = {
'1': {
id: '1',
name: '',
credentialType: '',
currentUserHasAccess: false,
},
];
};

mockCredentialsStore.state.credentials = {
'1': {
Expand All @@ -123,6 +123,24 @@ describe('WorkflowActivator', () => {
{ type: WOOCOMMERCE_TRIGGER_NODE_TYPE, disabled: false } as never,
];

mockWorkflowsStore.allNodes = [
{
credentials: {
openAiApi: {
name: 'OpenAI',
id: '1',
},
},
disabled: false,
position: [1, 1],
name: '',
id: '',
typeVersion: 0,
type: '',
parameters: {},
},
];

const { rerender } = renderComponent({
props: {
workflowActive: false,
Expand All @@ -143,4 +161,104 @@ describe('WorkflowActivator', () => {
}),
);
});

it('Should not show warning toast if the workflow to be activated has disabled node using free OpenAI credentials', async () => {
const toast = useToast();

mockWorkflowsStore.usedCredentials = {
'1': {
id: '1',
name: '',
credentialType: '',
currentUserHasAccess: false,
},
};

mockCredentialsStore.state.credentials = {
'1': {
id: '1',
name: 'OpenAI',
type: 'openAiApi',
data: '',
isManaged: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
};

mockWorkflowsStore.workflowTriggerNodes = [
{ type: WOOCOMMERCE_TRIGGER_NODE_TYPE, disabled: false } as never,
];

mockWorkflowsStore.allNodes = [
{
credentials: {
openAiApi: {
name: 'OpenAI',
id: '1',
},
},
disabled: true,
position: [1, 1],
name: '',
id: '',
typeVersion: 0,
type: '',
parameters: {},
},
];

const { rerender } = renderComponent({
props: {
workflowActive: false,
workflowId: '1',
workflowPermissions: { update: true },
},
});

await rerender({ workflowActive: true });

expect(toast.showMessage).not.toHaveBeenCalled();
});

it('Should not show warning toast if the workflow to be activated has no node with free OpenAI credential', async () => {
const toast = useToast();

mockWorkflowsStore.usedCredentials = {
'1': {
id: '1',
name: '',
credentialType: '',
currentUserHasAccess: false,
},
};

mockCredentialsStore.state.credentials = {
'1': {
id: '1',
name: 'Jira',
type: 'jiraApi',
data: '',
isManaged: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
};

mockWorkflowsStore.workflowTriggerNodes = [
{ type: WOOCOMMERCE_TRIGGER_NODE_TYPE, disabled: false } as never,
];

const { rerender } = renderComponent({
props: {
workflowActive: false,
workflowId: '1',
workflowPermissions: { update: true },
},
});

await rerender({ workflowActive: true });

expect(toast.showMessage).not.toHaveBeenCalled();
});
});
42 changes: 35 additions & 7 deletions packages/editor-ui/src/components/WorkflowActivator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import type { PermissionsRecord } from '@/permissions';
import { EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE, PLACEHOLDER_EMPTY_WORKFLOW_ID } from '@/constants';
import WorkflowActivationErrorMessage from './WorkflowActivationErrorMessage.vue';
import { useCredentialsStore } from '@/stores/credentials.store';
import type { IUsedCredential } from '@/Interface';
import type { INodeUi, IUsedCredential } from '@/Interface';
import { OPEN_AI_API_CREDENTIAL_TYPE } from 'n8n-workflow';
const props = defineProps<{
workflowActive: boolean;
Expand Down Expand Up @@ -72,12 +73,39 @@ const disabled = computed((): boolean => {
return false;
});
const currentWorkflowHasFreeAiCredits = computed((): boolean => {
if (!workflowsStore?.workflow?.usedCredentials) return false;
return workflowsStore.workflow.usedCredentials.some(
(usedCredential: IUsedCredential) =>
credentialsStore.state.credentials[usedCredential.id].isManaged,
function findManagedOpenAiCredentialId(
usedCredentials: Record<string, IUsedCredential>,
): string | undefined {
return Object.keys(usedCredentials).find((credentialId) => {
const credential = credentialsStore.state.credentials[credentialId];
return credential.isManaged && credential.type === OPEN_AI_API_CREDENTIAL_TYPE;
});
}
function hasActiveNodeUsingCredential(nodes: INodeUi[], credentialId: string): boolean {
return nodes.some(
(node) =>
node?.credentials?.[OPEN_AI_API_CREDENTIAL_TYPE]?.id === credentialId && !node.disabled,
);
}
/**
* Determines if the warning for free AI credits should be shown in the workflow.
*
* This computed property evaluates whether to display a warning about free AI credits
* in the workflow. The warning is shown when both conditions are met:
* 1. The workflow uses managed OpenAI API credentials
* 2. Those credentials are associated with at least one enabled node
*
*/
const shouldShowFreeAiCreditsWarning = computed((): boolean => {
const usedCredentials = workflowsStore?.usedCredentials;
if (!usedCredentials) return false;
const managedOpenAiCredentialId = findManagedOpenAiCredentialId(usedCredentials);
if (!managedOpenAiCredentialId) return false;
return hasActiveNodeUsingCredential(workflowsStore.allNodes, managedOpenAiCredentialId);
});
async function activeChanged(newActiveState: boolean) {
Expand Down Expand Up @@ -115,7 +143,7 @@ async function displayActivationError() {
watch(
() => props.workflowActive,
(workflowActive) => {
if (workflowActive && currentWorkflowHasFreeAiCredits.value) {
if (workflowActive && shouldShowFreeAiCreditsWarning.value) {
showMessage({
title: i18n.baseText('freeAi.credits.showWarning.workflow.activation.title'),
message: i18n.baseText('freeAi.credits.showWarning.workflow.activation.description'),
Expand Down

0 comments on commit 46f13cf

Please sign in to comment.