Skip to content

Commit 0042a02

Browse files
Sameera SineenSameera Sineen
authored andcommitted
Added Quicklinks, Job status and system status to dashbaord
1 parent 7caf8bd commit 0042a02

File tree

25 files changed

+3546
-1419
lines changed

25 files changed

+3546
-1419
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useQuery } from '@tanstack/react-query';
2+
import axios from 'axios';
3+
4+
export type TaccSystemLive = {
5+
display_name: string;
6+
hostname: string;
7+
online: boolean;
8+
load: number;
9+
running: number;
10+
waiting: number;
11+
in_maintenance: boolean;
12+
next_maintenance: string;
13+
};
14+
15+
type TaccStatusResponse = {
16+
[systemKey: string]: TaccSystemLive;
17+
};
18+
19+
const fetchSystemStatus = async (): Promise<TaccSystemLive[]> => {
20+
// TODO: Replace with backend proxy (/api/system/live-status) for production
21+
const proxyUrl = 'https://corsproxy.io/?';
22+
const targetUrl = 'https://tap.tacc.utexas.edu/status/';
23+
const fullUrl = `${proxyUrl}${encodeURIComponent(targetUrl)}`;
24+
25+
const res = await axios.get<TaccStatusResponse>(fullUrl);
26+
return Object.values(res.data);
27+
};
28+
29+
export const useGetLiveSystemStatus = () => {
30+
return useQuery({
31+
queryKey: ['tacc', 'liveSystemStatus'],
32+
queryFn: fetchSystemStatus,
33+
staleTime: 60_000, // 60 seconds
34+
});
35+
};

client/modules/dashboard/.babelrc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"presets": [
3+
[
4+
"@nx/react/babel",
5+
{
6+
"runtime": "automatic",
7+
"useBuiltIns": "usage"
8+
}
9+
]
10+
],
11+
"plugins": []
12+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"extends": ["plugin:@nx/react", "../../.eslintrc.base.json"],
3+
"ignorePatterns": ["!**/*"],
4+
"overrides": [
5+
{
6+
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
7+
"rules": {}
8+
},
9+
{
10+
"files": ["*.ts", "*.tsx"],
11+
"rules": {}
12+
},
13+
{
14+
"files": ["*.js", "*.jsx"],
15+
"rules": {}
16+
}
17+
]
18+
}

