Adds a new "procedural" tree type for linear step-by-step project workflows (domain controller setup, M365 onboarding, VPN config, etc). Includes intake form builder, two-panel step navigation, variable resolution, procedural exports, 3 seed templates, and UI rename from "Trees" to "Flows". Also archives 19 implemented plan docs and creates deferred features backlog. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
16 KiB
Tier 1 UX Enhancement: Consistent Notification System
Context
ResolutionFlow (Patherly) currently lacks a consistent feedback system for user actions. MSP engineers switching between multiple contexts need immediate confirmation that actions succeeded to reduce cognitive load and prevent errors. Research shows that 200-300ms feedback timing dramatically improves perceived reliability and user confidence.
Current State Problems
- No success notifications: Users don't get confirmation when trees/folders/sessions are saved or deleted
- Inconsistent patterns: Mix of button state changes, modal errors, and page-level banners
- Silent operations: "Add to Folder" silently succeeds with no feedback
- No dismissible errors: Error messages persist until page reload or modal close
- No notification history: Users can't review recent actions
User Impact
Engineers experience cognitive overload troubleshooting client issues. Without clear feedback:
- They second-guess themselves and repeat actions
- They abandon tasks when uncertain if changes saved
- They miss critical errors that appear briefly
- They waste time verifying actions succeeded
Why This Feature First
- Foundational infrastructure: Toast system benefits all future features
- Immediate wins: Every save/delete/export action gets better UX
- Low risk: Additive feature, doesn't break existing flows
- Quick implementation: 1-2 days to full deployment
- High perceived value: Users notice and appreciate immediate feedback
Design Overview
We'll integrate sonner (by shadcn creator) - a modern, accessible toast notification library that:
- Works perfectly with Tailwind CSS and our dark mode
- Provides beautiful default styling matching our design system
- Supports promise tracking (show loading → success/error automatically)
- Handles stacking, positioning, and auto-dismiss elegantly
- Only ~10KB gzipped
- Fully accessible (ARIA attributes, keyboard navigation)
Architecture: Toast as Global Service
frontend/src/
├── main.tsx
│ └── Wrap <App> with <Toaster /> provider
│
├── lib/
│ └── toast.ts (re-export sonner's toast with custom defaults)
│
├── components/
│ ├── library/TreeLibraryPage.tsx (add toast.success on delete)
│ ├── library/FolderEditModal.tsx (add toast.success on save)
│ ├── tree-editor/TreeEditorPage.tsx (replace error banner with toast)
│ ├── session/SessionDetailPage.tsx (add toast on export)
│ └── ...other components using toast
│
└── api/
└── client.ts (optional: global error toast interceptor)
Key Design Decisions:
- Single import point:
import { toast } from '@/lib/toast'everywhere - Custom defaults: Pre-configured duration, position, dark mode sync
- Promise pattern: Use
toast.promise()for async operations - Consistent vocabulary: "Saved", "Deleted", "Exported" (not "Success!")
- Error details: Show action + reason ("Failed to delete tree: Network error")
Implementation Plan
Phase 1: Install and Configure Sonner
1.1 Install dependencies
cd patherly/frontend
npm install sonner
1.2 Create toast utility wrapper (frontend/src/lib/toast.ts):
import { toast as sonnerToast } from 'sonner';
// Re-export with custom defaults
export const toast = {
success: (message: string, options?: any) =>
sonnerToast.success(message, { duration: 4000, ...options }),
error: (message: string, options?: any) =>
sonnerToast.error(message, { duration: 6000, ...options }),
info: (message: string, options?: any) =>
sonnerToast.info(message, { duration: 4000, ...options }),
loading: (message: string, options?: any) =>
sonnerToast.loading(message, { ...options }),
promise: sonnerToast.promise,
dismiss: sonnerToast.dismiss
};
1.3 Add Toaster provider to frontend/src/main.tsx:
import { Toaster } from 'sonner';
// Inside root render, wrap App:
<React.StrictMode>
<Toaster
position="top-right"
richColors
closeButton
theme={themeStore.theme === 'dark' ? 'dark' : 'light'}
/>
<App />
</React.StrictMode>
1.4 Sync theme with Toaster: Update themeStore.ts to re-render Toaster on theme change
Phase 2: Add Notifications to Core Actions
Success notifications to add:
| Component | Action | Toast Message | Type |
|---|---|---|---|
| TreeLibraryPage | Delete tree | "Tree deleted" | success |
| FolderEditModal | Save folder | "Folder saved" | success |
| FolderSidebar | Delete folder | "Folder deleted" | success |
| AddToFolderMenu | Add tree to folder | "Added to {folderName}" | success |
| AddToFolderMenu | Remove from folder | "Removed from {folderName}" | success |
| TreeEditorPage | Save tree | "Tree saved" | success |
| TreeEditorPage | Publish tree | "Tree published" | success |
| SessionDetailPage | Export session | "Session exported" | success |
| SettingsPage | Save preferences | "Settings saved" | success |
| AccountSettingsPage | Update account | "Account updated" | success |
2.1 Tree Library Actions (TreeLibraryPage.tsx):
- Remove confirmation dialog result logging
- Add
toast.success('Tree deleted')after successful delete - Replace inline error state with
toast.error(error)
2.2 Folder Management (FolderEditModal.tsx, FolderSidebar.tsx):
- Add success toast on folder create/update/delete
- Remove inline error messages (use toast.error instead)
- Keep loading state but add toast feedback on completion
2.3 Tree Editor (TreeEditorPage.tsx):
- Replace current error banner with toast notifications
- Add
toast.promise()for autosave operations:toast.promise(saveTree(), { loading: 'Saving tree...', success: 'Tree saved', error: 'Failed to save tree' }); - Remove
saveErrorstate and error banner div
2.4 Session Export (SessionDetailPage.tsx):
- Add toast on successful export:
toast.success('Session exported') - Add toast on copy to clipboard:
toast.success('Copied to clipboard') - Replace current inline copy feedback with toast
2.5 Settings Pages:
- Add success toasts on settings save
- Remove inline success messages if any exist
Phase 3: Standardize Error Handling
3.1 Global API Error Interceptor (client.ts):
apiClient.interceptors.response.use(
response => response,
error => {
// Show toast for non-form errors (4xx/5xx)
const message = error.response?.data?.detail || 'An error occurred';
// Don't toast validation errors (handled inline)
if (error.response?.status !== 422) {
toast.error(message);
}
return Promise.reject(error);
}
);
3.2 Remove redundant error handling:
- Keep form validation errors inline (modal errors)
- Use toast for unexpected/network errors
- Remove page-level error banner states where replaced by toast
Phase 4: Add Copy Feedback Consistency
4.1 Standardize clipboard operations: All "Copy to Clipboard" buttons should:
- Use
navigator.clipboard.writeText() - Show toast on success:
toast.success('Copied to clipboard') - Show toast on error:
toast.error('Failed to copy') - Remove button state toggle (icon + text change)
Components to update:
- SessionDetailPage.tsx (export copy button)
- ExportPreviewModal.tsx (copy button)
- AddToFolderMenu.tsx (if any copy functionality)
Critical Files to Modify
| File Path | Changes |
|---|---|
patherly/frontend/package.json |
Add sonner dependency |
patherly/frontend/src/main.tsx |
Add <Toaster> provider component |
patherly/frontend/src/lib/toast.ts |
NEW FILE - Toast utility wrapper |
patherly/frontend/src/store/themeStore.ts |
Sync theme changes to Toaster |
patherly/frontend/src/api/client.ts |
Add global error interceptor |
patherly/frontend/src/pages/TreeLibraryPage.tsx |
Add success/error toasts for delete |
patherly/frontend/src/pages/TreeEditorPage.tsx |
Replace error banner with toast.promise() |
patherly/frontend/src/pages/SessionDetailPage.tsx |
Add export/copy success toasts |
patherly/frontend/src/pages/SettingsPage.tsx |
Add settings save toast |
patherly/frontend/src/pages/AccountSettingsPage.tsx |
Add account update toast |
patherly/frontend/src/components/library/FolderEditModal.tsx |
Add folder save toast, remove inline errors |
patherly/frontend/src/components/library/FolderSidebar.tsx |
Add delete folder toast |
patherly/frontend/src/components/library/AddToFolderMenu.tsx |
Add add/remove from folder toasts |
patherly/frontend/src/components/session/ExportPreviewModal.tsx |
Standardize copy feedback |
Design Patterns and Best Practices
When to Use Each Toast Type
Success (green, 4s duration):
- Action completed successfully
- Examples: "Tree saved", "Folder deleted", "Exported"
- Only show for user-initiated actions, not automatic operations
Error (red, 6s duration):
- Action failed unexpectedly
- Examples: "Failed to save tree: Network error", "Could not delete folder"
- Include reason when available from API response
Info (blue, 4s duration):
- Neutral information
- Examples: "Session resumed", "Autosave enabled"
- Use sparingly - don't spam user with info toasts
Loading (infinite duration until dismissed):
- Long-running operations (>500ms expected)
- Examples: "Saving tree...", "Exporting session..."
- Use
toast.promise()to automatically transition to success/error
Promise Pattern Best Practice
For async operations with loading states:
// DON'T do this (manual dismiss logic):
const toastId = toast.loading('Saving...');
try {
await saveTree();
toast.success('Saved', { id: toastId });
} catch (error) {
toast.error('Failed', { id: toastId });
}
// DO this (automatic state transitions):
toast.promise(saveTree(), {
loading: 'Saving tree...',
success: 'Tree saved',
error: (err) => `Failed to save: ${err.message}`
});
Error Message Format
Always provide context:
- ❌ "Error" (too vague)
- ❌ "Failed" (what failed?)
- ✅ "Failed to delete tree: Permission denied"
- ✅ "Could not load folders: Network error"
When NOT to Use Toasts
Keep inline error messages for:
- Form validation errors: Show next to invalid field
- Modal-contained errors: Errors within a modal workflow
- Real-time feedback: Input validation as user types
- Critical blocking errors: Full-page error states
Verification Plan
Manual Testing Checklist
Tree Operations:
- Create new tree → "Tree saved" toast appears
- Edit existing tree → "Tree saved" toast appears
- Delete tree → Confirm dialog → "Tree deleted" toast appears
- Delete fails (network off) → "Failed to delete tree" toast with reason
- Autosave triggers → "Tree saved" toast (via promise pattern)
Folder Operations:
- Create folder → "Folder saved" toast appears
- Edit folder name → "Folder saved" toast appears
- Delete folder → "Folder deleted" toast appears
- Add tree to folder → "Added to [folder name]" toast appears
- Remove tree from folder → "Removed from [folder name]" toast appears
Session Operations:
- Export session (any format) → "Session exported" toast appears
- Copy to clipboard → "Copied to clipboard" toast appears
- Copy fails (permissions) → "Failed to copy" toast appears
- Download session → "Session exported" toast appears
Settings:
- Save user preferences → "Settings saved" toast appears
- Update account details → "Account updated" toast appears
Error Scenarios:
- Network offline → API errors show toast with meaningful message
- Permission denied → Toast shows "Permission denied" reason
- 500 server error → Toast shows generic "Server error" message
- 422 validation error → NO toast (inline validation only)
Dark Mode:
- Switch to dark mode → Toast background is dark themed
- Switch to light mode → Toast background is light themed
- Toast colors match theme (success green, error red, etc.)
Accessibility:
- Screen reader announces toast messages (ARIA live region)
- Toasts can be dismissed with keyboard (close button focusable)
- Toast position doesn't obscure critical UI (top-right safe zone)
- Color contrast meets WCAG AA standards
Stacking Behavior:
- Multiple toasts stack vertically without overlap
- Oldest toasts auto-dismiss while newer ones remain
- Maximum 3-4 toasts visible at once (sonner default)
Rollout Strategy
Phase 1: Core Infrastructure (Day 1, Morning)
- Install sonner package
- Create toast utility wrapper (
lib/toast.ts) - Add Toaster provider to
main.tsx - Sync with theme store
- Test basic toast functionality in dev
Phase 2: High-Impact Actions (Day 1, Afternoon)
- Tree save/delete operations
- Folder CRUD operations
- Session export/copy
- Remove old error banners
Phase 3: Error Standardization (Day 2, Morning)
- Add global API error interceptor
- Clean up redundant error handling
- Test error scenarios (network offline, permissions, etc.)
Phase 4: Refinement (Day 2, Afternoon)
- Verify all toast messages use consistent vocabulary
- Check dark mode appearance
- Test accessibility with screen reader
- Performance check (ensure no memory leaks from unmounted toasts)
- Update user documentation if needed
Future Enhancements (Out of Scope)
These can be added later if needed:
- Undo actions: Toast with "Undo" button for reversible operations
- Progress toasts: Show percentage for uploads/exports
- Grouped toasts: Collapse multiple similar actions ("3 trees deleted")
- Persistent notifications: Critical alerts that don't auto-dismiss
- Sound effects: Subtle audio feedback (accessibility feature)
- Action buttons in toasts: "View details" or "Retry" buttons
Risks and Mitigation
| Risk | Impact | Mitigation |
|---|---|---|
| Toast spam | Users annoyed by too many notifications | Only toast user-initiated actions, not automatic events |
| Theme sync issues | Toast theme doesn't match app theme | Subscribe to themeStore changes, update Toaster theme prop |
| Mobile viewport | Toasts obscure content on small screens | Use top-right position (least obtrusive), verify on mobile |
| Bundle size increase | +10KB to frontend bundle | Acceptable for significant UX improvement; sonner is already optimized |
| Breaking existing error handling | Some errors go unnoticed | Keep inline validation errors; only replace page-level banners |
Success Metrics
Qualitative:
- Users report feeling more confident about action completion
- Support tickets decrease for "Did my changes save?" questions
- User feedback mentions improved responsiveness
Quantitative:
- 0 console errors related to toast implementation
- Toast render time <50ms (measured in React DevTools)
- No accessibility violations in Lighthouse audit
- Frontend bundle size increase <15KB gzipped
References
- Sonner Documentation: https://sonner.emilkowal.ski/
- shadcn/ui Toast Component: https://ui.shadcn.com/docs/components/sonner
- UX Research on Feedback Timing: Nielsen Norman Group - "Response Times: The 3 Important Limits"
- Accessibility Guidelines: WCAG 2.1 Success Criterion 4.1.3 (Status Messages)