feat: bug fixes, layout improvements, and new features
Bug fixes: - Remove non-existent `role` column from admin users SQL query (A1) - Fix Nextcloud Talk chat API path v4 → v1 for messages/send/read (A2) - Fix ServiceModeTab sync: useState → useEffect to reflect DB state (A3) - Guard BookStack book_slug with book_id fallback to avoid broken URLs (A4) Layout & UI: - Chat panel: sticky full-height positioning, main content scrolls independently (B1) - Vehicle booking datetime inputs: explicit text color for dark mode (B2) - AnnouncementBanner moved into grid with full-width span (B3) Features: - Per-user widget visibility preferences stored in users.preferences JSONB (C1) - Link collections: grouped external links in admin UI and dashboard widget (C2) - Admin ping history: migration 026, checked_at timestamps, expandable history rows (C4) - Service mode end date picker with scheduled deactivation display (C5) - Vikunja startup config logging and configured:false warnings (C7) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import {
|
||||
Box, Card, CardContent, Typography, Switch, FormControlLabel,
|
||||
TextField, Button, Alert, CircularProgress,
|
||||
@@ -20,17 +20,19 @@ export default function ServiceModeTab() {
|
||||
const currentValue = setting?.value ?? { active: false, message: '' };
|
||||
const [active, setActive] = useState<boolean>(currentValue.active ?? false);
|
||||
const [message, setMessage] = useState<string>(currentValue.message ?? '');
|
||||
const [endsAt, setEndsAt] = useState<string>('');
|
||||
|
||||
// Sync state when data loads
|
||||
useState(() => {
|
||||
useEffect(() => {
|
||||
if (setting?.value) {
|
||||
setActive(setting.value.active ?? false);
|
||||
setMessage(setting.value.message ?? '');
|
||||
setEndsAt(setting.value.ends_at ?? '');
|
||||
}
|
||||
});
|
||||
}, [setting]);
|
||||
|
||||
const mutation = useMutation({
|
||||
mutationFn: (value: { active: boolean; message: string }) =>
|
||||
mutationFn: (value: { active: boolean; message: string; ends_at?: string | null }) =>
|
||||
settingsApi.update('service_mode', value),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['service-mode'] });
|
||||
@@ -41,7 +43,7 @@ export default function ServiceModeTab() {
|
||||
});
|
||||
|
||||
const handleSave = () => {
|
||||
mutation.mutate({ active, message });
|
||||
mutation.mutate({ active, message, ends_at: endsAt || null });
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
@@ -63,6 +65,12 @@ export default function ServiceModeTab() {
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{active && endsAt && (
|
||||
<Alert severity="info" sx={{ mb: 2 }}>
|
||||
Wartungsmodus endet automatisch am {new Date(endsAt).toLocaleString('de-DE')}.
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
@@ -87,6 +95,17 @@ export default function ServiceModeTab() {
|
||||
helperText="Diese Nachricht sehen Benutzer auf der Wartungsseite."
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Automatisch deaktivieren am"
|
||||
type="datetime-local"
|
||||
value={endsAt}
|
||||
onChange={(e) => setEndsAt(e.target.value)}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
helperText="Optional: Wartungsmodus wird automatisch zu diesem Zeitpunkt deaktiviert."
|
||||
sx={{ mb: 3, '& input': { color: 'text.primary' } }}
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color={active ? 'error' : 'primary'}
|
||||
|
||||
Reference in New Issue
Block a user