mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Prevent keyboard shortcuts to edit workflows in readonly mode (#6613)
This commit is contained in:
parent
7515f7d52a
commit
7383e7fd48
|
@ -391,7 +391,6 @@ import {
|
||||||
useRootStore,
|
useRootStore,
|
||||||
useWorkflowsEEStore,
|
useWorkflowsEEStore,
|
||||||
useUsersStore,
|
useUsersStore,
|
||||||
useSourceControlStore,
|
|
||||||
} from '@/stores';
|
} from '@/stores';
|
||||||
import { createEventBus } from 'n8n-design-system';
|
import { createEventBus } from 'n8n-design-system';
|
||||||
|
|
||||||
|
@ -469,7 +468,6 @@ export default defineComponent({
|
||||||
useSettingsStore,
|
useSettingsStore,
|
||||||
useWorkflowsStore,
|
useWorkflowsStore,
|
||||||
useWorkflowsEEStore,
|
useWorkflowsEEStore,
|
||||||
useSourceControlStore,
|
|
||||||
),
|
),
|
||||||
workflowName(): string {
|
workflowName(): string {
|
||||||
return this.workflowsStore.workflowName;
|
return this.workflowsStore.workflowName;
|
||||||
|
@ -493,9 +491,6 @@ export default defineComponent({
|
||||||
|
|
||||||
return this.workflowsEEStore.getWorkflowOwnerName(`${this.workflowId}`, fallback);
|
return this.workflowsEEStore.getWorkflowOwnerName(`${this.workflowId}`, fallback);
|
||||||
},
|
},
|
||||||
readOnlyEnv(): boolean {
|
|
||||||
return this.sourceControlStore.preferences.branchReadOnly;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.executionTimeout = this.rootStore.executionTimeout;
|
this.executionTimeout = this.rootStore.executionTimeout;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
import { mapStores } from 'pinia';
|
||||||
import dateformat from 'dateformat';
|
import dateformat from 'dateformat';
|
||||||
|
|
||||||
import { VIEWS } from '@/constants';
|
import { VIEWS } from '@/constants';
|
||||||
import { useToast } from '@/composables';
|
import { useToast } from '@/composables';
|
||||||
|
import { useSourceControlStore } from '@/stores';
|
||||||
|
|
||||||
export const genericHelpers = defineComponent({
|
export const genericHelpers = defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
|
@ -17,11 +18,15 @@ export const genericHelpers = defineComponent({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapStores(useSourceControlStore),
|
||||||
isReadOnlyRoute(): boolean {
|
isReadOnlyRoute(): boolean {
|
||||||
return ![VIEWS.WORKFLOW, VIEWS.NEW_WORKFLOW, VIEWS.LOG_STREAMING_SETTINGS].includes(
|
return ![VIEWS.WORKFLOW, VIEWS.NEW_WORKFLOW, VIEWS.LOG_STREAMING_SETTINGS].includes(
|
||||||
this.$route.name as VIEWS,
|
this.$route.name as VIEWS,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
readOnlyEnv(): boolean {
|
||||||
|
return this.sourceControlStore.preferences.branchReadOnly;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayTimer(msPassed: number, showMs = false): string {
|
displayTimer(msPassed: number, showMs = false): string {
|
||||||
|
@ -49,21 +54,6 @@ export const genericHelpers = defineComponent({
|
||||||
const [date, time] = formattedDate.split('#');
|
const [date, time] = formattedDate.split('#');
|
||||||
return { date, time };
|
return { date, time };
|
||||||
},
|
},
|
||||||
editAllowedCheck(): boolean {
|
|
||||||
if (this.isReadOnlyRoute) {
|
|
||||||
this.showMessage({
|
|
||||||
// title: 'Workflow can not be changed!',
|
|
||||||
title: this.$locale.baseText('genericHelpers.showMessage.title'),
|
|
||||||
message: this.$locale.baseText('genericHelpers.showMessage.message'),
|
|
||||||
type: 'info',
|
|
||||||
duration: 0,
|
|
||||||
dangerouslyUseHTMLString: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @note Loading helpers extracted as composable in useLoadingService
|
* @note Loading helpers extracted as composable in useLoadingService
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
@addNode="onAddNode"
|
@addNode="onAddNode"
|
||||||
/>
|
/>
|
||||||
<canvas-controls />
|
<canvas-controls />
|
||||||
<div class="workflow-execute-wrapper" v-if="!isReadOnlyRoute">
|
<div class="workflow-execute-wrapper" v-if="!isReadOnlyRoute && !readOnlyEnv">
|
||||||
<span
|
<span
|
||||||
@mouseenter="showTriggerMissingToltip(true)"
|
@mouseenter="showTriggerMissingToltip(true)"
|
||||||
@mouseleave="showTriggerMissingToltip(false)"
|
@mouseleave="showTriggerMissingToltip(false)"
|
||||||
|
@ -149,7 +149,13 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<n8n-icon-button
|
<n8n-icon-button
|
||||||
v-if="!isReadOnlyRoute && workflowExecution && !workflowRunning && !allTriggersDisabled"
|
v-if="
|
||||||
|
!isReadOnlyRoute &&
|
||||||
|
!readOnlyEnv &&
|
||||||
|
workflowExecution &&
|
||||||
|
!workflowRunning &&
|
||||||
|
!allTriggersDisabled
|
||||||
|
"
|
||||||
:title="$locale.baseText('nodeView.deletesTheCurrentExecutionData')"
|
:title="$locale.baseText('nodeView.deletesTheCurrentExecutionData')"
|
||||||
icon="trash"
|
icon="trash"
|
||||||
size="large"
|
size="large"
|
||||||
|
@ -281,7 +287,6 @@ import {
|
||||||
useSettingsStore,
|
useSettingsStore,
|
||||||
useUIStore,
|
useUIStore,
|
||||||
useHistoryStore,
|
useHistoryStore,
|
||||||
useSourceControlStore,
|
|
||||||
} from '@/stores';
|
} from '@/stores';
|
||||||
import * as NodeViewUtils from '@/utils/nodeViewUtils';
|
import * as NodeViewUtils from '@/utils/nodeViewUtils';
|
||||||
import { getAccountAge, getConnectionInfo, getNodeViewTab } from '@/utils';
|
import { getAccountAge, getConnectionInfo, getNodeViewTab } from '@/utils';
|
||||||
|
@ -483,11 +488,7 @@ export default defineComponent({
|
||||||
useEnvironmentsStore,
|
useEnvironmentsStore,
|
||||||
useWorkflowsEEStore,
|
useWorkflowsEEStore,
|
||||||
useHistoryStore,
|
useHistoryStore,
|
||||||
useSourceControlStore,
|
|
||||||
),
|
),
|
||||||
readOnlyEnv(): boolean {
|
|
||||||
return this.sourceControlStore.preferences.branchReadOnly;
|
|
||||||
},
|
|
||||||
nativelyNumberSuffixedDefaults(): string[] {
|
nativelyNumberSuffixedDefaults(): string[] {
|
||||||
return this.rootStore.nativelyNumberSuffixedDefaults;
|
return this.rootStore.nativelyNumberSuffixedDefaults;
|
||||||
},
|
},
|
||||||
|
@ -635,6 +636,21 @@ export default defineComponent({
|
||||||
this.unregisterCustomAction('showNodeCreator');
|
this.unregisterCustomAction('showNodeCreator');
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
editAllowedCheck(): boolean {
|
||||||
|
if (this.isReadOnlyRoute || this.readOnlyEnv) {
|
||||||
|
this.showMessage({
|
||||||
|
// title: 'Workflow can not be changed!',
|
||||||
|
title: this.$locale.baseText('genericHelpers.showMessage.title'),
|
||||||
|
message: this.$locale.baseText('genericHelpers.showMessage.message'),
|
||||||
|
type: 'info',
|
||||||
|
duration: 0,
|
||||||
|
dangerouslyUseHTMLString: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
showTriggerMissingToltip(isVisible: boolean) {
|
showTriggerMissingToltip(isVisible: boolean) {
|
||||||
this.showTriggerMissingTooltip = isVisible;
|
this.showTriggerMissingTooltip = isVisible;
|
||||||
},
|
},
|
||||||
|
@ -961,7 +977,7 @@ export default defineComponent({
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (this.isReadOnlyRoute) {
|
if (this.isReadOnlyRoute || this.readOnlyEnv) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1015,13 +1031,13 @@ export default defineComponent({
|
||||||
} else if (e.key === 'Tab') {
|
} else if (e.key === 'Tab') {
|
||||||
this.onToggleNodeCreator({
|
this.onToggleNodeCreator({
|
||||||
source: NODE_CREATOR_OPEN_SOURCES.TAB,
|
source: NODE_CREATOR_OPEN_SOURCES.TAB,
|
||||||
createNodeActive: !this.createNodeActive && !this.isReadOnlyRoute,
|
createNodeActive: !this.createNodeActive && !this.isReadOnlyRoute && !this.readOnlyEnv,
|
||||||
});
|
});
|
||||||
} else if (e.key === this.controlKeyCode) {
|
} else if (e.key === this.controlKeyCode) {
|
||||||
this.ctrlKeyPressed = true;
|
this.ctrlKeyPressed = true;
|
||||||
} else if (e.key === ' ') {
|
} else if (e.key === ' ') {
|
||||||
this.moveCanvasKeyPressed = true;
|
this.moveCanvasKeyPressed = true;
|
||||||
} else if (e.key === 'F2' && !this.isReadOnlyRoute) {
|
} else if (e.key === 'F2' && !this.isReadOnlyRoute && !this.readOnlyEnv) {
|
||||||
const lastSelectedNode = this.lastSelectedNode;
|
const lastSelectedNode = this.lastSelectedNode;
|
||||||
if (lastSelectedNode !== null && lastSelectedNode.type !== STICKY_NODE_TYPE) {
|
if (lastSelectedNode !== null && lastSelectedNode.type !== STICKY_NODE_TYPE) {
|
||||||
void this.callDebounced(
|
void this.callDebounced(
|
||||||
|
@ -1067,7 +1083,10 @@ export default defineComponent({
|
||||||
const lastSelectedNode = this.lastSelectedNode;
|
const lastSelectedNode = this.lastSelectedNode;
|
||||||
|
|
||||||
if (lastSelectedNode !== null) {
|
if (lastSelectedNode !== null) {
|
||||||
if (lastSelectedNode.type === STICKY_NODE_TYPE && this.isReadOnlyRoute) {
|
if (
|
||||||
|
lastSelectedNode.type === STICKY_NODE_TYPE &&
|
||||||
|
(this.isReadOnlyRoute || this.readOnlyEnv)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.ndvStore.activeNodeName = lastSelectedNode.name;
|
this.ndvStore.activeNodeName = lastSelectedNode.name;
|
||||||
|
@ -1307,7 +1326,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
cutSelectedNodes() {
|
cutSelectedNodes() {
|
||||||
const deleteCopiedNodes = !this.isReadOnlyRoute;
|
const deleteCopiedNodes = !this.isReadOnlyRoute && !this.readOnlyEnv;
|
||||||
this.copySelectedNodes(deleteCopiedNodes);
|
this.copySelectedNodes(deleteCopiedNodes);
|
||||||
if (deleteCopiedNodes) {
|
if (deleteCopiedNodes) {
|
||||||
this.deleteSelectedNodes();
|
this.deleteSelectedNodes();
|
||||||
|
@ -2162,7 +2181,7 @@ export default defineComponent({
|
||||||
if (!this.suspendRecordingDetachedConnections) {
|
if (!this.suspendRecordingDetachedConnections) {
|
||||||
this.historyStore.pushCommandToUndo(new AddConnectionCommand(connectionData));
|
this.historyStore.pushCommandToUndo(new AddConnectionCommand(connectionData));
|
||||||
}
|
}
|
||||||
if (!this.isReadOnlyRoute) {
|
if (!this.isReadOnlyRoute && !this.readOnlyEnv) {
|
||||||
NodeViewUtils.addConnectionActionsOverlay(
|
NodeViewUtils.addConnectionActionsOverlay(
|
||||||
info.connection,
|
info.connection,
|
||||||
() => {
|
() => {
|
||||||
|
@ -2609,7 +2628,7 @@ export default defineComponent({
|
||||||
// Create connections in DOM
|
// Create connections in DOM
|
||||||
this.instance?.connect({
|
this.instance?.connect({
|
||||||
uuids: uuid,
|
uuids: uuid,
|
||||||
detachable: !this.isReadOnlyRoute,
|
detachable: !this.isReadOnlyRoute && !this.readOnlyEnv,
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
|
@ -112,6 +112,7 @@ import { useUsersStore } from '@/stores/users.store';
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useCredentialsStore } from '@/stores/credentials.store';
|
import { useCredentialsStore } from '@/stores/credentials.store';
|
||||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||||
|
import { genericHelpers } from '@/mixins/genericHelpers';
|
||||||
|
|
||||||
type IResourcesListLayoutInstance = Vue & { sendFiltersTelemetry: (source: string) => void };
|
type IResourcesListLayoutInstance = Vue & { sendFiltersTelemetry: (source: string) => void };
|
||||||
|
|
||||||
|
@ -123,6 +124,7 @@ const StatusFilter = {
|
||||||
|
|
||||||
const WorkflowsView = defineComponent({
|
const WorkflowsView = defineComponent({
|
||||||
name: 'WorkflowsView',
|
name: 'WorkflowsView',
|
||||||
|
mixins: [genericHelpers],
|
||||||
components: {
|
components: {
|
||||||
ResourcesListLayout,
|
ResourcesListLayout,
|
||||||
WorkflowCard,
|
WorkflowCard,
|
||||||
|
@ -174,9 +176,6 @@ const WorkflowsView = defineComponent({
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
readOnlyEnv(): boolean {
|
|
||||||
return this.sourceControlStore.preferences.branchReadOnly;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addWorkflow() {
|
addWorkflow() {
|
||||||
|
|
Loading…
Reference in a new issue