mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
feat(editor): Add focus panel component (no-changelog) (#16620)
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
||||
} from 'vue';
|
||||
import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router';
|
||||
import WorkflowCanvas from '@/components/canvas/WorkflowCanvas.vue';
|
||||
import FocusPanel from '@/components/FocusPanel.vue';
|
||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
import CanvasRunWorkflowButton from '@/components/canvas/elements/buttons/CanvasRunWorkflowButton.vue';
|
||||
@@ -54,6 +55,7 @@ import {
|
||||
CHAT_TRIGGER_NODE_TYPE,
|
||||
DRAG_EVENT_DATA_KEY,
|
||||
EnterpriseEditionFeature,
|
||||
FOCUS_PANEL_EXPERIMENT,
|
||||
FROM_AI_PARAMETERS_MODAL_KEY,
|
||||
MAIN_HEADER_TABS,
|
||||
MANUAL_CHAT_TRIGGER_NODE_TYPE,
|
||||
@@ -69,6 +71,7 @@ import {
|
||||
} from '@/constants';
|
||||
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||
import { useNodeCreatorStore } from '@/stores/nodeCreator.store';
|
||||
import { usePostHog } from '@/stores/posthog.store';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
import {
|
||||
NodeConnectionTypes,
|
||||
@@ -242,6 +245,10 @@ const { extractWorkflow } = useWorkflowExtraction();
|
||||
const { applyExecutionData } = useExecutionDebugging();
|
||||
useClipboard({ onPaste: onClipboardPaste });
|
||||
|
||||
const isFocusPanelFeatureEnabled = computed(() => {
|
||||
return usePostHog().getVariant(FOCUS_PANEL_EXPERIMENT.name) === FOCUS_PANEL_EXPERIMENT.variant;
|
||||
});
|
||||
|
||||
const isLoading = ref(true);
|
||||
const isBlankRedirect = ref(false);
|
||||
const readOnlyNotification = ref<null | { visible: boolean }>(null);
|
||||
@@ -1981,146 +1988,154 @@ onBeforeUnmount(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<WorkflowCanvas
|
||||
v-if="editableWorkflow && editableWorkflowObject && !isLoading"
|
||||
:id="editableWorkflow.id"
|
||||
:workflow="editableWorkflow"
|
||||
:workflow-object="editableWorkflowObject"
|
||||
:fallback-nodes="fallbackNodes"
|
||||
:show-fallback-nodes="showFallbackNodes"
|
||||
:event-bus="canvasEventBus"
|
||||
:read-only="isCanvasReadOnly"
|
||||
:executing="isWorkflowRunning"
|
||||
:key-bindings="keyBindingsEnabled"
|
||||
@update:nodes:position="onUpdateNodesPosition"
|
||||
@update:node:position="onUpdateNodePosition"
|
||||
@update:node:activated="onSetNodeActivated"
|
||||
@update:node:deactivated="onSetNodeDeactivated"
|
||||
@update:node:selected="onSetNodeSelected"
|
||||
@update:node:enabled="onToggleNodeDisabled"
|
||||
@update:node:name="onOpenRenameNodeModal"
|
||||
@update:node:parameters="onUpdateNodeParameters"
|
||||
@update:node:inputs="onUpdateNodeInputs"
|
||||
@update:node:outputs="onUpdateNodeOutputs"
|
||||
@update:logs-open="logsStore.toggleOpen($event)"
|
||||
@update:logs:input-open="logsStore.toggleInputOpen"
|
||||
@update:logs:output-open="logsStore.toggleOutputOpen"
|
||||
@update:has-range-selection="canvasStore.setHasRangeSelection"
|
||||
@open:sub-workflow="onOpenSubWorkflow"
|
||||
@click:node="onClickNode"
|
||||
@click:node:add="onClickNodeAdd"
|
||||
@run:node="onRunWorkflowToNode"
|
||||
@delete:node="onDeleteNode"
|
||||
@create:connection="onCreateConnection"
|
||||
@create:connection:cancelled="onCreateConnectionCancelled"
|
||||
@delete:connection="onDeleteConnection"
|
||||
@click:connection:add="onClickConnectionAdd"
|
||||
@click:pane="onClickPane"
|
||||
@create:node="onOpenNodeCreatorFromCanvas"
|
||||
@create:sticky="onCreateSticky"
|
||||
@delete:nodes="onDeleteNodes"
|
||||
@update:nodes:enabled="onToggleNodesDisabled"
|
||||
@update:nodes:pin="onPinNodes"
|
||||
@duplicate:nodes="onDuplicateNodes"
|
||||
@copy:nodes="onCopyNodes"
|
||||
@cut:nodes="onCutNodes"
|
||||
@run:workflow="runEntireWorkflow('main')"
|
||||
@save:workflow="onSaveWorkflow"
|
||||
@create:workflow="onCreateWorkflow"
|
||||
@viewport:change="onViewportChange"
|
||||
@selection:end="onSelectionEnd"
|
||||
@drag-and-drop="onDragAndDrop"
|
||||
@tidy-up="onTidyUp"
|
||||
@extract-workflow="onExtractWorkflow"
|
||||
@start-chat="startChat()"
|
||||
>
|
||||
<Suspense>
|
||||
<LazySetupWorkflowCredentialsButton :class="$style.setupCredentialsButtonWrapper" />
|
||||
</Suspense>
|
||||
<div v-if="!isCanvasReadOnly" :class="$style.executionButtons">
|
||||
<CanvasRunWorkflowButton
|
||||
v-if="isRunWorkflowButtonVisible"
|
||||
:waiting-for-webhook="isExecutionWaitingForWebhook"
|
||||
:disabled="isExecutionDisabled"
|
||||
:executing="isWorkflowRunning"
|
||||
:trigger-nodes="triggerNodes"
|
||||
:get-node-type="nodeTypesStore.getNodeType"
|
||||
:selected-trigger-node-name="workflowsStore.selectedTriggerNodeName"
|
||||
@mouseenter="onRunWorkflowButtonMouseEnter"
|
||||
@mouseleave="onRunWorkflowButtonMouseLeave"
|
||||
@execute="runEntireWorkflow('main')"
|
||||
@select-trigger-node="workflowsStore.setSelectedTriggerNodeName"
|
||||
/>
|
||||
<template v-if="containsChatTriggerNodes">
|
||||
<CanvasChatButton
|
||||
v-if="isLogsPanelOpen"
|
||||
type="tertiary"
|
||||
:label="i18n.baseText('chat.hide')"
|
||||
:class="$style.chatButton"
|
||||
@click="logsStore.toggleOpen(false)"
|
||||
/>
|
||||
<KeyboardShortcutTooltip
|
||||
v-else
|
||||
:label="i18n.baseText('chat.open')"
|
||||
:shortcut="{ keys: ['c'] }"
|
||||
>
|
||||
<CanvasChatButton
|
||||
:type="isRunWorkflowButtonVisible ? 'secondary' : 'primary'"
|
||||
:label="i18n.baseText('chat.open')"
|
||||
:class="$style.chatButton"
|
||||
@click="onOpenChat"
|
||||
/>
|
||||
</KeyboardShortcutTooltip>
|
||||
</template>
|
||||
<CanvasStopCurrentExecutionButton
|
||||
v-if="isStopExecutionButtonVisible"
|
||||
:stopping="isStoppingExecution"
|
||||
@click="onStopExecution"
|
||||
/>
|
||||
<CanvasStopWaitingForWebhookButton
|
||||
v-if="isStopWaitingForWebhookButtonVisible"
|
||||
@click="onStopWaitingForWebhook"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<N8nCallout
|
||||
v-if="isReadOnlyEnvironment"
|
||||
theme="warning"
|
||||
icon="lock"
|
||||
:class="$style.readOnlyEnvironmentNotification"
|
||||
<div :class="$style.wrapper">
|
||||
<WorkflowCanvas
|
||||
v-if="editableWorkflow && editableWorkflowObject && !isLoading"
|
||||
:id="editableWorkflow.id"
|
||||
:workflow="editableWorkflow"
|
||||
:workflow-object="editableWorkflowObject"
|
||||
:fallback-nodes="fallbackNodes"
|
||||
:show-fallback-nodes="showFallbackNodes"
|
||||
:event-bus="canvasEventBus"
|
||||
:read-only="isCanvasReadOnly"
|
||||
:executing="isWorkflowRunning"
|
||||
:key-bindings="keyBindingsEnabled"
|
||||
@update:nodes:position="onUpdateNodesPosition"
|
||||
@update:node:position="onUpdateNodePosition"
|
||||
@update:node:activated="onSetNodeActivated"
|
||||
@update:node:deactivated="onSetNodeDeactivated"
|
||||
@update:node:selected="onSetNodeSelected"
|
||||
@update:node:enabled="onToggleNodeDisabled"
|
||||
@update:node:name="onOpenRenameNodeModal"
|
||||
@update:node:parameters="onUpdateNodeParameters"
|
||||
@update:node:inputs="onUpdateNodeInputs"
|
||||
@update:node:outputs="onUpdateNodeOutputs"
|
||||
@update:logs-open="logsStore.toggleOpen($event)"
|
||||
@update:logs:input-open="logsStore.toggleInputOpen"
|
||||
@update:logs:output-open="logsStore.toggleOutputOpen"
|
||||
@update:has-range-selection="canvasStore.setHasRangeSelection"
|
||||
@open:sub-workflow="onOpenSubWorkflow"
|
||||
@click:node="onClickNode"
|
||||
@click:node:add="onClickNodeAdd"
|
||||
@run:node="onRunWorkflowToNode"
|
||||
@delete:node="onDeleteNode"
|
||||
@create:connection="onCreateConnection"
|
||||
@create:connection:cancelled="onCreateConnectionCancelled"
|
||||
@delete:connection="onDeleteConnection"
|
||||
@click:connection:add="onClickConnectionAdd"
|
||||
@click:pane="onClickPane"
|
||||
@create:node="onOpenNodeCreatorFromCanvas"
|
||||
@create:sticky="onCreateSticky"
|
||||
@delete:nodes="onDeleteNodes"
|
||||
@update:nodes:enabled="onToggleNodesDisabled"
|
||||
@update:nodes:pin="onPinNodes"
|
||||
@duplicate:nodes="onDuplicateNodes"
|
||||
@copy:nodes="onCopyNodes"
|
||||
@cut:nodes="onCutNodes"
|
||||
@run:workflow="runEntireWorkflow('main')"
|
||||
@save:workflow="onSaveWorkflow"
|
||||
@create:workflow="onCreateWorkflow"
|
||||
@viewport:change="onViewportChange"
|
||||
@selection:end="onSelectionEnd"
|
||||
@drag-and-drop="onDragAndDrop"
|
||||
@tidy-up="onTidyUp"
|
||||
@extract-workflow="onExtractWorkflow"
|
||||
@start-chat="startChat()"
|
||||
>
|
||||
{{ i18n.baseText('readOnlyEnv.cantEditOrRun') }}
|
||||
</N8nCallout>
|
||||
<Suspense>
|
||||
<LazySetupWorkflowCredentialsButton :class="$style.setupCredentialsButtonWrapper" />
|
||||
</Suspense>
|
||||
<div v-if="!isCanvasReadOnly" :class="$style.executionButtons">
|
||||
<CanvasRunWorkflowButton
|
||||
v-if="isRunWorkflowButtonVisible"
|
||||
:waiting-for-webhook="isExecutionWaitingForWebhook"
|
||||
:disabled="isExecutionDisabled"
|
||||
:executing="isWorkflowRunning"
|
||||
:trigger-nodes="triggerNodes"
|
||||
:get-node-type="nodeTypesStore.getNodeType"
|
||||
:selected-trigger-node-name="workflowsStore.selectedTriggerNodeName"
|
||||
@mouseenter="onRunWorkflowButtonMouseEnter"
|
||||
@mouseleave="onRunWorkflowButtonMouseLeave"
|
||||
@execute="runEntireWorkflow('main')"
|
||||
@select-trigger-node="workflowsStore.setSelectedTriggerNodeName"
|
||||
/>
|
||||
<template v-if="containsChatTriggerNodes">
|
||||
<CanvasChatButton
|
||||
v-if="isLogsPanelOpen"
|
||||
type="tertiary"
|
||||
:label="i18n.baseText('chat.hide')"
|
||||
:class="$style.chatButton"
|
||||
@click="logsStore.toggleOpen(false)"
|
||||
/>
|
||||
<KeyboardShortcutTooltip
|
||||
v-else
|
||||
:label="i18n.baseText('chat.open')"
|
||||
:shortcut="{ keys: ['c'] }"
|
||||
>
|
||||
<CanvasChatButton
|
||||
:type="isRunWorkflowButtonVisible ? 'secondary' : 'primary'"
|
||||
:label="i18n.baseText('chat.open')"
|
||||
:class="$style.chatButton"
|
||||
@click="onOpenChat"
|
||||
/>
|
||||
</KeyboardShortcutTooltip>
|
||||
</template>
|
||||
<CanvasStopCurrentExecutionButton
|
||||
v-if="isStopExecutionButtonVisible"
|
||||
:stopping="isStoppingExecution"
|
||||
@click="onStopExecution"
|
||||
/>
|
||||
<CanvasStopWaitingForWebhookButton
|
||||
v-if="isStopWaitingForWebhookButtonVisible"
|
||||
@click="onStopWaitingForWebhook"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Suspense>
|
||||
<LazyNodeCreation
|
||||
v-if="!isCanvasReadOnly"
|
||||
:create-node-active="nodeCreatorStore.isCreateNodeActive"
|
||||
:node-view-scale="viewportTransform.zoom"
|
||||
@toggle-node-creator="onToggleNodeCreator"
|
||||
@add-nodes="onAddNodesAndConnections"
|
||||
/>
|
||||
</Suspense>
|
||||
<Suspense>
|
||||
<LazyNodeDetailsView
|
||||
:workflow-object="editableWorkflowObject"
|
||||
:read-only="isCanvasReadOnly"
|
||||
:is-production-execution-preview="isProductionExecutionPreview"
|
||||
:renaming="false"
|
||||
@value-changed="onRenameNode"
|
||||
@stop-execution="onStopExecution"
|
||||
@switch-selected-node="onSwitchActiveNode"
|
||||
@open-connection-node-creator="onOpenSelectiveNodeCreator"
|
||||
@save-keyboard-shortcut="onSaveWorkflow"
|
||||
/>
|
||||
<!--
|
||||
<N8nCallout
|
||||
v-if="isReadOnlyEnvironment"
|
||||
theme="warning"
|
||||
icon="lock"
|
||||
:class="$style.readOnlyEnvironmentNotification"
|
||||
>
|
||||
{{ i18n.baseText('readOnlyEnv.cantEditOrRun') }}
|
||||
</N8nCallout>
|
||||
|
||||
<Suspense>
|
||||
<LazyNodeCreation
|
||||
v-if="!isCanvasReadOnly"
|
||||
:create-node-active="nodeCreatorStore.isCreateNodeActive"
|
||||
:node-view-scale="viewportTransform.zoom"
|
||||
@toggle-node-creator="onToggleNodeCreator"
|
||||
@add-nodes="onAddNodesAndConnections"
|
||||
/>
|
||||
</Suspense>
|
||||
<Suspense>
|
||||
<LazyNodeDetailsView
|
||||
:workflow-object="editableWorkflowObject"
|
||||
:read-only="isCanvasReadOnly"
|
||||
:is-production-execution-preview="isProductionExecutionPreview"
|
||||
:renaming="false"
|
||||
@value-changed="onRenameNode"
|
||||
@stop-execution="onStopExecution"
|
||||
@switch-selected-node="onSwitchActiveNode"
|
||||
@open-connection-node-creator="onOpenSelectiveNodeCreator"
|
||||
@save-keyboard-shortcut="onSaveWorkflow"
|
||||
/>
|
||||
<!--
|
||||
:renaming="renamingActive"
|
||||
-->
|
||||
</Suspense>
|
||||
</WorkflowCanvas>
|
||||
</Suspense>
|
||||
</WorkflowCanvas>
|
||||
<FocusPanel v-if="isFocusPanelFeatureEnabled" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
.wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.executionButtons {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user