add filtering by creds

This commit is contained in:
Mutasem Aldmour 2024-10-30 13:03:18 +01:00
parent 32d3c8aa1a
commit 26877949b9
No known key found for this signature in database
GPG key ID: 3DFA8122BB7FD6B8
5 changed files with 56 additions and 46 deletions

View file

@ -637,6 +637,22 @@ export interface IWorkflowSettings extends IWorkflowSettingsWorkflow {
executionOrder: NonNullable<IWorkflowSettingsWorkflow['executionOrder']>;
}
export interface WorkflowsFetchOptions {
filter?: {
tags?: string[];
active?: boolean;
projectId?: string;
};
sort?: 'lastUpdated' | 'lastCreated' | 'nameDesc' | 'nameAsc';
webhookURL?: string;
httpNodeURL?: string;
nodeName?: string;
nodeTypes?: string[];
credentialIds?: string[];
skip?: number;
take?: number;
}
export interface ITimeoutHMS {
hours: number;
minutes: number;

View file

@ -4,6 +4,7 @@ import type {
IRestApiContext,
IWorkflowDb,
NewWorkflowResponse,
WorkflowsFetchOptions,
} from '@/Interface';
import type {
ExecutionFilters,
@ -33,10 +34,11 @@ export async function getWorkflow(context: IRestApiContext, id: string, filter?:
return await makeRestApiRequest<IWorkflowDb>(context, 'GET', `/workflows/${id}`, sendData);
}
export async function getWorkflows(context: IRestApiContext, filter?: object) {
export async function getWorkflows(context: IRestApiContext, options: WorkflowsFetchOptions) {
return await makeRestApiRequest<IWorkflowDb[]>(context, 'GET', '/workflows', {
includeScopes: true,
...(filter ? { filter } : {}),
...options,
credentialIds: options.credentialIds ? options.credentialIds.join(',') : undefined,
});
}

View file

@ -87,10 +87,12 @@ export const useProjectsStore = defineStore(STORES.PROJECTS, () => {
const getAllProjects = async () => {
projects.value = await projectsApi.getAllProjects(rootStore.restApiContext);
return projects.value;
};
const getMyProjects = async () => {
myProjects.value = await projectsApi.getMyProjects(rootStore.restApiContext);
return myProjects.value;
};
const getPersonalProject = async () => {
@ -99,9 +101,9 @@ export const useProjectsStore = defineStore(STORES.PROJECTS, () => {
const getAvailableProjects = async () => {
if (globalProjectPermissions.value.list) {
await getAllProjects();
return await getAllProjects();
} else {
await getMyProjects();
return await getMyProjects();
}
};

View file

@ -30,6 +30,7 @@ import type {
WorkflowMetadata,
IExecutionFlattedResponse,
IWorkflowTemplateNode,
WorkflowsFetchOptions,
} from '@/Interface';
import { defineStore } from 'pinia';
import type {
@ -472,17 +473,10 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
);
}
async function fetchAllWorkflows(projectId?: string): Promise<IWorkflowDb[]> {
async function fetchAllWorkflows(filters: WorkflowsFetchOptions): Promise<IWorkflowDb[]> {
const rootStore = useRootStore();
const filter = {
projectId,
};
const workflows = await workflowsApi.getWorkflows(
rootStore.restApiContext,
isEmpty(filter) ? undefined : filter,
);
const workflows = await workflowsApi.getWorkflows(rootStore.restApiContext, filters);
setWorkflows(workflows);
return workflows;
}

View file

@ -1,10 +1,10 @@
<script lang="ts" setup>
import { computed, onMounted, watch, ref } from 'vue';
import { computed, onMounted, watch, ref, onBeforeMount } from 'vue';
import ResourcesListLayout, { type IResource } from '@/components/layouts/ResourcesListLayout.vue';
import WorkflowCard from '@/components/WorkflowCard.vue';
import WorkflowTagsDropdown from '@/components/WorkflowTagsDropdown.vue';
import { EnterpriseEditionFeature, MORE_ONBOARDING_OPTIONS_EXPERIMENT, VIEWS } from '@/constants';
import type { ITag, IUser, IWorkflowDb } from '@/Interface';
import type { ITag, IUser, IWorkflowDb, WorkflowsFetchOptions } from '@/Interface';
import { useUIStore } from '@/stores/ui.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useUsersStore } from '@/stores/users.store';
@ -34,6 +34,7 @@ import {
import { pickBy } from 'lodash-es';
import { useCredentialsStore } from '@/stores/credentials.store';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { ProjectSharingData } from 'n8n-workflow';
const i18n = useI18n();
const route = useRoute();
@ -151,33 +152,11 @@ const emptyListDescription = computed(() => {
}
});
const onFilter = (
resource: IWorkflowDb,
newFilters: { tags: string[]; search: string; status: string | boolean },
matches: boolean,
): boolean => {
if (settingsStore.areTagsEnabled && newFilters.tags.length > 0) {
matches =
matches &&
newFilters.tags.every((tag) =>
(resource.tags as ITag[])?.find((resourceTag) =>
typeof resourceTag === 'object'
? `${resourceTag.id}` === `${tag}`
: `${resourceTag}` === `${tag}`,
),
);
}
if (newFilters.status !== '') {
matches = matches && resource.active === newFilters.status;
}
return matches;
};
// Methods
const onFiltersUpdated = (newFilters: Filters) => {
Object.assign(filters.value, newFilters);
fetchWorkflowsWithFilters();
};
const addWorkflow = () => {
@ -211,13 +190,28 @@ const trackCategoryLinkClick = (category: string) => {
});
};
const fetchWorkflowsWithFilters = async () => {
const { homeProject, status, credentials } = filters.value;
const options: WorkflowsFetchOptions = {
filter: {
projectId: homeProject ? homeProject : undefined,
active: status === StatusFilter.ACTIVE ? true : undefined,
},
credentialIds: credentials.length ? credentials : undefined,
};
console.log('fetching', options);
await workflowsStore.fetchAllWorkflows(options);
};
const initialize = async () => {
loading.value = true;
await setFiltersFromQueryString();
await Promise.all([
nodeTypesStore.loadNodeTypesIfNotLoaded(),
credentialsStore.fetchAllCredentials(route?.params?.projectId as string | undefined),
usersStore.fetchUsers(),
workflowsStore.fetchAllWorkflows(route.params?.projectId as string | undefined),
fetchWorkflowsWithFilters(),
workflowsStore.fetchActiveWorkflows(),
]);
loading.value = false;
@ -253,8 +247,8 @@ const saveFiltersOnQueryString = () => {
});
};
function isValidProjectId(projectId: string) {
return projectsStore.availableProjects.some((project) => project.id === projectId);
function isValidProjectId(availableProjects: ProjectSharingData[], projectId: string) {
return availableProjects.some((project) => project.id === projectId);
}
const setFiltersFromQueryString = async () => {
@ -263,8 +257,10 @@ const setFiltersFromQueryString = async () => {
const filtersToApply: { [key: string]: string | string[] | boolean } = {};
if (homeProject && typeof homeProject === 'string') {
await projectsStore.getAvailableProjects();
if (isValidProjectId(homeProject)) {
const available = await projectsStore.getAvailableProjects();
console.log('setting home project', homeProject);
if (isValidProjectId(available, homeProject)) {
console.log('valid home project', homeProject);
filtersToApply.homeProject = homeProject;
}
}
@ -307,9 +303,10 @@ watch(
async () => await initialize(),
);
onBeforeMount(async () => {});
onMounted(async () => {
documentTitle.set(i18n.baseText('workflows.heading'));
await setFiltersFromQueryString();
void usersStore.showPersonalizationSurvey();
});
</script>
@ -319,7 +316,6 @@ onMounted(async () => {
resource-key="workflows"
:resources="allWorkflows"
:filters="filters"
:additional-filters-handler="onFilter"
:type-props="{ itemSize: 80 }"
:shareable="isShareable"
:initialize="initialize"