[PUI] Added Server Info Modal (#5810)

* updated typing to allow either link or action

* fixed typing

* made it possible to use an action instead of a link

* added ServerInfo Modal skeleton

* fixed anchor

* added content to ServerInfo

* Factored database lookup out

* Extended status API to CUI level

* extended ServerInfo to CUI level

* Made modal larger

* fixed default settings
This commit is contained in:
Matthias Mair 2023-10-29 23:56:07 +01:00 committed by GitHub
parent 7ff3f99dc9
commit 8aad3eeefa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 257 additions and 33 deletions

View File

@ -18,10 +18,11 @@ from InvenTree.permissions import RolePermission
from part.templatetags.inventree_extras import plugins_info
from plugin.serializers import MetadataSerializer
from .email import is_email_configured
from .mixins import RetrieveUpdateAPI
from .status import is_worker_running
from .version import (inventreeApiVersion, inventreeInstanceName,
inventreeVersion)
from .status import check_system_health, is_worker_running
from .version import (inventreeApiVersion, inventreeDatabase,
inventreeInstanceName, inventreeVersion)
from .views import AjaxView
@ -48,6 +49,11 @@ class InfoView(AjaxView):
'worker_pending_tasks': self.worker_pending_tasks(),
'plugins_enabled': settings.PLUGINS_ENABLED,
'active_plugins': plugins_info(),
'email_configured': is_email_configured(),
'debug_mode': settings.DEBUG,
'docker_mode': settings.DOCKER,
'system_health': check_system_health() if request.user.is_staff else None,
'database': inventreeDatabase()if request.user.is_staff else None
}
return JsonResponse(data)

View File

