Skip to content

Commit 5e4e836

Browse files
committed
Display system stats and project size
1 parent 3f5be6b commit 5e4e836

File tree

6 files changed

+129
-13
lines changed

6 files changed

+129
-13
lines changed

web/src/App.tsx

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import { createHashRouter, RouterProvider } from 'react-router-dom'
2-
import React from 'react'
32
import { ConfigDataProvider } from './data-providers/ConfigDataProvider'
3+
import { MessageBannerProvider } from './data-providers/MessageBannerProvider'
44
import { ProjectDataProvider } from './data-providers/ProjectDataProvider'
5+
import { SearchProvider } from './data-providers/SearchProvider'
6+
import { StatsDataProvider } from './data-providers/StatsDataProvider'
57
import Claim from './pages/Claim'
68
import Delete from './pages/Delete'
79
import Docs from './pages/Docs'
10+
import EscapeSlashForDocsPath from './pages/EscapeSlashForDocsPath'
811
import Help from './pages/Help'
912
import Home from './pages/Home'
1013
import NotFound from './pages/NotFound'
1114
import Upload from './pages/Upload'
12-
import EscapeSlashForDocsPath from './pages/EscapeSlashForDocsPath'
13-
import { MessageBannerProvider } from './data-providers/MessageBannerProvider'
14-
import { SearchProvider } from './data-providers/SearchProvider'
1515

