From 06a126461b596564dddc88a6c6d5ca484a8c3301 Mon Sep 17 00:00:00 2001 From: rustmailer Date: Sun, 28 Dec 2025 13:54:35 +0800 Subject: [PATCH] feat: Replace min/max byte inputs with size preset selection #39 --- web/src/features/search/search-form.tsx | 84 ++++++++++++++++--------- web/src/locales/ar.json | 7 +++ web/src/locales/da.json | 7 +++ web/src/locales/de.json | 7 +++ web/src/locales/en.json | 7 +++ web/src/locales/es.json | 7 +++ web/src/locales/fi.json | 7 +++ web/src/locales/fr.json | 7 +++ web/src/locales/it.json | 7 +++ web/src/locales/jp.json | 7 +++ web/src/locales/ko.json | 7 +++ web/src/locales/nl.json | 7 +++ web/src/locales/no.json | 7 +++ web/src/locales/pl.json | 7 +++ web/src/locales/pt.json | 7 +++ web/src/locales/ru.json | 7 +++ web/src/locales/sv.json | 7 +++ web/src/locales/zh-tw.json | 2 +- web/src/locales/zh.json | 9 ++- 19 files changed, 176 insertions(+), 31 deletions(-) diff --git a/web/src/features/search/search-form.tsx b/web/src/features/search/search-form.tsx index b8b473e..e021553 100644 --- a/web/src/features/search/search-form.tsx +++ b/web/src/features/search/search-form.tsx @@ -37,6 +37,7 @@ import { useSearchContext } from "./context"; import { toast } from "@/hooks/use-toast"; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ui/sheet"; import { useTranslation } from "react-i18next"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; const getSearchFilterSchema = (t: (key: string) => string) => z.object({ text: z.string().optional().or(z.literal("")), @@ -66,8 +67,7 @@ const getSearchFilterSchema = (t: (key: string) => string) => z.object({ before: z.date().optional(), account_id: z.number().optional().or(z.literal("")), mailbox_id: z.number().optional().or(z.literal("")), - min_size: z.number().optional().or(z.literal("")), - max_size: z.number().optional().or(z.literal("")), + size_preset: z.enum(['any', 'tiny', 'small', 'medium', 'large']).optional(), message_id: z.string().optional().or(z.literal("")), }); @@ -98,6 +98,23 @@ const cleanEmpty = >(obj: T): Partial => { ) as Partial; }; +function withSizePreset(values: Record) { + const { size_preset, ...rest } = values; + + switch (size_preset) { + case 'tiny': + return { ...rest, max_size: 15 * 1024 }; + case 'small': + return { ...rest, max_size: 2 * 1024 * 1024 }; + case 'medium': + return { ...rest, max_size: 20 * 1024 * 1024 }; + case 'large': + return { ...rest, min_size: 20 * 1024 * 1024 }; + default: + return rest; + } +} + export function SearchFormDialog({ onSubmit, isLoading, reset, open, onOpenChange }: Props) { const { t } = useTranslation() const [showAdvanced, setShowAdvanced] = useState(false); @@ -116,8 +133,7 @@ export function SearchFormDialog({ onSubmit, isLoading, reset, open, onOpenChang bcc: "", attachment_name: "", message_id: "", - min_size: undefined, - max_size: undefined, + size_preset: 'any', has_attachment: false, since: undefined, before: undefined, @@ -143,11 +159,16 @@ export function SearchFormDialog({ onSubmit, isLoading, reset, open, onOpenChang const handleSubmit = (values: Record) => { let cleaned = cleanEmpty(values); - if (selectedTags.length > 0) { - cleaned.tags = selectedTags; - } - if (Object.keys(cleaned).length > 0) { - onSubmit(cleaned); + const payload = withSizePreset(cleaned); + + + const finalPayload = + selectedTags.length > 0 + ? { ...payload, tags: selectedTags } + : payload; + + if (Object.keys(finalPayload).length > 0) { + onSubmit(finalPayload); } else { toast({ title: t('search.pleaseSelectAtLeastOne'), @@ -168,8 +189,7 @@ export function SearchFormDialog({ onSubmit, isLoading, reset, open, onOpenChang before: undefined, account_id: undefined, mailbox_id: undefined, - min_size: undefined, - max_size: undefined, + size_preset: 'any', message_id: "", }); setSelectedAccountId(undefined); @@ -414,27 +434,33 @@ export function SearchFormDialog({ onSubmit, isLoading, reset, open, onOpenChang /> ( - {t('search.minSize')} (bytes): - - field.onChange(parseInt(e.target.value, 10))} /> - - - - )} - /> - ( - - {t('search.maxSize')} (bytes): - - field.onChange(parseInt(e.target.value, 10))} /> - + + {t('search.size')} + + + + {t('search.sizeDescription')} + )} /> diff --git a/web/src/locales/ar.json b/web/src/locales/ar.json index 6204542..28d7c7a 100644 --- a/web/src/locales/ar.json +++ b/web/src/locales/ar.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "الحجم", + "any": "الكل", + "tiny": "صغير جدًا (<15 كيلوبايت)", + "small": "صغير (<2 ميغابايت)", + "medium": "متوسط (<20 ميغابايت)", + "large": "كبير (≥20 ميغابايت)", + "sizeDescription": "يشير الحجم إلى الحجم الإجمالي للبريد الإلكتروني، بما في ذلك المرفقات.", "title": "بحث", "searching": "جارٍ البحث، يرجى الانتظار...", "noEmailsFound": "لم يتم العثور على رسائل بريد إلكتروني", diff --git a/web/src/locales/da.json b/web/src/locales/da.json index 754fa5b..09ca56e 100644 --- a/web/src/locales/da.json +++ b/web/src/locales/da.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Størrelse", + "any": "Alle", + "tiny": "Meget lille (<15 KB)", + "small": "Lille (<2 MB)", + "medium": "Mellem (<20 MB)", + "large": "Stor (≥20 MB)", + "sizeDescription": "Størrelsen henviser til den samlede e-mailstørrelse, inklusive vedhæftede filer.", "title": "Søg", "searching": "Søger, vent venligst...", "noEmailsFound": "Ingen e-mails fundet", diff --git a/web/src/locales/de.json b/web/src/locales/de.json index 6a6604c..6bc0a4b 100644 --- a/web/src/locales/de.json +++ b/web/src/locales/de.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Größe", + "any": "Beliebig", + "tiny": "Sehr klein (<15 KB)", + "small": "Klein (<2 MB)", + "medium": "Mittel (<20 MB)", + "large": "Groß (≥20 MB)", + "sizeDescription": "Die Größe bezieht sich auf die gesamte E-Mail inklusive Anhängen.", "title": "Suchen", "searching": "Wird gesucht, bitte warten Sie...", "noEmailsFound": "Keine E-Mails gefunden", diff --git a/web/src/locales/en.json b/web/src/locales/en.json index e69ba6a..c60b01e 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Size", + "any": "Any", + "tiny": "Tiny (<15 KB)", + "small": "Small (<2 MB)", + "medium": "Medium (<20 MB)", + "large": "Large (≥20 MB)", + "sizeDescription": "The size refers to the total email size, including attachments.", "title": "Search", "searching": "Searching, please wait…", "noEmailsFound": "No emails found", diff --git a/web/src/locales/es.json b/web/src/locales/es.json index f2aa5b2..a4b8287 100644 --- a/web/src/locales/es.json +++ b/web/src/locales/es.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Tamaño", + "any": "Cualquiera", + "tiny": "Muy pequeño (<15 KB)", + "small": "Pequeño (<2 MB)", + "medium": "Mediano (<20 MB)", + "large": "Grande (≥20 MB)", + "sizeDescription": "El tamaño se refiere al tamaño total del correo electrónico, incluidos los archivos adjuntos.", "title": "Buscar", "searching": "Buscando, por favor espera...", "noEmailsFound": "No se encontraron correos electrónicos", diff --git a/web/src/locales/fi.json b/web/src/locales/fi.json index b579b5b..0b1d335 100644 --- a/web/src/locales/fi.json +++ b/web/src/locales/fi.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Koko", + "any": "Kaikki", + "tiny": "Erittäin pieni (<15 KB)", + "small": "Pieni (<2 MB)", + "medium": "Keskikokoinen (<20 MB)", + "large": "Suuri (≥20 MB)", + "sizeDescription": "Koko tarkoittaa sähköpostin kokonaiskokoa, liitteet mukaan lukien.", "title": "Hae", "searching": "Haetaan, odota hetki...", "noEmailsFound": "Ei sähköposteja löydy", diff --git a/web/src/locales/fr.json b/web/src/locales/fr.json index 0f6daff..9aafaff 100644 --- a/web/src/locales/fr.json +++ b/web/src/locales/fr.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Taille", + "any": "Toutes", + "tiny": "Très petite (<15 KB)", + "small": "Petite (<2 MB)", + "medium": "Moyenne (<20 MB)", + "large": "Grande (≥20 MB)", + "sizeDescription": "La taille correspond à la taille totale de l’e-mail, pièces jointes incluses.", "title": "Recherche", "searching": "Recherche en cours, veuillez patienter...", "noEmailsFound": "Aucun e-mail trouvé", diff --git a/web/src/locales/it.json b/web/src/locales/it.json index 443fa72..5815544 100644 --- a/web/src/locales/it.json +++ b/web/src/locales/it.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Dimensione", + "any": "Qualsiasi", + "tiny": "Molto piccolo (<15 KB)", + "small": "Piccolo (<2 MB)", + "medium": "Medio (<20 MB)", + "large": "Grande (≥20 MB)", + "sizeDescription": "La dimensione indica la dimensione totale dell’email, inclusi gli allegati.", "title": "Cerca", "searching": "Ricerca in corso, attendere prego...", "noEmailsFound": "Nessuna email trovata", diff --git a/web/src/locales/jp.json b/web/src/locales/jp.json index 1673655..9811892 100644 --- a/web/src/locales/jp.json +++ b/web/src/locales/jp.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "サイズ", + "any": "指定なし", + "tiny": "極小(15 KB 未満)", + "small": "小(2 MB 未満)", + "medium": "中(20 MB 未満)", + "large": "大(20 MB 以上)", + "sizeDescription": "サイズは添付ファイルを含むメール全体の容量を指します。", "title": "検索", "searching": "検索中です。お待ちください…", "noEmailsFound": "メールが見つかりませんでした", diff --git a/web/src/locales/ko.json b/web/src/locales/ko.json index 3bfc8ff..ae298e5 100644 --- a/web/src/locales/ko.json +++ b/web/src/locales/ko.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "크기", + "any": "전체", + "tiny": "아주 작음 (<15 KB)", + "small": "작음 (<2 MB)", + "medium": "중간 (<20 MB)", + "large": "큼 (≥20 MB)", + "sizeDescription": "크기는 첨부 파일을 포함한 이메일 전체 크기를 의미합니다.", "title": "검색", "searching": "검색 중입니다. 잠시 기다려 주십시오...", "noEmailsFound": "이메일을 찾을 수 없습니다", diff --git a/web/src/locales/nl.json b/web/src/locales/nl.json index d63417e..b52e080 100644 --- a/web/src/locales/nl.json +++ b/web/src/locales/nl.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Grootte", + "any": "Alle", + "tiny": "Zeer klein (<15 KB)", + "small": "Klein (<2 MB)", + "medium": "Middelgroot (<20 MB)", + "large": "Groot (≥20 MB)", + "sizeDescription": "De grootte verwijst naar de totale e-mailgrootte, inclusief bijlagen.", "title": "Zoeken", "searching": "Bezig met zoeken, even geduld alstublieft…", "noEmailsFound": "Geen e-mails gevonden", diff --git a/web/src/locales/no.json b/web/src/locales/no.json index 03191c0..b9a2ce0 100644 --- a/web/src/locales/no.json +++ b/web/src/locales/no.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Størrelse", + "any": "Alle", + "tiny": "Svært liten (<15 KB)", + "small": "Liten (<2 MB)", + "medium": "Middels (<20 MB)", + "large": "Stor (≥20 MB)", + "sizeDescription": "Størrelsen viser til e-postens totale størrelse, inkludert vedlegg.", "title": "Søk", "searching": "Søker, vennligst vent…", "noEmailsFound": "Ingen e-poster funnet", diff --git a/web/src/locales/pl.json b/web/src/locales/pl.json index 3d3f83d..baab8e0 100644 --- a/web/src/locales/pl.json +++ b/web/src/locales/pl.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Rozmiar", + "any": "Dowolny", + "tiny": "Bardzo mały (<15 KB)", + "small": "Mały (<2 MB)", + "medium": "Średni (<20 MB)", + "large": "Duży (≥20 MB)", + "sizeDescription": "Rozmiar odnosi się do całkowitego rozmiaru wiadomości e-mail, łącznie z załącznikami.", "title": "Szukaj", "searching": "Wyszukiwanie, proszę czekać...", "noEmailsFound": "Nie znaleziono wiadomości", diff --git a/web/src/locales/pt.json b/web/src/locales/pt.json index 9823905..cd44192 100644 --- a/web/src/locales/pt.json +++ b/web/src/locales/pt.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Tamanho", + "any": "Qualquer", + "tiny": "Muito pequeno (<15 KB)", + "small": "Pequeno (<2 MB)", + "medium": "Médio (<20 MB)", + "large": "Grande (≥20 MB)", + "sizeDescription": "O tamanho refere-se ao tamanho total do e-mail, incluindo anexos.", "title": "Pesquisa", "searching": "Pesquisando, por favor, aguarde...", "noEmailsFound": "Nenhum email encontrado", diff --git a/web/src/locales/ru.json b/web/src/locales/ru.json index ca1ad13..7eb399a 100644 --- a/web/src/locales/ru.json +++ b/web/src/locales/ru.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Размер", + "any": "Любой", + "tiny": "Очень маленький (<15 КБ)", + "small": "Маленький (<2 МБ)", + "medium": "Средний (<20 МБ)", + "large": "Большой (≥20 МБ)", + "sizeDescription": "Размер означает общий размер электронного письма, включая вложения.", "title": "Поиск", "searching": "Поиск, пожалуйста, подождите...", "noEmailsFound": "Письма не найдены", diff --git a/web/src/locales/sv.json b/web/src/locales/sv.json index a669409..db4c4a2 100644 --- a/web/src/locales/sv.json +++ b/web/src/locales/sv.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "Storlek", + "any": "Alla", + "tiny": "Mycket liten (<15 KB)", + "small": "Liten (<2 MB)", + "medium": "Medelstor (<20 MB)", + "large": "Stor (≥20 MB)", + "sizeDescription": "Storleken avser e-postens totala storlek, inklusive bilagor.", "title": "Sök", "searching": "Söker, vänligen vänta…", "noEmailsFound": "Inga e-postmeddelanden hittades", diff --git a/web/src/locales/zh-tw.json b/web/src/locales/zh-tw.json index d046339..ec88770 100644 --- a/web/src/locales/zh-tw.json +++ b/web/src/locales/zh-tw.json @@ -428,7 +428,7 @@ "noActiveEmailAccount": "沒有啟用的電子郵件帳號。", "addEmailAccount": "新增電子郵件帳號", "noMailboxSelectAccount": "沒有信箱,請先選擇一個帳號。", - "searchInSubjectBody": "在主旨、內文或附件中搜尋...", + "searchInSubjectBody": "在主旨、內文或附件名字中搜尋...", "searchingButton": "正在搜尋...", "searchButton": "搜尋", "advanced": "進階", diff --git a/web/src/locales/zh.json b/web/src/locales/zh.json index d4fdaba..dd7789b 100644 --- a/web/src/locales/zh.json +++ b/web/src/locales/zh.json @@ -398,6 +398,13 @@ } }, "search": { + "size": "大小", + "any": "不限", + "tiny": "很小(<15 KB)", + "small": "小(<2 MB)", + "medium": "中(<20 MB)", + "large": "大(≥20 MB)", + "sizeDescription": "大小指的是邮件整体大小,包含附件。", "title": "搜索", "searching": "搜索中,请稍候…", "noEmailsFound": "未找到邮件", @@ -428,7 +435,7 @@ "noActiveEmailAccount": "没有活动的邮件账户。", "addEmailAccount": "添加邮件账户", "noMailboxSelectAccount": "没有邮箱。请先选择一个账户。", - "searchInSubjectBody": "在主题、正文、附件中搜索...", + "searchInSubjectBody": "在主题、正文、附件名字中搜索...", "searchingButton": "搜索中...", "searchButton": "搜索", "advanced": "高级",