feat(editor): Update Focus Panel design (no-changelog) (#17373)

This commit is contained in:
Daria
2025-07-17 17:07:10 +03:00
committed by GitHub
parent d36abb5a3a
commit ccac8f7d71
4 changed files with 94 additions and 40 deletions

View File

@@ -129,6 +129,7 @@ import IconLucideMousePointer from '~icons/lucide/mouse-pointer';
import IconLucideNetwork from '~icons/lucide/network'; import IconLucideNetwork from '~icons/lucide/network';
import IconLucidePackageOpen from '~icons/lucide/package-open'; import IconLucidePackageOpen from '~icons/lucide/package-open';
import IconLucidePalette from '~icons/lucide/palette'; import IconLucidePalette from '~icons/lucide/palette';
import IconLucidePanelRight from '~icons/lucide/panel-right';
import IconLucidePause from '~icons/lucide/pause'; import IconLucidePause from '~icons/lucide/pause';
import IconLucidePen from '~icons/lucide/pen'; import IconLucidePen from '~icons/lucide/pen';
import IconLucidePencil from '~icons/lucide/pencil'; import IconLucidePencil from '~icons/lucide/pencil';
@@ -524,6 +525,7 @@ export const updatedIconSet = {
network: IconLucideNetwork, network: IconLucideNetwork,
'package-open': IconLucidePackageOpen, 'package-open': IconLucidePackageOpen,
palette: IconLucidePalette, palette: IconLucidePalette,
'panel-right': IconLucidePanelRight,
pause: IconLucidePause, pause: IconLucidePause,
pen: IconLucidePen, pen: IconLucidePen,
pencil: IconLucidePencil, pencil: IconLucidePencil,

View File

@@ -1497,8 +1497,8 @@
"nodeView.couldntImportWorkflow": "Could not import workflow", "nodeView.couldntImportWorkflow": "Could not import workflow",
"nodeView.couldntLoadWorkflow.invalidWorkflowObject": "Invalid workflow object", "nodeView.couldntLoadWorkflow.invalidWorkflowObject": "Invalid workflow object",
"nodeView.deletesTheCurrentExecutionData": "Deletes the current execution data", "nodeView.deletesTheCurrentExecutionData": "Deletes the current execution data",
"nodeView.focusPanel.title": "Focus", "nodeView.focusPanel.noParameters.title": "Show a node parameter here, to iterate easily",
"nodeView.focusPanel.noParameters": "No parameters focused. Focus a parameter by clicking on the action dropdown in the node detail view.", "nodeView.focusPanel.noParameters.subtitle": "For example, keep your prompt always visible so you can run the workflow while tweaking it",
"nodeView.focusPanel.missingParameter": "This parameter is no longer visible on the node. A related parameter was likely changed, removing this one.", "nodeView.focusPanel.missingParameter": "This parameter is no longer visible on the node. A related parameter was likely changed, removing this one.",
"nodeView.itLooksLikeYouHaveBeenEditingSomething": "It looks like you made some edits. If you leave before saving, your changes will be lost.", "nodeView.itLooksLikeYouHaveBeenEditingSomething": "It looks like you made some edits. If you leave before saving, your changes will be lost.",
"nodeView.loadingTemplate": "Loading template", "nodeView.loadingTemplate": "Loading template",

View File

@@ -314,14 +314,6 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
@resize="onResizeThrottle" @resize="onResizeThrottle"
> >
<div :class="$style.container"> <div :class="$style.container">
<div :class="$style.header">
<N8nText size="small" :bold="true">
{{ locale.baseText('nodeView.focusPanel.title') }}
</N8nText>
<div :class="$style.closeButton" @click="focusPanelStore.closeFocusPanel">
<n8n-icon icon="arrow-right" color="text-base" />
</div>
</div>
<div v-if="resolvedParameter" :class="$style.content"> <div v-if="resolvedParameter" :class="$style.content">
<div :class="$style.tabHeader"> <div :class="$style.tabHeader">
<div :class="$style.tabHeaderText"> <div :class="$style.tabHeaderText">
@@ -330,17 +322,26 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
</N8nText> </N8nText>
<N8nText color="text-base" size="xsmall">{{ resolvedParameter.node.name }}</N8nText> <N8nText color="text-base" size="xsmall">{{ resolvedParameter.node.name }}</N8nText>
</div> </div>
<NodeExecuteButton <div :class="$style.buttonWrapper">
data-test-id="node-execute-button" <NodeExecuteButton
:node-name="resolvedParameter.node.name" data-test-id="node-execute-button"
:tooltip="`Execute ${resolvedParameter.node.name}`" :node-name="resolvedParameter.node.name"
:disabled="!isExecutable" :tooltip="`Execute ${resolvedParameter.node.name}`"
size="small" :disabled="!isExecutable"
icon="play" size="small"
:square="true" icon="play"
:hide-label="true" :square="true"
telemetry-source="focus" :hide-label="true"
></NodeExecuteButton> telemetry-source="focus"
></NodeExecuteButton>
<N8nIcon
:class="$style.closeButton"
icon="x"
color="text-base"
size="xlarge"
@click="focusPanelStore.closeFocusPanel"
/>
</div>
</div> </div>
<div :class="$style.parameterDetailsWrapper"> <div :class="$style.parameterDetailsWrapper">
<div :class="$style.parameterOptionsWrapper"> <div :class="$style.parameterOptionsWrapper">
@@ -448,8 +449,32 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
</div> </div>
<div v-else :class="[$style.content, $style.emptyContent]"> <div v-else :class="[$style.content, $style.emptyContent]">
<div :class="$style.emptyText"> <div :class="$style.emptyText">
<N8nText color="text-base"> <div :class="$style.focusParameterWrapper">
{{ locale.baseText('nodeView.focusPanel.noParameters') }} <div :class="$style.iconWrapper">
<N8nIcon :class="$style.forceHover" icon="panel-right" size="medium" />
<N8nIcon
:class="$style.pointerIcon"
icon="mouse-pointer"
color="text-dark"
size="large"
/>
</div>
<N8nIcon icon="ellipsis-vertical" size="small" color="text-base" />
<N8nRadioButtons
size="small"
:model-value="'expression'"
:disabled="true"
:options="[
{ label: locale.baseText('parameterInput.fixed'), value: 'fixed' },
{ label: locale.baseText('parameterInput.expression'), value: 'expression' },
]"
/>
</div>
<N8nText color="text-base" size="medium" :bold="true">
{{ locale.baseText('nodeView.focusPanel.noParameters.title') }}
</N8nText>
<N8nText color="text-base" size="small">
{{ locale.baseText('nodeView.focusPanel.noParameters.subtitle') }}
</N8nText> </N8nText>
</div> </div>
</div> </div>
@@ -463,7 +488,7 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
display: flex; display: flex;
flex-direction: row nowrap; flex-direction: row nowrap;
border-left: 1px solid var(--color-foreground-base); border-left: 1px solid var(--color-foreground-base);
background: var(--color-foreground-light); background: var(--color-background-xlight);
overflow-y: hidden; overflow-y: hidden;
height: 100%; height: 100%;
} }
@@ -474,18 +499,6 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
height: 100%; height: 100%;
} }
.closeButton:hover {
cursor: pointer;
}
.header {
display: flex;
padding: var(--spacing-2xs);
justify-content: space-between;
border-bottom: 1px solid var(--color-foreground-base);
background: var(--color-foreground-xlight);
}
.content { .content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -498,7 +511,35 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
align-items: center; align-items: center;
.emptyText { .emptyText {
max-width: 300px; margin: 0 var(--spacing-xl);
display: flex;
flex-direction: column;
gap: var(--spacing-2xs);
.focusParameterWrapper {
display: flex;
align-items: center;
justify-content: center;
gap: var(--spacing-2xs);
margin-bottom: var(--spacing-m);
.iconWrapper {
position: relative;
display: inline-block;
}
.pointerIcon {
position: absolute;
top: 100%;
left: 50%;
transform: translate(-20%, -30%);
pointer-events: none;
}
:global([class*='_disabled_']) {
cursor: default !important;
}
}
} }
} }
@@ -517,8 +558,8 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
.buttonWrapper { .buttonWrapper {
display: flex; display: flex;
padding: 6px 8px 6px 34px; gap: var(--spacing-2xs);
justify-content: flex-end; align-items: center;
} }
} }
@@ -545,6 +586,7 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
font-size: var(--font-size-2xs); font-size: var(--font-size-2xs);
:global(.cm-editor) { :global(.cm-editor) {
background-color: var(--color-code-background);
width: 100%; width: 100%;
} }
} }
@@ -552,7 +594,17 @@ const onResizeThrottle = useThrottleFn(onResize, 10);
} }
} }
.closeButton {
cursor: pointer;
}
.heightFull { .heightFull {
height: 100%; height: 100%;
} }
.forceHover {
color: var(--color-button-secondary-hover-active-focus-font);
border-color: var(--color-button-secondary-hover-active-focus-border);
background-color: var(--color-button-secondary-hover-active-focus-background);
}
</style> </style>

View File

@@ -135,7 +135,7 @@ function onAskAssistantButtonClick() {
<n8n-icon-button <n8n-icon-button
type="tertiary" type="tertiary"
size="large" size="large"
icon="list" icon="panel-right"
@click="focusPanelStore.toggleFocusPanel" @click="focusPanelStore.toggleFocusPanel"
/> />
</KeyboardShortcutTooltip> </KeyboardShortcutTooltip>