feat(client): update the messy search

This commit is contained in:
perf3ct 2025-06-26 18:49:24 +00:00
parent 8cafe14e89
commit e57935a4b5
No known key found for this signature in database
GPG Key ID: 569C4EEC436F5232
1 changed files with 66 additions and 64 deletions

View File

@ -42,8 +42,6 @@ import {
FilterList as FilterIcon, FilterList as FilterIcon,
Clear as ClearIcon, Clear as ClearIcon,
ExpandMore as ExpandMoreIcon, ExpandMore as ExpandMoreIcon,
GridView as GridViewIcon,
ViewList as ListViewIcon,
Download as DownloadIcon, Download as DownloadIcon,
PictureAsPdf as PdfIcon, PictureAsPdf as PdfIcon,
Image as ImageIcon, Image as ImageIcon,
@ -108,7 +106,6 @@ interface SearchFilters {
hasOcr?: string; hasOcr?: string;
} }
type ViewMode = 'grid' | 'list';
type SearchMode = 'simple' | 'phrase' | 'fuzzy' | 'boolean'; type SearchMode = 'simple' | 'phrase' | 'fuzzy' | 'boolean';
type OcrStatus = 'all' | 'yes' | 'no'; type OcrStatus = 'all' | 'yes' | 'no';
@ -133,7 +130,6 @@ const SearchPage: React.FC = () => {
const [searchResults, setSearchResults] = useState<Document[]>([]); const [searchResults, setSearchResults] = useState<Document[]>([]);
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [viewMode, setViewMode] = useState<ViewMode>('grid');
const [queryTime, setQueryTime] = useState<number>(0); const [queryTime, setQueryTime] = useState<number>(0);
const [totalResults, setTotalResults] = useState<number>(0); const [totalResults, setTotalResults] = useState<number>(0);
const [suggestions, setSuggestions] = useState<string[]>([]); const [suggestions, setSuggestions] = useState<string[]>([]);
@ -447,11 +443,6 @@ const SearchPage: React.FC = () => {
setSearchQuery(suggestion); setSearchQuery(suggestion);
}; };
const handleViewModeChange = (event: React.MouseEvent<HTMLElement>, newView: ViewMode | null): void => {
if (newView) {
setViewMode(newView);
}
};
const handleSearchModeChange = (event: React.MouseEvent<HTMLElement>, newMode: SearchMode | null): void => { const handleSearchModeChange = (event: React.MouseEvent<HTMLElement>, newMode: SearchMode | null): void => {
if (newMode) { if (newMode) {
@ -894,31 +885,12 @@ const SearchPage: React.FC = () => {
{/* Search Results */} {/* Search Results */}
<Grid item xs={12} md={9}> <Grid item xs={12} md={9}>
{/* Toolbar */} {/* Results Header */}
{searchQuery && ( {searchQuery && (
<Box sx={{ <Box sx={{ mb: 3 }}>
mb: 3,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}>
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
{loading ? 'Searching...' : `${searchResults.length} results found`} {loading ? 'Searching...' : `${searchResults.length} results found`}
</Typography> </Typography>
<ToggleButtonGroup
value={viewMode}
exclusive
onChange={handleViewModeChange}
size="small"
>
<ToggleButton value="grid">
<GridViewIcon />
</ToggleButton>
<ToggleButton value="list">
<ListViewIcon />
</ToggleButton>
</ToggleButtonGroup>
</Box> </Box>
)} )}
@ -1044,14 +1016,11 @@ const SearchPage: React.FC = () => {
)} )}
{!loading && !error && searchResults.length > 0 && ( {!loading && !error && searchResults.length > 0 && (
<Grid container spacing={viewMode === 'grid' ? 3 : 1}> <Grid container spacing={1}>
{searchResults.map((doc) => ( {searchResults.map((doc) => (
<Grid <Grid
item item
xs={12} xs={12}
sm={viewMode === 'grid' ? 6 : 12}
md={viewMode === 'grid' ? 6 : 12}
lg={viewMode === 'grid' ? 4 : 12}
key={doc.id} key={doc.id}
> >
<Card <Card
@ -1059,32 +1028,31 @@ const SearchPage: React.FC = () => {
sx={{ sx={{
height: '100%', height: '100%',
display: 'flex', display: 'flex',
flexDirection: viewMode === 'list' ? 'row' : 'column', flexDirection: 'row',
}} }}
> >
{viewMode === 'grid' && (
<Box <CardContent
sx={{ className="search-card"
height: 100, sx={{
display: 'flex', flexGrow: 1,
alignItems: 'center', overflow: 'hidden',
justifyContent: 'center', py: 1.5,
background: 'linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, rgba(139, 92, 246, 0.1) 100%)', px: 2,
}} '&:last-child': {
> pb: 1.5
<Box sx={{ fontSize: '2.5rem' }}> }
}}
>
<Box sx={{
display: 'flex',
alignItems: 'center',
gap: 1,
width: '100%'
}}>
<Box sx={{ mr: 1, mt: 0.5 }}>
{getFileIcon(doc.mime_type)} {getFileIcon(doc.mime_type)}
</Box> </Box>
</Box>
)}
<CardContent className="search-card" sx={{ flexGrow: 1, overflow: 'hidden' }}>
<Box sx={{ display: 'flex', alignItems: 'flex-start', gap: 1, width: '100%' }}>
{viewMode === 'list' && (
<Box sx={{ mr: 1, mt: 0.5 }}>
{getFileIcon(doc.mime_type)}
</Box>
)}
<Box sx={{ flexGrow: 1, minWidth: 0, overflow: 'hidden' }}> <Box sx={{ flexGrow: 1, minWidth: 0, overflow: 'hidden' }}>
<Typography <Typography
@ -1092,7 +1060,7 @@ const SearchPage: React.FC = () => {
sx={{ sx={{
fontSize: '0.95rem', fontSize: '0.95rem',
fontWeight: 600, fontWeight: 600,
mb: 1, mb: 0.5,
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
@ -1104,7 +1072,13 @@ const SearchPage: React.FC = () => {
{doc.original_filename} {doc.original_filename}
</Typography> </Typography>
<Box sx={{ mb: 1, display: 'flex', flexWrap: 'wrap', gap: 0.5, overflow: 'hidden' }}> <Box sx={{
mb: 0.5,
display: 'flex',
flexWrap: 'wrap',
gap: 0.5,
overflow: 'hidden'
}}>
<Chip <Chip
className="search-chip" className="search-chip"
label={formatFileSize(doc.file_size)} label={formatFileSize(doc.file_size)}
@ -1132,7 +1106,13 @@ const SearchPage: React.FC = () => {
</Box> </Box>
{doc.tags.length > 0 && ( {doc.tags.length > 0 && (
<Box sx={{ mb: 1, display: 'flex', flexWrap: 'wrap', gap: 0.5, overflow: 'hidden' }}> <Box sx={{
mb: 0.5,
display: 'flex',
flexWrap: 'wrap',
gap: 0.5,
overflow: 'hidden'
}}>
{doc.tags.slice(0, 2).map((tag, index) => ( {doc.tags.slice(0, 2).map((tag, index) => (
<Chip <Chip
key={index} key={index}
@ -1168,7 +1148,10 @@ const SearchPage: React.FC = () => {
{/* Enhanced Search Snippets */} {/* Enhanced Search Snippets */}
{doc.snippets && doc.snippets.length > 0 && ( {doc.snippets && doc.snippets.length > 0 && (
<Box sx={{ mt: 2, mb: 1 }}> <Box sx={{
mt: 1,
mb: 0.5
}}>
<EnhancedSnippetViewer <EnhancedSnippetViewer
snippets={doc.snippets} snippets={doc.snippets}
searchQuery={searchQuery} searchQuery={searchQuery}
@ -1183,7 +1166,10 @@ const SearchPage: React.FC = () => {
{/* Search Rank */} {/* Search Rank */}
{doc.search_rank && ( {doc.search_rank && (
<Box sx={{ mt: 1, overflow: 'hidden' }}> <Box sx={{
mt: 0.5,
overflow: 'hidden'
}}>
<Chip <Chip
className="search-chip" className="search-chip"
label={`Relevance: ${(doc.search_rank * 100).toFixed(1)}%`} label={`Relevance: ${(doc.search_rank * 100).toFixed(1)}%`}
@ -1206,23 +1192,39 @@ const SearchPage: React.FC = () => {
)} )}
</Box> </Box>
<Box sx={{ display: 'flex', flexShrink: 0, ml: 'auto' }}> <Box sx={{
display: 'flex',
flexShrink: 0,
ml: 'auto',
gap: 0.5,
alignItems: 'center'
}}>
<Tooltip title="View Details"> <Tooltip title="View Details">
<IconButton <IconButton
className="search-filter-button search-focusable" className="search-filter-button search-focusable"
size="small" size="small"
sx={{
p: 0.5,
minWidth: 28,
minHeight: 28
}}
onClick={() => navigate(`/documents/${doc.id}`)} onClick={() => navigate(`/documents/${doc.id}`)}
> >
<ViewIcon /> <ViewIcon sx={{ fontSize: '1rem' }} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title="Download"> <Tooltip title="Download">
<IconButton <IconButton
className="search-filter-button search-focusable" className="search-filter-button search-focusable"
size="small" size="small"
sx={{
p: 0.5,
minWidth: 28,
minHeight: 28
}}
onClick={() => handleDownload(doc)} onClick={() => handleDownload(doc)}
> >
<DownloadIcon /> <DownloadIcon sx={{ fontSize: '1rem' }} />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</Box> </Box>