Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
dd4fc15
feat(search): add attachments type filter to global search
victor-ferro Jul 23, 2026
04906d6
feat(search): add remaining file categories to attachments filter
victor-ferro Jul 24, 2026
0d2bb8f
feat(search): add date modified filter to global search
victor-ferro Jul 23, 2026
0fc1863
feat(search): add size filter to global search
victor-ferro Jul 24, 2026
99a1a51
refactor(search): share filter radio list and close panels on enter
victor-ferro Jul 24, 2026
8673153
Merge branch 'PB-6258-search-filters-sdk' into PB-6258-search-type-fi…
victor-ferro Jul 29, 2026
076197e
[PB-6258] refactor: import SearchFileCategory from local search service
victor-ferro Jul 29, 2026
755d696
Merge branch 'PB-6258-search-type-filter' into PB-6258-search-date-fi…
victor-ferro Jul 29, 2026
d6186c6
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 29, 2026
c420428
[PB-6258] fix: allow conflicting custom size range so the search show…
victor-ferro Jul 29, 2026
65c0d5a
Revert "[PB-6258] fix: allow conflicting custom size range so the sea…
victor-ferro Jul 29, 2026
89fb69e
[PB-6258] fix: make type filter rows fully clickable via shared Searc…
victor-ferro Jul 31, 2026
2e10b17
Merge branch 'PB-6258-search-type-filter' into PB-6258-search-date-fi…
victor-ferro Jul 31, 2026
e0ace0a
[PB-6258] fix: make date filter rows fully clickable via shared Searc…
victor-ferro Jul 31, 2026
5c942a9
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 31, 2026
27113b6
[PB-6258] fix: make size and date radio rows fully clickable via shar…
victor-ferro Jul 31, 2026
78af36e
[PB-6258] fix: disable future days in date calendar
victor-ferro Jul 31, 2026
8c56bc8
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 31, 2026
f08684a
[PB-6258] fix: reject future dates typed into the specific date inputs
victor-ferro Jul 31, 2026
2db17e6
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 31, 2026
1c5dc43
[PB-6258] test: document calendar locale mapping including the zh-TW …
victor-ferro Jul 31, 2026
5bd958b
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 31, 2026
167b3d0
[PB-6258] fix: make any type a real toggle in the search type filter
victor-ferro Aug 3, 2026
74bb655
Merge branch 'PB-6258-search-type-filter' into PB-6258-search-date-fi…
victor-ferro Aug 3, 2026
3fabc52
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Aug 3, 2026
10b5408
[PB-6258] fix: make the date filter clear control a real button
victor-ferro Aug 3, 2026
74e3c1f
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Aug 3, 2026
0440644
[PB-6258] fix: make the size filter clear control a real button
victor-ferro Aug 3, 2026
7208f3f
[PB-6258] fix: keep the search filter pills inside the results panel
victor-ferro Aug 4, 2026
0dd9b8e
[PB-6258] feat: show a spinner while the global search is loading
victor-ferro Aug 4, 2026
6f96c31
[PB-6258] fix: only mark the date and size filters as applied when th…
victor-ferro Aug 4, 2026
4c29b88
[PB-6258] fix: accept only digits in the specific date inputs
victor-ferro Aug 4, 2026
04388a6
[PB-6258] fix: switch between search filter dropdowns with a single c…
victor-ferro Aug 4, 2026
a4fde62
[PB-6258] fix: keep custom size values within the exact integer range
victor-ferro Aug 4, 2026
2cb5abc
Merge remote-tracking branch 'origin/PB-6258-search-filters-sdk' into…
victor-ferro Aug 6, 2026
d9a75b6
Merge remote-tracking branch 'origin/PB-6258-search-type-filter' into…
victor-ferro Aug 6, 2026
e82cc3e
Merge remote-tracking branch 'origin/PB-6258-search-date-filter' into…
victor-ferro Aug 6, 2026
d49bb0a
Merge branch 'PB-6258-search-filters-sdk' into PB-6258-search-type-fi…
victor-ferro Aug 13, 2026
18e6d58
Merge branch 'PB-6258-search-type-filter' into PB-6258-search-date-fi…
victor-ferro Aug 13, 2026
314f7df
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Aug 13, 2026
8305c04
Merge pull request #2073 from internxt/PB-6258-search-size-filter
victor-ferro Aug 13, 2026
52ebb08
Merge pull request #2071 from internxt/PB-6258-search-date-filter
victor-ferro Aug 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/app/i18n/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,17 @@
"image": "Bild",
"video": "Video",
"audio": "Audio",
"clear": "Löschen"
"attachments": "Anhänge",
"anyType": "Beliebiger Typ",
"zip": "Archiv (zip)",
"document": "Dokument",
"powerpoint": "Powerpoint",
"excel": "Excel",
"text": "Text (txt)",
"code": "Code",
"csv": "CSV",
"xml": "XML",
"figma": "Figma"
},
"emptyState": {
"title": "Dateien und Ordner finden",
Expand Down
12 changes: 11 additions & 1 deletion src/app/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,17 @@
"image": "Image",
"video": "Video",
"audio": "Audio",
"clear": "Clear"
"attachments": "Attachments",
"anyType": "Any type",
"zip": "Archive (zip)",
"document": "Document",
"powerpoint": "Powerpoint",
"excel": "Excel",
"text": "Text (txt)",
"code": "Code",
"csv": "CSV",
"xml": "XML",
"figma": "Figma"
},
"emptyState": {
"title": "Find files and folders",
Expand Down
12 changes: 11 additions & 1 deletion src/app/i18n/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,17 @@
"image": "Imagen",
"video": "Video",
"audio": "Audio",
"clear": "Borrar"
"attachments": "Adjuntos",
"anyType": "Cualquier tipo",
"zip": "Archivo (zip)",
"document": "Documento",
"powerpoint": "Powerpoint",
"excel": "Excel",
"text": "Texto (txt)",
"code": "Código",
"csv": "CSV",
"xml": "XML",
"figma": "Figma"
},
"emptyState": {
"title": "Buscar archivos y carpetas",
Expand Down
12 changes: 11 additions & 1 deletion src/app/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,17 @@
"image": "Image",
"video": "Vidéo",
"audio": "Audio",
"clear": "Clair"
"attachments": "Pièces jointes",
"anyType": "Tout type",
"zip": "Archive (zip)",
"document": "Document",
"powerpoint": "Powerpoint",
"excel": "Excel",
"text": "Texte (txt)",
"code": "Code",
"csv": "CSV",
"xml": "XML",
"figma": "Figma"
},
"emptyState": {
"title": "Rechercher des fichiers et des dossiers",
Expand Down
12 changes: 11 additions & 1 deletion src/app/i18n/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,17 @@
"image": "Immagine",
"video": "Video",
"audio": "Audio",
"clear": "Libero"
"attachments": "Allegati",
"anyType": "Qualsiasi tipo",
"zip": "Archivio (zip)",
"document": "Documento",
"powerpoint": "Powerpoint",
"excel": "Excel",
"text": "Testo (txt)",
"code": "Codice",
"csv": "CSV",
"xml": "XML",
"figma": "Figma"
},
"emptyState": {
"title": "Trovare file e cartelle",
Expand Down
12 changes: 11 additions & 1 deletion src/app/i18n/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,17 @@
"image": "Изображение",
"video": "Видео",
"audio": "Аудио",
"clear": "Очистить"
"attachments": "Вложения",
"anyType": "Любой тип",
"zip": "Архив (zip)",
"document": "Документ",
"powerpoint": "Powerpoint",
"excel": "Excel",
"text": "Текст (txt)",
"code": "Код",
"csv": "CSV",
"xml": "XML",
"figma": "Figma"
},
"emptyState": {
"title": "Поиск файлов и папок",
Expand Down
12 changes: 11 additions & 1 deletion src/app/i18n/locales/tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,17 @@
"image": "圖片",
"video": "視頻",
"audio": "音頻",
"clear": "清除"
"attachments": "附件",
"anyType": "任何類型",
"zip": "壓縮檔 (zip)",
"document": "文件",
"powerpoint": "Powerpoint",
"excel": "Excel",
"text": "文字 (txt)",
"code": "程式碼",
"csv": "CSV",
"xml": "XML",
"figma": "Figma"
},
"emptyState": {
"title": "尋找檔案和資料夾",
Expand Down
12 changes: 11 additions & 1 deletion src/app/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,17 @@
"image": "图片",
"video": "视频",
"audio": "语音",
"clear": "清除"
"attachments": "附件",
"anyType": "任何类型",
"zip": "压缩文件 (zip)",
"document": "文档",
"powerpoint": "Powerpoint",
"excel": "Excel",
"text": "文本 (txt)",
"code": "代码",
"csv": "CSV",
"xml": "XML",
"figma": "Figma"
},
"emptyState": {
"title": "查找文件和文件夹",
Expand Down
26 changes: 0 additions & 26 deletions src/views/Home/components/FilterItem.tsx

This file was deleted.

93 changes: 25 additions & 68 deletions src/views/Home/components/NavbarGlobalSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useEffect, useRef, FunctionComponent, SVGProps } from 'react';
import { useState, useEffect, useRef } from 'react';
import { connect } from 'react-redux';
import { RootState } from 'app/store';
import { storageSelectors } from 'app/store/slices/storage';
Expand All @@ -19,7 +19,8 @@ import storageThunks from 'app/store/slices/storage/storage.thunks';
import { uiActions } from 'app/store/slices/ui';
import NotFoundState from './NotFoundState';
import EmptyState from './EmptyState';
import FilterItem from './FilterItem';
import { toggleTypeCategory } from '../utils/typeFilterUtils';
import SearchTypeFilter from './SearchTypeFilter';
import { getItemPlainName } from 'app/crypto/services/utils';
import navigationService from 'services/navigation.service';
import workspacesSelectors from 'app/store/slices/workspaces/workspaces.selectors';
Expand All @@ -31,12 +32,6 @@ interface NavbarProps {
plan: PlanState;
}

