chore: fix ci problem
This commit is contained in:
parent
e5c2b9484f
commit
c7ff3666a7
@ -1,167 +0,0 @@
|
||||
import { Button, Dropdown, MenuProps, Space } from 'antd';
|
||||
import React, { useState } from 'react';
|
||||
import { trpc } from '../../api/trpc';
|
||||
import { useCurrentWorkspaceId } from '../../store/user';
|
||||
import { useDashboardStore } from '../../store/dashboard';
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
import clsx from 'clsx';
|
||||
import { useTranslation } from '@i18next-toolkit/react';
|
||||
|
||||
export const DashboardItemAddButton: React.FC = React.memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const workspaceId = useCurrentWorkspaceId();
|
||||
const { data: websites = [], isLoading: isWebsiteLoading } =
|
||||
trpc.website.all.useQuery({
|
||||
workspaceId,
|
||||
});
|
||||
const { data: monitors = [], isLoading: isMonitorLoading } =
|
||||
trpc.monitor.all.useQuery({
|
||||
workspaceId,
|
||||
});
|
||||
const { addItem } = useDashboardStore();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const isLoading = isWebsiteLoading || isMonitorLoading;
|
||||
|
||||
const menu: MenuProps = {
|
||||
items: [
|
||||
{
|
||||
key: 'website',
|
||||
label: t('Website'),
|
||||
children:
|
||||
websites.length > 0
|
||||
? websites.map((website) => ({
|
||||
key: `website#${website.id}`,
|
||||
label: website.name,
|
||||
children: [
|
||||
{
|
||||
key: `website#${website.id}#overview`,
|
||||
label: t('Overview'),
|
||||
onClick: () => {
|
||||
addItem(
|
||||
'websiteOverview',
|
||||
website.id,
|
||||
`${website.name}'s Overview`
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: `website#${website.id}#events`,
|
||||
label: t('Events'),
|
||||
onClick: () => {
|
||||
addItem(
|
||||
'websiteEvents',
|
||||
website.id,
|
||||
`${website.name}'s Events`
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
}))
|
||||
: [
|
||||
{
|
||||
key: `website#none`,
|
||||
label: t('(None)'),
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'monitor',
|
||||
label: t('Monitor'),
|
||||
children:
|
||||
monitors.length > 0
|
||||
? monitors.map((monitor) => ({
|
||||
key: `monitor#${monitor.id}`,
|
||||
label: monitor.name,
|
||||
children: [
|
||||
{
|
||||
key: `monitor#${monitor.id}#healthBar`,
|
||||
label: t('Health Bar'),
|
||||
onClick: () => {
|
||||
addItem(
|
||||
'monitorHealthBar',
|
||||
monitor.id,
|
||||
t("{{monitorName}}'s Health", {
|
||||
monitorName: monitor.name,
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: `monitor#${monitor.id}#metrics`,
|
||||
label: t('Metrics'),
|
||||
onClick: () => {
|
||||
addItem(
|
||||
'monitorMetrics',
|
||||
monitor.id,
|
||||
t("{{monitorName}}'s Metrics", {
|
||||
monitorName: monitor.name,
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: `monitor#${monitor.id}#chart`,
|
||||
label: t('Chart'),
|
||||
onClick: () => {
|
||||
addItem(
|
||||
'monitorChart',
|
||||
monitor.id,
|
||||
t("{{monitorName}}'s Chart", {
|
||||
monitorName: monitor.name,
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: `monitor#${monitor.id}#events`,
|
||||
label: t('Events'),
|
||||
onClick: () => {
|
||||
addItem(
|
||||
'monitorEvents',
|
||||
monitor.id,
|
||||
t("{{monitorName}}'s Events", {
|
||||
monitorName: monitor.name,
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
}))
|
||||
: [
|
||||
{
|
||||
key: `monitor#none`,
|
||||
label: t('(None)'),
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
disabled={isLoading}
|
||||
menu={menu}
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
>
|
||||
<Button type="primary" size="large" className="w-32">
|
||||
<Space>
|
||||
<span>{t('Add')}</span>
|
||||
<DownOutlined
|
||||
className={clsx(
|
||||
'scale-y-75 transition-transform',
|
||||
open && 'rotate-180'
|
||||
)}
|
||||
/>
|
||||
</Space>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
DashboardItemAddButton.displayName = 'DashboardItemAddButton';
|
@ -1,102 +0,0 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { DashboardGrid } from './Grid';
|
||||
import { DashboardItemAddButton } from './AddButton';
|
||||
import { defaultBlankLayouts, useDashboardStore } from '../../store/dashboard';
|
||||
import { useEvent } from '../../hooks/useEvent';
|
||||
import { Layouts } from 'react-grid-layout';
|
||||
import { Button, Empty, message } from 'antd';
|
||||
import { DateFilter } from '../DateFilter';
|
||||
import { trpc } from '../../api/trpc';
|
||||
import { useCurrentWorkspace, useCurrentWorkspaceId } from '../../store/user';
|
||||
import clsx from 'clsx';
|
||||
import { useTranslation } from '@i18next-toolkit/react';
|
||||
|
||||
export const Dashboard: React.FC = React.memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const { isEditMode, switchEditMode, layouts, items } = useDashboardStore();
|
||||
const mutation = trpc.workspace.saveDashboardLayout.useMutation();
|
||||
const workspaceId = useCurrentWorkspaceId();
|
||||
const workspace = useCurrentWorkspace();
|
||||
|
||||
useEffect(() => {
|
||||
// Init on mount
|
||||
const { items = [], layouts = defaultBlankLayouts } =
|
||||
workspace.dashboardLayout ?? {};
|
||||
|
||||
useDashboardStore.setState({
|
||||
items,
|
||||
layouts,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleChangeLayouts = useEvent((layouts: Layouts) => {
|
||||
useDashboardStore.setState({
|
||||
layouts,
|
||||
});
|
||||
});
|
||||
|
||||
const handleSaveDashboardLayout = useEvent(async () => {
|
||||
await mutation.mutateAsync({
|
||||
workspaceId,
|
||||
dashboardLayout: {
|
||||
layouts,
|
||||
items,
|
||||
},
|
||||
});
|
||||
switchEditMode();
|
||||
message.success(t('Layout saved success'));
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="py-4">
|
||||
<div
|
||||
className={clsx(
|
||||
'flex justify-end gap-2 bg-white py-2 dark:bg-gray-900',
|
||||
isEditMode && 'sticky top-0 z-10'
|
||||
)}
|
||||
>
|
||||
{isEditMode ? (
|
||||
<>
|
||||
<DashboardItemAddButton />
|
||||
<Button
|
||||
className="w-32"
|
||||
size="large"
|
||||
loading={mutation.isLoading}
|
||||
disabled={mutation.isLoading}
|
||||
onClick={handleSaveDashboardLayout}
|
||||
>
|
||||
{t('Done')}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<DateFilter />
|
||||
<Button
|
||||
className="w-32"
|
||||
type="primary"
|
||||
size="large"
|
||||
onClick={switchEditMode}
|
||||
>
|
||||
{t('Edit')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<DashboardGrid
|
||||
layouts={layouts}
|
||||
onChangeLayouts={handleChangeLayouts}
|
||||
items={items}
|
||||
isEditMode={isEditMode}
|
||||
/>
|
||||
|
||||
{items.length === 0 && (
|
||||
<Empty
|
||||
description={t(
|
||||
'You have not dashboard item yet, please enter edit mode and add you item.'
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
Dashboard.displayName = 'Dashboard';
|
@ -1,44 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Layouts, Responsive, WidthProvider } from 'react-grid-layout';
|
||||
import clsx from 'clsx';
|
||||
import { DashboardGridItem } from './items';
|
||||
import { DashboardItem } from '../../store/dashboard';
|
||||
import 'react-grid-layout/css/styles.css';
|
||||
import 'react-resizable/css/styles.css';
|
||||
|
||||
const ResponsiveGridLayout = WidthProvider(Responsive);
|
||||
|
||||
interface DashboardGridProps {
|
||||
isEditMode: boolean;
|
||||
items: DashboardItem[];
|
||||
layouts: Layouts;
|
||||
onChangeLayouts: (layouts: Layouts) => void;
|
||||
}
|
||||
export const DashboardGrid: React.FC<DashboardGridProps> = React.memo(
|
||||
(props) => {
|
||||
const { layouts, onChangeLayouts, items, isEditMode } = props;
|
||||
|
||||
return (
|
||||
<ResponsiveGridLayout
|
||||
className={clsx('layout', isEditMode && 'select-none')}
|
||||
layouts={layouts}
|
||||
rowHeight={50}
|
||||
draggableCancel=".non-draggable"
|
||||
isDraggable={isEditMode}
|
||||
isResizable={isEditMode}
|
||||
breakpoints={{ lg: 1200, md: 768, sm: 0 }}
|
||||
cols={{ lg: 4, md: 3, sm: 2 }}
|
||||
onLayoutChange={(currentLayout, allLayouts) => {
|
||||
onChangeLayouts(allLayouts);
|
||||
}}
|
||||
>
|
||||
{items.map((item) => (
|
||||
<div key={item.key}>
|
||||
<DashboardGridItem item={item} />
|
||||
</div>
|
||||
))}
|
||||
</ResponsiveGridLayout>
|
||||
);
|
||||
}
|
||||
);
|
||||
DashboardGrid.displayName = 'DashboardGrid';
|
@ -1,9 +0,0 @@
|
||||
import React from 'react';
|
||||
import { MonitorDataChart } from '../../monitor/MonitorDataChart';
|
||||
|
||||
export const MonitorChartItem: React.FC<{
|
||||
monitorId: string;
|
||||
}> = React.memo((props) => {
|
||||
return <MonitorDataChart monitorId={props.monitorId} />;
|
||||
});
|
||||
MonitorChartItem.displayName = 'MonitorChartItem';
|
@ -1,9 +0,0 @@
|
||||
import React from 'react';
|
||||
import { MonitorEventList } from '../../monitor/MonitorEventList';
|
||||
|
||||
export const MonitorEventsItem: React.FC<{
|
||||
monitorId: string;
|
||||
}> = React.memo((props) => {
|
||||
return <MonitorEventList monitorId={props.monitorId} />;
|
||||
});
|
||||
MonitorEventsItem.displayName = 'MonitorEventsItem';
|
@ -1,20 +0,0 @@
|
||||
import React from 'react';
|
||||
import { MonitorHealthBar } from '../../monitor/MonitorHealthBar';
|
||||
import { useCurrentWorkspaceId } from '../../../store/user';
|
||||
|
||||
export const MonitorHealthBarItem: React.FC<{
|
||||
monitorId: string;
|
||||
}> = React.memo((props) => {
|
||||
const workspaceId = useCurrentWorkspaceId();
|
||||
|
||||
return (
|
||||
<MonitorHealthBar
|
||||
workspaceId={workspaceId}
|
||||
monitorId={props.monitorId}
|
||||
count={40}
|
||||
size="large"
|
||||
showCurrentStatus={true}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MonitorHealthBarItem.displayName = 'MonitorHealthBarItem';
|
@ -1,33 +0,0 @@
|
||||
import React from 'react';
|
||||
import { trpc } from '../../../api/trpc';
|
||||
import { NotFoundTip } from '../../NotFoundTip';
|
||||
import { useCurrentWorkspaceId } from '../../../store/user';
|
||||
import { Loading } from '../../Loading';
|
||||
import { MonitorDataMetrics } from '../../monitor/MonitorDataMetrics';
|
||||
|
||||
export const MonitorMetricsItem: React.FC<{
|
||||
monitorId: string;
|
||||
}> = React.memo((props) => {
|
||||
const workspaceId = useCurrentWorkspaceId();
|
||||
|
||||
const { data: monitorInfo, isLoading } = trpc.monitor.get.useQuery({
|
||||
workspaceId,
|
||||
monitorId: props.monitorId,
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
if (!monitorInfo) {
|
||||
return <NotFoundTip />;
|
||||
}
|
||||
|
||||
return (
|
||||
<MonitorDataMetrics
|
||||
monitorId={monitorInfo.id}
|
||||
monitorType={monitorInfo.type}
|
||||
/>
|
||||
);
|
||||
});
|
||||
MonitorMetricsItem.displayName = 'MonitorMetricsItem';
|
@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import { WebsiteMetricsTable } from '../../website/WebsiteMetricsTable';
|
||||
import { useGlobalRangeDate } from '../../../hooks/useGlobalRangeDate';
|
||||
import { useTranslation } from '@i18next-toolkit/react';
|
||||
|
||||
export const WebsiteEventItem: React.FC<{
|
||||
websiteId: string;
|
||||
}> = React.memo((props) => {
|
||||
const { t } = useTranslation();
|
||||
const { startDate, endDate } = useGlobalRangeDate();
|
||||
const startAt = startDate.valueOf();
|
||||
const endAt = endDate.valueOf();
|
||||
|
||||
return (
|
||||
<WebsiteMetricsTable
|
||||
websiteId={props.websiteId}
|
||||
type="event"
|
||||
title={[t('Events'), t('Actions')]}
|
||||
startAt={startAt}
|
||||
endAt={endAt}
|
||||
/>
|
||||
);
|
||||
});
|
||||
WebsiteEventItem.displayName = 'WebsiteEventItem';
|
@ -1,46 +0,0 @@
|
||||
import React from 'react';
|
||||
import { trpc } from '../../../api/trpc';
|
||||
import { useCurrentWorkspaceId } from '../../../store/user';
|
||||
import { Loading } from '../../Loading';
|
||||
import { NotFoundTip } from '../../NotFoundTip';
|
||||
import { WebsiteOverview } from '../../website/WebsiteOverview';
|
||||
import { Button } from 'antd';
|
||||
import { ArrowRightOutlined } from '@ant-design/icons';
|
||||
import { useTranslation } from '@i18next-toolkit/react';
|
||||
import { Link } from '@tanstack/react-router';
|
||||
|
||||
export const WebsiteOverviewItem: React.FC<{
|
||||
websiteId: string;
|
||||
}> = React.memo((props) => {
|
||||
const { t } = useTranslation();
|
||||
const workspaceId = useCurrentWorkspaceId();
|
||||
|
||||
const { data: websiteInfo, isLoading } = trpc.website.info.useQuery({
|
||||
workspaceId,
|
||||
websiteId: props.websiteId,
|
||||
});
|
||||
|
||||
if (isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
if (!websiteInfo) {
|
||||
return <NotFoundTip />;
|
||||
}
|
||||
|
||||
return (
|
||||
<WebsiteOverview
|
||||
website={websiteInfo}
|
||||
actions={
|
||||
<>
|
||||
<Link to="/website/$websiteId" params={{ websiteId: websiteInfo.id }}>
|
||||
<Button type="primary" size="large">
|
||||
{t('View Details')} <ArrowRightOutlined />
|
||||
</Button>
|
||||
</Link>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
WebsiteOverviewItem.displayName = 'WebsiteOverviewItem';
|
@ -1,77 +0,0 @@
|
||||
import { useMemo } from 'react';
|
||||
import { DashboardItem, useDashboardStore } from '../../../store/dashboard';
|
||||
import { WebsiteOverviewItem } from './WebsiteOverviewItem';
|
||||
import { NotFoundTip } from '../../NotFoundTip';
|
||||
import { Button, Card, Input, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import { DeleteOutlined } from '@ant-design/icons';
|
||||
import { useEvent } from '../../../hooks/useEvent';
|
||||
import { WebsiteEventItem } from './WebsiteEventItem';
|
||||
import { MonitorHealthBarItem } from './MonitorHealthBarItem';
|
||||
import { MonitorMetricsItem } from './MonitorMetricsItem';
|
||||
import { MonitorChartItem } from './MonitorChartItem';
|
||||
import { MonitorEventsItem } from './MonitorEventsItem';
|
||||
import { EditableText } from '../../EditableText';
|
||||
|
||||
interface DashboardGridItemProps {
|
||||
item: DashboardItem;
|
||||
}
|
||||
export const DashboardGridItem: React.FC<DashboardGridItemProps> = React.memo(
|
||||
(props) => {
|
||||
const { isEditMode, removeItem, changeItemTitle } = useDashboardStore();
|
||||
const { key, id, title, type } = props.item;
|
||||
|
||||
const inner = useMemo(() => {
|
||||
if (type === 'websiteOverview') {
|
||||
return <WebsiteOverviewItem websiteId={id} />;
|
||||
} else if (type === 'websiteEvents') {
|
||||
return <WebsiteEventItem websiteId={id} />;
|
||||
} else if (type === 'monitorHealthBar') {
|
||||
return <MonitorHealthBarItem monitorId={id} />;
|
||||
} else if (type === 'monitorMetrics') {
|
||||
return <MonitorMetricsItem monitorId={id} />;
|
||||
} else if (type === 'monitorChart') {
|
||||
return <MonitorChartItem monitorId={id} />;
|
||||
} else if (type === 'monitorEvents') {
|
||||
return <MonitorEventsItem monitorId={id} />;
|
||||
} else {
|
||||
return <NotFoundTip />;
|
||||
}
|
||||
}, [id, type]);
|
||||
|
||||
const handleDelete = useEvent(
|
||||
(e: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||
e.stopPropagation();
|
||||
removeItem(key);
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="h-full w-full overflow-auto"
|
||||
title={
|
||||
<EditableText
|
||||
className="non-draggable"
|
||||
enable={isEditMode}
|
||||
defaultValue={title}
|
||||
onSave={(text) => changeItemTitle(key, text)}
|
||||
/>
|
||||
}
|
||||
headStyle={{ padding: 10, minHeight: 40 }}
|
||||
bodyStyle={{ padding: 10 }}
|
||||
extra={
|
||||
isEditMode && (
|
||||
<Button
|
||||
shape="circle"
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={handleDelete}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
{inner}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
);
|
||||
DashboardGridItem.displayName = 'DashboardGridItem';
|
@ -21,7 +21,6 @@ import { Route as PageImport } from './routes/page'
|
||||
import { Route as MonitorImport } from './routes/monitor'
|
||||
import { Route as LoginImport } from './routes/login'
|
||||
import { Route as FeedImport } from './routes/feed'
|
||||
import { Route as DashboardImport } from './routes/dashboard'
|
||||
import { Route as IndexImport } from './routes/index'
|
||||
import { Route as WebsiteOverviewImport } from './routes/website/overview'
|
||||
import { Route as WebsiteAddImport } from './routes/website/add'
|
||||
@ -98,11 +97,6 @@ const FeedRoute = FeedImport.update({
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const DashboardRoute = DashboardImport.update({
|
||||
path: '/dashboard',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const IndexRoute = IndexImport.update({
|
||||
path: '/',
|
||||
getParentRoute: () => rootRoute,
|
||||
@ -226,10 +220,6 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof IndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/dashboard': {
|
||||
preLoaderRoute: typeof DashboardImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/feed': {
|
||||
preLoaderRoute: typeof FeedImport
|
||||
parentRoute: typeof rootRoute
|
||||
@ -365,7 +355,6 @@ declare module '@tanstack/react-router' {
|
||||
|
||||
export const routeTree = rootRoute.addChildren([
|
||||
IndexRoute,
|
||||
DashboardRoute,
|
||||
FeedRoute.addChildren([
|
||||
FeedAddRoute,
|
||||
FeedChannelIdEditRoute,
|
||||
|
@ -1,9 +0,0 @@
|
||||
import { createFileRoute, redirect } from '@tanstack/react-router';
|
||||
|
||||
export const Route = createFileRoute('/dashboard')({
|
||||
beforeLoad: () => {
|
||||
redirect({
|
||||
to: '/',
|
||||
});
|
||||
},
|
||||
});
|
@ -8,6 +8,7 @@ export default defineConfig({
|
||||
root: __dirname,
|
||||
plugins: [
|
||||
react(),
|
||||
// @ts-ignore
|
||||
TanStackRouterVite({
|
||||
routesDirectory: './routes',
|
||||
generatedRouteTree: './routeTree.gen.ts',
|
||||
|
Loading…
Reference in New Issue
Block a user