mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(editor): Improve ai nodes, handles and connections design in new canvas (no-changelog) (#10969)
This commit is contained in:
parent
a62a9db8fa
commit
fe871d89a9
|
@ -125,6 +125,7 @@ export function createCanvasHandleProvide({
|
||||||
isConnected = false,
|
isConnected = false,
|
||||||
isConnecting = false,
|
isConnecting = false,
|
||||||
isReadOnly = false,
|
isReadOnly = false,
|
||||||
|
isRequired = false,
|
||||||
}: {
|
}: {
|
||||||
label?: string;
|
label?: string;
|
||||||
mode?: CanvasConnectionMode;
|
mode?: CanvasConnectionMode;
|
||||||
|
@ -134,6 +135,7 @@ export function createCanvasHandleProvide({
|
||||||
isConnected?: boolean;
|
isConnected?: boolean;
|
||||||
isConnecting?: boolean;
|
isConnecting?: boolean;
|
||||||
isReadOnly?: boolean;
|
isReadOnly?: boolean;
|
||||||
|
isRequired?: boolean;
|
||||||
} = {}) {
|
} = {}) {
|
||||||
return {
|
return {
|
||||||
[String(CanvasNodeHandleKey)]: {
|
[String(CanvasNodeHandleKey)]: {
|
||||||
|
@ -143,8 +145,9 @@ export function createCanvasHandleProvide({
|
||||||
index: ref(index),
|
index: ref(index),
|
||||||
isConnected: ref(isConnected),
|
isConnected: ref(isConnected),
|
||||||
isConnecting: ref(isConnecting),
|
isConnecting: ref(isConnecting),
|
||||||
runData: ref(runData),
|
|
||||||
isReadOnly: ref(isReadOnly),
|
isReadOnly: ref(isReadOnly),
|
||||||
|
isRequired: ref(isRequired),
|
||||||
|
runData: ref(runData),
|
||||||
} satisfies CanvasNodeHandleInjectionData,
|
} satisfies CanvasNodeHandleInjectionData,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { isValidNodeConnectionType } from '@/utils/typeGuards';
|
||||||
import type { Connection, EdgeProps } from '@vue-flow/core';
|
import type { Connection, EdgeProps } from '@vue-flow/core';
|
||||||
import { useVueFlow, BaseEdge, EdgeLabelRenderer } from '@vue-flow/core';
|
import { useVueFlow, BaseEdge, EdgeLabelRenderer } from '@vue-flow/core';
|
||||||
import { NodeConnectionType } from 'n8n-workflow';
|
import { NodeConnectionType } from 'n8n-workflow';
|
||||||
import { computed, useCssModule, ref } from 'vue';
|
import { computed, useCssModule, ref, toRef } from 'vue';
|
||||||
import CanvasEdgeToolbar from './CanvasEdgeToolbar.vue';
|
import CanvasEdgeToolbar from './CanvasEdgeToolbar.vue';
|
||||||
import { getCustomPath } from './utils/edgePath';
|
import { getCustomPath } from './utils/edgePath';
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ export type CanvasEdgeProps = EdgeProps<CanvasConnectionData> & {
|
||||||
|
|
||||||
const props = defineProps<CanvasEdgeProps>();
|
const props = defineProps<CanvasEdgeProps>();
|
||||||
|
|
||||||
|
const data = toRef(props, 'data');
|
||||||
|
|
||||||
const { onEdgeMouseEnter, onEdgeMouseLeave } = useVueFlow();
|
const { onEdgeMouseEnter, onEdgeMouseLeave } = useVueFlow();
|
||||||
|
|
||||||
const isHovered = ref(false);
|
const isHovered = ref(false);
|
||||||
|
@ -44,6 +46,8 @@ const connectionType = computed(() =>
|
||||||
|
|
||||||
const renderToolbar = computed(() => (props.selected || isHovered.value) && !props.readOnly);
|
const renderToolbar = computed(() => (props.selected || isHovered.value) && !props.readOnly);
|
||||||
|
|
||||||
|
const isMainConnection = computed(() => data.value.source.type === NodeConnectionType.Main);
|
||||||
|
|
||||||
const status = computed(() => props.data.status);
|
const status = computed(() => props.data.status);
|
||||||
const statusColor = computed(() => {
|
const statusColor = computed(() => {
|
||||||
if (props.selected) {
|
if (props.selected) {
|
||||||
|
@ -54,6 +58,8 @@ const statusColor = computed(() => {
|
||||||
return 'var(--color-secondary)';
|
return 'var(--color-secondary)';
|
||||||
} else if (status.value === 'running') {
|
} else if (status.value === 'running') {
|
||||||
return 'var(--color-primary)';
|
return 'var(--color-primary)';
|
||||||
|
} else if (!isMainConnection.value) {
|
||||||
|
return 'var(--node-type-supplemental-color)';
|
||||||
} else {
|
} else {
|
||||||
return 'var(--color-foreground-xdark)';
|
return 'var(--color-foreground-xdark)';
|
||||||
}
|
}
|
||||||
|
@ -61,6 +67,7 @@ const statusColor = computed(() => {
|
||||||
|
|
||||||
const edgeStyle = computed(() => ({
|
const edgeStyle = computed(() => ({
|
||||||
...props.style,
|
...props.style,
|
||||||
|
...(isMainConnection.value ? {} : { strokeDasharray: '8,8' }),
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
stroke: isHovered.value ? 'var(--color-primary)' : statusColor.value,
|
stroke: isHovered.value ? 'var(--color-primary)' : statusColor.value,
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -20,6 +20,7 @@ const props = defineProps<{
|
||||||
isConnecting?: boolean;
|
isConnecting?: boolean;
|
||||||
isReadOnly?: boolean;
|
isReadOnly?: boolean;
|
||||||
label?: string;
|
label?: string;
|
||||||
|
required?: boolean;
|
||||||
type: CanvasConnectionPort['type'];
|
type: CanvasConnectionPort['type'];
|
||||||
index: CanvasConnectionPort['index'];
|
index: CanvasConnectionPort['index'];
|
||||||
position: CanvasElementPortWithRenderData['position'];
|
position: CanvasElementPortWithRenderData['position'];
|
||||||
|
@ -116,6 +117,7 @@ const isReadOnly = toRef(props, 'isReadOnly');
|
||||||
const mode = toRef(props, 'mode');
|
const mode = toRef(props, 'mode');
|
||||||
const type = toRef(props, 'type');
|
const type = toRef(props, 'type');
|
||||||
const index = toRef(props, 'index');
|
const index = toRef(props, 'index');
|
||||||
|
const isRequired = toRef(props, 'required');
|
||||||
|
|
||||||
provide(CanvasNodeHandleKey, {
|
provide(CanvasNodeHandleKey, {
|
||||||
label,
|
label,
|
||||||
|
@ -123,6 +125,7 @@ provide(CanvasNodeHandleKey, {
|
||||||
type,
|
type,
|
||||||
index,
|
index,
|
||||||
runData,
|
runData,
|
||||||
|
isRequired,
|
||||||
isConnected,
|
isConnected,
|
||||||
isConnecting,
|
isConnecting,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useCanvasNodeHandle } from '@/composables/useCanvasNodeHandle';
|
import { useCanvasNodeHandle } from '@/composables/useCanvasNodeHandle';
|
||||||
|
import { computed, useCssModule } from 'vue';
|
||||||
|
|
||||||
const { label } = useCanvasNodeHandle();
|
const $style = useCssModule();
|
||||||
|
|
||||||
|
const { label, isRequired } = useCanvasNodeHandle();
|
||||||
|
|
||||||
|
const classes = computed(() => ({
|
||||||
|
'canvas-node-handle-main-input': true,
|
||||||
|
[$style.handle]: true,
|
||||||
|
[$style.required]: isRequired.value,
|
||||||
|
}));
|
||||||
|
|
||||||
const handleClasses = 'target';
|
const handleClasses = 'target';
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div :class="['canvas-node-handle-main-input', $style.handle]">
|
<div :class="classes">
|
||||||
<div :class="[$style.label]">{{ label }}</div>
|
<div :class="[$style.label]">{{ label }}</div>
|
||||||
<CanvasHandleRectangle :handle-classes="handleClasses" />
|
<CanvasHandleRectangle :handle-classes="handleClasses" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,4 +41,9 @@ const handleClasses = 'target';
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.required .label::after {
|
||||||
|
content: '*';
|
||||||
|
color: var(--color-danger);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useCanvasNodeHandle } from '@/composables/useCanvasNodeHandle';
|
import { useCanvasNodeHandle } from '@/composables/useCanvasNodeHandle';
|
||||||
import { useCanvasNode } from '@/composables/useCanvasNode';
|
import { useCanvasNode } from '@/composables/useCanvasNode';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref, useCssModule } from 'vue';
|
||||||
import type { CanvasNodeDefaultRender } from '@/types';
|
import type { CanvasNodeDefaultRender } from '@/types';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
|
|
||||||
|
@ -9,11 +9,20 @@ const emit = defineEmits<{
|
||||||
add: [];
|
add: [];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const $style = useCssModule();
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const { render } = useCanvasNode();
|
const { render } = useCanvasNode();
|
||||||
const { label, isConnected, isConnecting, isReadOnly, runData } = useCanvasNodeHandle();
|
const { label, isConnected, isConnecting, isReadOnly, isRequired, runData } = useCanvasNodeHandle();
|
||||||
|
|
||||||
const handleClasses = 'source';
|
const handleClasses = 'source';
|
||||||
|
|
||||||
|
const classes = computed(() => ({
|
||||||
|
'canvas-node-handle-main-output': true,
|
||||||
|
[$style.handle]: true,
|
||||||
|
[$style.required]: isRequired.value,
|
||||||
|
}));
|
||||||
|
|
||||||
const isHovered = ref(false);
|
const isHovered = ref(false);
|
||||||
|
|
||||||
const renderOptions = computed(() => render.value.options as CanvasNodeDefaultRender['options']);
|
const renderOptions = computed(() => render.value.options as CanvasNodeDefaultRender['options']);
|
||||||
|
@ -29,7 +38,7 @@ const runDataLabel = computed(() =>
|
||||||
|
|
||||||
const isHandlePlusVisible = computed(() => !isConnecting.value || isHovered.value);
|
const isHandlePlusVisible = computed(() => !isConnecting.value || isHovered.value);
|
||||||
|
|
||||||
const plusState = computed(() => (runData.value ? 'success' : 'default'));
|
const plusStatus = computed(() => (runData.value ? 'success' : 'default'));
|
||||||
|
|
||||||
const plusLineSize = computed(
|
const plusLineSize = computed(
|
||||||
() =>
|
() =>
|
||||||
|
@ -53,7 +62,7 @@ function onClickAdd() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div :class="['canvas-node-handle-main-output', $style.handle]">
|
<div :class="classes">
|
||||||
<div v-if="label" :class="[$style.label, $style.outputLabel]">{{ 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>
|
<div v-else-if="runData" :class="[$style.label, $style.runDataLabel]">{{ runDataLabel }}</div>
|
||||||
<CanvasHandleDot :handle-classes="handleClasses" />
|
<CanvasHandleDot :handle-classes="handleClasses" />
|
||||||
|
@ -64,7 +73,7 @@ function onClickAdd() {
|
||||||
data-test-id="canvas-handle-plus"
|
data-test-id="canvas-handle-plus"
|
||||||
:line-size="plusLineSize"
|
:line-size="plusLineSize"
|
||||||
:handle-classes="handleClasses"
|
:handle-classes="handleClasses"
|
||||||
:state="plusState"
|
:status="plusStatus"
|
||||||
@mouseenter="onMouseEnter"
|
@mouseenter="onMouseEnter"
|
||||||
@mouseleave="onMouseLeave"
|
@mouseleave="onMouseLeave"
|
||||||
@click:plus="onClickAdd"
|
@click:plus="onClickAdd"
|
||||||
|
@ -91,6 +100,11 @@ function onClickAdd() {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.required .label::after {
|
||||||
|
content: '*';
|
||||||
|
color: var(--color-danger);
|
||||||
|
}
|
||||||
|
|
||||||
.outputLabel {
|
.outputLabel {
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: var(--spacing-m);
|
left: var(--spacing-m);
|
||||||
|
|
|
@ -2,24 +2,36 @@
|
||||||
import CanvasHandlePlus from '@/components/canvas/elements/handles/render-types/parts/CanvasHandlePlus.vue';
|
import CanvasHandlePlus from '@/components/canvas/elements/handles/render-types/parts/CanvasHandlePlus.vue';
|
||||||
import { useCanvasNodeHandle } from '@/composables/useCanvasNodeHandle';
|
import { useCanvasNodeHandle } from '@/composables/useCanvasNodeHandle';
|
||||||
import { NodeConnectionType } from 'n8n-workflow';
|
import { NodeConnectionType } from 'n8n-workflow';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref, useCssModule } from 'vue';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
add: [];
|
add: [];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { label, isConnected, isConnecting, type } = useCanvasNodeHandle();
|
const $style = useCssModule();
|
||||||
|
|
||||||
|
const { label, isConnected, isConnecting, isRequired, type, runData } = useCanvasNodeHandle();
|
||||||
|
|
||||||
const handleClasses = 'target';
|
const handleClasses = 'target';
|
||||||
|
|
||||||
|
const classes = computed(() => ({
|
||||||
|
'canvas-node-handle-non-main-input': true,
|
||||||
|
[$style.handle]: true,
|
||||||
|
[$style.required]: isRequired.value,
|
||||||
|
}));
|
||||||
|
|
||||||
const supportsMultipleConnections = computed(() => type.value === NodeConnectionType.AiTool);
|
const supportsMultipleConnections = computed(() => type.value === NodeConnectionType.AiTool);
|
||||||
|
|
||||||
const isHandlePlusAvailable = computed(
|
const isHandlePlusAvailable = computed(
|
||||||
() => !isConnected.value || supportsMultipleConnections.value,
|
() => !isConnected.value || supportsMultipleConnections.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isHandlePlusVisible = computed(
|
const isHandlePlusVisible = computed(
|
||||||
() => !isConnecting.value || isHovered.value || supportsMultipleConnections.value,
|
() => !isConnecting.value || isHovered.value || supportsMultipleConnections.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const plusStatus = computed(() => (runData.value ? 'success' : 'ai'));
|
||||||
|
|
||||||
const isHovered = ref(false);
|
const isHovered = ref(false);
|
||||||
|
|
||||||
function onMouseEnter() {
|
function onMouseEnter() {
|
||||||
|
@ -35,7 +47,7 @@ function onClickAdd() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div :class="['canvas-node-handle-non-main-input', $style.handle]">
|
<div :class="classes">
|
||||||
<div :class="[$style.label]">{{ label }}</div>
|
<div :class="[$style.label]">{{ label }}</div>
|
||||||
<CanvasHandleDiamond :handle-classes="handleClasses" />
|
<CanvasHandleDiamond :handle-classes="handleClasses" />
|
||||||
<Transition name="canvas-node-handle-non-main-input">
|
<Transition name="canvas-node-handle-non-main-input">
|
||||||
|
@ -43,6 +55,7 @@ function onClickAdd() {
|
||||||
v-if="isHandlePlusAvailable"
|
v-if="isHandlePlusAvailable"
|
||||||
v-show="isHandlePlusVisible"
|
v-show="isHandlePlusVisible"
|
||||||
:handle-classes="handleClasses"
|
:handle-classes="handleClasses"
|
||||||
|
:status="plusStatus"
|
||||||
position="bottom"
|
position="bottom"
|
||||||
@mouseenter="onMouseEnter"
|
@mouseenter="onMouseEnter"
|
||||||
@mouseleave="onMouseLeave"
|
@mouseleave="onMouseLeave"
|
||||||
|
@ -66,12 +79,17 @@ function onClickAdd() {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
font-size: var(--font-size-2xs);
|
font-size: var(--font-size-2xs);
|
||||||
color: var(--color-foreground-xdark);
|
color: var(--node-type-supplemental-color);
|
||||||
background: var(--color-canvas-label-background);
|
background: var(--color-canvas-label-background);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.required .label::after {
|
||||||
|
content: '*';
|
||||||
|
color: var(--color-danger);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useCanvasNodeHandle } from '@/composables/useCanvasNodeHandle';
|
import { useCanvasNodeHandle } from '@/composables/useCanvasNodeHandle';
|
||||||
|
import { computed, useCssModule } from 'vue';
|
||||||
|
|
||||||
const { label } = useCanvasNodeHandle();
|
const $style = useCssModule();
|
||||||
|
const { label, isRequired } = useCanvasNodeHandle();
|
||||||
|
|
||||||
const handleClasses = 'source';
|
const handleClasses = 'source';
|
||||||
|
|
||||||
|
const classes = computed(() => ({
|
||||||
|
'canvas-node-handle-non-main-output': true,
|
||||||
|
[$style.handle]: true,
|
||||||
|
[$style.required]: isRequired.value,
|
||||||
|
}));
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div :class="['canvas-node-handle-non-main-output', $style.handle]">
|
<div :class="classes">
|
||||||
<div :class="[$style.label]">{{ label }}</div>
|
<div :class="$style.label">{{ label }}</div>
|
||||||
<CanvasHandleDiamond :handle-classes="handleClasses" />
|
<CanvasHandleDiamond :handle-classes="handleClasses" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -23,15 +31,20 @@ const handleClasses = 'source';
|
||||||
.label {
|
.label {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -20px;
|
top: -20px;
|
||||||
left: -50%;
|
left: 50%;
|
||||||
transform: translate(0%, 0);
|
transform: translate(-50%, 0);
|
||||||
font-size: var(--font-size-2xs);
|
font-size: var(--font-size-2xs);
|
||||||
color: var(--color-foreground-xdark);
|
color: var(--node-type-supplemental-color);
|
||||||
background: var(--color-canvas-label-background);
|
background: var(--color-canvas-label-background);
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.required .label::after {
|
||||||
|
content: '*';
|
||||||
|
color: var(--color-danger);
|
||||||
|
}
|
||||||
|
|
||||||
:global(.vue-flow__handle:not(.connectionindicator)) .plus {
|
:global(.vue-flow__handle:not(.connectionindicator)) .plus {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -40,9 +40,9 @@ describe('CanvasHandlePlus', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply correct classes based on state', () => {
|
it('should apply correct classes based on status', () => {
|
||||||
const { container } = renderComponent({
|
const { container } = renderComponent({
|
||||||
props: { state: 'success' },
|
props: { status: 'success' },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(container.firstChild).toHaveClass('success');
|
expect(container.firstChild).toHaveClass('success');
|
||||||
|
|
|
@ -7,14 +7,14 @@ const props = withDefaults(
|
||||||
handleClasses?: string;
|
handleClasses?: string;
|
||||||
plusSize?: number;
|
plusSize?: number;
|
||||||
lineSize?: number;
|
lineSize?: number;
|
||||||
state?: 'success' | 'default';
|
status?: 'success' | 'ai' | 'default';
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
position: 'right',
|
position: 'right',
|
||||||
handleClasses: undefined,
|
handleClasses: undefined,
|
||||||
plusSize: 24,
|
plusSize: 24,
|
||||||
lineSize: 46,
|
lineSize: 46,
|
||||||
state: 'default',
|
status: 'default',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ const style = useCssModule();
|
||||||
const classes = computed(() => [
|
const classes = computed(() => [
|
||||||
style.wrapper,
|
style.wrapper,
|
||||||
style[props.position],
|
style[props.position],
|
||||||
style[props.state],
|
style[props.status],
|
||||||
props.handleClasses,
|
props.handleClasses,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -135,8 +135,26 @@ function onClick(event: MouseEvent) {
|
||||||
.wrapper {
|
.wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&.success .line {
|
&.ai {
|
||||||
stroke: var(--color-success);
|
.line {
|
||||||
|
stroke: var(--node-type-supplemental-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.plus {
|
||||||
|
path {
|
||||||
|
fill: var(--node-type-supplemental-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
rect {
|
||||||
|
stroke: var(--node-type-supplemental-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
.line {
|
||||||
|
stroke: var(--color-success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,6 +269,7 @@ onBeforeUnmount(() => {
|
||||||
:index="source.index"
|
:index="source.index"
|
||||||
:position="source.position"
|
:position="source.position"
|
||||||
:offset="source.offset"
|
:offset="source.offset"
|
||||||
|
:required="source.required"
|
||||||
:is-connected="source.isConnected"
|
:is-connected="source.isConnected"
|
||||||
:is-connecting="source.isConnecting"
|
:is-connecting="source.isConnecting"
|
||||||
:is-read-only="readOnly"
|
:is-read-only="readOnly"
|
||||||
|
@ -286,6 +287,7 @@ onBeforeUnmount(() => {
|
||||||
:index="target.index"
|
:index="target.index"
|
||||||
:position="target.position"
|
:position="target.position"
|
||||||
:offset="target.offset"
|
:offset="target.offset"
|
||||||
|
:required="target.required"
|
||||||
:is-connected="target.isConnected"
|
:is-connected="target.isConnected"
|
||||||
:is-connecting="target.isConnecting"
|
:is-connecting="target.isConnecting"
|
||||||
:is-read-only="readOnly"
|
:is-read-only="readOnly"
|
||||||
|
|
|
@ -190,6 +190,7 @@ function openContextMenu(event: MouseEvent) {
|
||||||
.description {
|
.description {
|
||||||
top: unset;
|
top: unset;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin-top: 0;
|
||||||
margin-left: var(--spacing-s);
|
margin-left: var(--spacing-s);
|
||||||
width: auto;
|
width: auto;
|
||||||
min-width: unset;
|
min-width: unset;
|
||||||
|
@ -199,6 +200,19 @@ function openContextMenu(event: MouseEvent) {
|
||||||
) - 2 * var(--spacing-s)
|
) - 2 * var(--spacing-s)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.configuration {
|
||||||
|
--canvas-node--height: 75px;
|
||||||
|
|
||||||
|
.statusIcons {
|
||||||
|
right: calc(-1 * var(--spacing-2xs));
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,6 +15,7 @@ export function useCanvasNodeHandle() {
|
||||||
const isConnected = computed(() => handle?.isConnected.value ?? false);
|
const isConnected = computed(() => handle?.isConnected.value ?? false);
|
||||||
const isConnecting = computed(() => handle?.isConnecting.value ?? false);
|
const isConnecting = computed(() => handle?.isConnecting.value ?? false);
|
||||||
const isReadOnly = computed(() => handle?.isReadOnly.value);
|
const isReadOnly = computed(() => handle?.isReadOnly.value);
|
||||||
|
const isRequired = computed(() => handle?.isRequired.value);
|
||||||
const type = computed(() => handle?.type.value ?? NodeConnectionType.Main);
|
const type = computed(() => handle?.type.value ?? NodeConnectionType.Main);
|
||||||
const mode = computed(() => handle?.mode.value ?? CanvasConnectionMode.Input);
|
const mode = computed(() => handle?.mode.value ?? CanvasConnectionMode.Input);
|
||||||
const index = computed(() => handle?.index.value ?? 0);
|
const index = computed(() => handle?.index.value ?? 0);
|
||||||
|
@ -25,6 +26,7 @@ export function useCanvasNodeHandle() {
|
||||||
isConnected,
|
isConnected,
|
||||||
isConnecting,
|
isConnecting,
|
||||||
isReadOnly,
|
isReadOnly,
|
||||||
|
isRequired,
|
||||||
type,
|
type,
|
||||||
mode,
|
mode,
|
||||||
index,
|
index,
|
||||||
|
|
|
@ -165,6 +165,7 @@ export interface CanvasNodeHandleInjectionData {
|
||||||
mode: Ref<CanvasConnectionMode>;
|
mode: Ref<CanvasConnectionMode>;
|
||||||
type: Ref<NodeConnectionType>;
|
type: Ref<NodeConnectionType>;
|
||||||
index: Ref<number>;
|
index: Ref<number>;
|
||||||
|
isRequired: Ref<boolean | undefined>;
|
||||||
isConnected: Ref<boolean | undefined>;
|
isConnected: Ref<boolean | undefined>;
|
||||||
isConnecting: Ref<boolean | undefined>;
|
isConnecting: Ref<boolean | undefined>;
|
||||||
isReadOnly: Ref<boolean | undefined>;
|
isReadOnly: Ref<boolean | undefined>;
|
||||||
|
|
Loading…
Reference in a new issue