diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 6dd500581..adbf86741 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -63,6 +63,7 @@ RED.nodes = (function() { defaults: { label: {value:""}, disabled: {value: false}, + locked: {value: false}, info: {value: ""}, env: {value: []} } @@ -1052,6 +1053,9 @@ RED.nodes = (function() { node.type = n.type; for (var d in n._def.defaults) { if (n._def.defaults.hasOwnProperty(d)) { + if (d === 'locked' && !n.locked) { + continue + } node[d] = n[d]; } } diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index fb4c200f5..0a644ba42 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -1852,6 +1852,16 @@ RED.editor = (function() { } } + var locked = $("#node-input-locked").prop("checked"); + if (workspace.locked !== locked) { + editState.changes.locked = workspace.locked; + editState.changed = true; + workspace.locked = locked; + $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked); + // if (workspace.id === RED.workspaces.active()) { + // $("#red-ui-workspace").toggleClass("red-ui-workspace-locked",!!workspace.locked); + // } + } if (editState.changed) { var historyEvent = { t: "edit", @@ -1892,6 +1902,7 @@ RED.editor = (function() { var trayBody = tray.find('.red-ui-tray-body'); trayBody.parent().css('overflow','hidden'); var trayFooterLeft = $('').appendTo(trayFooter) + var trayFooterRight = $('').appendTo(trayFooter) var nodeEditPanes = [ 'editor-tab-flow-properties', @@ -1906,6 +1917,18 @@ RED.editor = (function() { disabledIcon: "fa-ban", invertState: true }) + + if (!workspace.hasOwnProperty("locked")) { + workspace.locked = false; + } + $('').prop("checked",workspace.locked).appendTo(trayFooterRight).toggleButton({ + enabledLabel: 'Unlocked', + enabledIcon: "fa-unlock-alt", + disabledLabel: 'Locked', + disabledIcon: "fa-lock", + invertState: true + }) + prepareEditDialog(trayBody, nodeEditPanes, workspace, {}, "node-input", defaultTab, function(_activeEditPanes) { activeEditPanes = _activeEditPanes; trayBody.i18n(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js index 32491f297..20bf627f0 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-info-outliner.js @@ -221,6 +221,22 @@ RED.sidebar.info.outliner = (function() { } else { $('
').appendTo(controls) } + if (n.type === 'tab') { + var lockToggleButton = $('').appendTo(controls).on("click",function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + if (n.locked) { + RED.workspaces.unlock(n.id) + } else { + RED.workspaces.lock(n.id) + } + }) + RED.popover.tooltip(lockToggleButton,function() { + return RED._("common.label."+(n.locked?"unlock":"lock")); + }); + } else { + $('
').appendTo(controls) + } controls.find("button").on("dblclick", function(evt) { evt.preventDefault(); evt.stopPropagation(); @@ -364,6 +380,8 @@ RED.sidebar.info.outliner = (function() { flowList.treeList.addChild(objects[ws.id]) objects[ws.id].element.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled) objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled) + objects[ws.id].element.toggleClass("red-ui-info-outline-item-locked", !!ws.locked) + // objects[ws.id].treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!ws.disabled) updateSearch(); } @@ -378,6 +396,7 @@ RED.sidebar.info.outliner = (function() { existingObject.element.find(".red-ui-info-outline-item-label").text(label); existingObject.element.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled) existingObject.treeList.container.toggleClass("red-ui-info-outline-item-disabled", !!n.disabled) + existingObject.element.toggleClass("red-ui-info-outline-item-locked", !!n.locked) updateSearch(); } function onFlowsReorder(order) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js index d274ba519..23171fb5a 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js @@ -58,6 +58,9 @@ RED.workspaces = (function() { if (!ws.closeable) { ws.hideable = true; } + if (!ws.hasOwnProperty('locked')) { + ws.locked = false + } workspace_tabs.addTab(ws,targetIndex); var hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}"); @@ -75,6 +78,7 @@ RED.workspaces = (function() { type: "tab", id: tabId, disabled: false, + locked: false, info: "", label: RED._('workspace.defaultName',{number:workspaceIndex}), env: [], @@ -329,6 +333,12 @@ RED.workspaces = (function() { if (tab.disabled) { $("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-disabled'); } + $(' ').prependTo("#red-ui-tab-"+(tab.id.replace(".","-"))+" .red-ui-tab-label"); + if (tab.locked) { + $("#red-ui-tab-"+(tab.id.replace(".","-"))).addClass('red-ui-workspace-locked'); + } + + RED.menu.setDisabled("menu-item-workspace-delete",activeWorkspace === 0 || workspaceTabCount <= 1); if (workspaceTabCount === 1) { showWorkspace(); @@ -465,6 +475,8 @@ RED.workspaces = (function() { RED.actions.add("core:remove-flow",removeWorkspace); RED.actions.add("core:enable-flow",enableWorkspace); RED.actions.add("core:disable-flow",disableWorkspace); + RED.actions.add("core:lock-flow",lockWorkspace); + RED.actions.add("core:unlock-flow",unlockWorkspace); 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') }); @@ -638,6 +650,49 @@ RED.workspaces = (function() { } } } + function lockWorkspace(id) { + setWorkspaceLockState(id,true); + } + function unlockWorkspace(id) { + setWorkspaceLockState(id,false); + } + function setWorkspaceLockState(id,locked) { + var workspace = RED.nodes.workspace(id||activeWorkspace); + if (!workspace) { + return; + } + if (workspace.locked !== locked) { + var changes = { locked: workspace.locked }; + workspace.locked = locked; + $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked); + if (!id || (id === activeWorkspace)) { + $("#red-ui-workspace").toggleClass("red-ui-workspace-locked",!!workspace.locked); + } + var historyEvent = { + t: "edit", + changes:changes, + node: workspace, + dirty: RED.nodes.dirty() + } + workspace.changed = true; + RED.history.push(historyEvent); + RED.events.emit("flows:change",workspace); + RED.nodes.dirty(true); + // RED.sidebar.config.refresh(); + // var selection = RED.view.selection(); + // if (!selection.nodes && !selection.links && workspace.id === activeWorkspace) { + // RED.sidebar.info.refresh(workspace); + // } + // if (changes.hasOwnProperty('disabled')) { + // RED.nodes.eachNode(function(n) { + // if (n.z === workspace.id) { + // n.dirty = true; + // } + // }); + // RED.view.redraw(); + // } + } + } function removeWorkspace(ws) { if (!ws) { @@ -793,6 +848,8 @@ RED.workspaces = (function() { workspace_tabs.resize(); }, enable: enableWorkspace, - disable: disableWorkspace + disable: disableWorkspace, + lock: lockWorkspace, + unlock: unlockWorkspace } })(); diff --git a/packages/node_modules/@node-red/editor-client/src/sass/tab-info.scss b/packages/node_modules/@node-red/editor-client/src/sass/tab-info.scss index 57dc7d6e3..ed526b263 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/tab-info.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/tab-info.scss @@ -467,6 +467,9 @@ div.red-ui-info-table { .fa-eye { display: none; } + .fa-unlock-alt { + display: none; + } } .red-ui-info-outline-item-control-reveal, .red-ui-info-outline-item-control-action { @@ -500,6 +503,17 @@ div.red-ui-info-table { display: none; } } + .fa-lock { + display: none; + } + .red-ui-info-outline-item.red-ui-info-outline-item-locked & { + .fa-lock { + display: inline-block; + } + .fa-unlock-alt { + display: none; + } + } button { margin-right: 3px } diff --git a/packages/node_modules/@node-red/editor-client/src/sass/workspace.scss b/packages/node_modules/@node-red/editor-client/src/sass/workspace.scss index 24e156b1e..c458d03d1 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/workspace.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/workspace.scss @@ -106,6 +106,28 @@ } } +.red-ui-workspace-locked-icon { + display: none; +} +.red-ui-workspace-locked { + &.red-ui-tab { + // border-top-style: dashed; + // border-left-style: dashed; + // border-right-style: dashed; + + // a { + // font-style: italic; + // color: var(--red-ui-tab-text-color-disabled-inactive) !important; + // } + // &.active a { + // font-weight: normal; + // color: var(--red-ui-tab-text-color-disabled-active) !important; + // } + .red-ui-workspace-locked-icon { + display: inline; + } + } +} #red-ui-navigator-canvas { position: absolute;