mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
feat(editor): Add universal Create Resource Menu (#11564)
Co-authored-by: Csaba Tuncsik <csaba@n8n.io>
This commit is contained in:
committed by
GitHub
parent
1d8fd13d84
commit
b38ce14ec9
@@ -537,13 +537,11 @@ code[class^='language-'] {
|
||||
}
|
||||
|
||||
.inputWrapper {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
bottom: 0;
|
||||
background-color: var(--color-foreground-xlight);
|
||||
border: var(--border-base);
|
||||
width: 100%;
|
||||
padding-top: 1px;
|
||||
border-top: 0;
|
||||
|
||||
textarea {
|
||||
border: none;
|
||||
|
||||
@@ -132,6 +132,7 @@ const onSelect = (item: IMenuItem): void => {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--menu-background, var(--color-background-xlight));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.menuHeader {
|
||||
|
||||
@@ -29,9 +29,10 @@ describe('N8nNavigationDropdown', () => {
|
||||
|
||||
await router.isReady();
|
||||
});
|
||||
|
||||
it('default slot should trigger first level', async () => {
|
||||
const { getByTestId, queryByTestId } = render(NavigationDropdown, {
|
||||
slots: { default: h('button', { ['data-test-id']: 'test-trigger' }) },
|
||||
slots: { default: h('button', { 'data-test-id': 'test-trigger' }) },
|
||||
props: { menu: [{ id: 'aaa', title: 'aaa', route: { name: 'projects' } }] },
|
||||
global: {
|
||||
plugins: [router],
|
||||
@@ -40,13 +41,13 @@ describe('N8nNavigationDropdown', () => {
|
||||
expect(getByTestId('test-trigger')).toBeVisible();
|
||||
expect(queryByTestId('navigation-menu-item')).not.toBeVisible();
|
||||
|
||||
await userEvent.hover(getByTestId('test-trigger'));
|
||||
await userEvent.click(getByTestId('test-trigger'));
|
||||
await waitFor(() => expect(queryByTestId('navigation-menu-item')).toBeVisible());
|
||||
});
|
||||
|
||||
it('redirect to route', async () => {
|
||||
const { getByTestId, queryByTestId } = render(NavigationDropdown, {
|
||||
slots: { default: h('button', { ['data-test-id']: 'test-trigger' }) },
|
||||
slots: { default: h('button', { 'data-test-id': 'test-trigger' }) },
|
||||
props: {
|
||||
menu: [
|
||||
{
|
||||
@@ -64,7 +65,7 @@ describe('N8nNavigationDropdown', () => {
|
||||
expect(getByTestId('test-trigger')).toBeVisible();
|
||||
expect(queryByTestId('navigation-submenu')).not.toBeVisible();
|
||||
|
||||
await userEvent.hover(getByTestId('test-trigger'));
|
||||
await userEvent.click(getByTestId('test-trigger'));
|
||||
|
||||
await waitFor(() => expect(getByTestId('navigation-submenu')).toBeVisible());
|
||||
|
||||
@@ -75,7 +76,7 @@ describe('N8nNavigationDropdown', () => {
|
||||
|
||||
it('should render icons in submenu when provided', () => {
|
||||
const { getByTestId } = render(NavigationDropdown, {
|
||||
slots: { default: h('button', { ['data-test-id']: 'test-trigger' }) },
|
||||
slots: { default: h('button', { 'data-test-id': 'test-trigger' }) },
|
||||
props: {
|
||||
menu: [
|
||||
{
|
||||
@@ -95,7 +96,7 @@ describe('N8nNavigationDropdown', () => {
|
||||
|
||||
it('should propagate events', async () => {
|
||||
const { getByTestId, emitted } = render(NavigationDropdown, {
|
||||
slots: { default: h('button', { ['data-test-id']: 'test-trigger' }) },
|
||||
slots: { default: h('button', { 'data-test-id': 'test-trigger' }) },
|
||||
props: {
|
||||
menu: [
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ElMenu, ElSubMenu, ElMenuItem, type MenuItemRegistered } from 'element-plus';
|
||||
import { ref, defineProps, defineEmits, defineOptions } from 'vue';
|
||||
import type { RouteLocationRaw } from 'vue-router';
|
||||
|
||||
import ConditionalRouterLink from '../ConditionalRouterLink';
|
||||
@@ -17,28 +18,51 @@ type Item = BaseItem & {
|
||||
submenu?: BaseItem[];
|
||||
};
|
||||
|
||||
defineOptions({
|
||||
name: 'N8nNavigationDropdown',
|
||||
});
|
||||
|
||||
defineProps<{
|
||||
menu: Item[];
|
||||
disabled?: boolean;
|
||||
teleport?: boolean;
|
||||
}>();
|
||||
|
||||
const menuRef = ref<typeof ElMenu | null>(null);
|
||||
const menuIndex = ref('-1');
|
||||
|
||||
const emit = defineEmits<{
|
||||
itemClick: [item: MenuItemRegistered];
|
||||
select: [id: Item['id']];
|
||||
}>();
|
||||
|
||||
const close = () => {
|
||||
menuRef.value?.close(menuIndex.value);
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
close,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElMenu
|
||||
ref="menuRef"
|
||||
mode="horizontal"
|
||||
unique-opened
|
||||
menu-trigger="click"
|
||||
:ellipsis="false"
|
||||
:class="$style.dropdown"
|
||||
@select="emit('select', $event)"
|
||||
@keyup.escape="close"
|
||||
>
|
||||
<ElSubMenu
|
||||
index="-1"
|
||||
:index="menuIndex"
|
||||
:class="$style.trigger"
|
||||
:popper-offset="-10"
|
||||
:popper-class="$style.submenu"
|
||||
:disabled
|
||||
:teleported="teleport"
|
||||
>
|
||||
<template #title>
|
||||
<slot />
|
||||
@@ -49,7 +73,7 @@ const emit = defineEmits<{
|
||||
<ElSubMenu :index="item.id" :popper-offset="-10" data-test-id="navigation-submenu">
|
||||
<template #title>{{ item.title }}</template>
|
||||
<template v-for="subitem in item.submenu" :key="subitem.id">
|
||||
<ConditionalRouterLink :to="subitem.route">
|
||||
<ConditionalRouterLink :to="!subitem.disabled && subitem.route">
|
||||
<ElMenuItem
|
||||
data-test-id="navigation-submenu-item"
|
||||
:index="subitem.id"
|
||||
@@ -63,7 +87,7 @@ const emit = defineEmits<{
|
||||
</template>
|
||||
</ElSubMenu>
|
||||
</template>
|
||||
<ConditionalRouterLink v-else :to="item.route">
|
||||
<ConditionalRouterLink v-else :to="!item.disabled && item.route">
|
||||
<ElMenuItem
|
||||
:index="item.id"
|
||||
:disabled="item.disabled"
|
||||
@@ -81,24 +105,29 @@ const emit = defineEmits<{
|
||||
:global(.el-menu).dropdown {
|
||||
border-bottom: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
:global(.el-sub-menu).trigger {
|
||||
:global(.el-sub-menu__title) {
|
||||
height: auto;
|
||||
line-height: initial;
|
||||
border-bottom: 0 !important;
|
||||
:global(.el-sub-menu__icon-arrow) {
|
||||
display: none;
|
||||
> :global(.el-sub-menu) {
|
||||
> :global(.el-sub-menu__title) {
|
||||
height: auto;
|
||||
line-height: initial;
|
||||
border-bottom: 0 !important;
|
||||
padding: 0;
|
||||
:global(.el-sub-menu__icon-arrow) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.el-sub-menu__title:hover) {
|
||||
background-color: transparent;
|
||||
&:global(.is-active) {
|
||||
:global(.el-sub-menu__title) {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.submenu {
|
||||
padding: 5px 0 !important;
|
||||
|
||||
:global(.el-menu--horizontal .el-menu .el-menu-item),
|
||||
:global(.el-menu--horizontal .el-menu .el-sub-menu__title) {
|
||||
color: var(--color-text-dark);
|
||||
@@ -109,6 +138,15 @@ const emit = defineEmits<{
|
||||
background-color: var(--color-foreground-base);
|
||||
}
|
||||
|
||||
:global(.el-popper) {
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
|
||||
:global(.el-menu--popup) {
|
||||
border: 1px solid var(--color-foreground-base);
|
||||
border-radius: var(--border-radius-base);
|
||||
}
|
||||
|
||||
:global(.el-menu--horizontal .el-menu .el-menu-item.is-disabled) {
|
||||
opacity: 1;
|
||||
cursor: default;
|
||||
|
||||
Reference in New Issue
Block a user