From b48ceb00f2a221c565b66d7b6f9e9aa56448e3fb Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Thu, 3 Apr 2025 09:03:07 +0200 Subject: [PATCH] refactor(frontend): seperate Alerts into own component (#9442) * refactor(frontend): seperate Alerts into own component * refactor debug mode info * add error code for debug mode and render help links in alerts * add error message for background worker * add error code for server restart required * Add error code for missing email settings * fix various typings * add error code for missing migrations --- docs/docs/settings/error_codes.md | 34 +++++ docs/docs/start/intro.md | 4 +- .../InvenTree/InvenTree/helpers_email.py | 7 +- src/backend/InvenTree/InvenTree/status.py | 2 +- src/backend/InvenTree/InvenTree/test_tasks.py | 2 +- .../src/components/modals/ServerInfoModal.tsx | 13 +- src/frontend/src/components/nav/Alerts.tsx | 130 ++++++++++++++++++ src/frontend/src/components/nav/Header.tsx | 90 +----------- src/frontend/src/defaults/links.tsx | 3 +- .../AdminCenter/TaskManagementPanel.tsx | 2 + 10 files changed, 185 insertions(+), 102 deletions(-) create mode 100644 src/frontend/src/components/nav/Alerts.tsx diff --git a/docs/docs/settings/error_codes.md b/docs/docs/settings/error_codes.md index 3f1d5f61b8..183bd77af3 100644 --- a/docs/docs/settings/error_codes.md +++ b/docs/docs/settings/error_codes.md @@ -52,6 +52,40 @@ See [INVE-W1](#inve-w1) See [INVE-W1](#inve-w1) +#### INVE-W4 +**Server is running in debug mode - Backend** + +InvenTree is running in debug mode. This is **not** recommended for production use, as it exposes sensitive information and makes the server more vulnerable to attacks. Debug mode is not intended for production/exposed instances, **even for short duration**. + +It is recommended to run InvenTree in production mode for better security and performance. See [Debug Mode Information](../start/intro.md#debug-mode). + +#### INVE-W5 +**Background worker process not running - Backend** + +The background worker seems to not be running. This is detected by a heartbeat that runs all 5 minutes - this error triggers after not being run in the last 10 minutes. +Check if the process for background workers is running and reaching the database. Steps vary between deployment methods. +See [Background Worker Information](../start/processes.md#background-worker). + +#### INVE-W6 +**Server restart required - Backend** + +The server needs a restart due to changes in settings. Steps very between deployment methods. + + +#### INVE-W7 +**Email settings not configured - Backend** + +Not all required settings for sending emails are configured. Not having an email provider configured might lead to degraded processes as password reset, update notifications and user notifications can not work. Setting up email is recommended. +See [Email information](../start/config.md#email-settings). + + +#### INVE-W8 +**Database Migrations required - Backend** + +There are database migrations waiting to be applied. This might lead to integrity and availability issues. Applying migrations as soon as possible is recommended. + +Some deployment methods support [auto applying of updates](../start/config.md#auto-update). See also [Perform Database Migrations](../start/install.md#perform-database-migrations). +Steps very between deployment methods. ### INVE-I (InvenTree Information) Information — These are not errors but information messages. They might point out potential issues or just provide information. diff --git a/docs/docs/start/intro.md b/docs/docs/start/intro.md index ffc12be80f..9a5b6b8937 100644 --- a/docs/docs/start/intro.md +++ b/docs/docs/start/intro.md @@ -125,9 +125,9 @@ Running in DEBUG mode provides many handy development features, however it is st So, for a production setup, you should set `INVENTREE_DEBUG=false` in the [configuration options](./config.md). -### Potential Issues +### Turning Debug Mode off -Turning off DEBUG mode creates further work for the system administrator. In particular, when running in DEBUG mode, the InvenTree web server natively manages *static* and *media* files, which means that when DEBUG mode is *disabled*, the InvenTree server can no longer run as a monolithic process. +When running in DEBUG mode, the InvenTree web server natively manages *static* and *media* files, which means that when DEBUG mode is *disabled*, the proxy setup has to be configured to handle this. !!! info "Read More" Refer to the [proxy server documentation](./processes.md#proxy-server) for more details diff --git a/src/backend/InvenTree/InvenTree/helpers_email.py b/src/backend/InvenTree/InvenTree/helpers_email.py index 6430c60741..dcb059d54e 100644 --- a/src/backend/InvenTree/InvenTree/helpers_email.py +++ b/src/backend/InvenTree/InvenTree/helpers_email.py @@ -30,15 +30,15 @@ def is_email_configured(): # Display warning unless in test mode if not testing: # pragma: no cover - logger.debug('EMAIL_HOST is not configured') + logger.debug('INVE-W7: EMAIL_HOST is not configured') # Display warning unless in test mode if not settings.EMAIL_HOST_USER and not testing: # pragma: no cover - logger.debug('EMAIL_HOST_USER is not configured') + logger.debug('INVE-W7: EMAIL_HOST_USER is not configured') # Display warning unless in test mode if not settings.EMAIL_HOST_PASSWORD and testing: # pragma: no cover - logger.debug('EMAIL_HOST_PASSWORD is not configured') + logger.debug('INVE-W7: EMAIL_HOST_PASSWORD is not configured') # Email sender must be configured if not settings.DEFAULT_FROM_EMAIL: @@ -64,6 +64,7 @@ def send_email(subject, body, recipients, from_email=None, html_message=None): if not is_email_configured() and not settings.TESTING: # Email is not configured / enabled + logger.info('INVE-W7: Email will not be send, no mail server configured') return # If a *from_email* is not specified, ensure that the default is set diff --git a/src/backend/InvenTree/InvenTree/status.py b/src/backend/InvenTree/InvenTree/status.py index b143ac0ee8..72fcca973a 100644 --- a/src/backend/InvenTree/InvenTree/status.py +++ b/src/backend/InvenTree/InvenTree/status.py @@ -67,7 +67,7 @@ def check_system_health(**kwargs): if not InvenTree.helpers_email.is_email_configured(): # pragma: no cover result = False if not settings.DEBUG: - logger.warning('Email backend not configured') + logger.warning('INVE-W7: Email backend not configured') if not result: # pragma: no cover if not settings.DEBUG: diff --git a/src/backend/InvenTree/InvenTree/test_tasks.py b/src/backend/InvenTree/InvenTree/test_tasks.py index 803a2832e5..784157db01 100644 --- a/src/backend/InvenTree/InvenTree/test_tasks.py +++ b/src/backend/InvenTree/InvenTree/test_tasks.py @@ -87,7 +87,7 @@ class InvenTreeTaskTests(TestCase): ): InvenTree.tasks.offload_task('InvenTree.test_tasks.doesnotexist') - def test_task_hearbeat(self): + def test_task_heartbeat(self): """Test the task heartbeat.""" InvenTree.tasks.offload_task(InvenTree.tasks.heartbeat) diff --git a/src/frontend/src/components/modals/ServerInfoModal.tsx b/src/frontend/src/components/modals/ServerInfoModal.tsx index 5024507d3e..b58b0c3fdd 100644 --- a/src/frontend/src/components/modals/ServerInfoModal.tsx +++ b/src/frontend/src/components/modals/ServerInfoModal.tsx @@ -52,6 +52,7 @@ export function ServerInfoModal({ Debug Mode + INVE-W4 Server is running in debug mode @@ -102,21 +103,19 @@ export function ServerInfoModal({ Background Worker - - Background worker not running - + INVE-W5 + The Background worker process is not running. )} - {server?.email_configured == false && ( + {!server?.email_configured && ( Email Settings - - Email settings not configured - + INVE-W7 + Email settings not configured. )} diff --git a/src/frontend/src/components/nav/Alerts.tsx b/src/frontend/src/components/nav/Alerts.tsx new file mode 100644 index 0000000000..046e8b41db --- /dev/null +++ b/src/frontend/src/components/nav/Alerts.tsx @@ -0,0 +1,130 @@ +import { ActionIcon, Alert, Menu, Tooltip } from '@mantine/core'; +import { IconExclamationCircle } from '@tabler/icons-react'; +import { useMemo, useState } from 'react'; + +import { t } from '@lingui/core/macro'; +import { docLinks } from '../../defaults/links'; +import { useServerApiState } from '../../states/ApiState'; +import { useGlobalSettingsState } from '../../states/SettingsState'; +import { useUserState } from '../../states/UserState'; + +interface AlertInfo { + key: string; + title: string; + code?: string; + message: string; +} + +/** + * The `Alerts` component displays a menu of alerts for staff users based on the server state + * and global settings. Alerts are shown as a dropdown menu with actionable items that can be dismissed. + * + * Dismissed alerts are filtered out and will not reappear in the current session. + * + * @returns A dropdown menu of alerts for staff users or `null` if there are no alerts or the user is not a staff member. + */ +export function Alerts() { + const user = useUserState(); + const [server] = useServerApiState((state) => [state.server]); + const globalSettings = useGlobalSettingsState(); + + const [dismissed, setDismissed] = useState([]); + + const alerts: AlertInfo[] = useMemo(() => { + const _alerts: AlertInfo[] = []; + + if (server?.debug_mode) { + _alerts.push({ + key: 'debug', + title: t`Debug Mode`, + code: 'INVE-W4', + message: t`The server is running in debug mode.` + }); + } + + if (!server?.worker_running) { + _alerts.push({ + key: 'worker', + title: t`Background Worker`, + code: 'INVE-W5', + message: t`The background worker process is not running.` + }); + } + + if (!server?.email_configured) { + _alerts.push({ + key: 'email', + title: t`Email settings`, + code: 'INVE-W7', + message: t`Email settings not configured.` + }); + } + + if (globalSettings.isSet('SERVER_RESTART_REQUIRED')) { + _alerts.push({ + key: 'restart', + title: t`Server Restart`, + code: 'INVE-W6', + message: t`The server requires a restart to apply changes.` + }); + } + + const n_migrations = + Number.parseInt(globalSettings.getSetting('_PENDING_MIGRATIONS')) ?? 0; + + if (n_migrations > 0) { + _alerts.push({ + key: 'migrations', + title: t`Database Migrations`, + code: 'INVE-W8', + message: t`There are pending database migrations.` + }); + } + + return _alerts.filter((alert) => !dismissed.includes(alert.key)); + }, [server, dismissed, globalSettings]); + + if (user.isStaff() && alerts.length > 0) + return ( + + + + + + + + + + {alerts.map((alert) => ( + + setDismissed([...dismissed, alert.key])} + > + {alert.message} + {alert.code && errorCodeLink(alert.code)} + + + ))} + + + ); + return null; +} +export function errorCodeLink(code: string) { + return ( + + {t`Learn more about ${code}`} + + ); +} diff --git a/src/frontend/src/components/nav/Header.tsx b/src/frontend/src/components/nav/Header.tsx index 0a8d73662f..620bda97ba 100644 --- a/src/frontend/src/components/nav/Header.tsx +++ b/src/frontend/src/components/nav/Header.tsx @@ -1,20 +1,14 @@ import { ActionIcon, - Alert, Container, Group, Indicator, - Menu, Tabs, Text, Tooltip } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; -import { - IconBell, - IconExclamationCircle, - IconSearch -} from '@tabler/icons-react'; +import { IconBell, IconSearch } from '@tabler/icons-react'; import { useQuery } from '@tanstack/react-query'; import { type ReactNode, useEffect, useMemo, useState } from 'react'; import { useMatch, useNavigate } from 'react-router-dom'; @@ -34,21 +28,14 @@ import { import { useUserState } from '../../states/UserState'; import { ScanButton } from '../buttons/ScanButton'; import { SpotlightButton } from '../buttons/SpotlightButton'; +import { Alerts } from './Alerts'; import { MainMenu } from './MainMenu'; import { NavHoverMenu } from './NavHoverMenu'; import { NavigationDrawer } from './NavigationDrawer'; import { NotificationDrawer } from './NotificationDrawer'; import { SearchDrawer } from './SearchDrawer'; -interface AlertInfo { - key: string; - title: string; - message: string; -} - export function Header() { - const user = useUserState(); - const [setNavigationOpen, navigationOpen] = useLocalState((state) => [ state.setNavigationOpen, state.navigationOpen @@ -74,49 +61,6 @@ export function Header() { return server.customize?.navbar_message; }, [server.customize]); - const [dismissed, setDismissed] = useState([]); - - const alerts: AlertInfo[] = useMemo(() => { - const _alerts: AlertInfo[] = []; - - if (server?.debug_mode) { - _alerts.push({ - key: 'debug', - title: t`Debug Mode`, - message: t`The server is running in debug mode.` - }); - } - - if (server?.worker_running == false) { - _alerts.push({ - key: 'worker', - title: t`Background Worker`, - message: t`The background worker process is not running.` - }); - } - - if (globalSettings.isSet('SERVER_RESTART_REQUIRED')) { - _alerts.push({ - key: 'restart', - title: t`Server Restart`, - message: t`The server requires a restart to apply changes.` - }); - } - - const n_migrations = - Number.parseInt(globalSettings.getSetting('_PENDING_MIGRATIONS')) ?? 0; - - if (n_migrations > 0) { - _alerts.push({ - key: 'migrations', - title: t`Database Migrations`, - message: t`There are pending database migrations.` - }); - } - - return _alerts.filter((alert) => !dismissed.includes(alert.key)); - }, [server, dismissed, globalSettings]); - // Fetch number of notifications for the current user const notifications = useQuery({ queryKey: ['notification-count'], @@ -213,35 +157,7 @@ export function Header() { - {user.isStaff() && alerts.length > 0 && ( - - - - - - - - - - {alerts.map((alert) => ( - - setDismissed([...dismissed, alert.key])} - > - {alert.message} - - - ))} - - - )} + diff --git a/src/frontend/src/defaults/links.tsx b/src/frontend/src/defaults/links.tsx index a60b7b6eba..b913dcac37 100644 --- a/src/frontend/src/defaults/links.tsx +++ b/src/frontend/src/defaults/links.tsx @@ -75,7 +75,8 @@ export const docLinks = { api: 'https://docs.inventree.org/en/latest/api/api/', developer: 'https://docs.inventree.org/en/latest/develop/contributing/', faq: 'https://docs.inventree.org/en/latest/faq/', - github: 'https://github.com/inventree/inventree' + github: 'https://github.com/inventree/inventree', + errorcodes: 'https://docs.inventree.org/en/latest/settings/error_codes/' }; export function DocumentationLinks(): MenuLinkItem[] { diff --git a/src/frontend/src/pages/Index/Settings/AdminCenter/TaskManagementPanel.tsx b/src/frontend/src/pages/Index/Settings/AdminCenter/TaskManagementPanel.tsx index ebd571990c..5d3e8f8f92 100644 --- a/src/frontend/src/pages/Index/Settings/AdminCenter/TaskManagementPanel.tsx +++ b/src/frontend/src/pages/Index/Settings/AdminCenter/TaskManagementPanel.tsx @@ -3,6 +3,7 @@ import { Accordion, Alert, Divider, Stack, Text } from '@mantine/core'; import { lazy } from 'react'; import { StylishText } from '../../../../components/items/StylishText'; +import { errorCodeLink } from '../../../../components/nav/Alerts'; import { FactCollection } from '../../../../components/settings/FactCollection'; import { ApiEndpoints } from '../../../../enums/ApiEndpoints'; import { Loadable } from '../../../../functions/loading'; @@ -28,6 +29,7 @@ export default function TaskManagementPanel() { {taskInfo?.is_running == false && ( {t`The background task manager service is not running. Contact your system administrator.`} + {errorCodeLink('INVE-W5')} )}