mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Fix schema view pill highlighting (#10936)
This commit is contained in:
parent
9bd247f06b
commit
1b973dcd8d
|
@ -121,6 +121,8 @@ async function onDrop(value: string, event: MouseEvent) {
|
|||
|
||||
const droppedSelection = await dropInEditor(toRaw(editor), event, value);
|
||||
|
||||
if (!ndvStore.isMappingOnboarded) ndvStore.setMappingOnboarded();
|
||||
|
||||
if (!ndvStore.isAutocompleteOnboarded) {
|
||||
setCursorPosition((droppedSelection.ranges.at(0)?.head ?? 3) - 3);
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -90,8 +90,8 @@ const allIssues = computed(() => {
|
|||
const now = computed(() => DateTime.now().toISO());
|
||||
|
||||
const leftParameter = computed<INodeProperties>(() => ({
|
||||
name: '',
|
||||
displayName: '',
|
||||
name: 'left',
|
||||
displayName: 'Left',
|
||||
default: '',
|
||||
placeholder:
|
||||
operator.value.type === 'dateTime'
|
||||
|
@ -103,8 +103,8 @@ const leftParameter = computed<INodeProperties>(() => ({
|
|||
const rightParameter = computed<INodeProperties>(() => {
|
||||
const type = operator.value.rightType ?? operator.value.type;
|
||||
return {
|
||||
name: '',
|
||||
displayName: '',
|
||||
name: 'right',
|
||||
displayName: 'Right',
|
||||
default: '',
|
||||
placeholder:
|
||||
type === 'dateTime' ? now.value : i18n.baseText('filter.condition.placeholderRight'),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import { EditorSelection, EditorState, type SelectionRange } from '@codemirror/state';
|
||||
import { type Completion, CompletionContext } from '@codemirror/autocomplete';
|
||||
import { datatypeCompletions } from '@/plugins/codemirror/completions/datatype.completions';
|
||||
|
@ -75,10 +75,18 @@ function getCompletionsWithDot(): readonly Completion[] {
|
|||
return completionResult?.options ?? [];
|
||||
}
|
||||
|
||||
watch(tip, (newTip) => {
|
||||
ndvStore.setHighlightDraggables(!ndvStore.isMappingOnboarded && newTip === 'drag');
|
||||
onBeforeUnmount(() => {
|
||||
ndvStore.setHighlightDraggables(false);
|
||||
});
|
||||
|
||||
watch(
|
||||
tip,
|
||||
(newTip) => {
|
||||
ndvStore.setHighlightDraggables(!ndvStore.isMappingOnboarded && newTip === 'drag');
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
watchDebounced(
|
||||
[() => props.selection, () => props.unresolvedExpression],
|
||||
() => {
|
||||
|
|
|
@ -27,6 +27,7 @@ describe('InlineExpressionTip.vue', () => {
|
|||
mockNdvState = {
|
||||
hasInputData: true,
|
||||
isNDVDataEmpty: vi.fn(() => true),
|
||||
setHighlightDraggables: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -43,11 +44,16 @@ describe('InlineExpressionTip.vue', () => {
|
|||
hasInputData: true,
|
||||
isNDVDataEmpty: vi.fn(() => false),
|
||||
focusedMappableInput: 'Some Input',
|
||||
setHighlightDraggables: vi.fn(),
|
||||
};
|
||||
const { container } = renderComponent(InlineExpressionTip, {
|
||||
const { container, unmount } = renderComponent(InlineExpressionTip, {
|
||||
pinia: createTestingPinia(),
|
||||
});
|
||||
expect(mockNdvState.setHighlightDraggables).toHaveBeenCalledWith(true);
|
||||
expect(container).toHaveTextContent('Tip: Drag aninput fieldfrom the left to use it here.');
|
||||
|
||||
unmount();
|
||||
expect(mockNdvState.setHighlightDraggables).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -58,6 +64,7 @@ describe('InlineExpressionTip.vue', () => {
|
|||
isInputParentOfActiveNode: true,
|
||||
isNDVDataEmpty: vi.fn(() => false),
|
||||
focusedMappableInput: 'Some Input',
|
||||
setHighlightDraggables: vi.fn(),
|
||||
};
|
||||
const { container } = renderComponent(InlineExpressionTip, {
|
||||
pinia: createTestingPinia(),
|
||||
|
|
|
@ -510,6 +510,28 @@ const isCodeNode = computed(
|
|||
|
||||
const isHtmlNode = computed(() => !!node.value && node.value.type === HTML_NODE_TYPE);
|
||||
|
||||
const isInputTypeString = computed(() => props.parameter.type === 'string');
|
||||
const isInputTypeNumber = computed(() => props.parameter.type === 'number');
|
||||
|
||||
const isInputDataEmpty = computed(() => ndvStore.isNDVDataEmpty('input'));
|
||||
const isDropDisabled = computed(
|
||||
() =>
|
||||
props.parameter.noDataExpression ||
|
||||
props.isReadOnly ||
|
||||
isResourceLocatorParameter.value ||
|
||||
isModelValueExpression.value,
|
||||
);
|
||||
const showDragnDropTip = computed(
|
||||
() =>
|
||||
isFocused.value &&
|
||||
(isInputTypeString.value || isInputTypeNumber.value) &&
|
||||
!isModelValueExpression.value &&
|
||||
!isDropDisabled.value &&
|
||||
(!ndvStore.hasInputData || !isInputDataEmpty.value) &&
|
||||
!ndvStore.isMappingOnboarded &&
|
||||
ndvStore.isInputParentOfActiveNode,
|
||||
);
|
||||
|
||||
function isRemoteParameterOption(option: INodePropertyOptions) {
|
||||
return remoteParameterOptionsKeys.value.includes(option.name);
|
||||
}
|
||||
|
@ -965,7 +987,11 @@ onUpdated(async () => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="wrapper" :class="parameterInputClasses" @keydown.stop>
|
||||
<div
|
||||
ref="wrapper"
|
||||
:class="[parameterInputClasses, { [$style.tipVisible]: showDragnDropTip }]"
|
||||
@keydown.stop
|
||||
>
|
||||
<ExpressionEditModal
|
||||
:dialog-visible="expressionEditDialogVisible"
|
||||
:model-value="modelValueExpressionEdit"
|
||||
|
@ -1447,6 +1473,9 @@ onUpdated(async () => {
|
|||
:disabled="isReadOnly"
|
||||
@update:model-value="valueChanged"
|
||||
/>
|
||||
<div v-if="showDragnDropTip" :class="$style.tip">
|
||||
<InlineExpressionTip />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ParameterIssues
|
||||
|
@ -1477,6 +1506,7 @@ onUpdated(async () => {
|
|||
|
||||
.parameter-input {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
:deep(.color-input) {
|
||||
display: flex;
|
||||
|
@ -1609,3 +1639,23 @@ onUpdated(async () => {
|
|||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" module>
|
||||
.tipVisible {
|
||||
--input-border-bottom-left-radius: 0;
|
||||
--input-border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.tip {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 100%;
|
||||
background: var(--color-code-background);
|
||||
border: var(--border-base);
|
||||
border-top: none;
|
||||
width: 100%;
|
||||
box-shadow: 0 2px 6px 0 rgba(#441c17, 0.1);
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -13,7 +13,6 @@ import { hasExpressionMapping, hasOnlyListMode, isValueExpression } from '@/util
|
|||
import { isResourceLocatorValue } from '@/utils/typeGuards';
|
||||
import { createEventBus } from 'n8n-design-system/utils';
|
||||
import type { INodeProperties, IParameterLabel, NodeParameterValueType } from 'n8n-workflow';
|
||||
import InlineExpressionTip from './InlineExpressionEditor/InlineExpressionTip.vue';
|
||||
|
||||
type Props = {
|
||||
parameter: INodeProperties;
|
||||
|
@ -57,8 +56,7 @@ const ndvStore = useNDVStore();
|
|||
|
||||
const node = computed(() => ndvStore.activeNode);
|
||||
const hint = computed(() => i18n.nodeText().hint(props.parameter, props.path));
|
||||
const isInputTypeString = computed(() => props.parameter.type === 'string');
|
||||
const isInputTypeNumber = computed(() => props.parameter.type === 'number');
|
||||
|
||||
const isResourceLocator = computed(
|
||||
() => props.parameter.type === 'resourceLocator' || props.parameter.type === 'workflowSelector',
|
||||
);
|
||||
|
@ -73,17 +71,6 @@ const isExpression = computed(() => isValueExpression(props.parameter, props.val
|
|||
const showExpressionSelector = computed(() =>
|
||||
isResourceLocator.value ? !hasOnlyListMode(props.parameter) : true,
|
||||
);
|
||||
const isInputDataEmpty = computed(() => ndvStore.isNDVDataEmpty('input'));
|
||||
const showDragnDropTip = computed(
|
||||
() =>
|
||||
focused.value &&
|
||||
(isInputTypeString.value || isInputTypeNumber.value) &&
|
||||
!isExpression.value &&
|
||||
!isDropDisabled.value &&
|
||||
(!ndvStore.hasInputData || !isInputDataEmpty.value) &&
|
||||
!ndvStore.isMappingOnboarded &&
|
||||
ndvStore.isInputParentOfActiveNode,
|
||||
);
|
||||
|
||||
function onFocus() {
|
||||
focused.value = true;
|
||||
|
@ -205,7 +192,7 @@ function onDrop(newParamValue: string) {
|
|||
|
||||
<template>
|
||||
<n8n-input-label
|
||||
:class="[$style.wrapper, { [$style.tipVisible]: showDragnDropTip }]"
|
||||
:class="[$style.wrapper]"
|
||||
:label="hideLabel ? '' : i18n.nodeText().inputLabelDisplayName(parameter, path)"
|
||||
:tooltip-text="hideLabel ? '' : i18n.nodeText().inputLabelDescription(parameter, path)"
|
||||
:show-tooltip="focused"
|
||||
|
@ -258,9 +245,6 @@ function onDrop(newParamValue: string) {
|
|||
/>
|
||||
</template>
|
||||
</DraggableTarget>
|
||||
<div v-if="showDragnDropTip" :class="$style.tip">
|
||||
<InlineExpressionTip />
|
||||
</div>
|
||||
<div
|
||||
:class="{
|
||||
[$style.options]: true,
|
||||
|
@ -292,24 +276,6 @@ function onDrop(newParamValue: string) {
|
|||
}
|
||||
}
|
||||
|
||||
.tipVisible {
|
||||
--input-border-bottom-left-radius: 0;
|
||||
--input-border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.tip {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 100%;
|
||||
background: var(--color-code-background);
|
||||
border: var(--border-base);
|
||||
border-top: none;
|
||||
width: 100%;
|
||||
box-shadow: 0 2px 6px 0 rgba(#441c17, 0.1);
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.options {
|
||||
position: absolute;
|
||||
bottom: -22px;
|
||||
|
|
|
@ -54,6 +54,7 @@ describe('ParameterInput.vue', () => {
|
|||
type: 'test',
|
||||
typeVersion: 1,
|
||||
},
|
||||
isNDVDataEmpty: vi.fn(() => false),
|
||||
};
|
||||
mockNodeTypesState = {
|
||||
allNodeTypes: [],
|
||||
|
|
Loading…
Reference in a new issue