diff --git a/web/app/components/plugins/base/__tests__/key-value-item.spec.tsx b/web/app/components/plugins/base/__tests__/key-value-item.spec.tsx index fd0964c90d..9c5ec03b7e 100644 --- a/web/app/components/plugins/base/__tests__/key-value-item.spec.tsx +++ b/web/app/components/plugins/base/__tests__/key-value-item.spec.tsx @@ -16,15 +16,16 @@ vi.mock('@/app/components/base/action-button', () => ({ ), })) -const mockCopy = vi.fn() -vi.mock('copy-to-clipboard', () => ({ - default: (...args: unknown[]) => mockCopy(...args), +const mockWriteTextToClipboard = vi.fn() +vi.mock('@/utils/clipboard', () => ({ + writeTextToClipboard: (...args: unknown[]) => mockWriteTextToClipboard(...args), })) describe('KeyValueItem', () => { beforeEach(() => { vi.clearAllMocks() vi.useFakeTimers() + mockWriteTextToClipboard.mockResolvedValue(undefined) }) afterEach(() => { @@ -44,10 +45,10 @@ describe('KeyValueItem', () => { expect(screen.queryByText('sk-secret')).not.toBeInTheDocument() }) - it('copies actual value (not masked) when copy button is clicked', () => { + it('copies actual value (not masked) when copy button is clicked', async () => { render() fireEvent.click(screen.getByTestId('action-button')) - expect(mockCopy).toHaveBeenCalledWith('sk-secret') + expect(mockWriteTextToClipboard).toHaveBeenCalledWith('sk-secret') }) it('renders copy tooltip', () => { diff --git a/web/app/components/plugins/base/key-value-item.tsx b/web/app/components/plugins/base/key-value-item.tsx index a2a3459b5d..442470bb98 100644 --- a/web/app/components/plugins/base/key-value-item.tsx +++ b/web/app/components/plugins/base/key-value-item.tsx @@ -2,11 +2,11 @@ import type { FC } from 'react' import { cn } from '@langgenius/dify-ui/cn' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' -import copy from 'copy-to-clipboard' import * as React from 'react' import { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import ActionButton from '@/app/components/base/action-button' +import { writeTextToClipboard } from '@/utils/clipboard' import { CopyCheck } from '../../base/icons/src/vender/line/files' type Props = { @@ -27,8 +27,9 @@ const KeyValueItem: FC = ({ const { t } = useTranslation() const [isCopied, setIsCopied] = useState(false) const handleCopy = useCallback(() => { - copy(value) - setIsCopied(true) + void writeTextToClipboard(value).then(() => { + setIsCopied(true) + }) }, [value]) useEffect(() => { diff --git a/web/app/components/plugins/plugin-detail-panel/__tests__/endpoint-card.spec.tsx b/web/app/components/plugins/plugin-detail-panel/__tests__/endpoint-card.spec.tsx index 1dab8bdf84..d1e3294a75 100644 --- a/web/app/components/plugins/plugin-detail-panel/__tests__/endpoint-card.spec.tsx +++ b/web/app/components/plugins/plugin-detail-panel/__tests__/endpoint-card.spec.tsx @@ -9,6 +9,7 @@ const mockDisableEndpoint = vi.fn() const mockDeleteEndpoint = vi.fn() const mockUpdateEndpoint = vi.fn() const mockToastNotify = vi.fn() +const mockWriteTextToClipboard = vi.fn() vi.mock('@langgenius/dify-ui/toast', () => ({ toast: Object.assign( @@ -72,6 +73,10 @@ vi.mock('@/service/use-endpoints', () => ({ }), })) +vi.mock('@/utils/clipboard', () => ({ + writeTextToClipboard: (...args: unknown[]) => mockWriteTextToClipboard(...args), +})) + vi.mock('@/app/components/header/indicator', () => ({ default: ({ color }: { color: string }) => , })) @@ -136,6 +141,7 @@ const mockPluginDetail: PluginDetail = { describe('EndpointCard', () => { beforeEach(() => { vi.clearAllMocks() + mockWriteTextToClipboard.mockResolvedValue(undefined) // Reset failure flags failureFlags.enable = false failureFlags.disable = false @@ -235,6 +241,14 @@ describe('EndpointCard', () => { expect(screen.getByTestId('endpoint-modal'))!.toBeInTheDocument() }) + it('should copy endpoint url when copy action is clicked', () => { + render() + + fireEvent.click(screen.getByRole('button', { name: 'common.operation.copy' })) + + expect(mockWriteTextToClipboard).toHaveBeenCalledWith('https://api.example.com/api/test') + }) + it('should call updateEndpoint when save in modal', () => { render() diff --git a/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx b/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx index 9aa944c4b3..0378504419 100644 --- a/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx +++ b/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx @@ -12,7 +12,6 @@ import { Switch } from '@langgenius/dify-ui/switch' import { toast } from '@langgenius/dify-ui/toast' import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip' import { useBoolean } from 'ahooks' -import copy from 'copy-to-clipboard' import * as React from 'react' import { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -26,6 +25,7 @@ import { useEnableEndpoint, useUpdateEndpoint, } from '@/service/use-endpoints' +import { writeTextToClipboard } from '@/utils/clipboard' import EndpointModal from './endpoint-modal' import { NAME_FIELD } from './utils' @@ -127,8 +127,9 @@ const EndpointCard = ({ const [isCopied, setIsCopied] = useState(false) const handleCopy = (value: string) => { - copy(value) - setIsCopied(true) + void writeTextToClipboard(value).then(() => { + setIsCopied(true) + }) } const handleDisableConfirmOpenChange = (open: boolean) => {