mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
✨ Add support to dynamically add menu items
* add menu items POC
* remove sidebar hook
* use getters
* update menu to add items
* add home icon for CLD-202
* center icon
* address comments
* ⚡ Minor improvements
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
parent
2273a4cff2
commit
75dd058ce2
|
@ -428,3 +428,20 @@ export interface ITimeoutHMS {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WorkflowTitleStatus = 'EXECUTING' | 'IDLE' | 'ERROR';
|
export type WorkflowTitleStatus = 'EXECUTING' | 'IDLE' | 'ERROR';
|
||||||
|
|
||||||
|
export type MenuItemType = 'link';
|
||||||
|
export type MenuItemPosition = 'top' | 'bottom';
|
||||||
|
|
||||||
|
export interface IMenuItem {
|
||||||
|
id: string;
|
||||||
|
type: MenuItemType;
|
||||||
|
position: MenuItemPosition;
|
||||||
|
properties: ILinkMenuItemProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILinkMenuItemProperties {
|
||||||
|
title: string;
|
||||||
|
icon: string;
|
||||||
|
href: string;
|
||||||
|
newWindow?: boolean;
|
||||||
|
}
|
|
@ -21,6 +21,22 @@
|
||||||
</a>
|
</a>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
|
||||||
|
<el-menu-item
|
||||||
|
v-for="item in sidebarMenuTopItems"
|
||||||
|
:key="item.id"
|
||||||
|
:index="item.id"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
v-if="item.type === 'link'"
|
||||||
|
:href="item.properties.href"
|
||||||
|
:target="item.properties.newWindow ? '_blank' : '_self'"
|
||||||
|
class="primary-item"
|
||||||
|
>
|
||||||
|
<font-awesome-icon :icon="item.properties.icon" />
|
||||||
|
<span slot="title" class="item-title-root">{{ item.properties.title }}</span>
|
||||||
|
</a>
|
||||||
|
</el-menu-item>
|
||||||
|
|
||||||
<el-submenu index="workflow" title="Workflow">
|
<el-submenu index="workflow" title="Workflow">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
<font-awesome-icon icon="network-wired"/>
|
<font-awesome-icon icon="network-wired"/>
|
||||||
|
@ -152,6 +168,22 @@
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</el-submenu>
|
</el-submenu>
|
||||||
|
|
||||||
|
<el-menu-item
|
||||||
|
v-for="item in sidebarMenuBottomItems"
|
||||||
|
:key="item.id"
|
||||||
|
:index="item.id"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
v-if="item.type === 'link'"
|
||||||
|
:href="item.properties.href"
|
||||||
|
:target="item.properties.newWindow ? '_blank' : '_self'"
|
||||||
|
class="primary-item"
|
||||||
|
>
|
||||||
|
<font-awesome-icon :icon="item.properties.icon" />
|
||||||
|
<span slot="title" class="item-title-root">{{ item.properties.title }}</span>
|
||||||
|
</a>
|
||||||
|
</el-menu-item>
|
||||||
|
|
||||||
</el-menu>
|
</el-menu>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -167,6 +199,7 @@ import {
|
||||||
IExecutionResponse,
|
IExecutionResponse,
|
||||||
IExecutionsStopData,
|
IExecutionsStopData,
|
||||||
IWorkflowDataUpdate,
|
IWorkflowDataUpdate,
|
||||||
|
IMenuItem,
|
||||||
} from '../Interface';
|
} from '../Interface';
|
||||||
|
|
||||||
import About from '@/components/About.vue';
|
import About from '@/components/About.vue';
|
||||||
|
@ -266,6 +299,12 @@ export default mixins(
|
||||||
workflowRunning (): boolean {
|
workflowRunning (): boolean {
|
||||||
return this.$store.getters.isActionActive('workflowRunning');
|
return this.$store.getters.isActionActive('workflowRunning');
|
||||||
},
|
},
|
||||||
|
sidebarMenuTopItems(): IMenuItem[] {
|
||||||
|
return this.$store.getters.sidebarMenuItems.filter((item: IMenuItem) => item.position === 'top');
|
||||||
|
},
|
||||||
|
sidebarMenuBottomItems(): IMenuItem[] {
|
||||||
|
return this.$store.getters.sidebarMenuItems.filter((item: IMenuItem) => item.position === 'bottom');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
clearExecutionData () {
|
clearExecutionData () {
|
||||||
|
@ -533,6 +572,11 @@ export default mixins(
|
||||||
.el-menu-item {
|
.el-menu-item {
|
||||||
a {
|
a {
|
||||||
color: #666;
|
color: #666;
|
||||||
|
|
||||||
|
&.primary-item {
|
||||||
|
color: $--color-primary;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.logo-item {
|
&.logo-item {
|
||||||
|
|
|
@ -56,6 +56,7 @@ import {
|
||||||
faFilePdf,
|
faFilePdf,
|
||||||
faFolderOpen,
|
faFolderOpen,
|
||||||
faHdd,
|
faHdd,
|
||||||
|
faHome,
|
||||||
faHourglass,
|
faHourglass,
|
||||||
faImage,
|
faImage,
|
||||||
faInbox,
|
faInbox,
|
||||||
|
@ -136,6 +137,7 @@ library.add(faFileImport);
|
||||||
library.add(faFilePdf);
|
library.add(faFilePdf);
|
||||||
library.add(faFolderOpen);
|
library.add(faFolderOpen);
|
||||||
library.add(faHdd);
|
library.add(faHdd);
|
||||||
|
library.add(faHome);
|
||||||
library.add(faHourglass);
|
library.add(faHourglass);
|
||||||
library.add(faImage);
|
library.add(faImage);
|
||||||
library.add(faInbox);
|
library.add(faInbox);
|
||||||
|
|
|
@ -21,12 +21,13 @@ import {
|
||||||
ICredentialsResponse,
|
ICredentialsResponse,
|
||||||
IExecutionResponse,
|
IExecutionResponse,
|
||||||
IExecutionsCurrentSummaryExtended,
|
IExecutionsCurrentSummaryExtended,
|
||||||
IPushDataExecutionFinished,
|
IMenuItem,
|
||||||
IPushDataNodeExecuteAfter,
|
|
||||||
IWorkflowDb,
|
|
||||||
INodeUi,
|
INodeUi,
|
||||||
INodeUpdatePropertiesInformation,
|
INodeUpdatePropertiesInformation,
|
||||||
|
IPushDataExecutionFinished,
|
||||||
|
IPushDataNodeExecuteAfter,
|
||||||
IUpdateInformation,
|
IUpdateInformation,
|
||||||
|
IWorkflowDb,
|
||||||
XYPositon,
|
XYPositon,
|
||||||
} from './Interface';
|
} from './Interface';
|
||||||
|
|
||||||
|
@ -79,6 +80,7 @@ export const store = new Vuex.Store({
|
||||||
nodes: [] as INodeUi[],
|
nodes: [] as INodeUi[],
|
||||||
settings: {} as IWorkflowSettings,
|
settings: {} as IWorkflowSettings,
|
||||||
} as IWorkflowDb,
|
} as IWorkflowDb,
|
||||||
|
sidebarMenuItems: [] as IMenuItem[],
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
// Active Actions
|
// Active Actions
|
||||||
|
@ -597,6 +599,11 @@ export const store = new Vuex.Store({
|
||||||
Vue.set(state, 'nodeTypes', updatedNodes);
|
Vue.set(state, 'nodeTypes', updatedNodes);
|
||||||
state.nodeTypes = updatedNodes;
|
state.nodeTypes = updatedNodes;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addSidebarMenuItems (state, menuItems: IMenuItem[]) {
|
||||||
|
const updated = state.sidebarMenuItems.concat(menuItems);
|
||||||
|
Vue.set(state, 'sidebarMenuItems', updated);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
|
|
||||||
|
@ -834,6 +841,9 @@ export const store = new Vuex.Store({
|
||||||
return workflowRunData[nodeName];
|
return workflowRunData[nodeName];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sidebarMenuItems: (state): IMenuItem[] => {
|
||||||
|
return state.sidebarMenuItems;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue