feat(editor): Show warning when user activates workflow with free AI credits credential (no-changelog) (#12510)

This commit is contained in:
Ricardo Espinoza 2025-01-08 10:58:54 -05:00 committed by GitHub
parent dba7d46f3e
commit dd36bb28bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 94 additions and 3 deletions

View file

@ -7,16 +7,31 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
import { createTestingPinia } from '@pinia/testing';
import { createComponentRenderer } from '@/__tests__/render';
import { mockedStore } from '@/__tests__/utils';
import { EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE } from '@/constants';
import { EXECUTE_WORKFLOW_TRIGGER_NODE_TYPE, WOOCOMMERCE_TRIGGER_NODE_TYPE } from '@/constants';
import { useCredentialsStore } from '@/stores/credentials.store';
import { useToast } from '@/composables/useToast';
const renderComponent = createComponentRenderer(WorkflowActivator);
let mockWorkflowsStore: ReturnType<typeof mockedStore<typeof useWorkflowsStore>>;
let mockCredentialsStore: ReturnType<typeof mockedStore<typeof useCredentialsStore>>;
vi.mock('@/composables/useToast', () => {
const showMessage = vi.fn();
return {
useToast: () => {
return {
showMessage,
};
},
};
});
describe('WorkflowActivator', () => {
beforeEach(() => {
createTestingPinia();
mockWorkflowsStore = mockedStore(useWorkflowsStore);
mockCredentialsStore = mockedStore(useCredentialsStore);
});
afterEach(() => {
@ -79,4 +94,53 @@ 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 () => {
const toast = useToast();
mockWorkflowsStore.workflow.usedCredentials = [
{
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,
];
const { rerender } = renderComponent({
props: {
workflowActive: false,
workflowId: '1',
workflowPermissions: { update: true },
},
});
await rerender({ workflowActive: true });
expect(toast.showMessage).toHaveBeenCalledWith(
expect.objectContaining({
title: "You're using free OpenAI API credits",
message:
'To make sure your workflow runs smoothly in the future, replace the free OpenAI API credits with your own API key.',
type: 'warning',
duration: 0,
}),
);
});
});

View file

@ -4,11 +4,13 @@ import { useWorkflowActivate } from '@/composables/useWorkflowActivate';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { getActivatableTriggerNodes } from '@/utils/nodeTypesUtils';
import type { VNode } from 'vue';
import { computed, h } from 'vue';
import { computed, h, watch } from 'vue';
import { useI18n } from '@/composables/useI18n';
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';
const props = defineProps<{
workflowActive: boolean;
@ -20,6 +22,7 @@ const workflowActivate = useWorkflowActivate();
const i18n = useI18n();
const workflowsStore = useWorkflowsStore();
const credentialsStore = useCredentialsStore();
const isWorkflowActive = computed((): boolean => {
const activeWorkflows = workflowsStore.activeWorkflows;
@ -69,6 +72,14 @@ 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,
);
});
async function activeChanged(newActiveState: boolean) {
return await workflowActivate.updateWorkflowActivation(props.workflowId, newActiveState);
}
@ -100,6 +111,20 @@ async function displayActivationError() {
duration: 0,
});
}
watch(
() => props.workflowActive,
(workflowActive) => {
if (workflowActive && currentWorkflowHasFreeAiCredits.value) {
showMessage({
title: i18n.baseText('freeAi.credits.showWarning.workflow.activation.title'),
message: i18n.baseText('freeAi.credits.showWarning.workflow.activation.description'),
type: 'warning',
duration: 0,
});
}
},
);
</script>
<template>

View file

@ -2848,5 +2848,7 @@
"freeAi.credits.callout.success.title.part2": "gpt-4o-mini, text-embedding-3-small, dall-e-3, tts-1, whisper-1, and text-moderation-latest",
"freeAi.credits.credentials.edit": "This is a managed credential and cannot be edited.",
"freeAi.credits.showError.claim.title": "Free AI credits",
"freeAi.credits.showError.claim.message": "Enable to claim credits"
"freeAi.credits.showError.claim.message": "Enable to claim credits",
"freeAi.credits.showWarning.workflow.activation.title": "You're using free OpenAI API credits",
"freeAi.credits.showWarning.workflow.activation.description": "To make sure your workflow runs smoothly in the future, replace the free OpenAI API credits with your own API key."
}