1616
function App(): JSX.Element {
1717
const router = createHashRouter([
@@ -79,9 +79,11 @@ function App(): JSX.Element {
7979
<MessageBannerProvider>
8080
<ConfigDataProvider>
8181
<ProjectDataProvider>
82-
<SearchProvider>
83-
<RouterProvider router={router} />
84-
</SearchProvider>
82+
<StatsDataProvider>
83+
<SearchProvider>
84+
<RouterProvider router={router} />
85+
</SearchProvider>
86+
</StatsDataProvider>
8587
</ProjectDataProvider>
8688
</ConfigDataProvider>
8789
</MessageBannerProvider>

web/src/components/Project.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { type Project as ProjectType } from '../models/ProjectsResponse'
33
import ProjectRepository from '../repositories/ProjectRepository'
44
import styles from './../style/components/Project.module.css'
55

6-
import { Box, Tooltip } from '@mui/material'
6+
import { Box, Tooltip, Typography } from '@mui/material'
77
import FavoriteStar from './FavoriteStar'
88

99
interface Props {
@@ -81,6 +81,7 @@ export default function Project(props: Props): JSX.Element {
8181
{props.project.versions.length === 1
8282
? `${props.project.versions.length} version`
8383
: `${props.project.versions.length} versions`}
84+
<Typography sx={{ marginLeft: 1.5 }} fontSize={'0.9em'} component={'span'} fontWeight={300}>{props.project.storage}</Typography>
8485
</div>
8586

8687
<FavoriteStar
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-assignment */
2+
/*
3+
We need any, because we don't know the type of the children,
4+
and we need the return those children again which is an "unsafe return"
5+
*/
6+
7+
import { createContext, useContext, useEffect, useState } from 'react'
8+
import { useMessageBanner } from './MessageBannerProvider'
9+
10+
11+
type Stats = {
12+
n_projects: number
13+
n_versions: number
14+
storage: string
15+
}
16+
17+
interface StatsState {
18+
stats: Stats | null
19+
loadingFailed: boolean
20+
reload: () => void
21+
}
22+
23+
const Context = createContext<StatsState>({
24+
stats: null,
25+
loadingFailed: false,
26+
reload: (): void => {
27+
console.warn('StatsProvider not initialized')
28+
}
29+
})
30+
31+
/**
32+
* Provides the stats of the docat instance
33+
* If reloading is required, call the reload function.
34+
*/
35+
export function StatsDataProvider({ children }: any): JSX.Element {
36+
const { showMessage } = useMessageBanner()
37+
38+
const loadData = (): void => {
39+
void (async (): Promise<void> => {
40+
try {
41+
const response = await fetch('/api/stats')
42+
43+
if (!response.ok) {
44+
throw new Error(
45+
`Failed to load stats, status code: ${response.status}`
46+
)
47+
}
48+
49+
const data: Stats = await response.json()
50+
setState({
51+
stats: data,
52+
loadingFailed: false,
53+
reload: loadData
54+
})
55+
} catch (e) {
56+
console.error(e)
57+
58+
showMessage({
59+
content: 'Failed to load stats',
60+
type: 'error',
61+
showMs: 6000
62+
})
63+
64+
setState({
65+
stats: null,
66+
loadingFailed: true,
67+
reload: loadData
68+
})
69+
}
70+
})()
71+
}
72+
73+
const [state, setState] = useState<StatsState>({
74+
stats: null,
75+
loadingFailed: false,
76+
reload: loadData
77+
})
78+
79+
useEffect(() => {
80+
loadData()
81+
}, [])
82+
83+
return <Context.Provider value={state}>{children}</Context.Provider>
84+
}
85+
86+
export const useStats = (): StatsState => useContext(Context)

web/src/models/ProjectsResponse.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type ProjectDetails from './ProjectDetails'
33
export interface Project {
44
name: string
55
logo: boolean
6+
storage: string
67
versions: ProjectDetails[]
78
}
89

web/src/pages/Home.tsx

+30-4
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ import LoadingPage from './LoadingPage';
1414

1515
import { Box, Button, IconButton, Tooltip, Typography } from '@mui/material';
1616
import SearchBar from '../components/SearchBar';
17+
import { useStats } from '../data-providers/StatsDataProvider';
1718
import styles from './../style/pages/Home.module.css';
1819

1920

2021
export default function Home(): JSX.Element {
2122
const { loadingFailed } = useProjects()
23+
const { stats, loadingFailed: statsLoadingFailed } = useStats()
2224
const { filteredProjects: projects, query, setQuery } = useSearch()
2325
const [showAll, setShowAll] = useState(false);
2426
const [favoriteProjects, setFavoriteProjects] = useState<Project[]>([])
@@ -54,7 +56,7 @@ export default function Home(): JSX.Element {
5456
updateFavorites()
5557
}, [projects])
5658

57-
if (loadingFailed) {
59+
if (loadingFailed || statsLoadingFailed) {
5860
return (
5961
<div className={styles.home}>
6062
<Header />
@@ -67,7 +69,7 @@ export default function Home(): JSX.Element {
6769
)
6870
}
6971

70-
if (projects == null) {
72+
if (projects == null || stats == null) {
7173
return <LoadingPage />
7274
}
7375

@@ -76,6 +78,9 @@ export default function Home(): JSX.Element {
7678
<Header />
7779

7880
<div className={styles['project-overview']}>
81+
<Box sx={{ width: '80%', maxWidth: '800px'}}>
82+
83+
7984
<Box sx={{
8085
display: 'flex',
8186
marginTop: '24px',
@@ -148,7 +153,7 @@ export default function Home(): JSX.Element {
148153
/>
149154
:
150155
<>
151-
<Typography sx={{ marginLeft: '24px', marginBottom: 1.5 }} fontWeight={200} fontSize={20}>FAVOURITES</Typography>
156+
<Typography sx={{ marginLeft: '24px', marginBottom: 1.5 }} fontWeight={300} fontSize={20}>FAVOURITES</Typography>
152157
{ (favoriteProjects.length === 0) ?
153158
<Box sx={{marginLeft: '24px'}}>
154159
No docs favourited at the moment, search for docs or
@@ -168,7 +173,28 @@ export default function Home(): JSX.Element {
168173
}
169174
</>
170175
}
171-
176+
</Box>
177+
<Box sx={{
178+
display: {
179+
sm: 'block',
180+
xs: 'none'
181+
}, borderLeft: '1px solid #efefef', paddingLeft: 2, marginTop: 15, width: '400px'}}>
182+
<Typography sx={{display: 'inline-block'}} fontWeight={300} fontSize={'1.1em'} component={'span'}>INSTANCE STATS</Typography>
183+
<Box />
184+
185+
<Typography fontSize={'1em'} fontWeight={200} sx={{ opacity: 0.8 }} component={'span'}># </Typography>
186+
<Typography sx={{width: 100, display: 'inline-block', marginTop: 1}} fontWeight={300} fontSize={'1em'} component={'span'}>DOCS </Typography>
187+
<Typography fontSize={'1em'} fontWeight={200} sx={{ opacity: 0.8 }} component={'span'}>{stats.n_projects}</Typography>
188+
189+
<Box />
190+
<Typography fontSize={'1em'} fontWeight={200} sx={{ opacity: 0.8 }} component={'span'}># </Typography>
191+
<Typography sx={{width: 100, display: 'inline-block', marginTop: 0.4}} fontWeight={300} fontSize={'1em'} component={'span'}>VERSIONS </Typography>
192+
<Typography fontSize={'1em'} fontWeight={200} sx={{ opacity: 0.8 }} component={'span'}>{stats.n_versions}</Typography>
193+
194+
<Box />
195+
<Typography sx={{width: 115, display: 'inline-block', marginTop: 0.4}} fontWeight={300} fontSize={'1em'} component={'span'}>STORAGE </Typography>
196+
<Typography fontSize={'1em'} fontWeight={200} sx={{ opacity: 0.8 }} component={'span'}>{stats.storage}</Typography>
197+
</Box>
172198
</div>
173199
<Footer />
174200
</div>

web/src/style/pages/Home.module.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
.project-overview {
2121
display: flex;
22-
flex-direction: column;
22+
flex-direction: row;
2323
}
2424

2525
.card {

0 commit comments

Comments
 (0)