mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #3930 from node-red/tab-context-menu
Improve UX around hiding flows via context menu
This commit is contained in:
commit
07c05c1f2a
@ -57,18 +57,22 @@
|
|||||||
"addFlowToRight": "Add flow to the right",
|
"addFlowToRight": "Add flow to the right",
|
||||||
"hideFlow": "Hide flow",
|
"hideFlow": "Hide flow",
|
||||||
"hideOtherFlows": "Hide other flows",
|
"hideOtherFlows": "Hide other flows",
|
||||||
"showAllFlows": "Show all flows",
|
"showAllFlows": "Show all flows (__count__ hidden)",
|
||||||
"hideAllFlows": "Hide all flows",
|
"hideAllFlows": "Hide all flows",
|
||||||
"hiddenFlows": "List __count__ hidden flow",
|
"hiddenFlows": "List __count__ hidden flow",
|
||||||
"hiddenFlows_plural": "List __count__ hidden flows",
|
"hiddenFlows_plural": "List __count__ hidden flows",
|
||||||
"showLastHiddenFlow": "Show last hidden flow",
|
"showLastHiddenFlow": "Reopen hidden flow",
|
||||||
"listFlows": "List flows",
|
"listFlows": "List flows",
|
||||||
"listSubflows": "List subflows",
|
"listSubflows": "List subflows",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"info": "Description",
|
"info": "Description",
|
||||||
"selectNodes": "Click nodes to select"
|
"selectNodes": "Click nodes to select",
|
||||||
|
"enableFlow": "Enable flow",
|
||||||
|
"disableFlow": "Disable flow",
|
||||||
|
"moveToStart": "Move flow to start",
|
||||||
|
"moveToEnd": "Move flow to end"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"label": {
|
"label": {
|
||||||
|
@ -2834,7 +2834,7 @@ RED.nodes = (function() {
|
|||||||
},
|
},
|
||||||
addWorkspace: addWorkspace,
|
addWorkspace: addWorkspace,
|
||||||
removeWorkspace: removeWorkspace,
|
removeWorkspace: removeWorkspace,
|
||||||
getWorkspaceOrder: function() { return workspacesOrder },
|
getWorkspaceOrder: function() { return [...workspacesOrder] },
|
||||||
setWorkspaceOrder: function(order) { workspacesOrder = order; },
|
setWorkspaceOrder: function(order) { workspacesOrder = order; },
|
||||||
workspace: getWorkspace,
|
workspace: getWorkspace,
|
||||||
|
|
||||||
|
@ -423,11 +423,10 @@ RED.clipboard = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showImportNodes(mode) {
|
function showImportNodes(library = 'clipboard') {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mode = mode || "clipboard";
|
|
||||||
|
|
||||||
dialogContainer.empty();
|
dialogContainer.empty();
|
||||||
dialogContainer.append($(importNodesDialog));
|
dialogContainer.append($(importNodesDialog));
|
||||||
@ -533,8 +532,8 @@ RED.clipboard = (function() {
|
|||||||
$("#red-ui-clipboard-dialog-import-file-upload").trigger("click");
|
$("#red-ui-clipboard-dialog-import-file-upload").trigger("click");
|
||||||
})
|
})
|
||||||
|
|
||||||
tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+mode);
|
tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+library);
|
||||||
if (mode === 'clipboard') {
|
if (library === 'clipboard') {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$("#red-ui-clipboard-dialog-import-text").trigger("focus");
|
$("#red-ui-clipboard-dialog-import-text").trigger("focus");
|
||||||
},100)
|
},100)
|
||||||
@ -558,13 +557,16 @@ RED.clipboard = (function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showExportNodes(mode) {
|
/**
|
||||||
|
* Show the export dialog
|
||||||
|
* @params library which export destination to show
|
||||||
|
* @params mode whether to default to 'auto' (default) or 'flow'
|
||||||
|
**/
|
||||||
|
function showExportNodes(library = 'clipboard', mode = 'auto' ) {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = mode || "clipboard";
|
|
||||||
|
|
||||||
dialogContainer.empty();
|
dialogContainer.empty();
|
||||||
dialogContainer.append($(exportNodesDialog));
|
dialogContainer.append($(exportNodesDialog));
|
||||||
|
|
||||||
@ -766,12 +768,15 @@ RED.clipboard = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mode === 'flow' && !$("#red-ui-clipboard-dialog-export-rng-flow").hasClass('disabled')) {
|
||||||
|
$("#red-ui-clipboard-dialog-export-rng-flow").trigger("click");
|
||||||
|
}
|
||||||
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
|
if (format === "red-ui-clipboard-dialog-export-fmt-full") {
|
||||||
$("#red-ui-clipboard-dialog-export-fmt-full").trigger("click");
|
$("#red-ui-clipboard-dialog-export-fmt-full").trigger("click");
|
||||||
} else {
|
} else {
|
||||||
$("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click");
|
$("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click");
|
||||||
}
|
}
|
||||||
tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode);
|
tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+library);
|
||||||
|
|
||||||
var dialogHeight = 400;
|
var dialogHeight = 400;
|
||||||
var winHeight = $(window).height();
|
var winHeight = $(window).height();
|
||||||
|
@ -94,8 +94,8 @@ RED.menu = (function() {
|
|||||||
|
|
||||||
var link = $(linkContent).appendTo(item);
|
var link = $(linkContent).appendTo(item);
|
||||||
opt.link = link;
|
opt.link = link;
|
||||||
if (typeof opt.onselect === 'string') {
|
if (typeof opt.onselect === 'string' || opt.shortcut) {
|
||||||
var shortcut = RED.keyboard.getShortcut(opt.onselect);
|
var shortcut = opt.shortcut || RED.keyboard.getShortcut(opt.onselect);
|
||||||
if (shortcut && shortcut.key) {
|
if (shortcut && shortcut.key) {
|
||||||
opt.shortcutSpan = $('<span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span>').appendTo(link.find(".red-ui-menu-label"));
|
opt.shortcutSpan = $('<span class="red-ui-popover-key">'+RED.keyboard.formatKey(shortcut.key, true)+'</span>').appendTo(link.find(".red-ui-menu-label"));
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,29 @@ RED.tabs = (function() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.contextmenu) {
|
||||||
|
wrapper.on('contextmenu', function(evt) {
|
||||||
|
let clickedTab
|
||||||
|
let target = evt.target
|
||||||
|
while(target.nodeName !== 'A' && target.nodeName !== 'UL' && target.nodeName !== 'BODY') {
|
||||||
|
target = target.parentNode
|
||||||
|
}
|
||||||
|
if (target.nodeName === 'A') {
|
||||||
|
const href = target.getAttribute('href')
|
||||||
|
if (href) {
|
||||||
|
clickedTab = tabs[href.slice(1)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
evt.preventDefault()
|
||||||
|
evt.stopPropagation()
|
||||||
|
RED.contextMenu.show({
|
||||||
|
x:evt.clientX-5,
|
||||||
|
y:evt.clientY-5,
|
||||||
|
options: options.contextmenu(clickedTab)
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var scrollLeft;
|
var scrollLeft;
|
||||||
var scrollRight;
|
var scrollRight;
|
||||||
@ -809,17 +831,17 @@ RED.tabs = (function() {
|
|||||||
});
|
});
|
||||||
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
||||||
}
|
}
|
||||||
if (tab.hideable) {
|
// if (tab.hideable) {
|
||||||
li.addClass("red-ui-tabs-closeable")
|
// li.addClass("red-ui-tabs-closeable")
|
||||||
var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li);
|
// var closeLink = $("<a/>",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li);
|
||||||
closeLink.append('<i class="fa fa-eye" />');
|
// closeLink.append('<i class="fa fa-eye" />');
|
||||||
closeLink.append('<i class="fa fa-eye-slash" />');
|
// closeLink.append('<i class="fa fa-eye-slash" />');
|
||||||
closeLink.on("click",function(event) {
|
// closeLink.on("click",function(event) {
|
||||||
event.preventDefault();
|
// event.preventDefault();
|
||||||
hideTab(tab.id);
|
// hideTab(tab.id);
|
||||||
});
|
// });
|
||||||
RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
// RED.popover.tooltip(closeLink,RED._("workspace.hideFlow"));
|
||||||
}
|
// }
|
||||||
|
|
||||||
var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li);
|
var badges = $('<span class="red-ui-tabs-badges"></span>').appendTo(li);
|
||||||
if (options.onselect) {
|
if (options.onselect) {
|
||||||
@ -938,6 +960,9 @@ RED.tabs = (function() {
|
|||||||
activeIndex: function() {
|
activeIndex: function() {
|
||||||
return ul.find("li.active").index()
|
return ul.find("li.active").index()
|
||||||
},
|
},
|
||||||
|
getTabIndex: function (id) {
|
||||||
|
return ul.find("a[href='#"+id+"']").parent().index()
|
||||||
|
},
|
||||||
contains: function(id) {
|
contains: function(id) {
|
||||||
return ul.find("a[href='#"+id+"']").length > 0;
|
return ul.find("a[href='#"+id+"']").length > 0;
|
||||||
},
|
},
|
||||||
|
@ -1,21 +1,6 @@
|
|||||||
RED.contextMenu = (function () {
|
RED.contextMenu = (function () {
|
||||||
|
|
||||||
let menu;
|
let menu;
|
||||||
function createMenu() {
|
|
||||||
// menu = RED.popover.menu({
|
|
||||||
// options: [
|
|
||||||
// {
|
|
||||||
// label: 'delete selection',
|
|
||||||
// onselect: function() {
|
|
||||||
// RED.actions.invoke('core:delete-selection')
|
|
||||||
// RED.view.focus()
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// { label: 'world' }
|
|
||||||
// ],
|
|
||||||
// width: 200,
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
|
|
||||||
function disposeMenu() {
|
function disposeMenu() {
|
||||||
$(document).off("mousedown.red-ui-workspace-context-menu");
|
$(document).off("mousedown.red-ui-workspace-context-menu");
|
||||||
@ -28,7 +13,10 @@ RED.contextMenu = (function () {
|
|||||||
if (menu) {
|
if (menu) {
|
||||||
menu.remove()
|
menu.remove()
|
||||||
}
|
}
|
||||||
|
let menuItems = []
|
||||||
|
if (options.options) {
|
||||||
|
menuItems = options.options
|
||||||
|
} else if (options.type === 'workspace') {
|
||||||
const selection = RED.view.selection()
|
const selection = RED.view.selection()
|
||||||
const noSelection = !selection || Object.keys(selection).length === 0
|
const noSelection = !selection || Object.keys(selection).length === 0
|
||||||
const hasSelection = (selection.nodes && selection.nodes.length > 0);
|
const hasSelection = (selection.nodes && selection.nodes.length > 0);
|
||||||
@ -53,7 +41,7 @@ RED.contextMenu = (function () {
|
|||||||
addY = gridSize * Math.floor(addY / gridSize)
|
addY = gridSize * Math.floor(addY / gridSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
const menuItems = [
|
menuItems.push(
|
||||||
{ onselect: 'core:show-action-list', onpostselect: function () { } },
|
{ onselect: 'core:show-action-list', onpostselect: function () { } },
|
||||||
{
|
{
|
||||||
label: RED._("contextMenu.insert"),
|
label: RED._("contextMenu.insert"),
|
||||||
@ -110,7 +98,7 @@ RED.contextMenu = (function () {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
]
|
)
|
||||||
|
|
||||||
menuItems.push(
|
menuItems.push(
|
||||||
null,
|
null,
|
||||||
@ -137,6 +125,7 @@ RED.contextMenu = (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var direction = "right";
|
var direction = "right";
|
||||||
var MENU_WIDTH = 500; // can not use menu width here
|
var MENU_WIDTH = 500; // can not use menu width here
|
||||||
|
@ -431,12 +431,29 @@ RED.subflow = (function() {
|
|||||||
|
|
||||||
$("#red-ui-subflow-delete").on("click", function(event) {
|
$("#red-ui-subflow-delete").on("click", function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var subflow = RED.nodes.subflow(RED.workspaces.active());
|
RED.subflow.delete(RED.workspaces.active())
|
||||||
|
});
|
||||||
|
|
||||||
|
refreshToolbar(activeSubflow);
|
||||||
|
|
||||||
|
$("#red-ui-workspace-chart").css({"margin-top": "40px"});
|
||||||
|
$("#red-ui-workspace-toolbar").show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideWorkspaceToolbar() {
|
||||||
|
$("#red-ui-workspace-toolbar").hide().empty();
|
||||||
|
$("#red-ui-workspace-chart").css({"margin-top": "0"});
|
||||||
|
}
|
||||||
|
function deleteSubflow(id) {
|
||||||
|
const subflow = RED.nodes.subflow(id || RED.workspaces.active());
|
||||||
|
if (!subflow) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (subflow.instances.length > 0) {
|
if (subflow.instances.length > 0) {
|
||||||
var msg = $('<div>')
|
const msg = $('<div>')
|
||||||
$('<p>').text(RED._("subflow.subflowInstances",{count: subflow.instances.length})).appendTo(msg);
|
$('<p>').text(RED._("subflow.subflowInstances",{count: subflow.instances.length})).appendTo(msg);
|
||||||
$('<p>').text(RED._("subflow.confirmDelete")).appendTo(msg);
|
$('<p>').text(RED._("subflow.confirmDelete")).appendTo(msg);
|
||||||
var confirmDeleteNotification = RED.notify(msg, {
|
const confirmDeleteNotification = RED.notify(msg, {
|
||||||
modal: true,
|
modal: true,
|
||||||
fixed: true,
|
fixed: true,
|
||||||
buttons: [
|
buttons: [
|
||||||
@ -462,26 +479,13 @@ RED.subflow = (function() {
|
|||||||
completeDelete();
|
completeDelete();
|
||||||
}
|
}
|
||||||
function completeDelete() {
|
function completeDelete() {
|
||||||
var startDirty = RED.nodes.dirty();
|
const startDirty = RED.nodes.dirty();
|
||||||
var historyEvent = removeSubflow(RED.workspaces.active());
|
const historyEvent = removeSubflow(subflow.id);
|
||||||
historyEvent.t = 'delete';
|
historyEvent.t = 'delete';
|
||||||
historyEvent.dirty = startDirty;
|
historyEvent.dirty = startDirty;
|
||||||
RED.history.push(historyEvent);
|
RED.history.push(historyEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
refreshToolbar(activeSubflow);
|
|
||||||
|
|
||||||
$("#red-ui-workspace-chart").css({"margin-top": "40px"});
|
|
||||||
$("#red-ui-workspace-toolbar").show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideWorkspaceToolbar() {
|
|
||||||
$("#red-ui-workspace-toolbar").hide().empty();
|
|
||||||
$("#red-ui-workspace-chart").css({"margin-top": "0"});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeSubflow(id, keepInstanceNodes) {
|
function removeSubflow(id, keepInstanceNodes) {
|
||||||
// TODO: A lot of this logic is common with RED.nodes.removeWorkspace
|
// TODO: A lot of this logic is common with RED.nodes.removeWorkspace
|
||||||
var removedNodes = [];
|
var removedNodes = [];
|
||||||
@ -1323,7 +1327,10 @@ RED.subflow = (function() {
|
|||||||
init: init,
|
init: init,
|
||||||
createSubflow: createSubflow,
|
createSubflow: createSubflow,
|
||||||
convertToSubflow: convertToSubflow,
|
convertToSubflow: convertToSubflow,
|
||||||
|
// removeSubflow: Internal function to remove subflow
|
||||||
removeSubflow: removeSubflow,
|
removeSubflow: removeSubflow,
|
||||||
|
// delete: Prompt user for confirmation
|
||||||
|
delete: deleteSubflow,
|
||||||
refresh: refresh,
|
refresh: refresh,
|
||||||
removeInput: removeSubflowInput,
|
removeInput: removeSubflowInput,
|
||||||
removeOutput: removeSubflowOutput,
|
removeOutput: removeSubflowOutput,
|
||||||
|
@ -211,6 +211,7 @@ RED.view = (function() {
|
|||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
evt.stopPropagation()
|
evt.stopPropagation()
|
||||||
RED.contextMenu.show({
|
RED.contextMenu.show({
|
||||||
|
type: 'workspace',
|
||||||
x:evt.clientX-5,
|
x:evt.clientX-5,
|
||||||
y:evt.clientY-5
|
y:evt.clientY-5
|
||||||
})
|
})
|
||||||
|
@ -126,6 +126,166 @@ RED.workspaces = (function() {
|
|||||||
|
|
||||||
var workspace_tabs;
|
var workspace_tabs;
|
||||||
var workspaceTabCount = 0;
|
var workspaceTabCount = 0;
|
||||||
|
|
||||||
|
function getMenuItems(isMenuButton, tab) {
|
||||||
|
let hiddenFlows = new Set()
|
||||||
|
for (let i = 0; i < hideStack.length; i++) {
|
||||||
|
let ids = hideStack[i]
|
||||||
|
if (!Array.isArray(ids)) {
|
||||||
|
ids = [ids]
|
||||||
|
}
|
||||||
|
ids.forEach(id => {
|
||||||
|
if (RED.nodes.workspace(id)) {
|
||||||
|
hiddenFlows.add(id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const hiddenflowCount = hiddenFlows.size;
|
||||||
|
let activeWorkspace = tab || RED.nodes.workspace(RED.workspaces.active()) || RED.nodes.subflow(RED.workspaces.active())
|
||||||
|
let isFlowDisabled = activeWorkspace ? activeWorkspace.disabled : false
|
||||||
|
|
||||||
|
var menuItems = []
|
||||||
|
if (isMenuButton) {
|
||||||
|
menuItems.push({
|
||||||
|
id:"red-ui-tabs-menu-option-search-flows",
|
||||||
|
label: RED._("workspace.listFlows"),
|
||||||
|
onselect: "core:list-flows"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:"red-ui-tabs-menu-option-search-subflows",
|
||||||
|
label: RED._("workspace.listSubflows"),
|
||||||
|
onselect: "core:list-subflows"
|
||||||
|
},
|
||||||
|
null)
|
||||||
|
}
|
||||||
|
menuItems.push(
|
||||||
|
{
|
||||||
|
id:"red-ui-tabs-menu-option-add-flow",
|
||||||
|
label: RED._("workspace.addFlow"),
|
||||||
|
onselect: "core:add-flow"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (isMenuButton || !!tab) {
|
||||||
|
menuItems.push(
|
||||||
|
{
|
||||||
|
id:"red-ui-tabs-menu-option-add-flow-right",
|
||||||
|
label: RED._("workspace.addFlowToRight"),
|
||||||
|
shortcut: RED.keyboard.getShortcut("core:add-flow-to-right"),
|
||||||
|
onselect: function() {
|
||||||
|
RED.actions.invoke("core:add-flow-to-right", tab)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null
|
||||||
|
)
|
||||||
|
if (activeWorkspace && activeWorkspace.type === 'tab') {
|
||||||
|
menuItems.push(
|
||||||
|
isFlowDisabled ? {
|
||||||
|
label: RED._("workspace.enableFlow"),
|
||||||
|
shortcut: RED.keyboard.getShortcut("core:enable-flow"),
|
||||||
|
onselect: function() {
|
||||||
|
RED.actions.invoke("core:enable-flow", tab?tab.id:undefined)
|
||||||
|
}
|
||||||
|
} : {
|
||||||
|
label: RED._("workspace.disableFlow"),
|
||||||
|
shortcut: RED.keyboard.getShortcut("core:disable-flow"),
|
||||||
|
onselect: function() {
|
||||||
|
RED.actions.invoke("core:disable-flow", tab?tab.id:undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const currentTabs = workspace_tabs.listTabs()
|
||||||
|
const activeIndex = currentTabs.findIndex(id => id === activeWorkspace.id)
|
||||||
|
menuItems.push(
|
||||||
|
{
|
||||||
|
label: RED._("workspace.moveToStart"),
|
||||||
|
shortcut: RED.keyboard.getShortcut("core:move-flow-to-start"),
|
||||||
|
onselect: function() {
|
||||||
|
RED.actions.invoke("core:move-flow-to-start", tab?tab.id:undefined)
|
||||||
|
},
|
||||||
|
disabled: activeIndex === 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: RED._("workspace.moveToEnd"),
|
||||||
|
shortcut: RED.keyboard.getShortcut("core:move-flow-to-end"),
|
||||||
|
onselect: function() {
|
||||||
|
RED.actions.invoke("core:move-flow-to-end", tab?tab.id:undefined)
|
||||||
|
},
|
||||||
|
disabled: activeIndex === currentTabs.length - 1
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
menuItems.push(null)
|
||||||
|
if (isMenuButton || !!tab) {
|
||||||
|
menuItems.push(
|
||||||
|
{
|
||||||
|
id:"red-ui-tabs-menu-option-add-hide-flows",
|
||||||
|
label: RED._("workspace.hideFlow"),
|
||||||
|
shortcut: RED.keyboard.getShortcut("core:hide-flow"),
|
||||||
|
onselect: function() {
|
||||||
|
RED.actions.invoke("core:hide-flow", tab)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:"red-ui-tabs-menu-option-add-hide-other-flows",
|
||||||
|
label: RED._("workspace.hideOtherFlows"),
|
||||||
|
shortcut: RED.keyboard.getShortcut("core:hide-other-flows"),
|
||||||
|
onselect: function() {
|
||||||
|
RED.actions.invoke("core:hide-other-flows", tab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
menuItems.push(
|
||||||
|
{
|
||||||
|
id:"red-ui-tabs-menu-option-add-hide-all-flows",
|
||||||
|
label: RED._("workspace.hideAllFlows"),
|
||||||
|
onselect: "core:hide-all-flows"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:"red-ui-tabs-menu-option-add-show-all-flows",
|
||||||
|
disabled: hiddenflowCount === 0,
|
||||||
|
label: RED._("workspace.showAllFlows", { count: hiddenflowCount }),
|
||||||
|
onselect: "core:show-all-flows"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id:"red-ui-tabs-menu-option-add-show-last-flow",
|
||||||
|
disabled: hideStack.length === 0,
|
||||||
|
label: RED._("workspace.showLastHiddenFlow"),
|
||||||
|
onselect: "core:show-last-hidden-flow"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (tab) {
|
||||||
|
menuItems.push(
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
label: RED._("common.label.delete"),
|
||||||
|
onselect: function() {
|
||||||
|
if (tab.type === 'tab') {
|
||||||
|
RED.workspaces.delete(tab)
|
||||||
|
} else if (tab.type === 'subflow') {
|
||||||
|
RED.subflow.delete(tab.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: RED._("menu.label.export"),
|
||||||
|
shortcut: RED.keyboard.getShortcut("core:show-export-dialog"),
|
||||||
|
onselect: function() {
|
||||||
|
RED.workspaces.show(tab.id)
|
||||||
|
RED.actions.invoke('core:show-export-dialog', null, 'flow')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// if (isMenuButton && hiddenflowCount > 0) {
|
||||||
|
// menuItems.unshift({
|
||||||
|
// label: RED._("workspace.hiddenFlows",{count: hiddenflowCount}),
|
||||||
|
// onselect: "core:list-hidden-flows"
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
return menuItems;
|
||||||
|
}
|
||||||
function createWorkspaceTabs() {
|
function createWorkspaceTabs() {
|
||||||
workspace_tabs = RED.tabs.create({
|
workspace_tabs = RED.tabs.create({
|
||||||
id: "red-ui-workspace-tabs",
|
id: "red-ui-workspace-tabs",
|
||||||
@ -189,13 +349,19 @@ RED.workspaces = (function() {
|
|||||||
RED.history.push({
|
RED.history.push({
|
||||||
t:'reorder',
|
t:'reorder',
|
||||||
workspaces: {
|
workspaces: {
|
||||||
from:oldOrder,
|
from: oldOrder,
|
||||||
to:newOrder
|
to: newOrder
|
||||||
},
|
},
|
||||||
dirty:RED.nodes.dirty()
|
dirty:RED.nodes.dirty()
|
||||||
});
|
});
|
||||||
|
// Only mark flows dirty if flow-order has changed (excluding subflows)
|
||||||
|
const filteredOldOrder = oldOrder.filter(id => !!RED.nodes.workspace(id))
|
||||||
|
const filteredNewOrder = newOrder.filter(id => !!RED.nodes.workspace(id))
|
||||||
|
|
||||||
|
if (JSON.stringify(filteredOldOrder) !== JSON.stringify(filteredNewOrder)) {
|
||||||
RED.nodes.dirty(true);
|
RED.nodes.dirty(true);
|
||||||
setWorkspaceOrder(newOrder);
|
setWorkspaceOrder(newOrder);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onselect: function(selectedTabs) {
|
onselect: function(selectedTabs) {
|
||||||
RED.view.select(false)
|
RED.view.select(false)
|
||||||
@ -214,12 +380,12 @@ RED.workspaces = (function() {
|
|||||||
},
|
},
|
||||||
onhide: function(tab) {
|
onhide: function(tab) {
|
||||||
hideStack.push(tab.id);
|
hideStack.push(tab.id);
|
||||||
|
if (tab.type === "tab") {
|
||||||
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}");
|
||||||
hiddenTabs[tab.id] = true;
|
hiddenTabs[tab.id] = true;
|
||||||
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
RED.settings.setLocal("hiddenTabs",JSON.stringify(hiddenTabs));
|
||||||
|
|
||||||
RED.events.emit("workspace:hide",{workspace: tab.id})
|
RED.events.emit("workspace:hide",{workspace: tab.id})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onshow: function(tab) {
|
onshow: function(tab) {
|
||||||
removeFromHideStack(tab.id);
|
removeFromHideStack(tab.id);
|
||||||
@ -234,77 +400,8 @@ RED.workspaces = (function() {
|
|||||||
scrollable: true,
|
scrollable: true,
|
||||||
addButton: "core:add-flow",
|
addButton: "core:add-flow",
|
||||||
addButtonCaption: RED._("workspace.addFlow"),
|
addButtonCaption: RED._("workspace.addFlow"),
|
||||||
menu: function() {
|
menu: function() { return getMenuItems(true) },
|
||||||
var menuItems = [
|
contextmenu: function(tab) { return getMenuItems(false, tab) }
|
||||||
{
|
|
||||||
id:"red-ui-tabs-menu-option-search-flows",
|
|
||||||
label: RED._("workspace.listFlows"),
|
|
||||||
onselect: "core:list-flows"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:"red-ui-tabs-menu-option-search-subflows",
|
|
||||||
label: RED._("workspace.listSubflows"),
|
|
||||||
onselect: "core:list-subflows"
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
{
|
|
||||||
id:"red-ui-tabs-menu-option-add-flow",
|
|
||||||
label: RED._("workspace.addFlow"),
|
|
||||||
onselect: "core:add-flow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:"red-ui-tabs-menu-option-add-flow-right",
|
|
||||||
label: RED._("workspace.addFlowToRight"),
|
|
||||||
onselect: "core:add-flow-to-right"
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
{
|
|
||||||
id:"red-ui-tabs-menu-option-add-hide-flows",
|
|
||||||
label: RED._("workspace.hideFlow"),
|
|
||||||
onselect: "core:hide-flow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:"red-ui-tabs-menu-option-add-hide-other-flows",
|
|
||||||
label: RED._("workspace.hideOtherFlows"),
|
|
||||||
onselect: "core:hide-other-flows"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:"red-ui-tabs-menu-option-add-show-all-flows",
|
|
||||||
label: RED._("workspace.showAllFlows"),
|
|
||||||
onselect: "core:show-all-flows"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:"red-ui-tabs-menu-option-add-hide-all-flows",
|
|
||||||
label: RED._("workspace.hideAllFlows"),
|
|
||||||
onselect: "core:hide-all-flows"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id:"red-ui-tabs-menu-option-add-show-last-flow",
|
|
||||||
label: RED._("workspace.showLastHiddenFlow"),
|
|
||||||
onselect: "core:show-last-hidden-flow"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
let hiddenFlows = new Set()
|
|
||||||
for (let i = 0; i < hideStack.length; i++) {
|
|
||||||
let ids = hideStack[i]
|
|
||||||
if (!Array.isArray(ids)) {
|
|
||||||
ids = [ids]
|
|
||||||
}
|
|
||||||
ids.forEach(id => {
|
|
||||||
if (RED.nodes.workspace(id)) {
|
|
||||||
hiddenFlows.add(id)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const flowCount = hiddenFlows.size;
|
|
||||||
if (flowCount > 0) {
|
|
||||||
menuItems.unshift({
|
|
||||||
label: RED._("workspace.hiddenFlows",{count: flowCount}),
|
|
||||||
onselect: "core:list-hidden-flows"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return menuItems;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
workspaceTabCount = 0;
|
workspaceTabCount = 0;
|
||||||
}
|
}
|
||||||
@ -355,17 +452,32 @@ RED.workspaces = (function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)});
|
RED.actions.add("core:add-flow",function(opts) { addWorkspace(undefined,undefined,opts?opts.index:undefined)});
|
||||||
RED.actions.add("core:add-flow-to-right",function(opts) { addWorkspace(undefined,undefined,workspace_tabs.activeIndex()+1)});
|
RED.actions.add("core:add-flow-to-right",function(workspace) {
|
||||||
|
let index
|
||||||
|
if (workspace) {
|
||||||
|
index = workspace_tabs.getTabIndex(workspace.id)+1
|
||||||
|
} else {
|
||||||
|
index = workspace_tabs.activeIndex()+1
|
||||||
|
}
|
||||||
|
addWorkspace(undefined,undefined,index)
|
||||||
|
});
|
||||||
RED.actions.add("core:edit-flow",editWorkspace);
|
RED.actions.add("core:edit-flow",editWorkspace);
|
||||||
RED.actions.add("core:remove-flow",removeWorkspace);
|
RED.actions.add("core:remove-flow",removeWorkspace);
|
||||||
RED.actions.add("core:enable-flow",enableWorkspace);
|
RED.actions.add("core:enable-flow",enableWorkspace);
|
||||||
RED.actions.add("core:disable-flow",disableWorkspace);
|
RED.actions.add("core:disable-flow",disableWorkspace);
|
||||||
|
RED.actions.add("core:move-flow-to-start", function(id) { moveWorkspace(id, 'start') });
|
||||||
|
RED.actions.add("core:move-flow-to-end", function(id) { moveWorkspace(id, 'end') });
|
||||||
|
|
||||||
RED.actions.add("core:hide-flow", function() {
|
RED.actions.add("core:hide-flow", function(workspace) {
|
||||||
var selection = workspace_tabs.selection();
|
let selection
|
||||||
|
if (workspace) {
|
||||||
|
selection = [workspace]
|
||||||
|
} else {
|
||||||
|
selection = workspace_tabs.selection();
|
||||||
if (selection.length === 0) {
|
if (selection.length === 0) {
|
||||||
selection = [{id:activeWorkspace}]
|
selection = [{id:activeWorkspace}]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var hiddenTabs = [];
|
var hiddenTabs = [];
|
||||||
selection.forEach(function(ws) {
|
selection.forEach(function(ws) {
|
||||||
RED.workspaces.hide(ws.id);
|
RED.workspaces.hide(ws.id);
|
||||||
@ -378,11 +490,16 @@ RED.workspaces = (function() {
|
|||||||
workspace_tabs.clearSelection();
|
workspace_tabs.clearSelection();
|
||||||
})
|
})
|
||||||
|
|
||||||
RED.actions.add("core:hide-other-flows", function() {
|
RED.actions.add("core:hide-other-flows", function(workspace) {
|
||||||
var selection = workspace_tabs.selection();
|
let selection
|
||||||
|
if (workspace) {
|
||||||
|
selection = [workspace]
|
||||||
|
} else {
|
||||||
|
selection = workspace_tabs.selection();
|
||||||
if (selection.length === 0) {
|
if (selection.length === 0) {
|
||||||
selection = [{id:activeWorkspace}]
|
selection = [{id:activeWorkspace}]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var selected = new Set(selection.map(function(ws) { return ws.id }))
|
var selected = new Set(selection.map(function(ws) { return ws.id }))
|
||||||
|
|
||||||
var currentTabs = workspace_tabs.listTabs();
|
var currentTabs = workspace_tabs.listTabs();
|
||||||
@ -535,16 +652,46 @@ RED.workspaces = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function moveWorkspace(id, direction) {
|
||||||
|
const workspace = RED.nodes.workspace(id||activeWorkspace) || RED.nodes.subflow(id||activeWorkspace);
|
||||||
|
if (!workspace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentOrder = workspace_tabs.listTabs()
|
||||||
|
const oldOrder = [...currentOrder]
|
||||||
|
const currentIndex = currentOrder.findIndex(id => id === workspace.id)
|
||||||
|
currentOrder.splice(currentIndex, 1)
|
||||||
|
if (direction === 'start') {
|
||||||
|
currentOrder.unshift(workspace.id)
|
||||||
|
} else if (direction === 'end') {
|
||||||
|
currentOrder.push(workspace.id)
|
||||||
|
}
|
||||||
|
const newOrder = setWorkspaceOrder(currentOrder)
|
||||||
|
if (JSON.stringify(newOrder) !== JSON.stringify(oldOrder)) {
|
||||||
|
RED.history.push({
|
||||||
|
t:'reorder',
|
||||||
|
workspaces: {
|
||||||
|
from:oldOrder,
|
||||||
|
to:newOrder
|
||||||
|
},
|
||||||
|
dirty:RED.nodes.dirty()
|
||||||
|
});
|
||||||
|
const filteredOldOrder = oldOrder.filter(id => !!RED.nodes.workspace(id))
|
||||||
|
const filteredNewOrder = newOrder.filter(id => !!RED.nodes.workspace(id))
|
||||||
|
if (JSON.stringify(filteredOldOrder) !== JSON.stringify(filteredNewOrder)) {
|
||||||
|
RED.nodes.dirty(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
function setWorkspaceOrder(order) {
|
function setWorkspaceOrder(order) {
|
||||||
var newOrder = order.filter(function(id) {
|
var newOrder = order.filter(id => !!RED.nodes.workspace(id))
|
||||||
return RED.nodes.workspace(id) !== undefined;
|
|
||||||
})
|
|
||||||
var currentOrder = RED.nodes.getWorkspaceOrder();
|
var currentOrder = RED.nodes.getWorkspaceOrder();
|
||||||
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
|
if (JSON.stringify(newOrder) !== JSON.stringify(currentOrder)) {
|
||||||
RED.nodes.setWorkspaceOrder(newOrder);
|
RED.nodes.setWorkspaceOrder(newOrder);
|
||||||
RED.events.emit("flows:reorder",newOrder);
|
RED.events.emit("flows:reorder",newOrder);
|
||||||
}
|
}
|
||||||
workspace_tabs.order(order);
|
workspace_tabs.order(order);
|
||||||
|
return newOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
function flashTab(tabId) {
|
function flashTab(tabId) {
|
||||||
|
Loading…
Reference in New Issue
Block a user