interface SearchFilterItem {
id: SearchFileCategory;
Icon: FunctionComponent<SVGProps<SVGSVGElement>>;
name: string;
}

const getSearchBoxClassName = (openSearchBox: boolean) => {
const baseClass = 'relative flex w-full items-center rounded-lg transition-all duration-150 ease-out';
const widthClass = openSearchBox ? 'max-w-screen-sm' : 'max-w-sm';
Expand All @@ -60,20 +55,13 @@ const getClearButtonClassName = (query: string, openSearchBox: boolean) => {

const getSearchResultsClassName = (openSearchBox: boolean) => {
const baseClass =
'absolute top-12 z-10 flex h-80 w-full max-w-screen-sm origin-top flex-col overflow-hidden rounded-xl bg-surface text-gray-100 shadow-subtle-hard ring-1 ring-gray-10 transition-all duration-150 ease-out dark:bg-gray-5';
'absolute top-12 z-10 flex h-80 w-full max-w-screen-sm origin-top flex-col rounded-xl bg-surface text-gray-100 shadow-subtle-hard ring-1 ring-gray-10 transition-all duration-150 ease-out dark:bg-gray-5';
if (openSearchBox) {
return `${baseClass} translate-y-1.5 scale-100 opacity-100`;
}
return `${baseClass} pointer-events-none -translate-y-0.5 scale-98 opacity-0`;
};

const getClearFiltersClassName = (filtersLength: number) => {
const baseClass =
'flex h-8 cursor-pointer items-center space-x-2 rounded-full bg-gray-1 px-3 text-sm font-medium text-gray-60 transition-all duration-100 ease-out hover:bg-gray-5 dark:hover:bg-surface';
const visibilityClass = filtersLength === 0 ? 'pointer-events-none opacity-0' : '';
return `${baseClass} ${visibilityClass}`;
};

const getSearchResultItemClassName = (isSelected: boolean) => {
const baseClass = 'flex h-11 shrink-0 cursor-pointer items-center space-x-2.5 px-4 text-gray-100';
const selectedClass = isSelected ? 'bg-gray-5 dark:bg-gray-10' : '';
Expand Down Expand Up @@ -134,8 +122,19 @@ const Navbar = (props: NavbarProps) => {
{ enableOnFormTags: ['INPUT'] },
);

const setTypeFilters = (updater: (current: SearchFileCategory[]) => SearchFileCategory[]) =>
setFilters((current) => ({ ...current, type: updater(current.type) }));
const toggleTypeFilter = (category: SearchFileCategory) =>
setFilters((current) => ({ ...current, type: toggleTypeCategory(current.type, category) }));

const clearTypeFilter = () => setFilters((current) => ({ ...current, type: [] }));

const openSearchBoxRef = useRef(openSearchBox);
openSearchBoxRef.current = openSearchBox;

const refocusSearchInput = () => {
setTimeout(() => {
if (openSearchBoxRef.current) searchInput.current?.focus();
}, 0);
};

useEffect(() => {
if (query.length > 0) {
Expand Down Expand Up @@ -239,34 +238,6 @@ const Navbar = (props: NavbarProps) => {
if (item) document.querySelector(`#searchResult_${item}`)?.scrollIntoView();
};

const filterItems: SearchFilterItem[] = [
{
id: 'folder',
Icon: iconService.getItemIcon(true),
name: translate('general.searchBar.filters.folder'),
},
{
id: 'pdf',
Icon: iconService.getItemIcon(false, 'pdf'),
name: translate('general.searchBar.filters.pdf'),
},
{
id: 'image',
Icon: iconService.getItemIcon(false, 'jpg'),
name: translate('general.searchBar.filters.image'),
},
{
id: 'video',
Icon: iconService.getItemIcon(false, 'mp4'),
name: translate('general.searchBar.filters.video'),
},
{
id: 'audio',
Icon: iconService.getItemIcon(false, 'mp3'),
name: translate('general.searchBar.filters.audio'),
},
];

return (
<div className="flex h-14 w-full items-center justify-between border-b border-gray-5 text-gray-40 dark:bg-gray-1">
<div className="flex h-full w-full items-center justify-between z-20">
Expand Down Expand Up @@ -328,31 +299,17 @@ const Navbar = (props: NavbarProps) => {
onMouseEnter={() => setPreventBlur(true)}
onMouseLeave={() => setPreventBlur(false)}
>
<div className="flex w-full shrink-0 items-center justify-between border-b border-gray-5 px-2.5 py-2.5 dark:border-gray-10">
<div className="flex items-center space-x-2">
{filterItems.map((item) => (
<FilterItem
key={item.id}
id={item.id}
Icon={item.Icon}
name={item.name}
filters={filters.type}
setFilters={setTypeFilters}
/>
))}
</div>

<button
type="button"
className={getClearFiltersClassName(filters.type.length)}
onClick={() => setFilters(emptySearchFilters)}
>
{translate('general.searchBar.filters.clear')}
</button>
<div className="flex w-full shrink-0 items-center space-x-2 border-b border-gray-5 px-2.5 py-2.5 dark:border-gray-10">
<SearchTypeFilter
selected={filters.type}
onToggle={toggleTypeFilter}
onSelectAny={clearTypeFilter}
onClose={refocusSearchInput}
/>
</div>

{shouldShowResults() ? (
<ul ref={searchResultList} className="flex h-full flex-col overflow-y-auto pb-4">
<ul ref={searchResultList} className="flex h-full flex-col overflow-y-auto rounded-b-xl pb-4">
{searchResult.map((item, index) => {
const isFolder = item.itemType === 'FOLDER' || item.itemType === 'folder';
const Icon = iconService.getItemIcon(isFolder, item.item.type);
Expand Down
72 changes: 72 additions & 0 deletions src/views/Home/components/SearchTypeFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Menu, MenuButton, MenuItems } from '@headlessui/react';
import { SearchFileCategory } from '../services';
import { Checkbox } from '@internxt/ui';
import { CaretDownIcon } from '@phosphor-icons/react';
import iconService from 'app/drive/services/icon.service';
import { useTranslationContext } from 'app/i18n/provider/TranslationProvider';
import { useEffect, useRef } from 'react';
import { TYPE_FILTER_ITEMS } from '../utils/typeFilterUtils';

interface SearchTypeFilterProps {
selected: SearchFileCategory[];
onToggle: (category: SearchFileCategory) => void;
onSelectAny: () => void;
onClose: () => void;
}

const MenuCloseObserver = ({ open, onClose }: { open: boolean; onClose: () => void }): null => {
const wasOpen = useRef(false);
useEffect(() => {
if (wasOpen.current && !open) onClose();
wasOpen.current = open;
}, [open]);
return null;
};

const SearchTypeFilter = ({ selected, onToggle, onSelectAny, onClose }: SearchTypeFilterProps): JSX.Element => {
const { translate } = useTranslationContext();
const isAnyType = selected.length === 0;

return (
<Menu as="div" className="relative">
{({ open }) => (
<>
<MenuCloseObserver open={open} onClose={onClose} />
<MenuButton
className={`${
isAnyType
? 'bg-surface text-gray-80 ring-gray-10 hover:bg-gray-1 hover:shadow-sm hover:ring-gray-20 dark:bg-gray-5 dark:hover:bg-gray-10'
: 'bg-primary/10 text-primary ring-primary/20 dark:bg-primary/20 dark:text-white dark:ring-primary/75'
} flex h-8 cursor-pointer items-center space-x-2 rounded-full px-3 font-medium shadow-sm outline-none ring-1 transition-all duration-100 ease-out`}
>
<span className="text-sm">{translate('general.searchBar.filters.attachments')}</span>
<CaretDownIcon size={16} />
</MenuButton>

<MenuItems
transition
className="absolute left-0 z-20 mt-1 flex min-w-[240px] origin-top-left flex-col rounded-lg border border-gray-10 bg-surface py-1.5 shadow-subtle-hard outline-none transition duration-100 ease-out data-[closed]:scale-95 data-[closed]:opacity-0 dark:bg-gray-5"
>
<div className="flex flex-row items-center gap-2 px-4 py-2">
<Checkbox checked={isAnyType} indeterminate={!isAnyType} onClick={onSelectAny} />
<p className="text-gray-100">{translate('general.searchBar.filters.anyType')}</p>
</div>
<div className="mx-4 border-t border-gray-10" />
{TYPE_FILTER_ITEMS.map(({ id, labelKey, extension }) => {
const Icon = iconService.getItemIcon(id === 'folder', extension);
return (
<div className="flex flex-row items-center gap-2 px-4 py-2" key={id}>
<Checkbox checked={isAnyType || selected.includes(id)} onClick={() => onToggle(id)} />
<Icon className="h-6 w-6 drop-shadow-soft" />
<p className="text-gray-100">{translate(`general.searchBar.filters.${labelKey}`)}</p>
</div>
);
})}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make clickable all the row instead only the checkbox, ask to designer if have doubts

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

</MenuItems>
</>
)}
</Menu>
);
};

export default SearchTypeFilter;
Loading
Loading