feat(editor): Show informative message in NDV when AI tools have no parameters (#15515)

This commit is contained in:
Daria
2025-05-20 12:45:51 +03:00
committed by GitHub
parent cf29b5f188
commit a426ecd2f1
4 changed files with 53 additions and 18 deletions

View File

@@ -55,7 +55,7 @@ const openAiNode: INodeUi = {
describe('NodeCredentials', () => { describe('NodeCredentials', () => {
const defaultRenderOptions: RenderOptions = { const defaultRenderOptions: RenderOptions = {
pinia: createTestingPinia(), pinia: createTestingPinia({ stubActions: false }),
props: { props: {
overrideCredType: 'openAiApi', overrideCredType: 'openAiApi',
node: httpNode, node: httpNode,

View File

@@ -85,31 +85,21 @@ const filter = ref('');
const listeningForAuthChange = ref(false); const listeningForAuthChange = ref(false);
const selectRefs = ref<Array<InstanceType<typeof N8nSelect>>>([]); const selectRefs = ref<Array<InstanceType<typeof N8nSelect>>>([]);
const credentialTypesNodeDescriptions = computed(() =>
credentialsStore.getCredentialTypesNodeDescriptions(props.overrideCredType, nodeType.value),
);
const credentialTypesNode = computed(() => const credentialTypesNode = computed(() =>
credentialTypesNodeDescription.value.map( credentialTypesNodeDescriptions.value.map(
(credentialTypeDescription) => credentialTypeDescription.name, (credentialTypeDescription) => credentialTypeDescription.name,
), ),
); );
const credentialTypesNodeDescriptionDisplayed = computed(() => const credentialTypesNodeDescriptionDisplayed = computed(() =>
credentialTypesNodeDescription.value credentialTypesNodeDescriptions.value
.filter((credentialTypeDescription) => displayCredentials(credentialTypeDescription)) .filter((credentialTypeDescription) => displayCredentials(credentialTypeDescription))
.map((type) => ({ type, options: getCredentialOptions(getAllRelatedCredentialTypes(type)) })), .map((type) => ({ type, options: getCredentialOptions(getAllRelatedCredentialTypes(type)) })),
); );
const credentialTypesNodeDescription = computed(() => {
if (typeof props.overrideCredType !== 'string') return [];
const credType = credentialsStore.getCredentialTypeByName(props.overrideCredType);
if (credType) return [credType];
const activeNodeType = nodeType.value;
if (activeNodeType?.credentials) {
return activeNodeType.credentials;
}
return [];
});
const credentialTypeNames = computed(() => { const credentialTypeNames = computed(() => {
const returnData: Record<string, string> = {}; const returnData: Record<string, string> = {};

View File

@@ -6,6 +6,7 @@ import type {
INodeProperties, INodeProperties,
NodeConnectionType, NodeConnectionType,
NodeParameterValue, NodeParameterValue,
INodeCredentialDescription,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import {
NodeHelpers, NodeHelpers,
@@ -204,9 +205,24 @@ const parameters = computed(() => {
const parametersSetting = computed(() => parameters.value.filter((item) => item.isNodeSetting)); const parametersSetting = computed(() => parameters.value.filter((item) => item.isNodeSetting));
const parametersNoneSetting = computed(() => const parametersNoneSetting = computed(() =>
// The connection hint notice is visually hidden via CSS in NodeDetails.vue when the node has output connections
parameters.value.filter((item) => !item.isNodeSetting), parameters.value.filter((item) => !item.isNodeSetting),
); );
const isDisplayingCredentials = computed(
() =>
credentialsStore
.getCredentialTypesNodeDescriptions('', props.nodeType)
.filter((credentialTypeDescription) => displayCredentials(credentialTypeDescription)).length >
0,
);
const showNoParametersNotice = computed(
() =>
!isDisplayingCredentials.value &&
parametersNoneSetting.value.filter((item) => item.type !== 'notice').length === 0,
);
const outputPanelEditMode = computed(() => ndvStore.outputPanelEditMode); const outputPanelEditMode = computed(() => ndvStore.outputPanelEditMode);
const isCommunityNode = computed(() => !!node.value && isCommunityPackageName(node.value.type)); const isCommunityNode = computed(() => !!node.value && isCommunityPackageName(node.value.type));
@@ -957,6 +973,18 @@ onBeforeUnmount(() => {
importCurlEventBus.off('setHttpNodeParameters', setHttpNodeParameters); importCurlEventBus.off('setHttpNodeParameters', setHttpNodeParameters);
ndvEventBus.off('updateParameterValue', valueChanged); ndvEventBus.off('updateParameterValue', valueChanged);
}); });
function displayCredentials(credentialTypeDescription: INodeCredentialDescription): boolean {
if (credentialTypeDescription.displayOptions === undefined) {
// If it is not defined no need to do a proper check
return true;
}
return (
!!node.value &&
nodeHelpers.displayParameter(node.value.parameters, credentialTypeDescription, '', node.value)
);
}
</script> </script>
<template> <template>
@@ -1077,7 +1105,7 @@ onBeforeUnmount(() => {
@blur="onParameterBlur" @blur="onParameterBlur"
/> />
</ParameterInputList> </ParameterInputList>
<div v-if="parametersNoneSetting.length === 0" class="no-parameters"> <div v-if="showNoParametersNotice" class="no-parameters">
<n8n-text> <n8n-text>
{{ i18n.baseText('nodeSettings.thisNodeDoesNotHaveAnyParameters') }} {{ i18n.baseText('nodeSettings.thisNodeDoesNotHaveAnyParameters') }}
</n8n-text> </n8n-text>

View File

@@ -20,7 +20,10 @@ import { isEmpty, isPresent } from '@/utils/typesUtils';
import type { import type {
ICredentialsDecrypted, ICredentialsDecrypted,
ICredentialType, ICredentialType,
INodeCredentialDescription,
INodeCredentialTestResult, INodeCredentialTestResult,
INodeTypeDescription,
NodeParameterValueType,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
@@ -298,6 +301,19 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, () => {
return await credentialsApi.getCredentialData(rootStore.restApiContext, id); return await credentialsApi.getCredentialData(rootStore.restApiContext, id);
}; };
const getCredentialTypesNodeDescriptions: (
overrideCredType: NodeParameterValueType,
nodeType: INodeTypeDescription | null,
) => INodeCredentialDescription[] = (overrideCredType, nodeType) => {
if (typeof overrideCredType !== 'string') return [];
const credType = getCredentialTypeByName.value(overrideCredType);
if (credType) return [credType];
return nodeType?.credentials ? nodeType.credentials : [];
};
const createNewCredential = async ( const createNewCredential = async (
data: ICredentialsDecrypted, data: ICredentialsDecrypted,
projectId?: string, projectId?: string,
@@ -444,6 +460,7 @@ export const useCredentialsStore = defineStore(STORES.CREDENTIALS, () => {
createNewCredential, createNewCredential,
updateCredential, updateCredential,
getCredentialData, getCredentialData,
getCredentialTypesNodeDescriptions,
oAuth1Authorize, oAuth1Authorize,
oAuth2Authorize, oAuth2Authorize,
getNewCredentialName, getNewCredentialName,