Skip to content

Commit

Permalink
fix(editor): Provide correct node output runData information in new…
Browse files Browse the repository at this point in the history
… canvas (no-changelog) (#10691)
  • Loading branch information
alexgrozav authored and riascho committed Sep 23, 2024
1 parent 1f870e8 commit 288493d
Show file tree
Hide file tree
Showing 16 changed files with 421 additions and 50 deletions.
9 changes: 8 additions & 1 deletion packages/editor-ui/src/__tests__/data/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
CanvasNodeEventBusEvents,
CanvasNodeHandleInjectionData,
CanvasNodeInjectionData,
ExecutionOutputMapData,
} from '@/types';
import { CanvasConnectionMode, CanvasNodeRenderType } from '@/types';
import { NodeConnectionType } from 'n8n-workflow';
Expand All @@ -25,7 +26,7 @@ export function createCanvasNodeData({
execution = { running: false },
issues = { items: [], visible: false },
pinnedData = { count: 0, visible: false },
runData = { count: 0, visible: false },
runData = { outputMap: {}, iterations: 0, visible: false },
render = {
type: CanvasNodeRenderType.Default,
options: { configurable: false, configuration: false, trigger: false },
Expand Down Expand Up @@ -119,13 +120,17 @@ export function createCanvasHandleProvide({
label = 'Handle',
mode = CanvasConnectionMode.Input,
type = NodeConnectionType.Main,
index = 0,
runData,
isConnected = false,
isConnecting = false,
isReadOnly = false,
}: {
label?: string;
mode?: CanvasConnectionMode;
type?: NodeConnectionType;
index?: number;
runData?: ExecutionOutputMapData;
isConnected?: boolean;
isConnecting?: boolean;
isReadOnly?: boolean;
Expand All @@ -135,8 +140,10 @@ export function createCanvasHandleProvide({
label: ref(label),
mode: ref(mode),
type: ref(type),
index: ref(index),
isConnected: ref(isConnected),
isConnecting: ref(isConnecting),
runData: ref(runData),
isReadOnly: ref(isReadOnly),
} satisfies CanvasNodeHandleInjectionData,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { computed, h, provide, toRef, useCssModule } from 'vue';
import type { CanvasConnectionPort, CanvasElementPortWithRenderData } from '@/types';
import { CanvasConnectionMode } from '@/types';
import type { ValidConnectionFunc } from '@vue-flow/core';
import { Handle } from '@vue-flow/core';
import { NodeConnectionType } from 'n8n-workflow';
Expand All @@ -13,6 +12,7 @@ import CanvasHandleNonMainInput from '@/components/canvas/elements/handles/rende
import CanvasHandleNonMainOutput from '@/components/canvas/elements/handles/render-types/CanvasHandleNonMainOutput.vue';
import { CanvasNodeHandleKey } from '@/constants';
import { createCanvasConnectionHandleString } from '@/utils/canvasUtilsV2';
import { useCanvasNode } from '@/composables/useCanvasNode';
const props = defineProps<{
mode: CanvasConnectionMode;
Expand Down Expand Up @@ -59,6 +59,18 @@ const isConnectableEnd = computed(() => {
const handleClasses = computed(() => [style.handle, style[props.type], style[props.mode]]);
/**
* Run data
*/
const { runDataOutputMap } = useCanvasNode();
const runData = computed(() =>
props.mode === CanvasConnectionMode.Output
? runDataOutputMap.value[props.type]?.[props.index]
: undefined,
);
/**
* Render additional elements
*/
Expand Down Expand Up @@ -103,11 +115,14 @@ const isConnecting = toRef(props, 'isConnecting');
const isReadOnly = toRef(props, 'isReadOnly');
const mode = toRef(props, 'mode');
const type = toRef(props, 'type');
const index = toRef(props, 'index');
provide(CanvasNodeHandleKey, {
label,
mode,
type,
index,
runData,
isConnected,
isConnecting,
isReadOnly,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,36 @@ describe('CanvasHandleMainOutput', () => {

expect(queryByTestId('canvas-handle-plus')).not.toBeInTheDocument();
});

it('should render run data label', async () => {
const runData = {
total: 1,
iterations: 1,
};
const { getByText } = renderComponent({
global: {
provide: {
...createCanvasHandleProvide({ label: '', runData }),
},
},
});
expect(getByText('1 item')).toBeInTheDocument();
});

it('should not render run data label if output label is available', async () => {
const runData = {
total: 1,
iterations: 1,
};
const { getByText } = renderComponent({
global: {
provide: {
...createCanvasHandleProvide({ label: 'Output', runData }),
},
},
});

expect(() => getByText('1 item')).toThrow();
expect(getByText('Output')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,41 @@ import { useCanvasNodeHandle } from '@/composables/useCanvasNodeHandle';
import { useCanvasNode } from '@/composables/useCanvasNode';
import { computed, ref } from 'vue';
import type { CanvasNodeDefaultRender } from '@/types';
import { useI18n } from '@/composables/useI18n';
const emit = defineEmits<{
add: [];
}>();
const i18n = useI18n();
const { render } = useCanvasNode();
const { label, isConnected, isConnecting, isReadOnly } = useCanvasNodeHandle();
const { label, isConnected, isConnecting, isReadOnly, runData } = useCanvasNodeHandle();
const handleClasses = 'source';
const isHovered = ref(false);
const renderOptions = computed(() => render.value.options as CanvasNodeDefaultRender['options']);
const runDataLabel = computed(() =>
runData.value
? i18n.baseText('ndv.output.items', {
adjustToNumber: runData.value.total,
interpolate: { count: String(runData.value.total) },
})
: '',
);
const isHandlePlusVisible = computed(() => !isConnecting.value || isHovered.value);
const plusState = computed(() => (runData.value ? 'success' : 'default'));
const plusLineSize = computed(
() =>
({
small: 46,
medium: 66,
large: 80,
})[renderOptions.value.outputs?.labelSize ?? 'small'],
})[renderOptions.value.outputs?.labelSize ?? runData.value ? 'large' : 'small'],
);
function onMouseEnter() {
Expand All @@ -41,7 +54,8 @@ function onClickAdd() {
</script>
<template>
<div :class="['canvas-node-handle-main-output', $style.handle]">
<div :class="[$style.label]">{{ label }}</div>
<div v-if="label" :class="[$style.label, $style.outputLabel]">{{ label }}</div>
<div v-else-if="runData" :class="[$style.label, $style.runDataLabel]">{{ runDataLabel }}</div>
<CanvasHandleDot :handle-classes="handleClasses" />
<Transition name="canvas-node-handle-main-output">
<CanvasHandlePlus
Expand All @@ -50,6 +64,7 @@ function onClickAdd() {
data-test-id="canvas-handle-plus"
:line-size="plusLineSize"
:handle-classes="handleClasses"
:state="plusState"
@mouseenter="onMouseEnter"
@mouseleave="onMouseLeave"
@click:plus="onClickAdd"
Expand All @@ -68,18 +83,30 @@ function onClickAdd() {
.label {
position: absolute;
top: 50%;
left: var(--spacing-m);
transform: translate(0, -50%);
font-size: var(--font-size-2xs);
color: var(--color-foreground-xdark);
background: var(--color-canvas-label-background);
z-index: 1;
max-width: calc(100% - var(--spacing-m) - 24px);
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.outputLabel {
top: 50%;
left: var(--spacing-m);
transform: translate(0, -50%);
font-size: var(--font-size-2xs);
color: var(--color-foreground-xdark);
}
.runDataLabel {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
font-size: var(--font-size-xs);
color: var(--color-success);
}
</style>

<style lang="scss">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ describe('CanvasHandlePlus', () => {
});
});

it('should apply correct classes based on state', () => {
const { container } = renderComponent({
props: { state: 'success' },
});

expect(container.firstChild).toHaveClass('success');
});

it('should render SVG elements correctly', () => {
const { container } = renderComponent();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ const props = withDefaults(
handleClasses?: string;
plusSize?: number;
lineSize?: number;
state?: 'success' | 'default';
}>(),
{
position: 'right',
handleClasses: undefined,
plusSize: 24,
lineSize: 46,
state: 'default',
},
);
Expand All @@ -22,7 +24,12 @@ const emit = defineEmits<{
const style = useCssModule();
const classes = computed(() => [style.wrapper, style[props.position], props.handleClasses]);
const classes = computed(() => [
style.wrapper,
style[props.position],
style[props.state],
props.handleClasses,
]);
const viewBox = computed(() => {
switch (props.position) {
Expand Down Expand Up @@ -91,7 +98,7 @@ function onClick(event: MouseEvent) {
<template>
<svg :class="classes" :viewBox="`0 0 ${viewBox.width} ${viewBox.height}`" :style="styles">
<line
:class="handleClasses"
:class="[handleClasses, $style.line]"
:x1="linePosition[0][0]"
:y1="linePosition[0][1]"
:x2="linePosition[1][0]"
Expand Down Expand Up @@ -127,6 +134,10 @@ function onClick(event: MouseEvent) {
<style lang="scss" module>
.wrapper {
position: relative;
&.success .line {
stroke: var(--color-success);
}
}
.plus {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`CanvasHandleDiamond > should render with default props 1`] = `
"<svg class="wrapper right" viewBox="0 0 70 24" style="width: 70px; height: 24px;">
<line class="" x1="0" y1="12" x2="47" y2="12" stroke="var(--color-foreground-xdark)" stroke-width="2"></line>
"<svg class="wrapper right default" viewBox="0 0 70 24" style="width: 70px; height: 24px;">
<line class="line" x1="0" y1="12" x2="47" y2="12" stroke="var(--color-foreground-xdark)" stroke-width="2"></line>
<g class="plus clickable" transform="translate(46, 0)">
<rect class="clickable" x="2" y="2" width="20" height="20" stroke="var(--color-foreground-xdark)" stroke-width="2" rx="4" fill="#ffffff"></rect>
<path class="clickable" fill="var(--color-foreground-xdark)" d="m16.40655,10.89837l-3.30491,0l0,-3.30491c0,-0.40555 -0.32889,-0.73443 -0.73443,-0.73443l-0.73443,0c-0.40554,0 -0.73442,0.32888 -0.73442,0.73443l0,3.30491l-3.30491,0c-0.40555,0 -0.73443,0.32888 -0.73443,0.73442l0,0.73443c0,0.40554 0.32888,0.73443 0.73443,0.73443l3.30491,0l0,3.30491c0,0.40554 0.32888,0.73442 0.73442,0.73442l0.73443,0c0.40554,0 0.73443,-0.32888 0.73443,-0.73442l0,-3.30491l3.30491,0c0.40554,0 0.73442,-0.32889 0.73442,-0.73443l0,-0.73443c0,-0.40554 -0.32888,-0.73442 -0.73442,-0.73442z"></path>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`CanvasHandlePlus > should render with default props 1`] = `
"<svg class="wrapper right" viewBox="0 0 70 24" style="width: 70px; height: 24px;">
<line class="" x1="0" y1="12" x2="47" y2="12" stroke="var(--color-foreground-xdark)" stroke-width="2"></line>
"<svg class="wrapper right default" viewBox="0 0 70 24" style="width: 70px; height: 24px;">
<line class="line" x1="0" y1="12" x2="47" y2="12" stroke="var(--color-foreground-xdark)" stroke-width="2"></line>
<g class="plus clickable" transform="translate(46, 0)">
<rect class="clickable" x="2" y="2" width="20" height="20" stroke="var(--color-foreground-xdark)" stroke-width="2" rx="4" fill="#ffffff"></rect>
<path class="clickable" fill="var(--color-foreground-xdark)" d="m16.40655,10.89837l-3.30491,0l0,-3.30491c0,-0.40555 -0.32889,-0.73443 -0.73443,-0.73443l-0.73443,0c-0.40554,0 -0.73442,0.32888 -0.73442,0.73443l0,3.30491l-3.30491,0c-0.40555,0 -0.73443,0.32888 -0.73443,0.73442l0,0.73443c0,0.40554 0.32888,0.73443 0.73443,0.73443l3.30491,0l0,3.30491c0,0.40554 0.32888,0.73442 0.73442,0.73442l0.73443,0c0.40554,0 0.73443,-0.32888 0.73443,-0.73442l0,-3.30491l3.30491,0c0.40554,0 0.73442,-0.32889 0.73442,-0.73443l0,-0.73443c0,-0.40554 -0.32888,-0.73442 -0.73442,-0.73442z"></path>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ describe('CanvasNodeStatusIcons', () => {
it('should render correctly for a node that ran successfully', () => {
const { getByTestId } = renderComponent({
global: {
provide: createCanvasNodeProvide({ data: { runData: { count: 15, visible: true } } }),
provide: createCanvasNodeProvide({
data: { runData: { outputMap: {}, iterations: 15, visible: true } },
}),
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const {
executionWaiting,
executionRunning,
hasRunData,
runDataCount,
runDataIterations,
} = useCanvasNode();
const hideNodeIssues = computed(() => false); // @TODO Implement this
Expand Down Expand Up @@ -67,7 +67,7 @@ const hideNodeIssues = computed(() => false); // @TODO Implement this
:class="[$style.status, $style.runData]"
>
<FontAwesomeIcon icon="check" />
<span v-if="runDataCount > 1" :class="$style.count"> {{ runDataCount }}</span>
<span v-if="runDataIterations > 1" :class="$style.count"> {{ runDataIterations }}</span>
</div>
</template>

Expand Down
Loading

0 comments on commit 288493d

Please sign in to comment.