diff --git a/src/frontend/src/components/buttons/ScanButton.tsx b/src/frontend/src/components/buttons/ScanButton.tsx
index 608663da62..68aa0d39db 100644
--- a/src/frontend/src/components/buttons/ScanButton.tsx
+++ b/src/frontend/src/components/buttons/ScanButton.tsx
@@ -1,5 +1,5 @@
import { t } from '@lingui/macro';
-import { ActionIcon } from '@mantine/core';
+import { ActionIcon, Tooltip } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { IconQrcode } from '@tabler/icons-react';
import BarcodeScanDialog from '../barcodes/BarcodeScanDialog';
@@ -12,13 +12,15 @@ export function ScanButton() {
return (
<>
-
-
-
+
+
+
+
+
>
);
diff --git a/src/frontend/src/components/buttons/SpotlightButton.tsx b/src/frontend/src/components/buttons/SpotlightButton.tsx
index 275650133b..93e706bb43 100644
--- a/src/frontend/src/components/buttons/SpotlightButton.tsx
+++ b/src/frontend/src/components/buttons/SpotlightButton.tsx
@@ -1,5 +1,5 @@
import { t } from '@lingui/macro';
-import { ActionIcon } from '@mantine/core';
+import { ActionIcon, Tooltip } from '@mantine/core';
import { IconCommand } from '@tabler/icons-react';
import { firstSpotlight } from '../nav/Layout';
@@ -9,13 +9,14 @@ import { firstSpotlight } from '../nav/Layout';
*/
export function SpotlightButton() {
return (
- firstSpotlight.open()}
- title={t`Open spotlight`}
- variant='transparent'
- aria-label='open-spotlight'
- >
-
-
+
+ firstSpotlight.open()}
+ variant='transparent'
+ aria-label='open-spotlight'
+ >
+
+
+
);
}
diff --git a/src/frontend/src/components/nav/Header.tsx b/src/frontend/src/components/nav/Header.tsx
index cfb830eb49..b4f3106a40 100644
--- a/src/frontend/src/components/nav/Header.tsx
+++ b/src/frontend/src/components/nav/Header.tsx
@@ -1,17 +1,25 @@
import {
ActionIcon,
+ Alert,
Container,
Group,
Indicator,
+ Menu,
Tabs,
- Text
+ Text,
+ Tooltip
} from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
-import { IconBell, IconSearch } from '@tabler/icons-react';
+import {
+ IconBell,
+ IconExclamationCircle,
+ 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';
+import { t } from '@lingui/macro';
import { api } from '../../App';
import { getNavTabs } from '../../defaults/links';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
@@ -32,7 +40,15 @@ 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
@@ -58,6 +74,49 @@ 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'],
@@ -125,13 +184,15 @@ export function Header() {
)}
-
-
-
+
+
+
+
+
{globalSettings.isSet('BARCODE_ENABLE') && }
-
-
-
+
+
+
+
+
+ {user.isStaff() && alerts.length > 0 && (
+
+ )}
@@ -179,8 +271,6 @@ function NavTabs() {
return;
}
- // TODO: Hide icons if user does not wish to display them!
-
_tabs.push(