feat(client): update the messy search
This commit is contained in:
parent
8cafe14e89
commit
e57935a4b5
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue