Просмотр исходного кода

fix(ui): restore missing per-user Notifications nav item (#1901)

The sidebar-ordering refactor in #1673 accidentally dropped the
`notifications` entry from `defaultNavItems` and its
`notifications:user_email` permission mapping, but kept the advanced-auth
visibility gate that references that id. With no nav entry the id never
enters the render set, so the /notifications page (route, page, and API
all intact) became reachable only by typing the URL — users could no
longer opt in/out of their own print email notifications from the menu.

Restore both the defaultNavItems entry and the permission gate, matching
the permission the user-email-preferences API actually requires
(notifications:user_email, held by both default groups). Add comments so
the entry isn't dropped again in a future sidebar refactor.
maziggy 2 месяцев назад
Родитель
Сommit
a82eeff483

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
CHANGELOG.md


+ 3 - 2
frontend/src/__tests__/pages/SettingsPage.test.tsx

@@ -303,7 +303,7 @@ describe('SettingsPage', () => {
 
       expect(localStorage.setItem).toHaveBeenCalledWith(
         SIDEBAR_ORDER_KEY,
-        JSON.stringify(['ext-7', 'printers', 'inventory', 'archives', 'queue', 'projects', 'files', 'makerworld', 'profiles', 'maintenance', 'stats', 'settings']),
+        JSON.stringify(['ext-7', 'printers', 'inventory', 'archives', 'queue', 'projects', 'files', 'makerworld', 'profiles', 'maintenance', 'stats', 'notifications', 'settings']),
       );
     });
 
@@ -345,7 +345,7 @@ describe('SettingsPage', () => {
       expect(localStorage.setItem).toHaveBeenCalledWith(SIDEBAR_HIDDEN_SYSTEM_ITEMS_KEY, JSON.stringify([]));
       expect(localStorage.setItem).toHaveBeenCalledWith(
         SIDEBAR_ORDER_KEY,
-        JSON.stringify(['printers', 'inventory', 'archives', 'queue', 'projects', 'files', 'makerworld', 'profiles', 'maintenance', 'stats', 'settings', 'ext-7']),
+        JSON.stringify(['printers', 'inventory', 'archives', 'queue', 'projects', 'files', 'makerworld', 'profiles', 'maintenance', 'stats', 'notifications', 'settings', 'ext-7']),
       );
 
       const settingsRow = screen.getAllByText('Settings')
@@ -416,6 +416,7 @@ describe('SettingsPage', () => {
           'profiles',
           'maintenance',
           'stats',
+          'notifications',
           'settings',
         ],
         hiddenSystemItemIds: ['stats'],

+ 11 - 1
frontend/src/components/Layout.tsx

@@ -1,6 +1,6 @@
 import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
 import { NavLink, Outlet, useNavigate, useLocation } from 'react-router-dom';
-import { Printer, Archive, ListOrdered, BarChart3, Cloud, Settings, Sun, Moon, Monitor, ChevronLeft, ChevronRight, Keyboard, Github, ArrowUpCircle, Wrench, FolderKanban, FolderOpen, X, Menu, Info, Plug, Bug, LogOut, Key, Loader2, Disc3, ShieldAlert, Globe, type LucideIcon } from 'lucide-react';
+import { Printer, Archive, ListOrdered, BarChart3, Cloud, Settings, Sun, Moon, Monitor, ChevronLeft, ChevronRight, Keyboard, Github, ArrowUpCircle, Wrench, FolderKanban, FolderOpen, X, Menu, Info, Plug, Bug, LogOut, Key, Loader2, Disc3, ShieldAlert, Globe, Bell, type LucideIcon } from 'lucide-react';
 import { useTranslation } from 'react-i18next';
 import { useTheme } from '../contexts/ThemeContext';
 import { KeyboardShortcutsModal } from './KeyboardShortcutsModal';
@@ -48,6 +48,11 @@ export const defaultNavItems: NavItem[] = [
   { id: 'profiles', to: '/profiles', icon: Cloud, labelKey: 'nav.profiles' },
   { id: 'maintenance', to: '/maintenance', icon: Wrench, labelKey: 'nav.maintenance' },
   { id: 'stats', to: '/stats', icon: BarChart3, labelKey: 'nav.stats' },
+  // User-account feature: gated in isHidden() on advanced auth + user_notifications
+  // + the notifications:user_email permission. Kept adjacent to Settings
+  // intentionally. Do not drop this entry — without it the /notifications page
+  // is orphaned (route + page still exist but no nav link) (#1901).
+  { id: 'notifications', to: '/notifications', icon: Bell, labelKey: 'nav.notifications' },
   { id: 'settings', to: '/settings', icon: Settings, labelKey: 'nav.settings' },
 ];
 
@@ -296,6 +301,11 @@ export function Layout() {
       files: ['library:read', 'library:read_own', 'library:read_all'],
       makerworld: 'makerworld:view',
       settings: 'settings:read',
+      // The user-email-preferences API requires notifications:user_email, so
+      // gate the nav item on the same permission (both default groups —
+      // Administrators and Operators — hold it). The advanced-auth /
+      // user_notifications enablement gate is applied separately below.
+      notifications: 'notifications:user_email',
     };
 
     const isHidden = (id: string) => {

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
static/assets/index-DqJZ0C8s.js


+ 1 - 1
static/index.html

@@ -26,7 +26,7 @@
 
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-Bwc9H1Fy.js"></script>
+    <script type="module" crossorigin src="/assets/index-DqJZ0C8s.js"></script>
     <link rel="stylesheet" crossorigin href="/assets/index-BxVhuRti.css">
   </head>
   <body>

Некоторые файлы не были показаны из-за большого количества измененных файлов