client/modules/dashboard/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# dashboard
2+
3+
This library was generated with [Nx](https://nx.dev).
4+
5+
## Running unit tests
6+
7+
Run `nx test dashboard` to execute the unit tests via [Vitest](https://vitest.dev/).
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "dashboard",
3+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
4+
"sourceRoot": "modules/dashboard/src",
5+
"projectType": "library",
6+
"tags": [],
7+
"targets": {
8+
"lint": {
9+
"executor": "@nx/eslint:lint",
10+
"outputs": ["{options.outputFile}"]
11+
},
12+
"test": {
13+
"executor": "@nx/vite:test",
14+
"outputs": ["{options.reportsDirectory}"],
15+
"options": {
16+
"reportsDirectory": "../../coverage/modules/dashboard"
17+
}
18+
}
19+
}
20+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Replace this with your own classes
3+
*
4+
* e.g.
5+
* .container {
6+
* }
7+
*/
8+
9+
.sidebar {
10+
background-color: #f5f7fa;
11+
color: #333;
12+
padding: 1.5rem;
13+
border-radius: 8px;
14+
width: 260px;
15+
min-height: calc(100vh - 80px);
16+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
17+
}
18+
19+
.sidebarTitle {
20+
font-size: 1.55rem;
21+
font-weight: 600;
22+
margin-bottom: 1.2rem;
23+
color: #2c3e50;
24+
border-bottom: 1px solid #ddd;
25+
padding-bottom: 0.4rem;
26+
}
27+
28+
.sidebarLink {
29+
display: block;
30+
margin: 0.75rem 0;
31+
color: #1f2d3d;
32+
font-size: 1.5rem;
33+
font-weight: 500;
34+
text-decoration: none;
35+
transition: all 0.2s ease;
36+
}
37+
38+
.sidebarLink:hover {
39+
color: #007bff;
40+
text-decoration: underline;
41+
padding-left: 5px;
42+
}
43+
.sidebar {
44+
position: sticky;
45+
top: 80px; /* after navbar */
46+
}
47+
.sidebarIcon {
48+
margin-right: 8px;
49+
vertical-align: middle;
50+
}
51+
/*for joblisting*/
52+
53+
.jobStatusContainer {
54+
background-color: #ffffff;
55+
border: 1px solid #e0e0e0;
56+
border-radius: 8px;
57+
padding: 1.5rem;
58+
margin-top: 2rem;
59+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.03);
60+
}
61+
62+
.jobStatusHeader {
63+
display: flex;
64+
justify-content: space-between;
65+
align-items: center;
66+
margin-bottom: 1rem;
67+
}
68+
69+
.jobStatusHeader h2 {
70+
font-size: 1.25rem;
71+
margin: 0;
72+
}
73+
74+
.viewAllLink {
75+
font-size: 0.9rem;
76+
color: #007bff;
77+
text-decoration: none;
78+
}
79+
80+
.viewAllLink:hover {
81+
text-decoration: underline;
82+
}
83+
84+
.jobsTableWrapper {
85+
overflow-x: auto;
86+
}
87+
.limitedWidthTable {
88+
max-width: 75%; /* or 800px, adjust as needed */
89+
min-width: 750px;
90+
}
91+
.recentJobsCard {
92+
max-width: 980px;
93+
background: white;
94+
padding: 16px;
95+
border-radius: 8px;
96+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
97+
}
98+
99+
.recentJobsHeader {
100+
display: flex;
101+
justify-content: space-between;
102+
align-items: center;
103+
margin-bottom: 1rem;
104+
}
105+
106+
.viewAllLink {
107+
font-size: 14px;
108+
color: #0073e6;
109+
text-decoration: none;
110+
}
111+
112+
.viewAllLink:hover {
113+
text-decoration: underline;
114+
}
115+
116+
.jobsTableWrapper {
117+
max-width: 100%;
118+
}
119+
.header-details {
120+
display: flex;
121+
gap: 20px;
122+
margin-top: 10px;
123+
font-size: 12px;
124+
color: #666;
125+
}
126+
127+
.header-details dt {
128+
font-weight: bold;
129+
margin-right: 5px;
130+
}
131+
132+
.header-details dd {
133+
margin: 0;
134+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { render } from '@testing-library/react';
2+
3+
import Dashboard from './Dashboard';
4+
5+
describe('Dashboard', () => {
6+
it('should render successfully', () => {
7+
const { baseElement } = render(<Dashboard />);
8+
expect(baseElement).toBeTruthy();
9+
});
10+
});
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import React from 'react';
2+
import styles from './Dashboard.module.css';
3+
import Quicklinks from './Quicklinks';
4+
import JobStatus from './Jobstatus';
5+
import { Table, Tag } from 'antd';
6+
import { useGetLiveSystemStatus } from '../../../_hooks/src/systems/useGetLiveSystemStatus';
7+
8+
export interface DashboardProps {}
9+
10+
export function Dashboard(props: DashboardProps) {
11+
const { data: liveSystems, isLoading } = useGetLiveSystemStatus();
12+
13+
const columns = [
14+
{
15+
title: 'System Name',
16+
dataIndex: 'display_name',
17+
key: 'name',
18+
},
19+
{
20+
title: 'Status',
21+
dataIndex: 'online',
22+
key: 'status',
23+
render: (online: boolean) => (
24+
<Tag color={online ? 'green' : 'red'}>{online ? 'UP' : 'DOWN'}</Tag>
25+
),
26+
},
27+
{
28+
title: 'Load',
29+
dataIndex: 'load',
30+
key: 'load',
31+
render: (load: number) => `${Math.round(load * 100)}%`,
32+
},
33+
{
34+
title: 'Running Jobs',
35+
dataIndex: 'running',
36+
key: 'running',
37+
},
38+
{
39+
title: 'Waiting Jobs',
40+
dataIndex: 'waiting',
41+
key: 'waiting',
42+
},
43+
];
44+
45+
return (
46+
<div style={{ display: 'flex', gap: '2rem' }}>
47+
{/* Sidebar on the left */}
48+
<Quicklinks />
49+
50+
{/* Middle section */}
51+
<div style={{ flex: 2 }}>
52+
<h1>DASHBOARD</h1>
53+
<JobStatus />
54+
</div>
55+
{/* Vertical separator */}
56+
<div
57+
style={{
58+
width: '1px',
59+
backgroundColor: '#ccc',
60+
marginTop: '2.5rem',
61+
marginBottom: '2rem',
62+
height: 'auto',
63+
minHeight: '300px',
64+
}}
65+
></div>
66+
67+
{/* System Status on the right */}
68+
<div style={{ flex: 1.3, paddingRight: '1.5rem' }}>
69+
<div
70+
style={{
71+
backgroundColor: '#fff',
72+
padding: '1.5rem',
73+
borderRadius: '8px',
74+
border: '1px solid #e0e0e0',
75+
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.05)',
76+
}}
77+
>
78+
<h3 style={{ marginBottom: '1rem' }}>System Status</h3>
79+
<Table
80+
columns={columns}
81+
dataSource={liveSystems?.map((sys) => ({
82+
key: sys.hostname,
83+
...sys,
84+
}))}
85+
loading={isLoading}
86+
size="small"
87+
pagination={false}
88+
/>
89+
</div>
90+
</div>
91+
</div>
92+
);
93+
}
94+
95+
export default Dashboard;

0 commit comments

Comments
 (0)