feat(editor): Add schema view to expression modal (#9976)

This commit is contained in:
Elias Meire
2024-08-12 16:47:14 +02:00
committed by GitHub
parent 9d7caacc69
commit 71b6c67179
29 changed files with 927 additions and 1793 deletions

View File

@@ -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>