mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 10:31:15 +00:00
fix: Hide cred setup button from canvas (no-changelog) (#8255)
This commit is contained in:
@@ -202,6 +202,8 @@ describe('Template credentials setup', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
getSetupWorkflowCredentialsButton().should('not.exist');
|
||||||
|
|
||||||
// We need to save the workflow or otherwise a browser native popup
|
// We need to save the workflow or otherwise a browser native popup
|
||||||
// will block cypress from continuing
|
// will block cypress from continuing
|
||||||
workflowPage.actions.saveWorkflowOnButtonClick();
|
workflowPage.actions.saveWorkflowOnButtonClick();
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ export class WorkflowService {
|
|||||||
'active',
|
'active',
|
||||||
'nodes',
|
'nodes',
|
||||||
'connections',
|
'connections',
|
||||||
|
'meta',
|
||||||
'settings',
|
'settings',
|
||||||
'staticData',
|
'staticData',
|
||||||
'pinData',
|
'pinData',
|
||||||
|
|||||||
@@ -609,6 +609,25 @@ describe('PATCH /workflows/:id', () => {
|
|||||||
expect(versionId).toBe(workflow.versionId);
|
expect(versionId).toBe(workflow.versionId);
|
||||||
expect(active).toBe(false);
|
expect(active).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should update workflow meta', async () => {
|
||||||
|
const workflow = await createWorkflow({}, owner);
|
||||||
|
const payload = {
|
||||||
|
...workflow,
|
||||||
|
meta: {
|
||||||
|
templateCredsSetupCompleted: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await authOwnerAgent.patch(`/workflows/${workflow.id}`).send(payload);
|
||||||
|
|
||||||
|
const { data: updatedWorkflow } = response.body;
|
||||||
|
|
||||||
|
expect(response.statusCode).toBe(200);
|
||||||
|
|
||||||
|
expect(updatedWorkflow.id).toBe(workflow.id);
|
||||||
|
expect(updatedWorkflow.meta).toEqual(payload.meta);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST /workflows/run', () => {
|
describe('POST /workflows/run', () => {
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ export interface WorkflowMetadata {
|
|||||||
onboardingId?: string;
|
onboardingId?: string;
|
||||||
templateId?: string;
|
templateId?: string;
|
||||||
instanceId?: string;
|
instanceId?: string;
|
||||||
|
templateCredsSetupCompleted?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Almost identical to cli.Interfaces.ts
|
// Almost identical to cli.Interfaces.ts
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { computed, onBeforeUnmount, watch } from 'vue';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { SETUP_CREDENTIALS_MODAL_KEY, TEMPLATE_CREDENTIAL_SETUP_EXPERIMENT } from '@/constants';
|
import { SETUP_CREDENTIALS_MODAL_KEY, TEMPLATE_CREDENTIAL_SETUP_EXPERIMENT } from '@/constants';
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
import { usePostHog } from '@/stores/posthog.store';
|
import { usePostHog } from '@/stores/posthog.store';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { doesNodeHaveCredentialsToFill } from '@/utils/nodes/nodeTransforms';
|
import { doesNodeHaveAllCredentialsFilled } from '@/utils/nodes/nodeTransforms';
|
||||||
import { computed, onBeforeUnmount } from 'vue';
|
|
||||||
|
|
||||||
const workflowsStore = useWorkflowsStore();
|
const workflowsStore = useWorkflowsStore();
|
||||||
const nodeTypesStore = useNodeTypesStore();
|
const nodeTypesStore = useNodeTypesStore();
|
||||||
@@ -14,15 +14,41 @@ const uiStore = useUIStore();
|
|||||||
const posthogStore = usePostHog();
|
const posthogStore = usePostHog();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const showButton = computed(() => {
|
const isTemplateSetupCompleted = computed(() => {
|
||||||
const isFeatureEnabled = posthogStore.isFeatureEnabled(TEMPLATE_CREDENTIAL_SETUP_EXPERIMENT);
|
return !!workflowsStore.workflow?.meta?.templateCredsSetupCompleted;
|
||||||
const isCreatedFromTemplate = !!workflowsStore.workflow?.meta?.templateId;
|
});
|
||||||
if (!isFeatureEnabled || !isCreatedFromTemplate) {
|
|
||||||
|
const allCredentialsFilled = computed(() => {
|
||||||
|
if (isTemplateSetupCompleted.value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodes = workflowsStore.getNodes();
|
||||||
|
if (!nodes.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodes = workflowsStore.workflow?.nodes ?? [];
|
return nodes.every((node) => doesNodeHaveAllCredentialsFilled(nodeTypesStore, node));
|
||||||
return nodes.some((node) => doesNodeHaveCredentialsToFill(nodeTypesStore, node));
|
});
|
||||||
|
|
||||||
|
const showButton = computed(() => {
|
||||||
|
const isFeatureEnabled = posthogStore.isFeatureEnabled(TEMPLATE_CREDENTIAL_SETUP_EXPERIMENT);
|
||||||
|
const isCreatedFromTemplate = !!workflowsStore.workflow?.meta?.templateId;
|
||||||
|
if (!isFeatureEnabled || !isCreatedFromTemplate || isTemplateSetupCompleted.value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !allCredentialsFilled.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const unsubscribe = watch(allCredentialsFilled, (newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
workflowsStore.addToWorkflowMetadata({
|
||||||
|
templateCredsSetupCompleted: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
unsubscribe();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ export function getNodeTypeDisplayableCredentials(
|
|||||||
return displayableCredentials;
|
return displayableCredentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given node has credentials that can be filled.
|
||||||
|
*/
|
||||||
export function doesNodeHaveCredentialsToFill(
|
export function doesNodeHaveCredentialsToFill(
|
||||||
nodeTypeProvider: NodeTypeProvider,
|
nodeTypeProvider: NodeTypeProvider,
|
||||||
node: Pick<INodeUi, 'parameters' | 'type' | 'typeVersion'>,
|
node: Pick<INodeUi, 'parameters' | 'type' | 'typeVersion'>,
|
||||||
@@ -40,3 +43,31 @@ export function doesNodeHaveCredentialsToFill(
|
|||||||
|
|
||||||
return requiredCredentials.length > 0;
|
return requiredCredentials.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does node has the given credential filled
|
||||||
|
*
|
||||||
|
* @param credentialName E.g. "telegramApi"
|
||||||
|
*/
|
||||||
|
export function hasNodeCredentialFilled(
|
||||||
|
node: Pick<INodeUi, 'credentials'>,
|
||||||
|
credentialName: string,
|
||||||
|
): boolean {
|
||||||
|
if (!node.credentials) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!node.credentials[credentialName];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given node has all credentials filled.
|
||||||
|
*/
|
||||||
|
export function doesNodeHaveAllCredentialsFilled(
|
||||||
|
nodeTypeProvider: NodeTypeProvider,
|
||||||
|
node: Pick<INodeUi, 'parameters' | 'type' | 'typeVersion' | 'credentials'>,
|
||||||
|
): boolean {
|
||||||
|
const requiredCredentials = getNodeTypeDisplayableCredentials(nodeTypeProvider, node);
|
||||||
|
|
||||||
|
return requiredCredentials.every((cred) => hasNodeCredentialFilled(node, cred.name));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user