From f9f0fdf40dddd84d52c5cdb7ea58c98d9cf862e0 Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Tue, 17 Jun 2025 10:24:48 +0200 Subject: [PATCH] fix(editor): Fix and enable copying to clipboard in PiP (#15632) Co-authored-by: autologie --- .../src/components/RunDataJsonActions.vue | 3 +- .../editor-ui/src/composables/useClipboard.ts | 29 +++++++++---------- packages/frontend/editor-ui/src/constants.ts | 6 ++-- .../logs/components/ChatMessagesPanel.vue | 3 +- .../features/logs/components/LogsPanel.vue | 1 + .../logs/components/LogsViewRunData.vue | 6 +++- .../features/logs/composables/usePiPWindow.ts | 4 +-- 7 files changed, 28 insertions(+), 24 deletions(-) diff --git a/packages/frontend/editor-ui/src/components/RunDataJsonActions.vue b/packages/frontend/editor-ui/src/components/RunDataJsonActions.vue index 281034733c..8673cf8f1a 100644 --- a/packages/frontend/editor-ui/src/components/RunDataJsonActions.vue +++ b/packages/frontend/editor-ui/src/components/RunDataJsonActions.vue @@ -39,9 +39,10 @@ const props = withDefaults( const ndvStore = useNDVStore(); const workflowsStore = useWorkflowsStore(); +const clipboard = useClipboard(); + const i18n = useI18n(); const nodeHelpers = useNodeHelpers(); -const clipboard = useClipboard(); const { activeNode } = ndvStore; const pinnedData = usePinnedData(activeNode); const { showToast } = useToast(); diff --git a/packages/frontend/editor-ui/src/composables/useClipboard.ts b/packages/frontend/editor-ui/src/composables/useClipboard.ts index 8b1b60a681..309a91dd72 100644 --- a/packages/frontend/editor-ui/src/composables/useClipboard.ts +++ b/packages/frontend/editor-ui/src/composables/useClipboard.ts @@ -1,23 +1,24 @@ -import { computed, inject, onBeforeUnmount, onMounted, ref, unref } from 'vue'; +import { inject, onBeforeUnmount, onMounted, ref } from 'vue'; import { useClipboard as useClipboardCore, useThrottleFn } from '@vueuse/core'; -import { IsInPiPWindowSymbol } from '@/constants'; +import { PiPWindowSymbol } from '@/constants'; type ClipboardEventFn = (data: string, event?: ClipboardEvent) => void; -export function useClipboard( - options: { - onPaste: ClipboardEventFn; - } = { - onPaste() {}, - }, -) { - const isInPiPWindow = inject(IsInPiPWindowSymbol, false); - const { copy, copied, isSupported, text } = useClipboardCore({ legacy: true }); +export function useClipboard({ + onPaste: onPasteFn = () => {}, +}: { + onPaste?: ClipboardEventFn; +} = {}) { + const pipWindow = inject(PiPWindowSymbol, ref()); + const { copy, copied, isSupported, text } = useClipboardCore({ + navigator: pipWindow?.value?.navigator ?? window.navigator, + legacy: true, + }); const ignoreClasses = ['el-messsage-box', 'ignore-key-press-canvas']; const initialized = ref(false); - const onPasteCallback = ref(options.onPaste || null); + const onPasteCallback = ref(onPasteFn || null); /** * Handles copy/paste events @@ -74,9 +75,7 @@ export function useClipboard( return { copy, copied, - // When the `copy()` method is invoked from inside of the document picture-in-picture (PiP) window, it throws the error "Document is not focused". - // Therefore, we disable copying features in the PiP window for now. - isSupported: computed(() => isSupported && !unref(isInPiPWindow)), + isSupported, text, onPaste: onPasteCallback, }; diff --git a/packages/frontend/editor-ui/src/constants.ts b/packages/frontend/editor-ui/src/constants.ts index b61764159b..5efa208b3c 100644 --- a/packages/frontend/editor-ui/src/constants.ts +++ b/packages/frontend/editor-ui/src/constants.ts @@ -10,7 +10,7 @@ import type { CanvasNodeHandleInjectionData, CanvasNodeInjectionData, } from '@/types'; -import type { InjectionKey, MaybeRefOrGetter } from 'vue'; +import type { InjectionKey, Ref } from 'vue'; export const MAX_WORKFLOW_SIZE = 1024 * 1024 * 16; // Workflow size limit in bytes export const MAX_EXPECTED_REQUEST_SIZE = 2048; // Expected maximum workflow request metadata (i.e. headers) size in bytes @@ -914,9 +914,7 @@ export const CanvasKey = 'canvas' as unknown as InjectionKey; export const CanvasNodeHandleKey = 'canvasNodeHandle' as unknown as InjectionKey; -export const IsInPiPWindowSymbol = 'IsInPipWindow' as unknown as InjectionKey< - MaybeRefOrGetter ->; +export const PiPWindowSymbol = 'PiPWindow' as unknown as InjectionKey>; /** Auth */ export const APP_MODALS_ELEMENT_ID = 'app-modals'; diff --git a/packages/frontend/editor-ui/src/features/logs/components/ChatMessagesPanel.vue b/packages/frontend/editor-ui/src/features/logs/components/ChatMessagesPanel.vue index 762472bac7..244b6689c5 100644 --- a/packages/frontend/editor-ui/src/features/logs/components/ChatMessagesPanel.vue +++ b/packages/frontend/editor-ui/src/features/logs/components/ChatMessagesPanel.vue @@ -36,6 +36,7 @@ const emit = defineEmits<{ }>(); const clipboard = useClipboard(); + const locale = useI18n(); const toast = useToast(); @@ -149,7 +150,7 @@ async function copySessionId() { @click="emit('clickHeader')" >