mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
[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:
parent
7ff3f99dc9
commit
8aad3eeefa
@ -18,10 +18,11 @@ from InvenTree.permissions import RolePermission
|
|||||||
from part.templatetags.inventree_extras import plugins_info
|
from part.templatetags.inventree_extras import plugins_info
|
||||||
from plugin.serializers import MetadataSerializer
|
from plugin.serializers import MetadataSerializer
|
||||||
|
|
||||||
|
from .email import is_email_configured
|
||||||
from .mixins import RetrieveUpdateAPI
|
from .mixins import RetrieveUpdateAPI
|
||||||
from .status import is_worker_running
|
from .status import check_system_health, is_worker_running
|
||||||
from .version import (inventreeApiVersion, inventreeInstanceName,
|
from .version import (inventreeApiVersion, inventreeDatabase,
|
||||||
inventreeVersion)
|
inventreeInstanceName, inventreeVersion)
|
||||||
from .views import AjaxView
|
from .views import AjaxView
|
||||||
|
|
||||||
|
|
||||||
@ -48,6 +49,11 @@ class InfoView(AjaxView):
|
|||||||
'worker_pending_tasks': self.worker_pending_tasks(),
|
'worker_pending_tasks': self.worker_pending_tasks(),
|
||||||
'plugins_enabled': settings.PLUGINS_ENABLED,
|
'plugins_enabled': settings.PLUGINS_ENABLED,
|
||||||
'active_plugins': plugins_info(),
|
'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)
|
return JsonResponse(data)
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
|
|
||||||
# InvenTree API version
|
# 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
|
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
|
v142 -> 2023-10-20: https://github.com/inventree/InvenTree/pull/5759
|
||||||
- Adds generic API endpoints for looking up status models
|
- Adds generic API endpoints for looking up status models
|
||||||
|
|
||||||
|
@ -199,3 +199,9 @@ def inventreeTarget():
|
|||||||
def inventreePlatform():
|
def inventreePlatform():
|
||||||
"""Returns the platform for the instance."""
|
"""Returns the platform for the instance."""
|
||||||
return platform.platform(aliased=True)
|
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.', '')
|
||||||
|
@ -183,13 +183,7 @@ def plugins_info(*args, **kwargs):
|
|||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def inventree_db_engine(*args, **kwargs):
|
def inventree_db_engine(*args, **kwargs):
|
||||||
"""Return the InvenTree database backend e.g. 'postgresql'."""
|
"""Return the InvenTree database backend e.g. 'postgresql'."""
|
||||||
db = djangosettings.DATABASES['default']
|
return version.inventreeDatabase() or _('Unknown database')
|
||||||
|
|
||||||
engine = db.get('ENGINE', _('Unknown database'))
|
|
||||||
|
|
||||||
engine = engine.replace('django.db.backends.', '')
|
|
||||||
|
|
||||||
return engine
|
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
|
@ -3,37 +3,81 @@ import { Anchor, Group, SimpleGrid, Text } from '@mantine/core';
|
|||||||
import { DocTooltip } from './DocTooltip';
|
import { DocTooltip } from './DocTooltip';
|
||||||
import { PlaceholderPill } from './Placeholder';
|
import { PlaceholderPill } from './Placeholder';
|
||||||
|
|
||||||
export interface DocumentationLinkItem {
|
interface DocumentationLinkBase {
|
||||||
id: string;
|
id: string;
|
||||||
title: string | JSX.Element;
|
title: string | JSX.Element;
|
||||||
description: string | JSX.Element;
|
description: string | JSX.Element;
|
||||||
link: string;
|
|
||||||
placeholder?: boolean;
|
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({
|
export function DocumentationLinks({
|
||||||
links
|
links
|
||||||
}: {
|
}: {
|
||||||
links: DocumentationLinkItem[];
|
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 (
|
return (
|
||||||
<SimpleGrid cols={2} spacing={0}>
|
<SimpleGrid cols={2} spacing={0}>
|
||||||
{links.map((link) => (
|
{links.map((link) => (
|
||||||
<DocTooltip key={link.id} text={link.description}>
|
<DocTooltip key={link.id} text={link.description}>
|
||||||
<Anchor href={link.link} key={link.id}>
|
<DocumentationLinkRenderer link={link} />
|
||||||
{link.placeholder ? (
|
|
||||||
<Group>
|
|
||||||
<Text size="sm" fw={500}>
|
|
||||||
{link.title}
|
|
||||||
</Text>
|
|
||||||
<PlaceholderPill />
|
|
||||||
</Group>
|
|
||||||
) : (
|
|
||||||
<Text size="sm" fw={500}>
|
|
||||||
{link.title}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Anchor>
|
|
||||||
</DocTooltip>
|
</DocTooltip>
|
||||||
))}
|
))}
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
|
10
src/frontend/src/components/items/OnlyStaff.tsx
Normal file
10
src/frontend/src/components/items/OnlyStaff.tsx
Normal 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>;
|
||||||
|
};
|
141
src/frontend/src/components/modals/ServerInfoModal.tsx
Normal file
141
src/frontend/src/components/modals/ServerInfoModal.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
@ -10,6 +10,7 @@ import { ModalsProvider } from '@mantine/modals';
|
|||||||
import { Notifications } from '@mantine/notifications';
|
import { Notifications } from '@mantine/notifications';
|
||||||
|
|
||||||
import { QrCodeModal } from '../components/modals/QrCodeModal';
|
import { QrCodeModal } from '../components/modals/QrCodeModal';
|
||||||
|
import { ServerInfoModal } from '../components/modals/ServerInfoModal';
|
||||||
import { useLocalState } from '../states/LocalState';
|
import { useLocalState } from '../states/LocalState';
|
||||||
|
|
||||||
export function ThemeContext({ children }: { children: JSX.Element }) {
|
export function ThemeContext({ children }: { children: JSX.Element }) {
|
||||||
@ -60,7 +61,7 @@ export function ThemeContext({ children }: { children: JSX.Element }) {
|
|||||||
<Notifications />
|
<Notifications />
|
||||||
<ModalsProvider
|
<ModalsProvider
|
||||||
labels={{ confirm: t`Submit`, cancel: t`Cancel` }}
|
labels={{ confirm: t`Submit`, cancel: t`Cancel` }}
|
||||||
modals={{ qr: QrCodeModal }}
|
modals={{ qr: QrCodeModal, info: ServerInfoModal }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</ModalsProvider>
|
</ModalsProvider>
|
||||||
|
@ -8,7 +8,12 @@ export const emptyServerAPI = {
|
|||||||
worker_running: null,
|
worker_running: null,
|
||||||
worker_pending_tasks: null,
|
worker_pending_tasks: null,
|
||||||
plugins_enabled: 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 {
|
export interface SiteMarkProps {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
|
import { openContextModal } from '@mantine/modals';
|
||||||
|
|
||||||
import { DocumentationLinkItem } from '../components/items/DocumentationLinks';
|
import { DocumentationLinkItem } from '../components/items/DocumentationLinks';
|
||||||
import { IS_DEV_OR_DEMO } from '../main';
|
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
|
// TODO @matmair: Add the following pages and adjust the links
|
||||||
export const aboutLinks: DocumentationLinkItem[] = [
|
export const aboutLinks: DocumentationLinkItem[] = [
|
||||||
{
|
{
|
||||||
id: 'instance',
|
id: 'instance',
|
||||||
title: <Trans>Instance</Trans>,
|
title: <Trans>System Information</Trans>,
|
||||||
description: <Trans>About this Inventree instance</Trans>,
|
description: <Trans>About this Inventree instance</Trans>,
|
||||||
link: '/instance',
|
action: serverInfo
|
||||||
placeholder: true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'about',
|
id: 'about',
|
||||||
title: <Trans>InvenTree</Trans>,
|
title: <Trans>About InvenTree</Trans>,
|
||||||
description: <Trans>About the InvenTree org</Trans>,
|
description: <Trans>About the InvenTree org</Trans>,
|
||||||
link: '/about',
|
link: '/about',
|
||||||
placeholder: true
|
placeholder: true
|
||||||
|
@ -28,6 +28,11 @@ export interface ServerAPIProps {
|
|||||||
worker_pending_tasks: null | number;
|
worker_pending_tasks: null | number;
|
||||||
plugins_enabled: null | boolean;
|
plugins_enabled: null | boolean;
|
||||||
active_plugins: PluginProps[];
|
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
|
// Type interface defining a single 'setting' object
|
||||||
|
Loading…
Reference in New Issue
Block a user