|
@@ -1,6 +1,15 @@
|
|
|
-import { makeStyles, Theme, Typography, useTheme } from '@material-ui/core';
|
|
|
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
|
+import {
|
|
|
+ makeStyles,
|
|
|
+ Theme,
|
|
|
+ Typography,
|
|
|
+ useTheme,
|
|
|
+ Card,
|
|
|
+ CardContent,
|
|
|
+} from '@material-ui/core';
|
|
|
+import { Link } from 'react-router-dom';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
+import dayjs from 'dayjs';
|
|
|
import { rootContext, webSocketContext, dataContext } from '@/context';
|
|
|
import EmptyCard from '@/components/cards/EmptyCard';
|
|
|
import icons from '@/components/icons/Icons';
|
|
@@ -13,22 +22,92 @@ import CollectionCard from './collectionCard/CollectionCard';
|
|
|
import StatisticsCard from './statisticsCard/StatisticsCard';
|
|
|
|
|
|
const useStyles = makeStyles((theme: Theme) => ({
|
|
|
+ overviewContainer: {
|
|
|
+ display: 'flex',
|
|
|
+ flexDirection: 'row',
|
|
|
+ gap: theme.spacing(4),
|
|
|
+ },
|
|
|
collectionTitle: {
|
|
|
margin: theme.spacing(2, 0),
|
|
|
- lineHeight: '20px',
|
|
|
- fontSize: '14px',
|
|
|
- color: theme.palette.attuGrey.dark,
|
|
|
+ fontSize: 16,
|
|
|
+ fontWeight: 'bold',
|
|
|
},
|
|
|
cardsWrapper: {
|
|
|
display: 'grid',
|
|
|
- gridTemplateColumns: 'repeat(auto-fill, minmax(380px, 1fr))',
|
|
|
+ gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))',
|
|
|
+ gap: theme.spacing(2),
|
|
|
+ },
|
|
|
+ sysCardsWrapper: {
|
|
|
+ display: 'grid',
|
|
|
+ gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))',
|
|
|
gap: theme.spacing(2),
|
|
|
},
|
|
|
+ h2: {
|
|
|
+ fontWeight: 'bold',
|
|
|
+ fontSize: '22px',
|
|
|
+ margin: theme.spacing(1, 0, 2, 0),
|
|
|
+ },
|
|
|
+ dbWrapper: {
|
|
|
+ width: '55%',
|
|
|
+ order: 1,
|
|
|
+ padding: theme.spacing(1, 0, 0),
|
|
|
+ },
|
|
|
+ emptyCard: {
|
|
|
+ minHeight: '50vh',
|
|
|
+ color: 'transparent',
|
|
|
+ },
|
|
|
+ sysWrapper: {
|
|
|
+ width: '45%',
|
|
|
+ background: 'rgb(239, 239, 239)',
|
|
|
+ padding: theme.spacing(1, 2, 2),
|
|
|
+ order: 1,
|
|
|
+ borderRadius: 8,
|
|
|
+ },
|
|
|
+ sysCard: {
|
|
|
+ '& p': {
|
|
|
+ fontSize: '24px',
|
|
|
+ margin: 0,
|
|
|
+ },
|
|
|
+ '& h3': {
|
|
|
+ margin: 0,
|
|
|
+ fontSize: '14px',
|
|
|
+ color: theme.palette.attuGrey.dark,
|
|
|
+ },
|
|
|
+ '& a': {
|
|
|
+ textDecoration: 'none',
|
|
|
+ color: '#000',
|
|
|
+ },
|
|
|
+ },
|
|
|
}));
|
|
|
|
|
|
+const SysCard = (data: {
|
|
|
+ title: string;
|
|
|
+ count: number | string;
|
|
|
+ des?: string;
|
|
|
+ link?: string;
|
|
|
+}) => {
|
|
|
+ const classes = useStyles();
|
|
|
+
|
|
|
+ const content = (
|
|
|
+ <>
|
|
|
+ <Typography component={'p'}>{data.count}</Typography>
|
|
|
+ <Typography component={'h3'}>{data.title}</Typography>
|
|
|
+ {data.des ? <Typography component={'p'}>{data.des}</Typography> : null}
|
|
|
+ </>
|
|
|
+ );
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Card className={classes.sysCard}>
|
|
|
+ <CardContent>
|
|
|
+ {data.link ? <Link to={data.link}>{content}</Link> : content}
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
const Overview = () => {
|
|
|
useNavigationHook(ALL_ROUTER_TYPES.OVERVIEW);
|
|
|
- const { database } = useContext(dataContext);
|
|
|
+ const { database, databases, data } = useContext(dataContext);
|
|
|
const classes = useStyles();
|
|
|
const theme = useTheme();
|
|
|
const { t: overviewTrans } = useTranslation('overview');
|
|
@@ -106,33 +185,93 @@ const Overview = () => {
|
|
|
|
|
|
const CollectionIcon = icons.navCollection;
|
|
|
|
|
|
+ // calculation diff to the rootCoord create time
|
|
|
+ const duration = useMemo(() => {
|
|
|
+ let rootCoordCreatedTime = data.rootCoord?.infos?.created_time;
|
|
|
+
|
|
|
+ let duration = '0';
|
|
|
+ if (rootCoordCreatedTime) {
|
|
|
+ rootCoordCreatedTime = rootCoordCreatedTime.substring(
|
|
|
+ 0,
|
|
|
+ rootCoordCreatedTime.lastIndexOf('m=')
|
|
|
+ );
|
|
|
+
|
|
|
+ const rootCoordCreatedTimeObj = dayjs(rootCoordCreatedTime);
|
|
|
+
|
|
|
+ const now = dayjs();
|
|
|
+ duration = now.diff(rootCoordCreatedTimeObj, 'day', true).toFixed(2);
|
|
|
+ }
|
|
|
+
|
|
|
+ return `${duration} ${overviewTrans('days')}`;
|
|
|
+ }, [data.rootCoord]);
|
|
|
+
|
|
|
return (
|
|
|
- <section className="page-wrapper">
|
|
|
- <StatisticsCard data={statisticsData.data} />
|
|
|
- <Typography className={classes.collectionTitle}>
|
|
|
- {overviewTrans('load')}
|
|
|
- </Typography>
|
|
|
-
|
|
|
- {loadCollections.length > 0 ? (
|
|
|
- <div className={classes.cardsWrapper}>
|
|
|
- {loadCollections.map(collection => (
|
|
|
- <CollectionCard
|
|
|
- key={collection._id}
|
|
|
- data={collection}
|
|
|
- onRelease={onRelease}
|
|
|
+ <section className={`page-wrapper ${classes.overviewContainer}`}>
|
|
|
+ <section className={classes.dbWrapper}>
|
|
|
+ <Typography component={'h2'} className={classes.h2}>
|
|
|
+ {overviewTrans('database')} {database}
|
|
|
+ </Typography>
|
|
|
+
|
|
|
+ <StatisticsCard data={statisticsData.data} />
|
|
|
+ <Typography component={'h4'} className={classes.collectionTitle}>
|
|
|
+ {overviewTrans('load')}
|
|
|
+ </Typography>
|
|
|
+
|
|
|
+ {loadCollections.length > 0 ? (
|
|
|
+ <div className={classes.cardsWrapper}>
|
|
|
+ {loadCollections.map(collection => (
|
|
|
+ <CollectionCard
|
|
|
+ key={collection._id}
|
|
|
+ data={collection}
|
|
|
+ onRelease={onRelease}
|
|
|
+ />
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ ) : (
|
|
|
+ <EmptyCard
|
|
|
+ loading={loading}
|
|
|
+ wrapperClass={classes.emptyCard}
|
|
|
+ icon={!loading ? <CollectionIcon /> : undefined}
|
|
|
+ text={
|
|
|
+ loading ? overviewTrans('loading') : collectionTrans('noLoadData')
|
|
|
+ }
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </section>
|
|
|
+
|
|
|
+ {data?.systemInfo ? (
|
|
|
+ <section className={classes.sysWrapper}>
|
|
|
+ <Typography component={'h2'} className={classes.h2}>
|
|
|
+ {overviewTrans('sysInfo')}
|
|
|
+ </Typography>
|
|
|
+ <div className={classes.sysCardsWrapper}>
|
|
|
+ <SysCard
|
|
|
+ title={'Milvus Version'}
|
|
|
+ count={data?.systemInfo?.build_version}
|
|
|
+ />
|
|
|
+ <SysCard title={overviewTrans('upTime')} count={duration} />
|
|
|
+ <SysCard
|
|
|
+ title={overviewTrans('deployMode')}
|
|
|
+ count={data?.deployMode}
|
|
|
+ />
|
|
|
+ <SysCard
|
|
|
+ title={overviewTrans('databases')}
|
|
|
+ count={databases?.length}
|
|
|
+ link="databases"
|
|
|
+ />
|
|
|
+ <SysCard
|
|
|
+ title={overviewTrans('users')}
|
|
|
+ count={data?.users?.length}
|
|
|
+ link="users"
|
|
|
+ />
|
|
|
+ <SysCard
|
|
|
+ title={overviewTrans('roles')}
|
|
|
+ count={data?.roles?.length}
|
|
|
+ link="users?activeIndex=1"
|
|
|
/>
|
|
|
- ))}
|
|
|
- </div>
|
|
|
- ) : (
|
|
|
- <EmptyCard
|
|
|
- loading={loading}
|
|
|
- wrapperClass="page-empty-card"
|
|
|
- icon={!loading ? <CollectionIcon /> : undefined}
|
|
|
- text={
|
|
|
- loading ? overviewTrans('loading') : collectionTrans('noLoadData')
|
|
|
- }
|
|
|
- />
|
|
|
- )}
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+ ) : null}
|
|
|
</section>
|
|
|
);
|
|
|
};
|