mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
fix: Filter source control credentials by project (#16732)
This commit is contained in:
committed by
GitHub
parent
1934e6fc0f
commit
0debbc3503
@@ -82,6 +82,7 @@
|
|||||||
"generic.upgrade": "Upgrade",
|
"generic.upgrade": "Upgrade",
|
||||||
"generic.upgradeNow": "Upgrade now",
|
"generic.upgradeNow": "Upgrade now",
|
||||||
"generic.credential": "Credential | {count} Credential | {count} Credentials",
|
"generic.credential": "Credential | {count} Credential | {count} Credentials",
|
||||||
|
"generic.credentials": "Credentials",
|
||||||
"generic.workflow": "Workflow | {count} Workflow | {count} Workflows",
|
"generic.workflow": "Workflow | {count} Workflow | {count} Workflows",
|
||||||
"generic.workflowSaved": "Workflow changes saved",
|
"generic.workflowSaved": "Workflow changes saved",
|
||||||
"generic.editor": "Editor",
|
"generic.editor": "Editor",
|
||||||
@@ -2188,6 +2189,7 @@
|
|||||||
"settings.sourceControl.modals.push.description": "The following will be committed: ",
|
"settings.sourceControl.modals.push.description": "The following will be committed: ",
|
||||||
"settings.sourceControl.modals.push.description.learnMore": "More info",
|
"settings.sourceControl.modals.push.description.learnMore": "More info",
|
||||||
"settings.sourceControl.modals.push.filesToCommit": "Files to commit",
|
"settings.sourceControl.modals.push.filesToCommit": "Files to commit",
|
||||||
|
"settings.sourceControl.modals.push.filter": "Filters are applied. Showing {count} {entity}.",
|
||||||
"settings.sourceControl.modals.push.workflowsToCommit": "Select workflows",
|
"settings.sourceControl.modals.push.workflowsToCommit": "Select workflows",
|
||||||
"settings.sourceControl.modals.push.everythingIsUpToDate": "Everything is up to date",
|
"settings.sourceControl.modals.push.everythingIsUpToDate": "Everything is up to date",
|
||||||
"settings.sourceControl.modals.push.noWorkflowChanges": "There are no workflow changes but the following will be committed: {link}",
|
"settings.sourceControl.modals.push.noWorkflowChanges": "There are no workflow changes but the following will be committed: {link}",
|
||||||
@@ -2198,6 +2200,7 @@
|
|||||||
"settings.sourceControl.modals.push.buttons.save": "Commit and push",
|
"settings.sourceControl.modals.push.buttons.save": "Commit and push",
|
||||||
"settings.sourceControl.modals.push.success.title": "Pushed successfully",
|
"settings.sourceControl.modals.push.success.title": "Pushed successfully",
|
||||||
"settings.sourceControl.modals.push.success.description": "were committed and pushed to your remote repository",
|
"settings.sourceControl.modals.push.success.description": "were committed and pushed to your remote repository",
|
||||||
|
"settings.sourceControl.modals.push.projectAdmin.callout": "If you want to push workflows from your personal space, move then to a project first.",
|
||||||
"settings.sourceControl.status.modified": "Modified",
|
"settings.sourceControl.status.modified": "Modified",
|
||||||
"settings.sourceControl.status.deleted": "Deleted",
|
"settings.sourceControl.status.deleted": "Deleted",
|
||||||
"settings.sourceControl.status.created": "New",
|
"settings.sourceControl.status.created": "New",
|
||||||
|
|||||||
@@ -323,7 +323,6 @@ describe('SourceControlPushModal', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show credentials in a different tab', async () => {
|
it('should show credentials in a different tab', async () => {
|
||||||
// source-control-push-modal-tab
|
|
||||||
const status: SourceControlledFile[] = [
|
const status: SourceControlledFile[] = [
|
||||||
{
|
{
|
||||||
id: 'gTbbBkkYTnNyX1jD',
|
id: 'gTbbBkkYTnNyX1jD',
|
||||||
@@ -486,15 +485,18 @@ describe('SourceControlPushModal', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter by project', async () => {
|
test.each([
|
||||||
|
['credential', 'Credentials'],
|
||||||
|
['workflow', 'Workflows'],
|
||||||
|
])('should filter %s by project', async (entity, name) => {
|
||||||
const projectsStore = mockedStore(useProjectsStore);
|
const projectsStore = mockedStore(useProjectsStore);
|
||||||
projectsStore.availableProjects = projects as unknown as ProjectListItem[];
|
projectsStore.availableProjects = projects as unknown as ProjectListItem[];
|
||||||
|
|
||||||
const status: SourceControlledFile[] = [
|
const status: SourceControlledFile[] = [
|
||||||
{
|
{
|
||||||
id: 'gTbbBkkYTnNyX1jD',
|
id: 'gTbbBkkYTnNyX1jD',
|
||||||
name: 'My workflow 1',
|
name: `My ${name} 1`,
|
||||||
type: 'workflow',
|
type: entity as SourceControlledFile['type'],
|
||||||
status: 'created',
|
status: 'created',
|
||||||
location: 'local',
|
location: 'local',
|
||||||
conflict: false,
|
conflict: false,
|
||||||
@@ -508,8 +510,8 @@ describe('SourceControlPushModal', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'JIGKevgZagmJAnM6',
|
id: 'JIGKevgZagmJAnM6',
|
||||||
name: 'My workflow 2',
|
name: `My ${name} 1`,
|
||||||
type: 'workflow',
|
type: entity as SourceControlledFile['type'],
|
||||||
status: 'created',
|
status: 'created',
|
||||||
location: 'local',
|
location: 'local',
|
||||||
conflict: false,
|
conflict: false,
|
||||||
@@ -532,6 +534,12 @@ describe('SourceControlPushModal', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tab = getAllByTestId('source-control-push-modal-tab').filter(({ textContent }) =>
|
||||||
|
textContent?.includes(name),
|
||||||
|
);
|
||||||
|
|
||||||
|
await userEvent.click(tab[0]);
|
||||||
|
|
||||||
expect(getAllByTestId('source-control-push-modal-file-checkbox')).toHaveLength(2);
|
expect(getAllByTestId('source-control-push-modal-file-checkbox')).toHaveLength(2);
|
||||||
|
|
||||||
await userEvent.click(getByTestId('source-control-filter-dropdown'));
|
await userEvent.click(getByTestId('source-control-filter-dropdown'));
|
||||||
@@ -545,6 +553,9 @@ describe('SourceControlPushModal', () => {
|
|||||||
await userEvent.click(getAllByTestId('project-sharing-info')[0]);
|
await userEvent.click(getAllByTestId('project-sharing-info')[0]);
|
||||||
|
|
||||||
expect(getAllByTestId('source-control-push-modal-file-checkbox')).toHaveLength(1);
|
expect(getAllByTestId('source-control-push-modal-file-checkbox')).toHaveLength(1);
|
||||||
|
expect(getByTestId('source-control-push-modal-file-checkbox')).toHaveTextContent(
|
||||||
|
`My ${name} 1`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reset', async () => {
|
it('should reset', async () => {
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import { useLoadingService } from '@/composables/useLoadingService';
|
|||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import { SOURCE_CONTROL_PUSH_MODAL_KEY, VIEWS } from '@/constants';
|
import { SOURCE_CONTROL_PUSH_MODAL_KEY, VIEWS } from '@/constants';
|
||||||
|
import type { WorkflowResource } from '@/Interface';
|
||||||
import { useProjectsStore } from '@/stores/projects.store';
|
import { useProjectsStore } from '@/stores/projects.store';
|
||||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
import type { ProjectListItem, ProjectSharingData } from '@/types/projects.types';
|
import type { ProjectListItem, ProjectSharingData } from '@/types/projects.types';
|
||||||
import { ResourceType } from '@/utils/projects.utils';
|
import { ResourceType } from '@/utils/projects.utils';
|
||||||
import { getPushPriorityByStatus, getStatusText, getStatusTheme } from '@/utils/sourceControlUtils';
|
import { getPushPriorityByStatus, getStatusText, getStatusTheme } from '@/utils/sourceControlUtils';
|
||||||
|
import type { SourceControlledFile } from '@n8n/api-types';
|
||||||
import {
|
import {
|
||||||
type SourceControlledFile,
|
ROLE,
|
||||||
SOURCE_CONTROL_FILE_LOCATION,
|
SOURCE_CONTROL_FILE_LOCATION,
|
||||||
SOURCE_CONTROL_FILE_STATUS,
|
SOURCE_CONTROL_FILE_STATUS,
|
||||||
SOURCE_CONTROL_FILE_TYPE,
|
SOURCE_CONTROL_FILE_TYPE,
|
||||||
@@ -19,6 +22,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
N8nBadge,
|
N8nBadge,
|
||||||
N8nButton,
|
N8nButton,
|
||||||
|
N8nCallout,
|
||||||
N8nHeading,
|
N8nHeading,
|
||||||
N8nIcon,
|
N8nIcon,
|
||||||
N8nInput,
|
N8nInput,
|
||||||
@@ -32,7 +36,7 @@ import {
|
|||||||
} from '@n8n/design-system';
|
} from '@n8n/design-system';
|
||||||
import { useI18n } from '@n8n/i18n';
|
import { useI18n } from '@n8n/i18n';
|
||||||
import type { EventBus } from '@n8n/utils/event-bus';
|
import type { EventBus } from '@n8n/utils/event-bus';
|
||||||
import { refDebounced } from '@vueuse/core';
|
import { refDebounced, useStorage } from '@vueuse/core';
|
||||||
import dateformat from 'dateformat';
|
import dateformat from 'dateformat';
|
||||||
import orderBy from 'lodash/orderBy';
|
import orderBy from 'lodash/orderBy';
|
||||||
import { computed, onBeforeMount, onMounted, reactive, ref, toRaw, watch } from 'vue';
|
import { computed, onBeforeMount, onMounted, reactive, ref, toRaw, watch } from 'vue';
|
||||||
@@ -40,7 +44,6 @@ import { useRoute } from 'vue-router';
|
|||||||
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller';
|
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller';
|
||||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
|
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
|
||||||
import Modal from './Modal.vue';
|
import Modal from './Modal.vue';
|
||||||
import { type WorkflowResource } from '@/Interface';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
data: { eventBus: EventBus; status: SourceControlledFile[] };
|
data: { eventBus: EventBus; status: SourceControlledFile[] };
|
||||||
@@ -54,11 +57,25 @@ const sourceControlStore = useSourceControlStore();
|
|||||||
const projectsStore = useProjectsStore();
|
const projectsStore = useProjectsStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
const usersStore = useUsersStore();
|
||||||
|
|
||||||
|
const projectAdminCalloutDismissed = useStorage(
|
||||||
|
'SOURCE_CONTROL_PROJECT_ADMIN_CALLOUT_DISMISSED',
|
||||||
|
false,
|
||||||
|
localStorage,
|
||||||
|
);
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
void projectsStore.getAvailableProjects();
|
void projectsStore.getAvailableProjects();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const projectsForFilters = computed(() => {
|
||||||
|
return projectsStore.availableProjects.filter(
|
||||||
|
// global admins role is empty...
|
||||||
|
(project) => !project.role || project.role === 'project:admin',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const concatenateWithAnd = (messages: string[]) =>
|
const concatenateWithAnd = (messages: string[]) =>
|
||||||
new Intl.ListFormat(i18n.locale, { style: 'long', type: 'conjunction' }).format(messages);
|
new Intl.ListFormat(i18n.locale, { style: 'long', type: 'conjunction' }).format(messages);
|
||||||
|
|
||||||
@@ -172,11 +189,31 @@ const maybeSelectCurrentWorkflow = (workflow?: SourceControlledFileWithProject)
|
|||||||
|
|
||||||
onMounted(() => maybeSelectCurrentWorkflow(changes.value.currentWorkflow));
|
onMounted(() => maybeSelectCurrentWorkflow(changes.value.currentWorkflow));
|
||||||
|
|
||||||
|
const currentProject = computed(() => {
|
||||||
|
if (!route.params.projectId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = projectsStore.availableProjects.find(
|
||||||
|
(project) => project.id === route.params.projectId?.toString(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!project) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!project.role || project.role === 'project:admin') {
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
const filters = ref<{ status?: SourceControlledFileStatus; project: ProjectSharingData | null }>({
|
const filters = ref<{ status?: SourceControlledFileStatus; project: ProjectSharingData | null }>({
|
||||||
project: null,
|
project: currentProject.value,
|
||||||
});
|
});
|
||||||
const filtersApplied = computed(
|
const filtersApplied = computed(
|
||||||
() => Boolean(search.value) || Boolean(Object.keys(filters.value).length),
|
() => Boolean(search.value) || Boolean(Object.values(filters.value).filter(Boolean).length),
|
||||||
);
|
);
|
||||||
const resetFilters = () => {
|
const resetFilters = () => {
|
||||||
filters.value = { project: null };
|
filters.value = { project: null };
|
||||||
@@ -244,6 +281,10 @@ const filteredCredentials = computed(() => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (credential.project && filters.value.project) {
|
||||||
|
return credential.project.id === filters.value.project.id;
|
||||||
|
}
|
||||||
|
|
||||||
return !(filters.value.status && filters.value.status !== credential.status);
|
return !(filters.value.status && filters.value.status !== credential.status);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -417,6 +458,10 @@ const allVisibleItemsSelected = computed(() => {
|
|||||||
|
|
||||||
if (activeTab.value === SOURCE_CONTROL_FILE_TYPE.workflow) {
|
if (activeTab.value === SOURCE_CONTROL_FILE_TYPE.workflow) {
|
||||||
const workflowsSet = new Set(sortedWorkflows.value.map(({ id }) => id));
|
const workflowsSet = new Set(sortedWorkflows.value.map(({ id }) => id));
|
||||||
|
|
||||||
|
if (!workflowsSet.size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const notSelectedVisibleItems = workflowsSet.difference(toRaw(activeSelection.value));
|
const notSelectedVisibleItems = workflowsSet.difference(toRaw(activeSelection.value));
|
||||||
|
|
||||||
return !Boolean(notSelectedVisibleItems.size);
|
return !Boolean(notSelectedVisibleItems.size);
|
||||||
@@ -424,6 +469,9 @@ const allVisibleItemsSelected = computed(() => {
|
|||||||
|
|
||||||
if (activeTab.value === SOURCE_CONTROL_FILE_TYPE.credential) {
|
if (activeTab.value === SOURCE_CONTROL_FILE_TYPE.credential) {
|
||||||
const credentialsSet = new Set(sortedCredentials.value.map(({ id }) => id));
|
const credentialsSet = new Set(sortedCredentials.value.map(({ id }) => id));
|
||||||
|
if (!credentialsSet.size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const notSelectedVisibleItems = credentialsSet.difference(toRaw(activeSelection.value));
|
const notSelectedVisibleItems = credentialsSet.difference(toRaw(activeSelection.value));
|
||||||
|
|
||||||
return !Boolean(notSelectedVisibleItems.size);
|
return !Boolean(notSelectedVisibleItems.size);
|
||||||
@@ -460,6 +508,14 @@ const activeDataSourceFiltered = computed(() => {
|
|||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const activeEntityLocale = computed(() => {
|
||||||
|
if (activeTab.value === SOURCE_CONTROL_FILE_TYPE.workflow) {
|
||||||
|
return 'generic.workflows';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'generic.credentials';
|
||||||
|
});
|
||||||
|
|
||||||
const activeSelection = computed(() => {
|
const activeSelection = computed(() => {
|
||||||
if (activeTab.value === SOURCE_CONTROL_FILE_TYPE.workflow) {
|
if (activeTab.value === SOURCE_CONTROL_FILE_TYPE.workflow) {
|
||||||
return selectedWorkflows;
|
return selectedWorkflows;
|
||||||
@@ -487,11 +543,11 @@ const tabs = computed(() => {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
const filtersActiveText = computed(() => {
|
const filtersNoResultText = computed(() => {
|
||||||
if (activeTab.value === SOURCE_CONTROL_FILE_TYPE.workflow) {
|
if (activeTab.value === SOURCE_CONTROL_FILE_TYPE.workflow) {
|
||||||
return i18n.baseText('workflows.filters.active');
|
return i18n.baseText('workflows.noResults');
|
||||||
}
|
}
|
||||||
return i18n.baseText('credentials.filters.active');
|
return i18n.baseText('credentials.noResults');
|
||||||
});
|
});
|
||||||
|
|
||||||
function castType(type: string): ResourceType {
|
function castType(type: string): ResourceType {
|
||||||
@@ -519,7 +575,11 @@ function castProject(project: ProjectListItem) {
|
|||||||
{{ i18n.baseText('settings.sourceControl.modals.push.title') }}
|
{{ i18n.baseText('settings.sourceControl.modals.push.title') }}
|
||||||
</N8nHeading>
|
</N8nHeading>
|
||||||
|
|
||||||
<div v-if="changes.workflow.length" :class="[$style.filtersRow]" class="mt-l">
|
<div
|
||||||
|
v-if="changes.workflow.length || changes.credential.length"
|
||||||
|
:class="[$style.filtersRow]"
|
||||||
|
class="mt-l"
|
||||||
|
>
|
||||||
<div :class="[$style.filters]">
|
<div :class="[$style.filters]">
|
||||||
<N8nInput
|
<N8nInput
|
||||||
v-model="search"
|
v-model="search"
|
||||||
@@ -576,7 +636,7 @@ function castProject(project: ProjectListItem) {
|
|||||||
<ProjectSharing
|
<ProjectSharing
|
||||||
v-model="filters.project"
|
v-model="filters.project"
|
||||||
data-test-id="source-control-push-modal-project-search"
|
data-test-id="source-control-push-modal-project-search"
|
||||||
:projects="projectsStore.availableProjects"
|
:projects="projectsForFilters"
|
||||||
:placeholder="i18n.baseText('forms.resourceFiltersDropdown.owner.placeholder')"
|
:placeholder="i18n.baseText('forms.resourceFiltersDropdown.owner.placeholder')"
|
||||||
:empty-options-text="i18n.baseText('projects.sharing.noMatchingProjects')"
|
:empty-options-text="i18n.baseText('projects.sharing.noMatchingProjects')"
|
||||||
/>
|
/>
|
||||||
@@ -588,6 +648,26 @@ function castProject(project: ProjectListItem) {
|
|||||||
</N8nPopover>
|
</N8nPopover>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<template v-if="usersStore.currentUser && usersStore.currentUser.role">
|
||||||
|
<template
|
||||||
|
v-if="
|
||||||
|
usersStore.currentUser.role !== ROLE.Owner && usersStore.currentUser.role !== ROLE.Admin
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<N8nCallout theme="secondary" class="mt-s" v-if="!projectAdminCalloutDismissed">
|
||||||
|
{{ i18n.baseText('settings.sourceControl.modals.push.projectAdmin.callout') }}
|
||||||
|
<template #trailingContent>
|
||||||
|
<N8nIcon
|
||||||
|
icon="times"
|
||||||
|
title="Dismiss"
|
||||||
|
size="medium"
|
||||||
|
type="secondary"
|
||||||
|
@click="projectAdminCalloutDismissed = true"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</N8nCallout>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div style="display: flex; height: 100%">
|
<div style="display: flex; height: 100%">
|
||||||
@@ -614,18 +694,25 @@ function castProject(project: ProjectListItem) {
|
|||||||
:indeterminate="selectAllIndeterminate"
|
:indeterminate="selectAllIndeterminate"
|
||||||
:model-value="allVisibleItemsSelected"
|
:model-value="allVisibleItemsSelected"
|
||||||
data-test-id="source-control-push-modal-toggle-all"
|
data-test-id="source-control-push-modal-toggle-all"
|
||||||
|
:disabled="activeDataSourceFiltered.length === 0"
|
||||||
@update:model-value="onToggleSelectAll"
|
@update:model-value="onToggleSelectAll"
|
||||||
>
|
>
|
||||||
<N8nText> Title </N8nText>
|
<N8nText> Title </N8nText>
|
||||||
</N8nCheckbox>
|
</N8nCheckbox>
|
||||||
</div>
|
|
||||||
<div style="flex: 1; overflow: hidden">
|
|
||||||
<N8nInfoTip
|
<N8nInfoTip
|
||||||
v-if="filtersApplied && activeDataSource.length && !activeDataSourceFiltered.length"
|
v-if="filtersApplied"
|
||||||
class="p-xs"
|
class="p-xs"
|
||||||
:bold="false"
|
:bold="false"
|
||||||
|
:class="$style.filtersApplied"
|
||||||
>
|
>
|
||||||
{{ filtersActiveText }}
|
{{
|
||||||
|
i18n.baseText('settings.sourceControl.modals.push.filter', {
|
||||||
|
interpolate: {
|
||||||
|
count: `${activeDataSourceFiltered.length} / ${activeDataSource.length}`,
|
||||||
|
entity: i18n.baseText(activeEntityLocale).toLowerCase(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}}
|
||||||
<N8nLink
|
<N8nLink
|
||||||
size="small"
|
size="small"
|
||||||
data-test-id="source-control-filters-reset"
|
data-test-id="source-control-filters-reset"
|
||||||
@@ -634,6 +721,11 @@ function castProject(project: ProjectListItem) {
|
|||||||
{{ i18n.baseText('workflows.filters.active.reset') }}
|
{{ i18n.baseText('workflows.filters.active.reset') }}
|
||||||
</N8nLink>
|
</N8nLink>
|
||||||
</N8nInfoTip>
|
</N8nInfoTip>
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1; overflow: hidden">
|
||||||
|
<N8nInfoTip v-if="!activeDataSourceFiltered.length" class="p-xs" :bold="false">
|
||||||
|
{{ filtersNoResultText }}
|
||||||
|
</N8nInfoTip>
|
||||||
<DynamicScroller
|
<DynamicScroller
|
||||||
v-if="activeDataSourceFiltered.length"
|
v-if="activeDataSourceFiltered.length"
|
||||||
:class="[$style.scroller]"
|
:class="[$style.scroller]"
|
||||||
@@ -784,6 +876,11 @@ function castProject(project: ProjectListItem) {
|
|||||||
.selectAll {
|
.selectAll {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
padding: 10px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filtersApplied {
|
||||||
|
border-top: var(--border-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroller {
|
.scroller {
|
||||||
@@ -863,7 +960,8 @@ function castProject(project: ProjectListItem) {
|
|||||||
|
|
||||||
.tableHeader {
|
.tableHeader {
|
||||||
border-bottom: var(--border-base);
|
border-bottom: var(--border-base);
|
||||||
padding: 10px 16px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
|
|||||||
Reference in New Issue
Block a user