fix bookstack display error
This commit is contained in:
@@ -78,7 +78,23 @@ const BookStackRecentWidget: React.FC = () => {
|
||||
const configured = data?.configured ?? true;
|
||||
const pages = data?.data ?? [];
|
||||
|
||||
if (!configured) return null;
|
||||
if (!configured) {
|
||||
return (
|
||||
<Card sx={{ height: '100%' }}>
|
||||
<CardContent>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
|
||||
<MenuBook color="disabled" />
|
||||
<Typography variant="h6" sx={{ flexGrow: 1 }} color="text.secondary">
|
||||
BookStack — Neueste Seiten
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ py: 2, textAlign: 'center' }}>
|
||||
BookStack nicht eingerichtet
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
|
||||
@@ -8,8 +8,10 @@ import {
|
||||
Divider,
|
||||
CircularProgress,
|
||||
InputAdornment,
|
||||
Skeleton,
|
||||
} from '@mui/material';
|
||||
import { Search, MenuBook } from '@mui/icons-material';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { bookstackApi } from '../../services/bookstack';
|
||||
import type { BookStackSearchResult } from '../../types/bookstack.types';
|
||||
|
||||
@@ -63,29 +65,47 @@ const ResultRow: React.FC<{ result: BookStackSearchResult; showDivider: boolean
|
||||
const BookStackSearchWidget: React.FC = () => {
|
||||
const [query, setQuery] = useState('');
|
||||
const [results, setResults] = useState<BookStackSearchResult[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [configured, setConfigured] = useState(true);
|
||||
const [searching, setSearching] = useState(false);
|
||||
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const latestQueryRef = useRef<string>('');
|
||||
|
||||
const { data, isLoading: configLoading } = useQuery({
|
||||
queryKey: ['bookstack-recent'],
|
||||
queryFn: () => bookstackApi.getRecent(),
|
||||
refetchInterval: 5 * 60 * 1000,
|
||||
retry: 1,
|
||||
});
|
||||
|
||||
// undefined while loading, true/false once known
|
||||
const configured = configLoading ? undefined : (data?.configured ?? false);
|
||||
|
||||
useEffect(() => {
|
||||
if (debounceRef.current) clearTimeout(debounceRef.current);
|
||||
|
||||
if (!query.trim()) {
|
||||
setResults([]);
|
||||
setLoading(false);
|
||||
setSearching(false);
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
setSearching(true);
|
||||
const thisQuery = query.trim();
|
||||
latestQueryRef.current = thisQuery;
|
||||
|
||||
debounceRef.current = setTimeout(async () => {
|
||||
try {
|
||||
const response = await bookstackApi.search(query.trim());
|
||||
setConfigured(response.configured);
|
||||
setResults(response.data);
|
||||
const response = await bookstackApi.search(thisQuery);
|
||||
if (latestQueryRef.current === thisQuery) {
|
||||
setResults(response.data);
|
||||
}
|
||||
} catch {
|
||||
setResults([]);
|
||||
if (latestQueryRef.current === thisQuery) {
|
||||
setResults([]);
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
if (latestQueryRef.current === thisQuery) {
|
||||
setSearching(false);
|
||||
}
|
||||
}
|
||||
}, 400);
|
||||
|
||||
@@ -94,7 +114,37 @@ const BookStackSearchWidget: React.FC = () => {
|
||||
};
|
||||
}, [query]);
|
||||
|
||||
if (!configured) return null;
|
||||
if (configured === undefined) {
|
||||
return (
|
||||
<Card sx={{ height: '100%' }}>
|
||||
<CardContent>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
|
||||
<MenuBook color="primary" />
|
||||
<Skeleton variant="text" width={160} height={32} />
|
||||
</Box>
|
||||
<Skeleton variant="rectangular" height={40} sx={{ borderRadius: 1 }} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
if (configured === false) {
|
||||
return (
|
||||
<Card sx={{ height: '100%' }}>
|
||||
<CardContent>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
|
||||
<MenuBook color="disabled" />
|
||||
<Typography variant="h6" sx={{ flexGrow: 1 }} color="text.secondary">
|
||||
BookStack — Suche
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ py: 2, textAlign: 'center' }}>
|
||||
BookStack nicht eingerichtet
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
@@ -121,13 +171,13 @@ const BookStackSearchWidget: React.FC = () => {
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
{loading ? <CircularProgress size={16} /> : <Search fontSize="small" />}
|
||||
{searching ? <CircularProgress size={16} /> : <Search fontSize="small" />}
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
{!loading && query.trim() && results.length === 0 && (
|
||||
{!searching && query.trim() && results.length === 0 && (
|
||||
<Typography variant="body2" color="text.secondary" sx={{ py: 2, textAlign: 'center' }}>
|
||||
Keine Ergebnisse für „{query}"
|
||||
</Typography>
|
||||
|
||||
@@ -4,3 +4,5 @@ export { default as StatsCard } from './StatsCard';
|
||||
export { default as DashboardLayout } from './DashboardLayout';
|
||||
export { default as PersonalWarningsBanner } from './PersonalWarningsBanner';
|
||||
export { default as UpcomingEventsWidget } from './UpcomingEventsWidget';
|
||||
export { default as BookStackRecentWidget } from './BookStackRecentWidget';
|
||||
export { default as BookStackSearchWidget } from './BookStackSearchWidget';
|
||||
|
||||
Reference in New Issue
Block a user