2024-01-07 16:01:49 +00:00
|
|
|
import React, { useState } from 'react';
|
2024-01-28 08:45:26 +00:00
|
|
|
import { Outlet, useNavigate, useSearchParams } from 'react-router-dom';
|
2023-08-31 16:11:47 +00:00
|
|
|
import { NavItem } from '../components/NavItem';
|
2024-01-07 16:01:49 +00:00
|
|
|
import { MobileNavItem } from '../components/MobileNavItem';
|
2023-08-31 16:11:47 +00:00
|
|
|
import { UserOutlined } from '@ant-design/icons';
|
2024-01-24 13:26:42 +00:00
|
|
|
import { Button, Divider, Drawer, Dropdown } from 'antd';
|
2023-09-03 13:30:19 +00:00
|
|
|
import { useUserStore } from '../store/user';
|
2023-10-20 15:12:42 +00:00
|
|
|
import { useLogout } from '../api/model/user';
|
2023-12-08 13:49:49 +00:00
|
|
|
import { ColorSchemeSwitcher } from '../components/ColorSchemeSwitcher';
|
2024-01-24 13:26:42 +00:00
|
|
|
import { version } from '@tianji/shared';
|
2024-01-07 16:01:49 +00:00
|
|
|
import { useIsMobile } from '../hooks/useIsMobile';
|
|
|
|
import { RiMenuUnfoldLine } from 'react-icons/ri';
|
2024-02-11 16:10:38 +00:00
|
|
|
import { useTranslation } from '@i18next-toolkit/react';
|
|
|
|
import { LanguageSelector } from '../components/LanguageSelector';
|
2024-02-17 16:47:22 +00:00
|
|
|
import { useGlobalConfig } from '../hooks/useConfig';
|
2023-08-31 16:11:47 +00:00
|
|
|
|
|
|
|
export const Layout: React.FC = React.memo(() => {
|
2023-10-08 11:06:59 +00:00
|
|
|
const [params] = useSearchParams();
|
2023-09-03 13:30:19 +00:00
|
|
|
const workspaces = useUserStore((state) => {
|
|
|
|
const userInfo = state.info;
|
|
|
|
if (userInfo) {
|
|
|
|
return userInfo.workspaces.map((w) => ({
|
|
|
|
id: w.workspace.id,
|
|
|
|
name: w.workspace.name,
|
|
|
|
role: w.role,
|
2023-10-20 15:12:42 +00:00
|
|
|
current: userInfo.currentWorkspace?.id === w.workspace.id,
|
2023-09-03 13:30:19 +00:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
return [];
|
|
|
|
});
|
2024-01-07 16:01:49 +00:00
|
|
|
const [openDraw, setOpenDraw] = useState(false);
|
2023-10-20 15:12:42 +00:00
|
|
|
const logout = useLogout();
|
2024-01-07 16:01:49 +00:00
|
|
|
const isMobile = useIsMobile();
|
2023-10-08 11:06:59 +00:00
|
|
|
const showHeader = !params.has('hideHeader');
|
2024-01-28 08:45:26 +00:00
|
|
|
const navigate = useNavigate();
|
2024-02-11 16:10:38 +00:00
|
|
|
const { t } = useTranslation();
|
2024-02-17 16:47:22 +00:00
|
|
|
const { alphaMode } = useGlobalConfig();
|
2023-09-03 13:30:19 +00:00
|
|
|
|
2024-01-07 16:01:49 +00:00
|
|
|
const accountEl = (
|
|
|
|
<Dropdown
|
|
|
|
placement="bottomRight"
|
|
|
|
menu={{
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
key: 'workspaces',
|
2024-02-11 16:10:38 +00:00
|
|
|
label: t('Workspaces'),
|
2024-01-07 16:01:49 +00:00
|
|
|
children: workspaces.map((w) => ({
|
|
|
|
key: w.id,
|
|
|
|
label: `${w.name}${w.current ? '(current)' : ''}`,
|
|
|
|
disabled: w.current,
|
|
|
|
})),
|
|
|
|
},
|
2024-01-28 08:45:26 +00:00
|
|
|
{
|
|
|
|
key: 'settings',
|
2024-02-11 16:10:38 +00:00
|
|
|
label: t('Settings'),
|
2024-01-28 08:45:26 +00:00
|
|
|
onClick: () => {
|
|
|
|
navigate('/settings');
|
|
|
|
},
|
|
|
|
},
|
2024-01-07 16:01:49 +00:00
|
|
|
{
|
|
|
|
key: 'logout',
|
2024-02-11 16:10:38 +00:00
|
|
|
label: t('Logout'),
|
2024-01-07 16:01:49 +00:00
|
|
|
onClick: () => {
|
|
|
|
logout();
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'divider',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: 'version',
|
|
|
|
label: `v${version}`,
|
|
|
|
disabled: true,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Button shape="circle" size="large" icon={<UserOutlined />} />
|
|
|
|
</Dropdown>
|
|
|
|
);
|
|
|
|
|
2023-08-31 16:11:47 +00:00
|
|
|
return (
|
2023-12-08 13:49:49 +00:00
|
|
|
<div className="flex flex-col h-full dark:bg-gray-900 dark:text-gray-300">
|
2023-10-08 11:06:59 +00:00
|
|
|
{showHeader && (
|
2024-01-07 16:01:49 +00:00
|
|
|
<div className="flex items-center bg-gray-100 dark:bg-gray-800 px-4 sticky top-0 z-20 h-[62px]">
|
|
|
|
{isMobile && (
|
|
|
|
<>
|
|
|
|
<Button
|
|
|
|
className="mr-2"
|
|
|
|
icon={<RiMenuUnfoldLine className="anticon" />}
|
|
|
|
onClick={() => setOpenDraw(true)}
|
|
|
|
/>
|
|
|
|
<Drawer
|
|
|
|
open={openDraw}
|
|
|
|
onClose={() => setOpenDraw(false)}
|
|
|
|
placement="left"
|
|
|
|
closeIcon={false}
|
|
|
|
>
|
|
|
|
<div className="flex flex-col h-full pt-12">
|
|
|
|
<div className="flex-1">
|
|
|
|
<MobileNavItem
|
|
|
|
to="/dashboard"
|
2024-02-11 16:10:38 +00:00
|
|
|
label={t('Dashboard')}
|
2024-01-07 16:01:49 +00:00
|
|
|
onClick={() => setOpenDraw(false)}
|
|
|
|
/>
|
|
|
|
<MobileNavItem
|
|
|
|
to="/monitor"
|
2024-02-11 16:10:38 +00:00
|
|
|
label={t('Monitor')}
|
2024-01-07 16:01:49 +00:00
|
|
|
onClick={() => setOpenDraw(false)}
|
|
|
|
/>
|
|
|
|
<MobileNavItem
|
|
|
|
to="/website"
|
2024-02-11 16:10:38 +00:00
|
|
|
label={t('Website')}
|
2024-01-07 16:01:49 +00:00
|
|
|
onClick={() => setOpenDraw(false)}
|
|
|
|
/>
|
|
|
|
<MobileNavItem
|
|
|
|
to="/servers"
|
2024-02-11 16:10:38 +00:00
|
|
|
label={t('Servers')}
|
2024-01-07 16:01:49 +00:00
|
|
|
onClick={() => setOpenDraw(false)}
|
|
|
|
/>
|
2024-02-17 16:47:22 +00:00
|
|
|
{alphaMode && (
|
|
|
|
<MobileNavItem
|
|
|
|
to="/telemetry"
|
|
|
|
label={t('Telemetry')}
|
|
|
|
onClick={() => setOpenDraw(false)}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
|
2024-01-07 16:01:49 +00:00
|
|
|
<MobileNavItem
|
|
|
|
to="/settings"
|
2024-02-11 16:10:38 +00:00
|
|
|
label={t('Settings')}
|
2024-01-07 16:01:49 +00:00
|
|
|
onClick={() => setOpenDraw(false)}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<Divider />
|
|
|
|
|
|
|
|
<div className="flex justify-between">
|
|
|
|
<ColorSchemeSwitcher />
|
|
|
|
{accountEl}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</Drawer>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
|
2023-10-13 13:50:17 +00:00
|
|
|
<div className="px-2 mr-10 font-bold flex items-center">
|
|
|
|
<img src="/icon.svg" className="w-10 h-10 mr-2" />
|
2023-12-08 13:49:49 +00:00
|
|
|
<span className="text-xl dark:text-gray-200">Tianji</span>
|
2023-10-13 13:50:17 +00:00
|
|
|
</div>
|
2023-08-31 16:11:47 +00:00
|
|
|
|
2024-01-07 16:01:49 +00:00
|
|
|
{!isMobile && (
|
|
|
|
<>
|
|
|
|
<div className="flex gap-8">
|
2024-02-11 16:10:38 +00:00
|
|
|
<NavItem to="/dashboard" label={t('Dashboard')} />
|
|
|
|
<NavItem to="/monitor" label={t('Monitor')} />
|
|
|
|
<NavItem to="/website" label={t('Website')} />
|
|
|
|
<NavItem to="/servers" label={t('Servers')} />
|
2024-02-17 16:47:22 +00:00
|
|
|
<NavItem to="/telemetry" label={t('Telemetry')} />
|
2024-02-11 16:10:38 +00:00
|
|
|
<NavItem to="/settings" label={t('Settings')} />
|
2024-01-07 16:01:49 +00:00
|
|
|
</div>
|
2023-08-31 16:11:47 +00:00
|
|
|
|
2024-01-07 16:01:49 +00:00
|
|
|
<div className="flex-1" />
|
2023-12-08 13:49:49 +00:00
|
|
|
|
2024-01-07 16:01:49 +00:00
|
|
|
<div className="flex gap-2">
|
2024-02-11 16:10:38 +00:00
|
|
|
<LanguageSelector />
|
|
|
|
|
2024-01-07 16:01:49 +00:00
|
|
|
<ColorSchemeSwitcher />
|
|
|
|
|
|
|
|
{accountEl}
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
)}
|
2023-08-31 16:11:47 +00:00
|
|
|
</div>
|
2023-10-08 11:06:59 +00:00
|
|
|
)}
|
2023-10-28 17:25:29 +00:00
|
|
|
<div className="flex-1 w-full overflow-hidden">
|
2023-12-12 11:19:50 +00:00
|
|
|
<div className="h-full px-1 sm:px-4 overflow-auto">
|
2023-10-28 17:25:29 +00:00
|
|
|
<div className="max-w-7xl m-auto">
|
|
|
|
<Outlet />
|
|
|
|
</div>
|
2023-09-10 07:55:04 +00:00
|
|
|
</div>
|
2023-08-31 16:11:47 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
Layout.displayName = 'Layout';
|