From ee21b4d435d44806abeb40c252dd44ceb838f886 Mon Sep 17 00:00:00 2001 From: yessenia Date: Mon, 13 Oct 2025 17:04:31 +0800 Subject: [PATCH] feat: support copy to clipboard in input component --- .../base/form/components/base/base-field.tsx | 2 ++ web/app/components/base/form/types.ts | 1 + web/app/components/base/input/index.tsx | 23 ++++++++++++++----- .../subscription-list/create/common-modal.tsx | 8 ++----- .../subscription-list/list-view.tsx | 17 ++++---------- .../subscription-list/log-viewer.tsx | 21 ++++++++++------- 6 files changed, 40 insertions(+), 32 deletions(-) diff --git a/web/app/components/base/form/components/base/base-field.tsx b/web/app/components/base/form/components/base/base-field.tsx index 443c4cb708..79a554fa4a 100644 --- a/web/app/components/base/form/components/base/base-field.tsx +++ b/web/app/components/base/form/components/base/base-field.tsx @@ -90,6 +90,7 @@ const BaseField = ({ dynamicSelectParams, multiple = false, tooltip, + showCopy, } = formSchema const disabled = propsDisabled || formSchemaDisabled @@ -202,6 +203,7 @@ const BaseField = ({ disabled={disabled} placeholder={memorizedPlaceholder} {...getExtraProps(formItemType)} + showCopyIcon={showCopy} /> ) } diff --git a/web/app/components/base/form/types.ts b/web/app/components/base/form/types.ts index 9cb9b5fda6..d04a08be87 100644 --- a/web/app/components/base/form/types.ts +++ b/web/app/components/base/form/types.ts @@ -71,6 +71,7 @@ export type FormSchema = { validators?: AnyValidators showRadioUI?: boolean disabled?: boolean + showCopy?: boolean dynamicSelectParams?: { plugin_id: string provider: string diff --git a/web/app/components/base/input/index.tsx b/web/app/components/base/input/index.tsx index 881aa1d610..688e1dd880 100644 --- a/web/app/components/base/input/index.tsx +++ b/web/app/components/base/input/index.tsx @@ -1,10 +1,11 @@ +import cn from '@/utils/classnames' +import { RiCloseCircleFill, RiErrorWarningLine, RiSearchLine } from '@remixicon/react' +import { type VariantProps, cva } from 'class-variance-authority' +import { noop } from 'lodash-es' import type { CSSProperties, ChangeEventHandler, FocusEventHandler } from 'react' import React from 'react' import { useTranslation } from 'react-i18next' -import { RiCloseCircleFill, RiErrorWarningLine, RiSearchLine } from '@remixicon/react' -import { type VariantProps, cva } from 'class-variance-authority' -import cn from '@/utils/classnames' -import { noop } from 'lodash-es' +import { CopyFeedbackNew } from '../copy-feedback' export const inputVariants = cva( '', @@ -24,6 +25,7 @@ export const inputVariants = cva( export type InputProps = { showLeftIcon?: boolean showClearIcon?: boolean + showCopyIcon?: boolean onClear?: () => void disabled?: boolean destructive?: boolean @@ -41,6 +43,7 @@ const Input = ({ destructive, showLeftIcon, showClearIcon, + showCopyIcon, onClear, wrapperClassName, className, @@ -92,8 +95,8 @@ const Input = ({ showLeftIcon && size === 'large' && 'pl-7', showClearIcon && value && 'pr-[26px]', showClearIcon && value && size === 'large' && 'pr-7', - destructive && 'pr-[26px]', - destructive && size === 'large' && 'pr-7', + (destructive || showCopyIcon) && 'pr-[26px]', + (destructive || showCopyIcon) && size === 'large' && 'pr-7', disabled && 'cursor-not-allowed border-transparent bg-components-input-bg-disabled text-components-input-text-filled-disabled hover:border-transparent hover:bg-components-input-bg-disabled', destructive && 'border-components-input-border-destructive bg-components-input-bg-destructive text-components-input-text-filled hover:border-components-input-border-destructive hover:bg-components-input-bg-destructive focus:border-components-input-border-destructive focus:bg-components-input-bg-destructive', className, @@ -115,6 +118,14 @@ const Input = ({ {destructive && ( )} + {showCopyIcon && ( +
+ +
+ )} { unit && (
diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx index 58365d461d..6c62bc03d8 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx @@ -284,6 +284,7 @@ export const CommonCreateModal = ({ onClose, createType, builder }: Props) => { onConfirm={handleConfirm} disabled={isVerifyingCredentials || isBuilding} bottomSlot={currentStep === ApiKeyStep.Verify ? : null} + size={createType === SupportedCreationMethods.MANUAL ? 'md' : 'sm'} > {createType === SupportedCreationMethods.APIKEY && } {currentStep === ApiKeyStep.Verify && ( @@ -321,12 +322,7 @@ export const CommonCreateModal = ({ onClose, createType, builder }: Props) => { default: subscriptionBuilder?.endpoint || '', disabled: true, tooltip: t('pluginTrigger.modal.form.callbackUrl.tooltip'), - // extra: subscriptionBuilder?.endpoint ? ( - // - // ) : undefined, + showCopy: true, }, ]} ref={subscriptionFormRef} diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/list-view.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/list-view.tsx index dc26a2a97e..beb6dc6ec3 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/list-view.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/list-view.tsx @@ -1,11 +1,11 @@ 'use client' +import Tooltip from '@/app/components/base/tooltip' +import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types' +import cn from '@/utils/classnames' import React from 'react' import { useTranslation } from 'react-i18next' -import Tooltip from '@/app/components/base/tooltip' -import cn from '@/utils/classnames' import { CreateButtonType, CreateSubscriptionButton } from './create' import SubscriptionCard from './subscription-card' -import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types' type SubscriptionListViewProps = { subscriptions?: TriggerSubscription[] @@ -20,15 +20,8 @@ export const SubscriptionListView: React.FC = ({ }) => { const { t } = useTranslation() - if (isLoading) { - return ( -
-
-
{t('common.dataLoading')}
-
-
- ) - } + if (isLoading) return null + const subscriptionCount = subscriptions?.length || 0 return ( diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx index 7c7cad69c1..2602dd5e10 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx @@ -20,6 +20,11 @@ type Props = { className?: string } +enum LogTypeEnum { + REQUEST = 'REQUEST', + RESPONSE = 'RESPONSE', +} + const LogViewer = ({ logs, className }: Props) => { const { t } = useTranslation() const [expandedLogs, setExpandedLogs] = useState>(new Set()) @@ -56,8 +61,8 @@ const LogViewer = ({ logs, className }: Props) => { } } - const renderJsonContent = (data: any, title: string) => { - const parsedData = title === 'REQUEST' ? parseRequestData(data) : data + const renderJsonContent = (originalData: any, title: LogTypeEnum) => { + const parsedData = title === LogTypeEnum.REQUEST ? { headers: originalData.headers, data: parseRequestData(originalData.data) } : originalData const isJsonObject = typeof parsedData === 'object' if (isJsonObject) { @@ -127,13 +132,13 @@ const LogViewer = ({ logs, className }: Props) => {
- + - - - + + + @@ -174,8 +179,8 @@ const LogViewer = ({ logs, className }: Props) => { {isExpanded && (
- {renderJsonContent(log.request.data, 'REQUEST')} - {renderJsonContent(log.response.data, 'RESPONSE')} + {renderJsonContent(log.request, LogTypeEnum.REQUEST)} + {renderJsonContent(log.response, LogTypeEnum.RESPONSE)}
)}