mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
feat(editor): Add breadcrumbs to project card badges (no-changelog) (#14256)
This commit is contained in:
committed by
GitHub
parent
beb0dcabea
commit
bfe3d469ea
@@ -514,7 +514,7 @@ describe('Projects', { disableAutoLogin: true }, () => {
|
||||
workflowsPage.getters.workflowCards().should('have.length', 3);
|
||||
workflowsPage.getters
|
||||
.workflowCards()
|
||||
.filter(':has([data-test-id="workflow-card-breadcrumbs"]:contains("Project"))')
|
||||
.filter(':has([data-test-id="card-badge"]:contains("Project"))')
|
||||
.should('have.length', 2);
|
||||
workflowsPage.getters.workflowCardActions('Workflow in Home project').click();
|
||||
workflowsPage.getters.workflowMoveButton().click();
|
||||
|
||||
@@ -17,6 +17,7 @@ interface BadgeProps {
|
||||
theme?: (typeof THEME)[number];
|
||||
size?: TextSize;
|
||||
bold?: boolean;
|
||||
showBorder?: boolean;
|
||||
}
|
||||
|
||||
defineOptions({ name: 'N8nBadge' });
|
||||
@@ -24,11 +25,12 @@ withDefaults(defineProps<BadgeProps>(), {
|
||||
theme: 'default',
|
||||
size: 'small',
|
||||
bold: false,
|
||||
showBorder: true,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span :class="['n8n-badge', $style[theme]]">
|
||||
<span :class="['n8n-badge', { [$style[theme]]: true, [$style.border]: showBorder }]">
|
||||
<N8nText :size="size" :bold="bold" :compact="true">
|
||||
<slot></slot>
|
||||
</N8nText>
|
||||
@@ -40,8 +42,11 @@ withDefaults(defineProps<BadgeProps>(), {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing-5xs) var(--spacing-4xs);
|
||||
border: var(--border-base);
|
||||
white-space: nowrap;
|
||||
|
||||
&.border {
|
||||
border: var(--border-base);
|
||||
}
|
||||
}
|
||||
|
||||
.default {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`components > N8nBadge > props > should render default theme correctly 1`] = `"<span class="n8n-badge default"><n8n-text-stub bold="true" size="large" compact="true" tag="span"></n8n-text-stub></span>"`;
|
||||
exports[`components > N8nBadge > props > should render default theme correctly 1`] = `"<span class="n8n-badge default border"><n8n-text-stub bold="true" size="large" compact="true" tag="span"></n8n-text-stub></span>"`;
|
||||
|
||||
exports[`components > N8nBadge > props > should render secondary theme correctly 1`] = `"<span class="n8n-badge secondary"><n8n-text-stub bold="false" size="medium" compact="true" tag="span"></n8n-text-stub></span>"`;
|
||||
exports[`components > N8nBadge > props > should render secondary theme correctly 1`] = `"<span class="n8n-badge secondary border"><n8n-text-stub bold="false" size="medium" compact="true" tag="span"></n8n-text-stub></span>"`;
|
||||
|
||||
exports[`components > N8nBadge > props > should render with default values correctly 1`] = `"<span class="n8n-badge default"><n8n-text-stub bold="false" size="small" compact="true" tag="span"></n8n-text-stub></span>"`;
|
||||
exports[`components > N8nBadge > props > should render with default values correctly 1`] = `"<span class="n8n-badge default border"><n8n-text-stub bold="false" size="small" compact="true" tag="span"></n8n-text-stub></span>"`;
|
||||
|
||||
@@ -274,8 +274,8 @@ describe('Breadcrumbs', async () => {
|
||||
{ id: '4', label: 'Current' },
|
||||
];
|
||||
const hiddenItems = [
|
||||
{ id: '3', label: 'Parent 1', href: '/hidden1' },
|
||||
{ id: '4', label: 'Parent 2', href: '/hidden2' },
|
||||
{ id: '5', label: 'Parent 1', href: '/hidden1' },
|
||||
{ id: '6', label: 'Parent 2', href: '/hidden2' },
|
||||
];
|
||||
|
||||
const { container, emitted, getByTestId, getAllByTestId } = render(Breadcrumbs, {
|
||||
|
||||
@@ -113,7 +113,7 @@ const onHiddenMenuVisibleChange = async (visible: boolean) => {
|
||||
};
|
||||
|
||||
const emitItemSelected = (id: string) => {
|
||||
const item = [...loadedHiddenItems.value, ...props.items].find((i) => i.id === id);
|
||||
const item = [...props.items, ...loadedHiddenItems.value].find((i) => i.id === id);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
@@ -135,6 +135,7 @@ const handleTooltipClose = () => {
|
||||
[$style.container]: true,
|
||||
[$style.border]: props.showBorder,
|
||||
[$style[props.theme]]: true,
|
||||
['n8n-breadcrumbs']: true,
|
||||
}"
|
||||
>
|
||||
<slot name="prepend"></slot>
|
||||
@@ -355,7 +356,6 @@ const handleTooltipClose = () => {
|
||||
.item * {
|
||||
color: var(--color-text-base);
|
||||
font-size: var(--font-size-2xs);
|
||||
font-weight: var(--font-weight-bold);
|
||||
line-height: var(--font-line-heigh-xsmall);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`Breadcrumbs > does not highlight last item for "highlightLastItem = false" 1`] = `
|
||||
"<div class="container medium">
|
||||
"<div class="container medium n8n-breadcrumbs">
|
||||
<ul class="list">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
@@ -19,7 +19,7 @@ exports[`Breadcrumbs > does not highlight last item for "highlightLastItem = fal
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs > renders custom separator correctly 1`] = `
|
||||
"<div class="container medium">
|
||||
"<div class="container medium n8n-breadcrumbs">
|
||||
<ul class="list">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
@@ -37,7 +37,7 @@ exports[`Breadcrumbs > renders custom separator correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs > renders default version correctly 1`] = `
|
||||
"<div class="container medium">
|
||||
"<div class="container medium n8n-breadcrumbs">
|
||||
<ul class="list">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
@@ -55,7 +55,7 @@ exports[`Breadcrumbs > renders default version correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs > renders slots correctly 1`] = `
|
||||
"<div class="container medium">
|
||||
"<div class="container medium n8n-breadcrumbs">
|
||||
<div>[PRE] Custom content</div>
|
||||
<ul class="list">
|
||||
<li class="separator">/</li>
|
||||
@@ -75,7 +75,7 @@ exports[`Breadcrumbs > renders slots correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs > renders small version correctly 1`] = `
|
||||
"<div class="container small">
|
||||
"<div class="container small n8n-breadcrumbs">
|
||||
<ul class="list">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
import { computed } from 'vue';
|
||||
import { FOLDER_LIST_ITEM_ACTIONS } from './constants';
|
||||
import type { FolderResource } from '../layouts/ResourcesListLayout.vue';
|
||||
import { type ProjectIcon, ProjectTypes } from '@/types/projects.types';
|
||||
import type { Project } from '@/types/projects.types';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { VIEWS } from '@/constants';
|
||||
import type { UserAction } from '@/Interface';
|
||||
import { ResourceType } from '@/utils/projects.utils';
|
||||
|
||||
type Props = {
|
||||
data: FolderResource;
|
||||
personalProject: Project | null;
|
||||
actions: UserAction[];
|
||||
readOnly?: boolean;
|
||||
};
|
||||
@@ -28,22 +30,7 @@ const emit = defineEmits<{
|
||||
folderOpened: [{ folder: FolderResource }];
|
||||
}>();
|
||||
|
||||
const projectIcon = computed<ProjectIcon>(() => {
|
||||
const defaultIcon: ProjectIcon = { type: 'icon', value: 'layer-group' };
|
||||
if (props.data.homeProject?.type === ProjectTypes.Personal) {
|
||||
return { type: 'icon', value: 'user' };
|
||||
} else if (props.data.homeProject?.type === ProjectTypes.Team) {
|
||||
return props.data.homeProject.icon ?? defaultIcon;
|
||||
}
|
||||
return defaultIcon;
|
||||
});
|
||||
|
||||
const projectName = computed(() => {
|
||||
if (props.data.homeProject?.type === ProjectTypes.Personal) {
|
||||
return i18n.baseText('projects.menu.personal');
|
||||
}
|
||||
return props.data.homeProject?.name;
|
||||
});
|
||||
const resourceTypeLabel = computed(() => i18n.baseText('generic.folder').toLowerCase());
|
||||
|
||||
const cardUrl = computed(() => {
|
||||
return getFolderUrl(props.data.id);
|
||||
@@ -112,7 +99,11 @@ const onAction = async (action: string) => {
|
||||
:class="[$style['info-cell'], $style['info-cell--workflow-count']]"
|
||||
data-test-id="folder-card-workflow-count"
|
||||
>
|
||||
{{ i18n.baseText('generic.folder', { interpolate: { count: data.subFolderCount } }) }}
|
||||
{{
|
||||
i18n.baseText('generic.folderCount', {
|
||||
interpolate: { count: data.subFolderCount },
|
||||
})
|
||||
}}
|
||||
</n8n-text>
|
||||
<n8n-text
|
||||
size="small"
|
||||
@@ -137,14 +128,14 @@ const onAction = async (action: string) => {
|
||||
<template #append>
|
||||
<div :class="$style['card-actions']" @click.prevent>
|
||||
<div v-if="data.homeProject" :class="$style['project-pill']">
|
||||
<div :class="$style['home-project']" data-test-id="folder-card-home-project">
|
||||
<n8n-link :to="`/projects/${data.homeProject.id}`">
|
||||
<ProjectIcon :icon="projectIcon" :border-less="true" size="mini" />
|
||||
<n8n-text size="small" :compact="true" :bold="true" color="text-base">
|
||||
{{ projectName }}
|
||||
</n8n-text>
|
||||
</n8n-link>
|
||||
</div>
|
||||
<ProjectCardBadge
|
||||
:class="{ [$style.cardBadge]: true, [$style['with-breadcrumbs']]: false }"
|
||||
:resource="data"
|
||||
:resource-type="ResourceType.Workflow"
|
||||
:resource-type-label="resourceTypeLabel"
|
||||
:personal-project="personalProject"
|
||||
:show-badge-border="true"
|
||||
/>
|
||||
</div>
|
||||
<n8n-action-toggle
|
||||
v-if="actions.length"
|
||||
@@ -205,21 +196,6 @@ const onAction = async (action: string) => {
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.project-pill {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing-4xs) var(--spacing-2xs);
|
||||
border: var(--border-base);
|
||||
border-radius: var(--border-radius-base);
|
||||
}
|
||||
|
||||
.home-project span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-3xs);
|
||||
color: var(—color-text-base);
|
||||
}
|
||||
|
||||
@include mixins.breakpoint('sm-and-down') {
|
||||
.card {
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -2,7 +2,15 @@ import { createComponentRenderer } from '@/__tests__/render';
|
||||
import ProjectCardBadge from '@/components/Projects/ProjectCardBadge.vue';
|
||||
import { truncate } from '@n8n/utils/string/truncate';
|
||||
|
||||
const renderComponent = createComponentRenderer(ProjectCardBadge);
|
||||
const renderComponent = createComponentRenderer(ProjectCardBadge, {
|
||||
global: {
|
||||
stubs: {
|
||||
'router-link': {
|
||||
template: '<div><slot /></div>',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
describe('ProjectCardBadge', () => {
|
||||
it('should show "Personal" badge if there is no homeProject', () => {
|
||||
@@ -52,7 +60,7 @@ describe('ProjectCardBadge', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(getByText('+ 3')).toBeVisible();
|
||||
expect(getByText('+3')).toBeVisible();
|
||||
});
|
||||
|
||||
test.each([
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import type { ResourceType } from '@/utils/projects.utils';
|
||||
import { ResourceType } from '@/utils/projects.utils';
|
||||
import { splitName } from '@/utils/projects.utils';
|
||||
import type { Project, ProjectIcon as BadgeIcon } from '@/types/projects.types';
|
||||
import { ProjectTypes } from '@/types/projects.types';
|
||||
import type { CredentialsResource, WorkflowResource } from '../layouts/ResourcesListLayout.vue';
|
||||
import type {
|
||||
CredentialsResource,
|
||||
FolderResource,
|
||||
WorkflowResource,
|
||||
} from '../layouts/ResourcesListLayout.vue';
|
||||
import { VIEWS } from '@/constants';
|
||||
|
||||
type Props = {
|
||||
resource: WorkflowResource | CredentialsResource;
|
||||
resource: WorkflowResource | CredentialsResource | FolderResource;
|
||||
resourceType: ResourceType;
|
||||
resourceTypeLabel: string;
|
||||
personalProject: Project | null;
|
||||
showBadgeBorder?: boolean;
|
||||
};
|
||||
|
||||
const enum ProjectState {
|
||||
@@ -24,7 +30,9 @@ const enum ProjectState {
|
||||
Unknown = 'unknown',
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
showBadgeBorder: true,
|
||||
});
|
||||
|
||||
const i18n = useI18n();
|
||||
|
||||
@@ -68,10 +76,13 @@ const badgeText = computed(() => {
|
||||
return name ?? email ?? '';
|
||||
}
|
||||
});
|
||||
|
||||
const badgeIcon = computed<BadgeIcon>(() => {
|
||||
switch (projectState.value) {
|
||||
case ProjectState.Owned:
|
||||
case ProjectState.SharedOwned:
|
||||
case ProjectState.Personal:
|
||||
case ProjectState.SharedPersonal:
|
||||
return { type: 'icon', value: 'user' };
|
||||
case ProjectState.Team:
|
||||
case ProjectState.SharedTeam:
|
||||
@@ -123,38 +134,68 @@ const badgeTooltip = computed(() => {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
const projectLocation = computed(() => {
|
||||
if (
|
||||
projectState.value !== ProjectState.Personal &&
|
||||
projectState.value !== ProjectState.SharedPersonal &&
|
||||
props.resource.homeProject?.id &&
|
||||
props.resourceType === ResourceType.Workflow
|
||||
) {
|
||||
return {
|
||||
name: VIEWS.PROJECTS_WORKFLOWS,
|
||||
params: { projectId: props.resource.homeProject.id },
|
||||
};
|
||||
}
|
||||
return null;
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<N8nTooltip :disabled="!badgeTooltip" placement="top">
|
||||
<div :class="$style.wrapper" v-bind="$attrs">
|
||||
<div :class="{ [$style.wrapper]: true, [$style['no-border']]: showBadgeBorder }" v-bind="$attrs">
|
||||
<N8nTooltip :disabled="!badgeTooltip || numberOfMembersInHomeTeamProject !== 0" placement="top">
|
||||
<N8nBadge
|
||||
v-if="badgeText"
|
||||
:class="[$style.badge, $style.projectBadge]"
|
||||
theme="tertiary"
|
||||
bold
|
||||
data-test-id="card-badge"
|
||||
:show-border="showBadgeBorder"
|
||||
>
|
||||
<ProjectIcon :icon="badgeIcon" :border-less="true" size="mini" />
|
||||
<span v-n8n-truncate:20>{{ badgeText }}</span>
|
||||
<router-link v-if="projectLocation" :to="projectLocation">
|
||||
<span v-n8n-truncate:20>{{ badgeText }}</span>
|
||||
</router-link>
|
||||
<span v-else v-n8n-truncate:20>{{ badgeText }}</span>
|
||||
</N8nBadge>
|
||||
<N8nBadge
|
||||
<template #content>
|
||||
{{ badgeTooltip }}
|
||||
</template>
|
||||
</N8nTooltip>
|
||||
<slot />
|
||||
<N8nTooltip :disabled="!badgeTooltip || numberOfMembersInHomeTeamProject === 0" placement="top">
|
||||
<div
|
||||
v-if="numberOfMembersInHomeTeamProject"
|
||||
:class="[$style.badge, $style.countBadge]"
|
||||
:class="$style['count-badge']"
|
||||
theme="tertiary"
|
||||
bold
|
||||
>
|
||||
+ {{ numberOfMembersInHomeTeamProject }}
|
||||
</N8nBadge>
|
||||
</div>
|
||||
<template #content>
|
||||
{{ badgeTooltip }}
|
||||
</template>
|
||||
</N8nTooltip>
|
||||
+{{ numberOfMembersInHomeTeamProject }}
|
||||
</div>
|
||||
<template #content>
|
||||
{{ badgeTooltip }}
|
||||
</template>
|
||||
</N8nTooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
.wrapper {
|
||||
margin-right: var(--spacing-xs);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: var(--border-base);
|
||||
border-radius: var(--border-radius-base);
|
||||
|
||||
&.no-border {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
@@ -165,7 +206,8 @@ const badgeTooltip = computed(() => {
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
height: 23px;
|
||||
:global(.n8n-text) {
|
||||
:global(.n8n-text),
|
||||
a {
|
||||
color: var(--color-text-base);
|
||||
}
|
||||
}
|
||||
@@ -177,13 +219,11 @@ const badgeTooltip = computed(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.countBadge {
|
||||
margin-left: -5px;
|
||||
z-index: 0;
|
||||
position: relative;
|
||||
height: 23px;
|
||||
:global(.n8n-text) {
|
||||
color: var(--color-text-light);
|
||||
}
|
||||
.count-badge {
|
||||
font-size: var(--font-size-2xs);
|
||||
padding: var(--spacing-4xs) var(--spacing-3xs);
|
||||
color: var(--color-text-base);
|
||||
border-left: var(--border-base);
|
||||
line-height: var(--font-line-height-regular);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -26,7 +26,7 @@ import { ResourceType } from '@/utils/projects.utils';
|
||||
import type { EventBus } from '@n8n/utils/event-bus';
|
||||
import type { WorkflowResource } from './layouts/ResourcesListLayout.vue';
|
||||
import type { IUser } from 'n8n-workflow';
|
||||
import { type ProjectIcon as CardProjectIcon, ProjectTypes } from '@/types/projects.types';
|
||||
import { ProjectTypes } from '@/types/projects.types';
|
||||
import type { PathItem } from '@n8n/design-system/components/N8nBreadcrumbs/Breadcrumbs.vue';
|
||||
import { useFoldersStore } from '@/stores/folders.store';
|
||||
|
||||
@@ -84,14 +84,8 @@ const showFolders = computed(() => {
|
||||
return settingsStore.isFoldersFeatureEnabled && route.name !== VIEWS.WORKFLOWS;
|
||||
});
|
||||
|
||||
const projectIcon = computed<CardProjectIcon>(() => {
|
||||
const defaultIcon: CardProjectIcon = { type: 'icon', value: 'layer-group' };
|
||||
if (props.data.homeProject?.type === ProjectTypes.Personal) {
|
||||
return { type: 'icon', value: 'user' };
|
||||
} else if (props.data.homeProject?.type === ProjectTypes.Team) {
|
||||
return props.data.homeProject.icon ?? defaultIcon;
|
||||
}
|
||||
return defaultIcon;
|
||||
const showCardBreadcrumbs = computed(() => {
|
||||
return isOverviewPage.value && !isSomeoneElsesWorkflow.value && cardBreadcrumbs.value.length;
|
||||
});
|
||||
|
||||
const projectName = computed(() => {
|
||||
@@ -172,6 +166,12 @@ const formattedCreatedAtDate = computed(() => {
|
||||
);
|
||||
});
|
||||
|
||||
const isSomeoneElsesWorkflow = computed(
|
||||
() =>
|
||||
props.data.homeProject?.type !== ProjectTypes.Team &&
|
||||
props.data.homeProject?.id !== projectsStore.personalProject?.id,
|
||||
);
|
||||
|
||||
async function onClick(event?: KeyboardEvent | PointerEvent) {
|
||||
if (event?.ctrlKey || event?.metaKey) {
|
||||
const route = router.resolve({
|
||||
@@ -350,39 +350,30 @@ const onBreadcrumbItemClick = async (item: PathItem) => {
|
||||
</div>
|
||||
<template #append>
|
||||
<div :class="$style.cardActions" @click.stop>
|
||||
<div v-if="isOverviewPage" :class="$style.breadcrumbs">
|
||||
<n8n-breadcrumbs
|
||||
:items="cardBreadcrumbs"
|
||||
:hidden-items="hiddenBreadcrumbsItemsAsync"
|
||||
:path-truncated="true"
|
||||
:show-border="true"
|
||||
:highlight-last-item="false"
|
||||
hidden-items-trigger="hover"
|
||||
theme="small"
|
||||
data-test-id="workflow-card-breadcrumbs"
|
||||
@tooltip-opened="fetchHiddenBreadCrumbsItems"
|
||||
@item-selected="onBreadcrumbItemClick"
|
||||
>
|
||||
<template v-if="data.homeProject" #prepend>
|
||||
<div :class="$style['home-project']">
|
||||
<n8n-link :to="`/projects/${data.homeProject.id}`">
|
||||
<ProjectIcon :icon="projectIcon" :border-less="true" size="mini" />
|
||||
<n8n-text size="small" :compact="true" :bold="true" color="text-base">{{
|
||||
projectName
|
||||
}}</n8n-text>
|
||||
</n8n-link>
|
||||
</div>
|
||||
</template>
|
||||
</n8n-breadcrumbs>
|
||||
</div>
|
||||
<ProjectCardBadge
|
||||
v-else
|
||||
:class="$style.cardBadge"
|
||||
:class="{ [$style.cardBadge]: true, [$style['with-breadcrumbs']]: showCardBreadcrumbs }"
|
||||
:resource="data"
|
||||
:resource-type="ResourceType.Workflow"
|
||||
:resource-type-label="resourceTypeLabel"
|
||||
:personal-project="projectsStore.personalProject"
|
||||
/>
|
||||
:show-badge-border="false"
|
||||
>
|
||||
<div v-if="showCardBreadcrumbs" :class="$style.breadcrumbs">
|
||||
<n8n-breadcrumbs
|
||||
:items="cardBreadcrumbs"
|
||||
:hidden-items="hiddenBreadcrumbsItemsAsync"
|
||||
:path-truncated="true"
|
||||
:highlight-last-item="false"
|
||||
hidden-items-trigger="hover"
|
||||
theme="small"
|
||||
data-test-id="workflow-card-breadcrumbs"
|
||||
@tooltip-opened="fetchHiddenBreadCrumbsItems"
|
||||
@item-selected="onBreadcrumbItemClick"
|
||||
>
|
||||
<template #prepend></template>
|
||||
</n8n-breadcrumbs>
|
||||
</div>
|
||||
</ProjectCardBadge>
|
||||
<WorkflowActivator
|
||||
class="mr-s"
|
||||
:workflow-active="data.active"
|
||||
@@ -442,11 +433,13 @@ const onBreadcrumbItemClick = async (item: PathItem) => {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.home-project span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-3xs);
|
||||
color: var(--color-text-base);
|
||||
.cardBadge.with-breadcrumbs {
|
||||
:global(.n8n-badge) {
|
||||
padding-right: 0;
|
||||
}
|
||||
:global(.n8n-breadcrumbs) {
|
||||
padding-left: var(--spacing-5xs);
|
||||
}
|
||||
}
|
||||
|
||||
@include mixins.breakpoint('sm-and-down') {
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
"generic.filtersApplied": "Filters are currently applied.",
|
||||
"generic.field": "field",
|
||||
"generic.fields": "fields",
|
||||
"generic.folder": "Folder | {count} Folder | {count} Folders",
|
||||
"generic.folderCount": "Folder | {count} Folder | {count} Folders",
|
||||
"generic.folder": "folder",
|
||||
"generic.learnMore": "Learn more",
|
||||
"generic.reset": "Reset",
|
||||
"generic.resetAllFilters": "Reset all filters",
|
||||
|
||||
@@ -1319,6 +1319,7 @@ const onCreateWorkflowClick = () => {
|
||||
:data="data as FolderResource"
|
||||
:actions="folderCardActions"
|
||||
:read-only="readOnlyEnv || (!hasPermissionToDeleteFolders && !hasPermissionToCreateFolders)"
|
||||
:personal-project="projectsStore.personalProject"
|
||||
class="mb-2xs"
|
||||
@action="onFolderCardAction"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user