Adds a navigation-aware request cancellation mechanism that automatically
aborts all route-specific API requests when the user navigates to a
different route. This prevents silent state-update errors from responses
arriving after component unmount and conserves bandwidth by cancelling
now-irrelevant requests.
Key additions:
- NavigationCancellationContext: Context for managing route-specific signals
- NavigationCancellationProvider: Provider that detects route changes and
aborts all signals from the previous route
- useNavigationAbortSignal hook: Allows components to subscribe to
navigation-aware cancellation signals
- Comprehensive tests for the cancellation lifecycle
- Documentation in Web-Development.md for request lifecycle policy
The provider is placed in the app hierarchy between BrowserRouter and
AuthProvider, ensuring consistent cancellation behavior across all routes.
Long-lived background tasks (polling, session validation) can opt-out by
managing their own AbortController lifecycle.
Closes#23 from Tasks.md: No global cancellation policy on route transitions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implement standardized skeleton loading placeholders to reduce perceived
loading time and prevent layout shift during data fetches. These components
match actual content dimensions exactly, improving perceived responsiveness.
New skeleton components in src/components/skeletons/:
- SkeletonTable: Table/grid loading with customizable rows and cells
- SkeletonTableRow: Individual animated skeleton row
- SkeletonChart: Chart/graph loading with bars matching dimensions
- SkeletonStat: Stat card loading with label and value
- SkeletonFormField: Form input loading placeholder
- PageLoadingSkeleton: Convenience wrapper for page-level loading states
Implementation details:
- All skeletons use global 'skeleton-pulse' animation (2s cycle)
- Dimensions match real content to prevent layout shift on arrival
- Marked with aria-hidden and role=presentation for accessibility
- Theme-aware colors using Fluent UI tokens
- Respects prefers-reduced-motion setting
Updates:
- ChartStateWrapper: Uses SkeletonChart instead of spinner
- PageFeedback: Added PageLoadingSkeleton component
- App.tsx: Injects skeleton styles at startup
- Web-Design.md: Added § 8a with loading UX guidance and usage examples
All components tested (22 tests, 100% passing) and linted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This addresses issue #19 by making the implicit provider dependency order
explicit and order-sensitive.
Changes:
1. Created PROVIDER_ORDER.md - comprehensive documentation explaining:
- The provider hierarchy from outermost to innermost
- Why each provider must be at its position
- Order-sensitive pitfalls and what would break
- Guidelines for adding new providers in the future
2. Added provider composition tests (providerComposition.test.tsx):
- 13 comprehensive tests validating provider order and dependencies
- Tests verify all providers mount correctly
- Tests check that hooks only work inside correct providers
- Tests validate async initialization (AuthProvider, TimezoneProvider)
- Tests verify theme persistence and notification propagation
3. Updated App.tsx with inline documentation:
- Added detailed provider order contract in JSDoc header
- Inline comments explaining each provider's position
- Reference to PROVIDER_ORDER.md for detailed rationale
4. Updated Web-Development.md:
- Added new section 5.5 'Provider Order Contract'
- Documents provider hierarchy and rationale
- Links to comprehensive provider documentation
- References regression test suite
All tests pass. TypeScript compilation succeeds. Build succeeds.
The provider order is now explicit and future refactors can validate
compliance through the regression test suite.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Create NotificationService with context provider for centralized error/success messaging
- Add NotificationContainer component to render notification stack
- Integrate NotificationProvider into App root
- Refactor BanUnbanForm to use notification service instead of local error state
- Update fetchError utility to optionally use notification callbacks
- Add comprehensive error handling guidelines to Web-Development.md
- Prevent duplicate notifications with deduplication logic
- Support auto-dismiss with configurable TTL per notification type
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Create ErrorBoundary component to handle React render errors
- Wrap App component with ErrorBoundary for global error handling
- Add comprehensive tests for ErrorBoundary functionality
- Show fallback UI with error message when errors occur
- Add v7_startTransition and v7_relativeSplatPath future flags to
BrowserRouter to silence React Router deprecation warnings
- Add hidden autocomplete='username' inputs to LoginPage and SetupPage
so password managers and browsers stop warning about missing username
fields in password forms
- Mount fail2ban-dev-config volume into backend container at /config:ro
so ban_service can open the fail2ban SQLite database returned by
'get dbfile'; this fixes the 500 on GET /api/dashboard/bans
- Track compose.debug.yml in git (was previously untracked)
- Add SetupGuard component: redirects to /setup if setup not complete,
shown as spinner while loading. All routes except /setup now wrapped.
- SetupPage redirects to /login on mount when setup already done.
- Fix async blocking: offload bcrypt.hashpw and bcrypt.checkpw to
run_in_executor so they never stall the asyncio event loop.
- Hash password with SHA-256 (SubtleCrypto) before transmission; added
src/utils/crypto.ts with sha256Hex(). Backend stores bcrypt(sha256).
- Add Makefile with make up/down/restart/logs/clean targets.
- Add tests: _check_password async, concurrent bcrypt, expired session,
login-without-setup, run_setup event-loop interleaving.
- Update Architekture.md and Features.md to reflect all changes.