mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 03:26:45 +00:00
[UI] Alerts (#9365)
* remove TODO (now implemented) * Add Mantine tooltips * Add "alerts" to header * Add more alert types
This commit is contained in:
parent
8997f193c9
commit
136e179cc4
@ -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 (
|
||||
<>
|
||||
<ActionIcon
|
||||
onClick={open}
|
||||
variant='transparent'
|
||||
title={t`Open Barcode Scanner`}
|
||||
>
|
||||
<IconQrcode />
|
||||
</ActionIcon>
|
||||
<Tooltip position='bottom-end' label={t`Scan Barcode`}>
|
||||
<ActionIcon
|
||||
onClick={open}
|
||||
variant='transparent'
|
||||
title={t`Open Barcode Scanner`}
|
||||
>
|
||||
<IconQrcode />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<BarcodeScanDialog opened={opened} onClose={close} />
|
||||
</>
|
||||
);
|
||||
|
@ -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 (
|
||||
<ActionIcon
|
||||
onClick={() => firstSpotlight.open()}
|
||||
title={t`Open spotlight`}
|
||||
variant='transparent'
|
||||
aria-label='open-spotlight'
|
||||
>
|
||||
<IconCommand />
|
||||
</ActionIcon>
|
||||
<Tooltip position='bottom-end' label={t`Open spotlight`}>
|
||||
<ActionIcon
|
||||
onClick={() => firstSpotlight.open()}
|
||||
variant='transparent'
|
||||
aria-label='open-spotlight'
|
||||
>
|
||||
<IconCommand />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
@ -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<string[]>([]);
|
||||
|
||||
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() {
|
||||
</Text>
|
||||
)}
|
||||
<Group>
|
||||
<ActionIcon
|
||||
onClick={openSearchDrawer}
|
||||
variant='transparent'
|
||||
aria-label='open-search'
|
||||
>
|
||||
<IconSearch />
|
||||
</ActionIcon>
|
||||
<Tooltip position='bottom-end' label={t`Search`}>
|
||||
<ActionIcon
|
||||
onClick={openSearchDrawer}
|
||||
variant='transparent'
|
||||
aria-label='open-search'
|
||||
>
|
||||
<IconSearch />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<SpotlightButton />
|
||||
{globalSettings.isSet('BARCODE_ENABLE') && <ScanButton />}
|
||||
<Indicator
|
||||
@ -142,14 +203,45 @@ export function Header() {
|
||||
disabled={notificationCount <= 0}
|
||||
inline
|
||||
>
|
||||
<ActionIcon
|
||||
onClick={openNotificationDrawer}
|
||||
variant='transparent'
|
||||
aria-label='open-notifications'
|
||||
>
|
||||
<IconBell />
|
||||
</ActionIcon>
|
||||
<Tooltip position='bottom-end' label={t`Notifications`}>
|
||||
<ActionIcon
|
||||
onClick={openNotificationDrawer}
|
||||
variant='transparent'
|
||||
aria-label='open-notifications'
|
||||
>
|
||||
<IconBell />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Indicator>
|
||||
{user.isStaff() && alerts.length > 0 && (
|
||||
<Menu withinPortal={true} position='bottom-end'>
|
||||
<Menu.Target>
|
||||
<Tooltip position='bottom-end' label={t`Alerts`}>
|
||||
<ActionIcon
|
||||
variant='transparent'
|
||||
aria-label='open-alerts'
|
||||
color='red'
|
||||
>
|
||||
<IconExclamationCircle />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown>
|
||||
{alerts.map((alert) => (
|
||||
<Menu.Item key={`alert-item-${alert.key}`}>
|
||||
<Alert
|
||||
withCloseButton
|
||||
color='red'
|
||||
title={alert.title}
|
||||
onClose={() => setDismissed([...dismissed, alert.key])}
|
||||
>
|
||||
{alert.message}
|
||||
</Alert>
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
)}
|
||||
<MainMenu />
|
||||
</Group>
|
||||
</Group>
|
||||
@ -179,8 +271,6 @@ function NavTabs() {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Hide icons if user does not wish to display them!
|
||||
|
||||
_tabs.push(
|
||||
<Tabs.Tab
|
||||
value={tab.name}
|
||||
|
Loading…
x
Reference in New Issue
Block a user