2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-05-01 13:06:45 +00:00

Added base for admin center (#5862)

This commit is contained in:
Matthias Mair 2023-11-04 22:33:46 +01:00 committed by GitHub
parent fb7020a85a
commit 93f642c790
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 142 additions and 18 deletions

View File

@ -5,6 +5,7 @@ import {
IconLogout, IconLogout,
IconPlugConnected, IconPlugConnected,
IconSettings, IconSettings,
IconUserBolt,
IconUserCog IconUserCog
} from '@tabler/icons-react'; } from '@tabler/icons-react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@ -34,6 +35,15 @@ export function MainMenu() {
</UnstyledButton> </UnstyledButton>
</Menu.Target> </Menu.Target>
<Menu.Dropdown> <Menu.Dropdown>
{userState.user?.is_staff && (
<Menu.Item
icon={<IconUserBolt />}
component={Link}
to="/settings/admin"
>
<Trans>Admin Center</Trans>
</Menu.Item>
)}
<Menu.Label> <Menu.Label>
<Trans>Settings</Trans> <Trans>Settings</Trans>
</Menu.Label> </Menu.Label>

View File

@ -35,18 +35,21 @@ export type PanelType = {
* @param activePanel : string - The name of the currently active panel (defaults to the first panel) * @param activePanel : string - The name of the currently active panel (defaults to the first panel)
* @param setActivePanel : (panel: string) => void - Function to set the active panel * @param setActivePanel : (panel: string) => void - Function to set the active panel
* @param onPanelChange : (panel: string) => void - Callback when the active panel changes * @param onPanelChange : (panel: string) => void - Callback when the active panel changes
* @param collabsible : boolean - If true, the panel group can be collapsed (defaults to true)
* @returns * @returns
*/ */
export function PanelGroup({ export function PanelGroup({
pageKey, pageKey,
panels, panels,
selectedPanel, selectedPanel,
onPanelChange onPanelChange,
collabsible = true
}: { }: {
pageKey: string; pageKey: string;
panels: PanelType[]; panels: PanelType[];
selectedPanel?: string; selectedPanel?: string;
onPanelChange?: (panel: string) => void; onPanelChange?: (panel: string) => void;
collabsible?: boolean;
}): ReactNode { }): ReactNode {
const [activePanel, setActivePanel] = useLocalStorage<string>({ const [activePanel, setActivePanel] = useLocalStorage<string>({
key: `panel-group-active-panel-${pageKey}`, key: `panel-group-active-panel-${pageKey}`,
@ -105,18 +108,20 @@ export function PanelGroup({
</Tooltip> </Tooltip>
) )
)} )}
<ActionIcon {collabsible && (
style={{ <ActionIcon
paddingLeft: '10px' style={{
}} paddingLeft: '10px'
onClick={() => setExpanded(!expanded)} }}
> onClick={() => setExpanded(!expanded)}
{expanded ? ( >
<IconLayoutSidebarLeftCollapse opacity={0.5} /> {expanded ? (
) : ( <IconLayoutSidebarLeftCollapse opacity={0.5} />
<IconLayoutSidebarRightCollapse opacity={0.5} /> ) : (
)} <IconLayoutSidebarRightCollapse opacity={0.5} />
</ActionIcon> )}
</ActionIcon>
)}
</Tabs.List> </Tabs.List>
{panels.map( {panels.map(
(panel, idx) => (panel, idx) =>

View File

@ -14,12 +14,12 @@ export function SettingsHeader({
switch_text, switch_text,
switch_link switch_link
}: { }: {
title: string; title: string | ReactNode;
shorthand?: string; shorthand?: string;
subtitle: string | ReactNode; subtitle: string | ReactNode;
switch_condition?: boolean; switch_condition?: boolean;
switch_text: string | ReactNode; switch_text?: string | ReactNode;
switch_link: string; switch_link?: string;
}) { }) {
return ( return (
<Stack spacing="0" ml={'sm'}> <Stack spacing="0" ml={'sm'}>
@ -29,7 +29,7 @@ export function SettingsHeader({
</Group> </Group>
<Group> <Group>
<Text c="dimmed">{subtitle}</Text> <Text c="dimmed">{subtitle}</Text>
{switch_condition && ( {switch_text && switch_link && switch_condition && (
<Anchor component={Link} to={switch_link}> <Anchor component={Link} to={switch_link}>
<IconSwitch size={14} /> <IconSwitch size={14} />
{switch_text} {switch_text}

View File

@ -0,0 +1,105 @@
import { Trans, t } from '@lingui/macro';
import {
Anchor,
Divider,
Group,
Paper,
SimpleGrid,
Stack,
Text,
Title
} from '@mantine/core';
import { useMemo } from 'react';
import { Link } from 'react-router-dom';
import { PlaceholderPill } from '../../../components/items/Placeholder';
import { PanelGroup, PanelType } from '../../../components/nav/PanelGroup';
import { SettingsHeader } from '../../../components/nav/SettingsHeader';
import { GlobalSettingList } from '../../../components/settings/SettingList';
/**
* System settings page
*/
export default function AdminCenter() {
const adminCenterPanels: PanelType[] = useMemo(() => {
return [
{
name: 'user',
label: t`User Management`,
content: (
<Stack spacing="xs">
<PlaceholderPill />
<Divider />
<Stack spacing={0}>
<Text>
<Trans>Settings</Trans>
</Text>
<Group>
<Text c="dimmed">
<Trans>
Select settings relevant for user lifecycle. More available
in
</Trans>
</Text>
<Anchor component={Link} to={'/settings/system'}>
<Trans>System settings</Trans>
</Anchor>
</Group>
</Stack>
<GlobalSettingList
keys={[
'LOGIN_ENABLE_REG',
'SIGNUP_GROUP',
'LOGIN_ENABLE_SSO_REG'
]}
/>
</Stack>
)
}
];
}, []);
const QuickAction = () => (
<Stack spacing={'xs'} ml={'sm'}>
<Title order={5}>
<Trans>Quick Actions</Trans>
</Title>
<SimpleGrid cols={3}>
<Paper shadow="xs" p="sm" withBorder>
<Text>
<Trans>Add a new user</Trans>
</Text>
</Paper>
<Paper shadow="xs" p="sm" withBorder>
<PlaceholderPill />
</Paper>
<Paper shadow="xs" p="sm" withBorder>
<PlaceholderPill />
</Paper>
</SimpleGrid>
</Stack>
);
return (
<>
<Stack spacing="xs">
<SettingsHeader
title={<Trans>Admin Center</Trans>}
subtitle={
<Trans>Advanced Amininistrative Options for InvenTree</Trans>
}
switch_link="/settings/system"
switch_text="System Settings"
/>
<QuickAction />
<PanelGroup
pageKey="admin-center"
panels={adminCenterPanels}
collabsible={false}
/>
</Stack>
</>
);
}

View File

@ -92,6 +92,9 @@ export const SystemSettings = Loadable(
export const PluginSettings = Loadable( export const PluginSettings = Loadable(
lazy(() => import('./pages/Index/Settings/PluginSettings')) lazy(() => import('./pages/Index/Settings/PluginSettings'))
); );
export const AdminCenter = Loadable(
lazy(() => import('./pages/Index/Settings/AdminCenter'))
);
export const NotFound = Loadable(lazy(() => import('./pages/NotFound'))); export const NotFound = Loadable(lazy(() => import('./pages/NotFound')));
export const Login = Loadable(lazy(() => import('./pages/Auth/Login'))); export const Login = Loadable(lazy(() => import('./pages/Auth/Login')));
@ -113,7 +116,8 @@ export const routes = (
<Route path="playground/" element={<Playground />} />, <Route path="playground/" element={<Playground />} />,
<Route path="scan/" element={<Scan />} />, <Route path="scan/" element={<Scan />} />,
<Route path="settings/"> <Route path="settings/">
<Route index element={<SystemSettings />} /> <Route index element={<AdminCenter />} />
<Route path="admin/" element={<AdminCenter />} />
<Route path="system/" element={<SystemSettings />} /> <Route path="system/" element={<SystemSettings />} />
<Route path="user/" element={<UserSettings />} /> <Route path="user/" element={<UserSettings />} />
<Route path="plugin/" element={<PluginSettings />} /> <Route path="plugin/" element={<PluginSettings />} />