mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
feat(editor): Add schema view to expression modal (#9976)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, toRaw, watch } from 'vue';
|
||||
|
||||
import ExpressionFunctionIcon from '@/components/ExpressionFunctionIcon.vue';
|
||||
import InlineExpressionEditorInput from '@/components/InlineExpressionEditor/InlineExpressionEditorInput.vue';
|
||||
@@ -9,10 +9,12 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { createExpressionTelemetryPayload } from '@/utils/telemetryUtils';
|
||||
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
import { dropInEditor } from '@/plugins/codemirror/dragAndDrop';
|
||||
import type { Segment } from '@/types/expressions';
|
||||
import { createEventBus, type EventBus } from 'n8n-design-system/utils';
|
||||
import type { IDataObject } from 'n8n-workflow';
|
||||
import { startCompletion } from '@codemirror/autocomplete';
|
||||
import type { EditorState, SelectionRange } from '@codemirror/state';
|
||||
import type { IDataObject } from 'n8n-workflow';
|
||||
import { createEventBus, type EventBus } from 'n8n-design-system';
|
||||
|
||||
const isFocused = ref(false);
|
||||
const segments = ref<Segment[]>([]);
|
||||
@@ -25,9 +27,9 @@ type Props = {
|
||||
modelValue: string;
|
||||
rows?: number;
|
||||
additionalExpressionData?: IDataObject;
|
||||
eventBus?: EventBus;
|
||||
isReadOnly?: boolean;
|
||||
isAssignment?: boolean;
|
||||
eventBus?: EventBus;
|
||||
};
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -109,6 +111,45 @@ function onSelectionChange({
|
||||
selection.value = newSelection;
|
||||
}
|
||||
|
||||
async function onDrop(value: string, event: MouseEvent) {
|
||||
if (!inlineInput.value) return;
|
||||
const { editor, setCursorPosition } = inlineInput.value;
|
||||
|
||||
if (!editor) return;
|
||||
|
||||
const droppedSelection = await dropInEditor(toRaw(editor), event, value);
|
||||
|
||||
if (!ndvStore.isAutocompleteOnboarded) {
|
||||
setCursorPosition((droppedSelection.ranges.at(0)?.head ?? 3) - 3);
|
||||
setTimeout(() => {
|
||||
startCompletion(editor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function onDropOnFixedInput() {
|
||||
await nextTick();
|
||||
|
||||
if (!inlineInput.value) return;
|
||||
const { editor, setCursorPosition } = inlineInput.value;
|
||||
|
||||
if (!editor || ndvStore.isAutocompleteOnboarded) return;
|
||||
|
||||
setCursorPosition('lastExpression');
|
||||
setTimeout(() => {
|
||||
focus();
|
||||
startCompletion(editor);
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
props.eventBus.on('drop', onDropOnFixedInput);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
props.eventBus.off('drop', onDropOnFixedInput);
|
||||
});
|
||||
|
||||
watch(isDragging, (newIsDragging) => {
|
||||
if (newIsDragging) {
|
||||
onBlur();
|
||||
@@ -134,19 +175,23 @@ defineExpose({ focus });
|
||||
<span v-if="isAssignment">=</span>
|
||||
<ExpressionFunctionIcon v-else />
|
||||
</div>
|
||||
<InlineExpressionEditorInput
|
||||
ref="inlineInput"
|
||||
:model-value="modelValue"
|
||||
:path="path"
|
||||
:is-read-only="isReadOnly"
|
||||
:rows="rows"
|
||||
:additional-data="additionalExpressionData"
|
||||
:event-bus="eventBus"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
@update:model-value="onValueChange"
|
||||
@update:selection="onSelectionChange"
|
||||
/>
|
||||
<DraggableTarget type="mapping" :disabled="isReadOnly" @drop="onDrop">
|
||||
<template #default="{ activeDrop, droppable }">
|
||||
<InlineExpressionEditorInput
|
||||
ref="inlineInput"
|
||||
:model-value="modelValue"
|
||||
:path="path"
|
||||
:is-read-only="isReadOnly"
|
||||
:rows="rows"
|
||||
:additional-data="additionalExpressionData"
|
||||
:class="{ [$style.activeDrop]: activeDrop, [$style.droppable]: droppable }"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
@update:model-value="onValueChange"
|
||||
@update:selection="onSelectionChange"
|
||||
/>
|
||||
</template>
|
||||
</DraggableTarget>
|
||||
<n8n-button
|
||||
v-if="!isDragging"
|
||||
square
|
||||
@@ -240,4 +285,26 @@ defineExpose({ focus });
|
||||
border-bottom-right-radius: 0;
|
||||
background-color: var(--color-code-background);
|
||||
}
|
||||
|
||||
.droppable {
|
||||
--input-border-color: var(--color-ndv-droppable-parameter);
|
||||
--input-border-right-color: var(--color-ndv-droppable-parameter);
|
||||
--input-border-style: dashed;
|
||||
|
||||
:global(.cm-editor) {
|
||||
border-width: 1.5px;
|
||||
}
|
||||
}
|
||||
|
||||
.activeDrop {
|
||||
--input-border-color: var(--color-success);
|
||||
--input-border-right-color: var(--color-success);
|
||||
--input-background-color: var(--color-foreground-xlight);
|
||||
--input-border-style: solid;
|
||||
|
||||
:global(.cm-editor) {
|
||||
cursor: grabbing !important;
|
||||
border-width: 1px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user