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 00000000000..586ac069a99 Binary files /dev/null and b/web/public/images/file-scan/clamav.png differ diff --git a/web/public/images/file-scan/cloudmersive.png b/web/public/images/file-scan/cloudmersive.png new file mode 100644 index 00000000000..39be00fe55a Binary files /dev/null and b/web/public/images/file-scan/cloudmersive.png differ diff --git a/web/public/images/file-scan/metadefender.png b/web/public/images/file-scan/metadefender.png new file mode 100644 index 00000000000..05619ccb475 Binary files /dev/null and b/web/public/images/file-scan/metadefender.png differ 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 @@ + + + +