From 1879bcf975fe9bf5ca9fcd15a66c61607190822b Mon Sep 17 00:00:00 2001 From: Jyong Date: Wed, 11 Nov 2026 21:06:45 +0800 Subject: [PATCH] feat(file-scan): show each scanner vendor's own logo Co-Authored-By: Claude Fable 5.2 --- .../__tests__/provider-type-icon.spec.tsx | 26 ++++++++++++++ web/features/file-scan/provider-type-icon.tsx | 34 ++++++++++++++++++ web/features/file-scan/scanner-dialog.tsx | 15 +------- web/features/file-scan/scanner-page.tsx | 8 ++++- web/public/images/file-scan/clamav.png | Bin 0 -> 4471 bytes web/public/images/file-scan/cloudmersive.png | Bin 0 -> 1062 bytes web/public/images/file-scan/metadefender.png | Bin 0 -> 6687 bytes web/public/images/file-scan/scanii.svg | 6 ++++ 8 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 web/features/file-scan/__tests__/provider-type-icon.spec.tsx create mode 100644 web/features/file-scan/provider-type-icon.tsx create mode 100644 web/public/images/file-scan/clamav.png create mode 100644 web/public/images/file-scan/cloudmersive.png create mode 100644 web/public/images/file-scan/metadefender.png create mode 100644 web/public/images/file-scan/scanii.svg diff --git a/web/features/file-scan/__tests__/provider-type-icon.spec.tsx b/web/features/file-scan/__tests__/provider-type-icon.spec.tsx new file mode 100644 index 00000000000..0e2c920b220 --- /dev/null +++ b/web/features/file-scan/__tests__/provider-type-icon.spec.tsx @@ -0,0 +1,26 @@ +import { render } from '@testing-library/react' +import { describe, expect, it } from 'vite-plus/test' +import { ProviderTypeIcon } from '../provider-type-icon' + +describe('ProviderTypeIcon', () => { + it.each([ + ['clamav', '/images/file-scan/clamav.png'], + ['cloudmersive', '/images/file-scan/cloudmersive.png'], + ['scanii', '/images/file-scan/scanii.svg'], + ['metadefender', '/images/file-scan/metadefender.png'], + ] as const)('shows the %s brand logo', (type, path) => { + const { container } = render() + + const logo = container.querySelector('img') + expect(logo).toHaveAttribute('src', expect.stringContaining(path)) + // Decorative: the type name is always shown next to it. + expect(logo).toHaveAttribute('alt', '') + }) + + it('keeps a generic icon for a custom endpoint, which has no brand', () => { + const { container } = render() + + expect(container.querySelector('img')).not.toBeInTheDocument() + expect(container.querySelector('.i-ri-plug-line')).toBeInTheDocument() + }) +}) diff --git a/web/features/file-scan/provider-type-icon.tsx b/web/features/file-scan/provider-type-icon.tsx new file mode 100644 index 00000000000..d99222c5d5d --- /dev/null +++ b/web/features/file-scan/provider-type-icon.tsx @@ -0,0 +1,34 @@ +import type { FileScanProviderType } from './provider-types' +import { cn } from '@langgenius/dify-ui/cn' +import { basePath } from '@/utils/var' + +// Each vendor's own mark, taken from its official site, so a scanner is recognizable at a glance. +const BRAND_LOGOS: Partial> = { + clamav: 'clamav.png', + cloudmersive: 'cloudmersive.png', + scanii: 'scanii.svg', + metadefender: 'metadefender.png', +} + +type ProviderTypeIconProps = { + type: FileScanProviderType + className?: string +} + +/** The brand logo of a scanner type; a custom endpoint has no brand and keeps a generic icon. */ +export function ProviderTypeIcon({ type, className }: ProviderTypeIconProps) { + const logo = BRAND_LOGOS[type] + if (!logo) { + return ( + + ) + } + return ( + + ) +} diff --git a/web/features/file-scan/scanner-dialog.tsx b/web/features/file-scan/scanner-dialog.tsx index 83b0d466b18..1e7ccc55bc1 100644 --- a/web/features/file-scan/scanner-dialog.tsx +++ b/web/features/file-scan/scanner-dialog.tsx @@ -36,6 +36,7 @@ import { useTranslation } from 'react-i18next' import { ApiBasedExtensionSelector } from '@/app/components/header/account-setting/api-based-extension-page/selector' import { consoleQuery } from '@/service/console' import { getErrorMessage } from '@/utils/error-message' +import { ProviderTypeIcon } from './provider-type-icon' import { FILE_SCAN_PROVIDER_TYPES, fileScanProviderSendsFileContents, @@ -56,20 +57,6 @@ type FileScanProviderDialogProps = { const stringSetting = (value: unknown) => (typeof value === 'string' ? value : '') -function ProviderTypeIcon({ type }: { type: FileScanProviderType }) { - return ( - - ) -} - export function FileScanProviderDialog({ onOpenChange, onSaved, diff --git a/web/features/file-scan/scanner-page.tsx b/web/features/file-scan/scanner-page.tsx index 45b46da586f..07eb4443462 100644 --- a/web/features/file-scan/scanner-page.tsx +++ b/web/features/file-scan/scanner-page.tsx @@ -25,7 +25,8 @@ import { isCurrentWorkspaceManagerAtom } from '@/context/workspace-state' import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now' import { consoleQuery } from '@/service/console' import { getErrorMessage } from '@/utils/error-message' -import { useFileScanProviderTypeLabel } from './provider-types' +import { ProviderTypeIcon } from './provider-type-icon' +import { isFileScanProviderType, useFileScanProviderTypeLabel } from './provider-types' import { FileScanProviderDialog } from './scanner-dialog' type DialogState = { mode: 'create' } | { mode: 'edit'; provider: FileScanProviderResponse } | null @@ -64,6 +65,11 @@ function ScannerItem({ return (
  • + {isFileScanProviderType(provider.provider_type) && ( + + + + )}
    diff --git a/web/public/images/file-scan/clamav.png b/web/public/images/file-scan/clamav.png new file mode 100644 index 0000000000000000000000000000000000000000..586ac069a991e0a6395d975314973b1957d9c80a GIT binary patch literal 4471 zcmV--5s2=IP)004R=004l4008;_004mL004C`008P>0026e000+nl3&F}0000) zWmrjOO-%qQ0000800D<-00aO40096102%-Q00003paB2_0000100961paK8{00001 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 JPDHLkV1j*dZxsLl literal 0 HcmV?d00001 diff --git a/web/public/images/file-scan/cloudmersive.png b/web/public/images/file-scan/cloudmersive.png new file mode 100644 index 0000000000000000000000000000000000000000..39be00fe55a406363cc29b22f836f9b5a706f311 GIT binary patch literal 1062 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 literal 0 HcmV?d00001 diff --git a/web/public/images/file-scan/scanii.svg b/web/public/images/file-scan/scanii.svg new file mode 100644 index 00000000000..251befb2d01 --- /dev/null +++ b/web/public/images/file-scan/scanii.svg @@ -0,0 +1,6 @@ + + + +