diff --git a/frontend/src/components/format/FormatPage.jsx b/frontend/src/components/format/FormatPage.jsx
index 71f368c..cccace5 100644
--- a/frontend/src/components/format/FormatPage.jsx
+++ b/frontend/src/components/format/FormatPage.jsx
@@ -13,6 +13,7 @@ import MassActionsBar from '@ui/MassActionsBar';
import ImportModal from '@ui/ImportModal';
import {importFormats} from '@api/import';
import DataBar from '@ui/DataBar/DataBar';
+import useSearch from '@hooks/useSearch';
const loadingMessages = [
'Formatting the formatters...',
@@ -62,19 +63,40 @@ function FormatPage() {
const [formats, setFormats] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedFormat, setSelectedFormat] = useState(null);
- const [sortBy, setSortBy] = useState('name');
- const [filterType, setFilterType] = useState('none');
- const [filterValue, setFilterValue] = useState('');
const [allTags, setAllTags] = useState([]);
const [isCloning, setIsCloning] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [mergeConflicts, setMergeConflicts] = useState([]);
- const [searchQuery, setSearchQuery] = useState('');
const [isImportModalOpen, setIsImportModalOpen] = useState(false);
const [willBeSelected, setWillBeSelected] = useState([]);
const navigate = useNavigate();
+ // Initialize useSearch hook
+ const {
+ searchTerms,
+ currentInput,
+ setCurrentInput,
+ addSearchTerm,
+ removeSearchTerm,
+ clearSearchTerms,
+ filterType,
+ setFilterType,
+ filterValue,
+ setFilterValue,
+ sortBy,
+ setSortBy,
+ items: filteredFormats
+ } = useSearch(formats, {
+ searchableFields: ['content.name', 'content.tags'],
+ initialSortBy: 'name',
+ sortOptions: {
+ name: (a, b) => a.content.name.localeCompare(b.content.name),
+ dateModified: (a, b) =>
+ new Date(b.modified_date) - new Date(a.modified_date)
+ }
+ });
+
const {
selectedItems,
isSelectionMode,
@@ -228,7 +250,6 @@ function FormatPage() {
const handleMassDelete = async () => {
try {
- const filteredFormats = getFilteredAndSortedFormats();
const selectedFormats = Array.from(selectedItems).map(
index => filteredFormats[index]
);
@@ -246,7 +267,6 @@ function FormatPage() {
'Failed to delete selected formats'
);
} finally {
- // Always reload data and reset selection state, regardless of success/failure
fetchFormats();
toggleSelectionMode();
clearSelection();
@@ -255,7 +275,6 @@ function FormatPage() {
const handleMassImport = async arr => {
try {
- const filteredFormats = getFilteredAndSortedFormats();
const selectedFormats = Array.from(selectedItems).map(
index => filteredFormats[index]
);
@@ -275,7 +294,7 @@ function FormatPage() {
if (e.shiftKey) {
handleMouseEnter(index, true);
}
- handleSelect(formatName, index, e, getFilteredAndSortedFormats());
+ handleSelect(formatName, index, e, filteredFormats);
};
const handleMouseEnter = (index, isShiftKey) => {
@@ -283,7 +302,7 @@ function FormatPage() {
const start = Math.min(lastSelectedIndex, index);
const end = Math.max(lastSelectedIndex, index);
- const potentialSelection = getFilteredAndSortedFormats()
+ const potentialSelection = filteredFormats
.slice(start, end + 1)
.map((format, idx) => idx + start);
@@ -291,40 +310,6 @@ function FormatPage() {
}
};
- const getFilteredAndSortedFormats = () => {
- let filtered = [...formats];
-
- if (searchQuery) {
- filtered = filtered.filter(
- format =>
- format.content.name
- .toLowerCase()
- .includes(searchQuery.toLowerCase()) ||
- format.content.tags?.some(tag =>
- tag.toLowerCase().includes(searchQuery.toLowerCase())
- )
- );
- }
-
- if (filterType === 'tag' && filterValue) {
- filtered = filtered.filter(format =>
- format.content.tags?.includes(filterValue)
- );
- }
-
- return filtered.sort((a, b) => {
- switch (sortBy) {
- case 'dateModified':
- return (
- new Date(b.modified_date) - new Date(a.modified_date)
- );
- case 'name':
- default:
- return a.content.name.localeCompare(b.content.name);
- }
- });
- };
-
if (isLoading) {
return ;
}
@@ -338,7 +323,12 @@ function FormatPage() {
return (
- {getFilteredAndSortedFormats().map((format, index) => (
+ {filteredFormats.map((format, index) => (
(
@@ -57,19 +58,50 @@ function ProfilePage() {
const [formats, setFormats] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedProfile, setSelectedProfile] = useState(null);
- const [sortBy, setSortBy] = useState('name');
- const [filterType, setFilterType] = useState('none');
- const [filterValue, setFilterValue] = useState('');
const [allTags, setAllTags] = useState([]);
const [isCloning, setIsCloning] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [mergeConflicts, setMergeConflicts] = useState([]);
- const [searchQuery, setSearchQuery] = useState('');
const [isImportModalOpen, setIsImportModalOpen] = useState(false);
const [willBeSelected, setWillBeSelected] = useState([]);
const navigate = useNavigate();
+ // Initialize useSearch hook with profile-specific configuration
+ const {
+ searchTerms,
+ currentInput,
+ setCurrentInput,
+ addSearchTerm,
+ removeSearchTerm,
+ clearSearchTerms,
+ filterType,
+ setFilterType,
+ filterValue,
+ setFilterValue,
+ sortBy,
+ setSortBy,
+ items: filteredProfiles
+ } = useSearch(profiles, {
+ searchableFields: ['content.name', 'content.tags'],
+ initialSortBy: 'name',
+ sortOptions: {
+ name: (a, b) => a.content.name.localeCompare(b.content.name),
+ dateModified: (a, b) =>
+ new Date(b.modified_date) - new Date(a.modified_date),
+ dateCreated: (a, b) =>
+ new Date(b.created_date) - new Date(a.created_date)
+ },
+ customFilters: {
+ date: (item, value) => {
+ if (!value) return true;
+ const itemDate = new Date(item.modified_date);
+ const filterDate = new Date(value);
+ return itemDate.toDateString() === filterDate.toDateString();
+ }
+ }
+ });
+
const {
selectedItems,
isSelectionMode,
@@ -227,7 +259,7 @@ function ProfilePage() {
const handleMassDelete = async () => {
try {
const selectedProfiles = Array.from(selectedItems).map(
- index => profiles[index]
+ index => filteredProfiles[index]
);
for (const profile of selectedProfiles) {
await Profiles.delete(profile.file_name.replace('.yml', ''));
@@ -244,7 +276,7 @@ function ProfilePage() {
const handleMassImport = async arr => {
try {
const selectedProfilesList = Array.from(selectedItems)
- .map(index => profiles[index])
+ .map(index => filteredProfiles[index])
.filter(profile => profile);
if (selectedProfilesList.length === 0) {
@@ -269,7 +301,7 @@ function ProfilePage() {
if (e.shiftKey) {
handleMouseEnter(index, true);
}
- handleSelect(profileName, index, e, getFilteredAndSortedProfiles());
+ handleSelect(profileName, index, e, filteredProfiles);
};
const handleMouseEnter = (index, isShiftKey) => {
@@ -277,7 +309,7 @@ function ProfilePage() {
const start = Math.min(lastSelectedIndex, index);
const end = Math.max(lastSelectedIndex, index);
- const potentialSelection = getFilteredAndSortedProfiles()
+ const potentialSelection = filteredProfiles
.slice(start, end + 1)
.map((profile, idx) => idx + start);
@@ -285,54 +317,6 @@ function ProfilePage() {
}
};
- const getFilteredAndSortedProfiles = () => {
- return profiles
- .filter(profile => {
- if (searchQuery) {
- return (
- profile.content.name
- .toLowerCase()
- .includes(searchQuery.toLowerCase()) ||
- profile.content.tags?.some(tag =>
- tag
- .toLowerCase()
- .includes(searchQuery.toLowerCase())
- )
- );
- }
-
- if (filterType === 'tag') {
- return profile.content.tags?.includes(filterValue);
- }
-
- if (filterType === 'date') {
- const profileDate = new Date(profile.modified_date);
- const filterDate = new Date(filterValue);
- return (
- profileDate.toDateString() === filterDate.toDateString()
- );
- }
-
- return true;
- })
- .sort((a, b) => {
- switch (sortBy) {
- case 'dateModified':
- return (
- new Date(b.modified_date) -
- new Date(a.modified_date)
- );
- case 'dateCreated':
- return (
- new Date(b.created_date) - new Date(a.created_date)
- );
- case 'name':
- default:
- return a.content.name.localeCompare(b.content.name);
- }
- });
- };
-
const formatDate = dateString => {
return new Date(dateString).toLocaleString();
};
@@ -347,12 +331,15 @@ function ProfilePage() {
);
}
- const filteredProfiles = getFilteredAndSortedProfiles();
-
return (
(
);
function RegexPage() {
+ // Basic state
const [patterns, setPatterns] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedPattern, setSelectedPattern] = useState(null);
- const [sortBy, setSortBy] = useState('name');
- const [filterType, setFilterType] = useState('none');
- const [filterValue, setFilterValue] = useState('');
const [allTags, setAllTags] = useState([]);
const [isCloning, setIsCloning] = useState(false);
const [isLoading, setIsLoading] = useState(true);
- const [searchQuery, setSearchQuery] = useState('');
const [willBeSelected, setWillBeSelected] = useState([]);
- const [originalIndices, setOriginalIndices] = useState(new Map());
+ // Initialize useSearch hook
+ const {
+ searchTerms,
+ currentInput,
+ setCurrentInput,
+ addSearchTerm,
+ removeSearchTerm,
+ clearSearchTerms,
+ filterType,
+ setFilterType,
+ filterValue,
+ setFilterValue,
+ sortBy,
+ setSortBy,
+ items: filteredPatterns
+ } = useSearch(patterns, {
+ searchableFields: ['name', 'tags'],
+ initialSortBy: 'name',
+ sortOptions: {
+ name: (a, b) => a.name.localeCompare(b.name),
+ dateModified: (a, b) =>
+ new Date(b.modified_date) - new Date(a.modified_date)
+ }
+ });
+
+ // Mass selection functionality
const {
selectedItems,
isSelectionMode,
@@ -54,12 +77,10 @@ function RegexPage() {
lastSelectedIndex
} = useMassSelection();
+ // Keyboard shortcuts
useKeyboardShortcut('a', toggleSelectionMode, {ctrl: true});
- useEffect(() => {
- loadPatterns();
- }, []);
-
+ // Mouse position tracking for shift-select
useEffect(() => {
const handleKeyDown = e => {
if (e.key === 'Shift' && lastSelectedIndex !== null) {
@@ -99,6 +120,11 @@ function RegexPage() {
};
}, [lastSelectedIndex]);
+ // Initial load
+ useEffect(() => {
+ loadPatterns();
+ }, []);
+
const loadPatterns = async () => {
setIsLoading(true);
try {
@@ -158,7 +184,6 @@ function RegexPage() {
const handleMassDelete = async () => {
try {
- const filteredPatterns = getFilteredAndSortedPatterns();
const selectedPatterns = Array.from(selectedItems).map(
index => filteredPatterns[index]
);
@@ -173,7 +198,6 @@ function RegexPage() {
console.error('Error deleting patterns:', error);
Alert.error('Failed to delete selected patterns');
} finally {
- // Always reload data and reset selection state, regardless of success/failure
loadPatterns();
toggleSelectionMode();
clearSelection();
@@ -184,59 +208,20 @@ function RegexPage() {
if (e.shiftKey) {
handleMouseEnter(index, true);
}
- handleSelect(patternName, index, e, getFilteredAndSortedPatterns());
+ handleSelect(patternName, index, e, filteredPatterns);
};
const handleMouseEnter = (index, isShiftKey) => {
if (isShiftKey && lastSelectedIndex !== null) {
const start = Math.min(lastSelectedIndex, index);
const end = Math.max(lastSelectedIndex, index);
-
- const potentialSelection = getFilteredAndSortedPatterns()
+ const potentialSelection = filteredPatterns
.slice(start, end + 1)
.map((pattern, idx) => idx + start);
-
setWillBeSelected(potentialSelection);
}
};
- const getFilteredAndSortedPatterns = () => {
- let filtered = patterns.map((pattern, index) => ({
- ...pattern,
- originalIndex: index
- }));
-
- if (searchQuery) {
- filtered = filtered.filter(
- pattern =>
- pattern.name
- .toLowerCase()
- .includes(searchQuery.toLowerCase()) ||
- pattern.tags?.some(tag =>
- tag.toLowerCase().includes(searchQuery.toLowerCase())
- )
- );
- }
-
- if (filterType === 'tag' && filterValue) {
- filtered = filtered.filter(pattern =>
- pattern.tags?.includes(filterValue)
- );
- }
-
- return filtered.sort((a, b) => {
- switch (sortBy) {
- case 'dateModified':
- return (
- new Date(b.modified_date) - new Date(a.modified_date)
- );
- case 'name':
- default:
- return a.name.localeCompare(b.name);
- }
- });
- };
-
const formatDate = dateString => {
return new Date(dateString).toLocaleString();
};
@@ -248,8 +233,12 @@ function RegexPage() {
return (
- {getFilteredAndSortedPatterns().map((pattern, index) => (
+ {filteredPatterns.map((pattern, index) => (