feat: add status basic page

This commit is contained in:
moonrailgun 2023-12-16 00:33:36 +08:00
parent 3c195b1245
commit 63145c1e4b
11 changed files with 106 additions and 8 deletions

View File

@ -18,6 +18,7 @@ import { useInjectWebsiteScript } from './hooks/useInjectWebsiteScript';
import { ConfigProvider, theme } from 'antd'; import { ConfigProvider, theme } from 'antd';
import clsx from 'clsx'; import clsx from 'clsx';
import { useSettingsStore } from './store/settings'; import { useSettingsStore } from './store/settings';
import { StatusPage } from './pages/Status';
export const AppRoutes: React.FC = React.memo(() => { export const AppRoutes: React.FC = React.memo(() => {
const { info } = useUserStore(); const { info } = useUserStore();
@ -42,6 +43,8 @@ export const AppRoutes: React.FC = React.memo(() => {
</Route> </Route>
)} )}
<Route path="/status/:slug" element={<StatusPage />} />
<Route <Route
path="*" path="*"
element={ element={

View File

@ -1,11 +1,15 @@
import React from 'react'; import React from 'react';
import { MonitorHealthBar } from '../../monitor/MonitorHealthBar'; import { MonitorHealthBar } from '../../monitor/MonitorHealthBar';
import { useCurrentWorkspaceId } from '../../../store/user';
export const MonitorHealthBarItem: React.FC<{ export const MonitorHealthBarItem: React.FC<{
monitorId: string; monitorId: string;
}> = React.memo((props) => { }> = React.memo((props) => {
const workspaceId = useCurrentWorkspaceId();
return ( return (
<MonitorHealthBar <MonitorHealthBar
workspaceId={workspaceId}
monitorId={props.monitorId} monitorId={props.monitorId}
count={40} count={40}
size="large" size="large"

View File

@ -8,6 +8,7 @@ import { useCurrentWorkspaceId } from '../../store/user';
import { useWatch } from '../../hooks/useWatch'; import { useWatch } from '../../hooks/useWatch';
interface MonitorHealthBarProps { interface MonitorHealthBarProps {
workspaceId: string;
monitorId: string; monitorId: string;
count?: number; count?: number;
size?: HealthBarProps['size']; size?: HealthBarProps['size'];
@ -18,8 +19,13 @@ interface MonitorHealthBarProps {
} }
export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo( export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
(props) => { (props) => {
const { monitorId, size, count = 20, showCurrentStatus = false } = props; const {
const workspaceId = useCurrentWorkspaceId(); workspaceId,
monitorId,
size,
count = 20,
showCurrentStatus = false,
} = props;
const { data: recent = [] } = trpc.monitor.recentData.useQuery({ const { data: recent = [] } = trpc.monitor.recentData.useQuery({
workspaceId, workspaceId,
monitorId, monitorId,

View File

@ -166,6 +166,7 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
<Card> <Card>
<MonitorHealthBar <MonitorHealthBar
workspaceId={workspaceId}
monitorId={monitorId} monitorId={monitorId}
count={40} count={40}
size="large" size="large"

View File

@ -65,6 +65,7 @@ export const MonitorListItem: React.FC<{
}> = React.memo((props) => { }> = React.memo((props) => {
const { monitor, selectedMonitorId, setSelectedMonitorId } = props; const { monitor, selectedMonitorId, setSelectedMonitorId } = props;
const navigate = useNavigate(); const navigate = useNavigate();
const workspaceId = useCurrentWorkspaceId();
const [beats, setBeats] = useState< const [beats, setBeats] = useState<
({ ({
value: number; value: number;
@ -126,7 +127,11 @@ export const MonitorListItem: React.FC<{
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<MonitorHealthBar monitorId={monitor.id} onBeatsItemUpdate={setBeats} /> <MonitorHealthBar
workspaceId={workspaceId}
monitorId={monitor.id}
onBeatsItemUpdate={setBeats}
/>
</div> </div>
</div> </div>
); );

View File

@ -91,7 +91,10 @@ export const WebsiteOverview: React.FC<{
className="cursor-pointer" className="cursor-pointer"
onClick={() => navigate(`/monitor/${website.monitorId}`)} onClick={() => navigate(`/monitor/${website.monitorId}`)}
> >
<MonitorHealthBar monitorId={website.monitorId} /> <MonitorHealthBar
workspaceId={website.workspaceId}
monitorId={website.monitorId}
/>
</div> </div>
)} )}

View File

@ -4,4 +4,4 @@ import { Dashboard } from '../components/dashboard/Dashboard';
export const DashboardPage: React.FC = React.memo(() => { export const DashboardPage: React.FC = React.memo(() => {
return <Dashboard />; return <Dashboard />;
}); });
Dashboard.displayName = 'Dashboard'; DashboardPage.displayName = 'DashboardPage';

View File

@ -0,0 +1,46 @@
import React from 'react';
import { useParams } from 'react-router';
import { trpc } from '../api/trpc';
import { Empty } from 'antd';
import { MonitorHealthBar } from '../components/monitor/MonitorHealthBar';
import { useUserStore } from '../store/user';
export const StatusPage: React.FC = React.memo(() => {
const { slug } = useParams<{ slug: string }>();
useUserStore();
const { data: info } = trpc.monitor.getPageInfo.useQuery({
slug: slug!,
});
const monitorList = info?.monitorList ?? [];
return (
<div className="w-4/5 mx-auto py-8">
<div className="text-2xl mb-4">{info?.title}</div>
<div className="text-lg mb-2">Services</div>
{info && (
<div className="shadow-2xl p-2.5">
{monitorList.length > 0 ? (
monitorList.map((item) => (
<div key={item.id} className="hover:bg-black hover:bg-opacity-20">
<MonitorHealthBar
workspaceId={info.workspaceId}
monitorId={item.id}
count={40}
size="large"
showCurrentStatus={true}
/>
</div>
))
) : (
<Empty description="No any monitor has been set" />
)}
</div>
)}
</div>
);
});
StatusPage.displayName = 'StatusPage';

View File

@ -15,7 +15,10 @@ export const useUserStore = create<UserState>(() => ({
export function setUserInfo(info: UserLoginInfo) { export function setUserInfo(info: UserLoginInfo) {
if (!info.currentWorkspace && info.workspaces[0]) { if (!info.currentWorkspace && info.workspaces[0]) {
// Make sure currentWorkspace existed // Make sure currentWorkspace existed
info.currentWorkspace = info.workspaces[0].workspace; info.currentWorkspace = {
...info.workspaces[0].workspace,
dashboardLayout: null,
};
} }
useUserStore.setState({ useUserStore.setState({
@ -28,6 +31,10 @@ export function setUserInfo(info: UserLoginInfo) {
} }
} }
export function useUserInfo(): UserLoginInfo | null {
return useUserStore((state) => state.info);
}
export function useCurrentWorkspace() { export function useCurrentWorkspace() {
const currentWorkspace = useUserStore( const currentWorkspace = useUserStore(
(state) => state.info?.currentWorkspace (state) => state.info?.currentWorkspace

View File

@ -28,8 +28,7 @@ export const userInfoSchema = z.object({
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date(), updatedAt: z.date(),
deletedAt: z.date().nullable(), deletedAt: z.date().nullable(),
currentWorkspace: z.intersection( currentWorkspace: workspaceSchema.merge(
workspaceSchema,
z.object({ z.object({
dashboardLayout: workspaceDashboardLayoutSchema.nullable(), dashboardLayout: workspaceDashboardLayoutSchema.nullable(),
}) })

View File

@ -1,5 +1,6 @@
import { import {
OpenApiMetaInfo, OpenApiMetaInfo,
publicProcedure,
router, router,
workspaceOwnerProcedure, workspaceOwnerProcedure,
workspaceProcedure, workspaceProcedure,
@ -435,6 +436,29 @@ export const monitorRouter = router({
}, },
}); });
}), }),
getPageInfo: publicProcedure
.meta({
openapi: {
tags: [OPENAPI_TAG.MONITOR],
method: 'GET',
path: '/monitor/getPageInfo',
},
})
.input(
z.object({
slug: z.string(),
})
)
.output(MonitorStatusPageModelSchema.nullable())
.query(({ input }) => {
const { slug } = input;
return prisma.monitorStatusPage.findUnique({
where: {
slug,
},
});
}),
createPage: workspaceOwnerProcedure createPage: workspaceOwnerProcedure
.meta( .meta(
buildMonitorOpenapi({ buildMonitorOpenapi({