mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
fix(core): Add optional context parameter to track creation source for workflows, credentials, and projects (#18736)
Co-authored-by: r00gm <raul00gm@gmail.com>
This commit is contained in:
@@ -52,6 +52,7 @@ import {
|
||||
import { isCredentialModalState, isValidCredentialResponse } from '@/utils/typeGuards';
|
||||
import { useI18n } from '@n8n/i18n';
|
||||
import { useElementSize } from '@vueuse/core';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
type Props = {
|
||||
modalName: string;
|
||||
@@ -75,6 +76,7 @@ const toast = useToast();
|
||||
const message = useMessage();
|
||||
const i18n = useI18n();
|
||||
const telemetry = useTelemetry();
|
||||
const router = useRouter();
|
||||
|
||||
const activeTab = ref('connection');
|
||||
const authError = ref('');
|
||||
@@ -801,7 +803,16 @@ async function createCredential(
|
||||
let credential;
|
||||
|
||||
try {
|
||||
credential = await credentialsStore.createNewCredential(credentialDetails, project?.id);
|
||||
credential = await credentialsStore.createNewCredential(
|
||||
credentialDetails,
|
||||
project?.id,
|
||||
router.currentRoute.value.query.uiContext?.toString(),
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { uiContext, ...rest } = router.currentRoute.value.query;
|
||||
void router.replace({ query: rest });
|
||||
|
||||
hasUnsavedChanges.value = false;
|
||||
|
||||
const { title, message } = createToastMessagingForNewCredentials(project);
|
||||
|
||||
@@ -266,13 +266,15 @@ describe('ProjectHeader', () => {
|
||||
|
||||
await userEvent.click(getByTestId('action-credential'));
|
||||
|
||||
expect(mockPush).toHaveBeenCalledWith({
|
||||
name: VIEWS.PROJECTS_CREDENTIALS,
|
||||
params: {
|
||||
projectId: project.id,
|
||||
credentialId: 'create',
|
||||
},
|
||||
});
|
||||
expect(mockPush).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
name: VIEWS.PROJECTS_CREDENTIALS,
|
||||
params: {
|
||||
projectId: project.id,
|
||||
credentialId: 'create',
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -162,6 +162,37 @@ const showProjectIcon = computed(() => {
|
||||
);
|
||||
});
|
||||
|
||||
function isCredentialsListView(routeName: string) {
|
||||
const CREDENTIAL_VIEWS: string[] = [
|
||||
VIEWS.PROJECTS_CREDENTIALS,
|
||||
VIEWS.CREDENTIALS,
|
||||
VIEWS.SHARED_CREDENTIALS,
|
||||
];
|
||||
|
||||
return CREDENTIAL_VIEWS.includes(routeName);
|
||||
}
|
||||
|
||||
function isWorkflowListView(routeName: string) {
|
||||
const WORKFLOWS_VIEWS: string[] = [
|
||||
VIEWS.PROJECTS_WORKFLOWS,
|
||||
VIEWS.WORKFLOWS,
|
||||
VIEWS.SHARED_WORKFLOWS,
|
||||
VIEWS.PROJECTS_FOLDERS,
|
||||
];
|
||||
|
||||
return WORKFLOWS_VIEWS.includes(routeName);
|
||||
}
|
||||
|
||||
function getUIContext(routeName: string) {
|
||||
if (isCredentialsListView(routeName)) {
|
||||
return 'credentials_list';
|
||||
} else if (isWorkflowListView(routeName)) {
|
||||
return 'workflow_list';
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const actions: Record<ActionTypes, (projectId: string) => void> = {
|
||||
[ACTION_TYPES.WORKFLOW]: (projectId: string) => {
|
||||
void router.push({
|
||||
@@ -169,6 +200,7 @@ const actions: Record<ActionTypes, (projectId: string) => void> = {
|
||||
query: {
|
||||
projectId,
|
||||
parentFolderId: route.params.folderId as string,
|
||||
uiContext: getUIContext(route.name?.toString() ?? ''),
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -179,6 +211,9 @@ const actions: Record<ActionTypes, (projectId: string) => void> = {
|
||||
projectId,
|
||||
credentialId: 'create',
|
||||
},
|
||||
query: {
|
||||
uiContext: getUIContext(route.name?.toString() ?? ''),
|
||||
},
|
||||
});
|
||||
},
|
||||
[ACTION_TYPES.FOLDER]: () => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, onBeforeMount } from 'vue';
|
||||
import type { IMenuItem } from '@n8n/design-system/types';
|
||||
import { useI18n } from '@n8n/i18n';
|
||||
import { useGlobalEntityCreation } from '@/composables/useGlobalEntityCreation';
|
||||
import { VIEWS } from '@/constants';
|
||||
import { useProjectsStore } from '@/stores/projects.store';
|
||||
import type { ProjectListItem } from '@/types/projects.types';
|
||||
import { useGlobalEntityCreation } from '@/composables/useGlobalEntityCreation';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import type { ProjectListItem } from '@/types/projects.types';
|
||||
import type { IMenuItem } from '@n8n/design-system/types';
|
||||
import { useI18n } from '@n8n/i18n';
|
||||
import { ElMenu } from 'element-plus';
|
||||
import { computed, onBeforeMount } from 'vue';
|
||||
|
||||
type Props = {
|
||||
collapsed: boolean;
|
||||
@@ -28,7 +28,7 @@ const isCreatingProject = computed(() => globalEntityCreation.isCreatingProject.
|
||||
const displayProjects = computed(() => globalEntityCreation.displayProjects.value);
|
||||
const isFoldersFeatureEnabled = computed(() => settingsStore.isFoldersFeatureEnabled);
|
||||
const hasMultipleVerifiedUsers = computed(
|
||||
() => usersStore.allUsers.filter((user) => user.isPendingUser === false).length > 1,
|
||||
() => usersStore.allUsers.filter((user) => !user.isPendingUser).length > 1,
|
||||
);
|
||||
|
||||
const home = computed<IMenuItem>(() => ({
|
||||
@@ -140,7 +140,7 @@ onBeforeMount(async () => {
|
||||
data-test-id="project-plus-button"
|
||||
:disabled="isCreatingProject || !projectsStore.hasPermissionToCreateProjects"
|
||||
:class="$style.plusBtn"
|
||||
@click="globalEntityCreation.createProject"
|
||||
@click="globalEntityCreation.createProject('add_icon')"
|
||||
/>
|
||||
</N8nTooltip>
|
||||
</N8nText>
|
||||
|
||||
Reference in New Issue
Block a user