mirror of
https://github.com/n8n-io/n8n.git
synced 2026-08-30 18:01:23 +08:00
fix(editor): Make selector dropdowns usable in Instance AI workflow setup (#33971)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -37,6 +37,16 @@ export const ExecutionDataStoreKey: InjectionKey<
|
||||
// derived from it via injectWorkflowExecutionStateStore(), so a subtree's
|
||||
// document scope and execution scope can never diverge.
|
||||
export const CanvasRenderDataKey: InjectionKey<Ref<CanvasRenderData>> = Symbol('CanvasRenderData');
|
||||
/**
|
||||
* Opts resource-locator dropdowns into teleporting to `<body>`. Defaults to
|
||||
* `false` (stay in the local stacking context, e.g. inside the NDV dialog).
|
||||
* Hosts that render parameters inside a scroll container overlaid by sticky
|
||||
* elements (e.g. the Instance AI workflow setup card above the chat input)
|
||||
* provide `true` so the dropdown isn't painted underneath those overlays.
|
||||
*/
|
||||
export const ResourceLocatorDropdownTeleportedKey: InjectionKey<boolean> = Symbol(
|
||||
'ResourceLocatorDropdownTeleported',
|
||||
);
|
||||
export const ChatHubToolContextKey: InjectionKey<boolean> = Symbol('ChatHubToolContext');
|
||||
export const AiBuilderScrollToBottomKey: InjectionKey<() => void> = Symbol('ChatScrollToBottom');
|
||||
/**
|
||||
|
||||
+4
-1
@@ -1,9 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import { toRef } from 'vue';
|
||||
import { provide, toRef } from 'vue';
|
||||
import type { InstanceAiCredentialFlow, InstanceAiWorkflowSetupNode } from '@n8n/api-types';
|
||||
import WorkflowSetupWizard from './components/WorkflowSetupWizard.vue';
|
||||
import WorkflowSetupStatus from './components/WorkflowSetupStatus.vue';
|
||||
import { provideWorkflowSetupContext } from './composables/useWorkflowSetupContext';
|
||||
import { ResourceLocatorDropdownTeleportedKey } from '@/app/constants';
|
||||
|
||||
const props = defineProps<{
|
||||
requestId: string;
|
||||
@@ -13,6 +14,8 @@ const props = defineProps<{
|
||||
credentialFlow?: InstanceAiCredentialFlow;
|
||||
}>();
|
||||
|
||||
provide(ResourceLocatorDropdownTeleportedKey, true);
|
||||
|
||||
const ctx = provideWorkflowSetupContext({
|
||||
requestId: toRef(props, 'requestId'),
|
||||
setupRequests: toRef(props, 'setupRequests'),
|
||||
|
||||
+18
-2
@@ -951,11 +951,27 @@ async function onQuickConnectSignIn(credentialTypeName: string) {
|
||||
data-test-id="node-credentials-empty-state"
|
||||
>
|
||||
<N8nSelect
|
||||
ref="selectRefs"
|
||||
:class="$style.emptySelect"
|
||||
size="small"
|
||||
disabled
|
||||
:disabled="!canCreateCredentials"
|
||||
:placeholder="i18n.baseText('nodeCredentials.emptyState.noCredentials')"
|
||||
/>
|
||||
:popper-class="$style.selectPopper"
|
||||
>
|
||||
<template #empty> </template>
|
||||
<template #footer>
|
||||
<button
|
||||
type="button"
|
||||
data-test-id="node-credentials-select-item-new"
|
||||
:class="[$style.newCredential]"
|
||||
:disabled="!canCreateCredentials"
|
||||
@click="onClickCreateCredential(type)"
|
||||
>
|
||||
<N8nIcon size="xsmall" icon="plus" />
|
||||
{{ NEW_CREDENTIALS_TEXT }}
|
||||
</button>
|
||||
</template>
|
||||
</N8nSelect>
|
||||
<N8nButton
|
||||
v-if="canCreateCredentials"
|
||||
variant="subtle"
|
||||
|
||||
+4
-1
@@ -264,7 +264,10 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
onClickOutside(dropdown, () => {
|
||||
onClickOutside(dropdown, (event) => {
|
||||
if (event.target instanceof HTMLElement && dropdown.value?.isWithinDropdown(event.target)) {
|
||||
return;
|
||||
}
|
||||
isDropdownVisible.value = false;
|
||||
});
|
||||
|
||||
|
||||
+6
-1
@@ -636,7 +636,12 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
});
|
||||
|
||||
onClickOutside(dropdownRef as Ref<VueInstance>, hideResourceDropdown);
|
||||
onClickOutside(dropdownRef as Ref<VueInstance>, (event) => {
|
||||
if (event.target instanceof HTMLElement && dropdownRef.value?.isWithinDropdown(event.target)) {
|
||||
return;
|
||||
}
|
||||
hideResourceDropdown();
|
||||
});
|
||||
|
||||
function setWidth() {
|
||||
if (containerRef.value) {
|
||||
|
||||
+5
-2
@@ -6,7 +6,8 @@ import { useI18n } from '@n8n/i18n';
|
||||
import type { EventBus } from '@n8n/utils/event-bus';
|
||||
import { createEventBus } from '@n8n/utils/event-bus';
|
||||
import type { INodeParameterResourceLocator } from 'n8n-workflow';
|
||||
import { computed, onBeforeUnmount, onMounted, ref, useCssModule, watch } from 'vue';
|
||||
import { computed, inject, onBeforeUnmount, onMounted, ref, useCssModule, watch } from 'vue';
|
||||
import { ResourceLocatorDropdownTeleportedKey } from '@/app/constants';
|
||||
|
||||
const SEARCH_BAR_HEIGHT_PX = 40;
|
||||
const SCROLL_MARGIN_PX = 10;
|
||||
@@ -65,6 +66,8 @@ const debouncedLoadMore = debounce(
|
||||
const i18n = useI18n();
|
||||
const $style = useCssModule();
|
||||
|
||||
const teleported = inject(ResourceLocatorDropdownTeleportedKey, false);
|
||||
|
||||
const hoverIndex = ref(0);
|
||||
const showHoverUrl = ref(false);
|
||||
const searchRef = ref<HTMLInputElement>();
|
||||
@@ -269,7 +272,7 @@ watch(
|
||||
:width="props.width ? `${props.width}px` : undefined"
|
||||
:content-class="$style.popover"
|
||||
:open="props.show"
|
||||
:teleported="false"
|
||||
:teleported="teleported"
|
||||
:enable-scrolling="false"
|
||||
data-test-id="resource-locator-dropdown"
|
||||
>
|
||||
|
||||
+4
-1
@@ -277,7 +277,10 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
onClickOutside(dropdown, () => {
|
||||
onClickOutside(dropdown, (event) => {
|
||||
if (event.target instanceof HTMLElement && dropdown.value?.isWithinDropdown(event.target)) {
|
||||
return;
|
||||
}
|
||||
isDropdownVisible.value = false;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user