@ -2,11 +2,14 @@
# InvenTree API version
INVENTREE_API_VERSION = 142
INVENTREE_API_VERSION = 143
"""
Increment this API version number whenever there is a significant change to the API that any clients need to know about
v143 -> 2023-10-29: https://github.com/inventree/InvenTree/pull/5810
- Extends the status endpoint to include information about system status and health
v142 -> 2023-10-20: https://github.com/inventree/InvenTree/pull/5759
- Adds generic API endpoints for looking up status models

View File

@ -199,3 +199,9 @@ def inventreeTarget():
def inventreePlatform():
"""Returns the platform for the instance."""
return platform.platform(aliased=True)
def inventreeDatabase():
"""Return the InvenTree database backend e.g. 'postgresql'."""
db = settings.DATABASES['default']
return db.get('ENGINE', None).replace('django.db.backends.', '')

View File

@ -183,13 +183,7 @@ def plugins_info(*args, **kwargs):
@register.simple_tag()
def inventree_db_engine(*args, **kwargs):
"""Return the InvenTree database backend e.g. 'postgresql'."""
db = djangosettings.DATABASES['default']
engine = db.get('ENGINE', _('Unknown database'))
engine = engine.replace('django.db.backends.', '')
return engine
return version.inventreeDatabase() or _('Unknown database')
@register.simple_tag()

View File

@ -3,37 +3,81 @@ import { Anchor, Group, SimpleGrid, Text } from '@mantine/core';
import { DocTooltip } from './DocTooltip';
import { PlaceholderPill } from './Placeholder';
export interface DocumentationLinkItem {
interface DocumentationLinkBase {
id: string;
title: string | JSX.Element;
description: string | JSX.Element;
link: string;
placeholder?: boolean;
}
interface DocumentationLinkItemLink extends DocumentationLinkBase {
link: string;
action?: never;
}
interface DocumentationLinkItemAction extends DocumentationLinkBase {
link?: never;
action: () => void;
}
export type DocumentationLinkItem =
| DocumentationLinkItemLink
| DocumentationLinkItemAction;
export function DocumentationLinks({
links
}: {
links: DocumentationLinkItem[];
}) {
const DocumentationLinkRenderer = ({
link
}: {
link: DocumentationLinkItem;
}) => {
const content = (
<Text size="sm" fw={500}>
{link.title}
</Text>
);
const Linker = ({ children }: { children: any }) => {
if (link.link)
return (
<Anchor href={link.link} key={link.id}>
{children}
</Anchor>
);
if (link.action)
return (
<Anchor component="button" type="button" onClick={link.action}>
{children}
</Anchor>
);
console.log('Neither link nor action found for link:', link);
return children;
};
return (
<Linker>
{link.placeholder ? (
<Group>
{content}
<PlaceholderPill />
</Group>
) : (
content
)}
</Linker>
);
};
return (
<SimpleGrid cols={2} spacing={0}>
{links.map((link) => (
<DocTooltip key={link.id} text={link.description}>
<Anchor href={link.link} key={link.id}>
{link.placeholder ? (
<Group>
<Text size="sm" fw={500}>
{link.title}
</Text>
<PlaceholderPill />
</Group>
) : (
<Text size="sm" fw={500}>
{link.title}
</Text>
)}
</Anchor>
<DocumentationLinkRenderer link={link} />
</DocTooltip>
))}
</SimpleGrid>

View File

@ -0,0 +1,10 @@
import { Trans } from '@lingui/macro';
import { useUserState } from '../../states/UserState';
export const OnlyStaff = ({ children }: { children: any }) => {
const [user] = useUserState((state) => [state.user]);
if (user?.is_staff) return children;
return <Trans>This information is only available for staff users</Trans>;
};

View File

@ -0,0 +1,141 @@
import { Trans } from '@lingui/macro';
import { Badge, Button, Stack, Table, Title } from '@mantine/core';
import { ContextModalProps } from '@mantine/modals';
import { useServerApiState } from '../../states/ApiState';
import { OnlyStaff } from '../items/OnlyStaff';
export function ServerInfoModal({
context,
id
}: ContextModalProps<{ modalBody: string }>) {
const [server] = useServerApiState((state) => [state.server]);
return (
<Stack>
<Title order={5}>
<Trans>Server</Trans>
</Title>
<Table>
<tbody>
<tr>
<td>
<Trans>Instance Name</Trans>
</td>
<td>{server.instance}</td>
</tr>
<tr>
<td>
<Trans>Database</Trans>
</td>
<td>
<OnlyStaff>{server.database}</OnlyStaff>
</td>
</tr>
{server.debug_mode && (
<tr>
<td>
<Trans>Bebug Mode</Trans>
</td>
<td>
<Trans>Server is running in debug mode</Trans>
</td>
</tr>
)}
{server.docker_mode && (
<tr>
<td>
<Trans>Docker Mode</Trans>
</td>
<td>
<Trans>Server is deployed using docker</Trans>
</td>
</tr>
)}
<tr>
<td>
<Trans>Plugin Support</Trans>
</td>
<td>
<Badge color={server.plugins_enabled ? 'green' : 'red'}>
{server.plugins_enabled ? (
<Trans>Plugin support enabled</Trans>
) : (
<Trans>Plugin support disabled</Trans>
)}
</Badge>
</td>
</tr>
<tr>
<td>
<Trans>Server status</Trans>
</td>
<td>
<OnlyStaff>
<Badge color={server.system_health ? 'green' : 'yellow'}>
{server.system_health ? (
<Trans>Healthy</Trans>
) : (
<Trans>Issues detected</Trans>
)}
</Badge>
</OnlyStaff>
</td>
</tr>
{server.worker_running != true && (
<tr>
<td>
<Trans>Background Worker</Trans>
</td>
<td>
<Badge color="red">
<Trans>Background worker not running</Trans>
</Badge>
</td>
</tr>
)}
{server.email_configured != true && (
<tr>
<td>
<Trans>Email Settings</Trans>
</td>
<td>
<Badge color="red">
<Trans>Email settings not configured</Trans>
</Badge>
</td>
</tr>
)}
</tbody>
</Table>
<Title order={5}>
<Trans>Version</Trans>
</Title>
<Table>
<tbody>
<tr>
<td>
<Trans>Server Version</Trans>
</td>
<td>{server.version}</td>
</tr>
<tr>
<td>
<Trans>API Version</Trans>
</td>
<td>{server.apiVersion}</td>
</tr>
</tbody>
</Table>
<Button
color="red"
variant="outline"
onClick={() => {
context.closeModal(id);
}}
>
<Trans>Close modal</Trans>
</Button>
</Stack>
);
}

View File

@ -10,6 +10,7 @@ import { ModalsProvider } from '@mantine/modals';
import { Notifications } from '@mantine/notifications';
import { QrCodeModal } from '../components/modals/QrCodeModal';
import { ServerInfoModal } from '../components/modals/ServerInfoModal';
import { useLocalState } from '../states/LocalState';
export function ThemeContext({ children }: { children: JSX.Element }) {
@ -60,7 +61,7 @@ export function ThemeContext({ children }: { children: JSX.Element }) {
<Notifications />
<ModalsProvider
labels={{ confirm: t`Submit`, cancel: t`Cancel` }}
modals={{ qr: QrCodeModal }}
modals={{ qr: QrCodeModal, info: ServerInfoModal }}
>
{children}
</ModalsProvider>

View File

@ -8,7 +8,12 @@ export const emptyServerAPI = {
worker_running: null,
worker_pending_tasks: null,
plugins_enabled: null,
active_plugins: []
active_plugins: [],
email_configured: null,
debug_mode: null,
docker_mode: null,
database: null,
system_health: null
};
export interface SiteMarkProps {

View File

@ -1,4 +1,5 @@
import { Trans } from '@lingui/macro';
import { openContextModal } from '@mantine/modals';
import { DocumentationLinkItem } from '../components/items/DocumentationLinks';
import { IS_DEV_OR_DEMO } from '../main';
@ -69,18 +70,26 @@ export const navDocLinks: DocumentationLinkItem[] = [
}
];
function serverInfo() {
return openContextModal({
modal: 'info',
title: <Trans>System Information</Trans>,
size: 'xl',
innerProps: {}
});
}
// TODO @matmair: Add the following pages and adjust the links
export const aboutLinks: DocumentationLinkItem[] = [
{
id: 'instance',
title: <Trans>Instance</Trans>,
title: <Trans>System Information</Trans>,
description: <Trans>About this Inventree instance</Trans>,
link: '/instance',
placeholder: true
action: serverInfo
},
{
id: 'about',
title: <Trans>InvenTree</Trans>,
title: <Trans>About InvenTree</Trans>,
description: <Trans>About the InvenTree org</Trans>,
link: '/about',
placeholder: true

View File

@ -28,6 +28,11 @@ export interface ServerAPIProps {
worker_pending_tasks: null | number;
plugins_enabled: null | boolean;
active_plugins: PluginProps[];
email_configured: null | boolean;
debug_mode: null | boolean;
docker_mode: null | boolean;
database: null | string;
system_health: null | boolean;
}
// Type interface defining a single 'setting' object