Skip to content

Commit 04320cc

Browse files
Merge pull request #7 from Monokaix/optimization
pagination pod and job from cache
2 parents 0d1b633 + cd7a9e6 commit 04320cc

File tree

6 files changed

+95
-83
lines changed

6 files changed

+95
-83
lines changed

backend/src/server.js

+40-56
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ app.get("/api/jobs", async (req, res) => {
1616
try {
1717
const namespace = req.query.namespace || "";
1818
const searchTerm = req.query.search || "";
19-
const page = parseInt(req.query.page) || 1;
20-
const limit = parseInt(req.query.limit) || 10;
2119
const queueFilter = req.query.queue || "";
2220
const statusFilter = req.query.status || "";
2321

24-
console.log('Fetching jobs with params:', {page, limit, searchTerm, namespace, queueFilter});
22+
console.log('Fetching jobs with params:', {namespace, searchTerm, queueFilter, statusFilter});
2523

2624
let response;
2725
if (namespace === "" || namespace === "All") {
@@ -61,17 +59,9 @@ app.get("/api/jobs", async (req, res) => {
6159
);
6260
}
6361

64-
const totalCount = filteredJobs.length;
65-
const startIndex = (page - 1) * limit;
66-
const endIndex = Math.min(startIndex + limit, totalCount);
67-
const paginatedJobs = filteredJobs.slice(startIndex, endIndex);
68-
6962
res.json({
70-
items: paginatedJobs,
71-
totalCount: totalCount,
72-
page: page,
73-
limit: limit,
74-
totalPages: Math.ceil(totalCount / limit)
63+
items: filteredJobs,
64+
totalCount: filteredJobs.length,
7565
});
7666
} catch (err) {
7767
console.error("Error fetching jobs:", err);
@@ -186,6 +176,8 @@ app.get("/api/queues", async (req, res) => {
186176
const searchTerm = req.query.search || "";
187177
const stateFilter = req.query.state || "";
188178

179+
console.log('Fetching queues with params:', {page, limit, searchTerm, stateFilter});
180+
189181
const response = await k8sApi.listClusterCustomObject(
190182
"scheduling.volcano.sh",
191183
"v1beta1",
@@ -230,7 +222,6 @@ app.get("/api/queues", async (req, res) => {
230222
// get all ns
231223
app.get("/api/namespaces", async (req, res) => {
232224
try {
233-
234225
const response = await k8sCoreApi.listNamespace()
235226

236227
res.json({
@@ -246,54 +237,47 @@ app.get("/api/namespaces", async (req, res) => {
246237
});
247238

248239
app.get('/api/pods', async (req, res) => {
249-
const namespace = req.query.namespace || "";
250-
const searchTerm = req.query.search || "";
251-
const page = parseInt(req.query.page) || 1;
252-
const limit = parseInt(req.query.limit) || 10;
253-
const statusFilter = req.query.status || "";
254-
255-
let response;
256-
if (
257-
namespace === "" || namespace === "All") {
258-
response = await k8sCoreApi.listPodForAllNamespaces();
259-
} else {
260-
response = await k8sCoreApi.listNamespacedPod(namespace);
261-
}
262-
263-
let filteredPods = response.body.items || [];
264-
265-
// Apply search filter
266-
if (searchTerm) {
267-
filteredPods = filteredPods.filter(pod =>
268-
pod.metadata.name.toLowerCase().includes(searchTerm.toLowerCase())
269-
);
270-
}
240+
try {
241+
const namespace = req.query.namespace || "";
242+
const searchTerm = req.query.search || "";
243+
const statusFilter = req.query.status || "";
271244

272-
if (statusFilter && statusFilter !== "All") {
273-
filteredPods = filteredPods.filter((pod) =>
274-
pod.status.phase === statusFilter
275-
);
276-
}
245+
console.log('Fetching pods with params:', {namespace, searchTerm, statusFilter});
277246

278-
// Calculate the total
279-
const totalCount = filteredPods.length;
247+
let response;
248+
if (
249+
namespace === "" || namespace === "All") {
250+
response = await k8sCoreApi.listPodForAllNamespaces();
251+
} else {
252+
response = await k8sCoreApi.listNamespacedPod(namespace);
253+
}
280254

255+
let filteredPods = response.body.items || [];
281256

282-
// Apply pagination
283-
const startIndex = (page - 1) * limit;
284-
const endIndex = Math.min(startIndex + limit, totalCount);
285-
const paginatedPods = filteredPods.slice(startIndex, endIndex);
257+
// Apply search filter
258+
if (searchTerm) {
259+
filteredPods = filteredPods.filter(pod =>
260+
pod.metadata.name.toLowerCase().includes(searchTerm.toLowerCase())
261+
);
262+
}
286263

287-
console.log(`Page: ${page}, Limit: ${limit}, Total: ${totalCount}`);
288-
console.log(`Showing pods from ${startIndex} to ${endIndex}`);
264+
if (statusFilter && statusFilter !== "All") {
265+
filteredPods = filteredPods.filter((pod) =>
266+
pod.status.phase === statusFilter
267+
);
268+
}
289269

290-
res.json({
291-
items: paginatedPods,
292-
totalCount: totalCount,
293-
page: page,
294-
limit: limit,
295-
totalPages: Math.ceil(totalCount / limit)
296-
});
270+
res.json({
271+
items: filteredPods,
272+
totalCount: filteredPods.length,
273+
});
274+
} catch (err) {
275+
console.error("Error fetching pods:", err);
276+
res.status(500).json({
277+
error: "Failed to fetch pods",
278+
details: err.message
279+
});
280+
}
297281
});
298282

299283
// Get details of a specific Pod

deployment/volcano-dashboard.yaml

+10-2
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ spec:
1818
spec:
1919
serviceAccountName: volcano-dashboard
2020
containers:
21-
- image: volcanosh/vc-dashboard-frontend:v0.1
21+
- image: volcanosh/vc-dashboard-frontend:latest
2222
imagePullPolicy: Always
2323
name: frontend
2424
ports:
2525
- containerPort: 80
2626
name: frontend
2727
protocol: TCP
28-
- image: volcanosh/vc-dashboard-backend:v0.1
28+
- image: volcanosh/vc-dashboard-backend:latest
2929
imagePullPolicy: Always
3030
name: backend
3131
ports:
@@ -81,6 +81,14 @@ rules:
8181
- get
8282
- list
8383
- watch
84+
- apiGroups:
85+
- ""
86+
resources:
87+
- namespaces
88+
verbs:
89+
- get
90+
- list
91+
- watch
8492
- apiGroups:
8593
- scheduling.incubator.k8s.io
8694
- scheduling.volcano.sh

frontend/src/components/Jobs.jsx

+23-11
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ import {
2323
Typography,
2424
useTheme,
2525
} from "@mui/material";
26-
import {ArrowDownward, ArrowUpward, Clear, Error, FilterList, Refresh, Search} from "@mui/icons-material";
26+
import {ArrowDownward, ArrowUpward, Clear, Error, FilterList, Refresh, Search, UnfoldMore} from "@mui/icons-material";
2727
import axios from "axios";
2828
import {fetchAllNamespaces, fetchAllQueues} from "./utils";
2929

3030
const Jobs = () => {
3131
const [jobs, setJobs] = useState([]);
32+
const [cachedJobs, setCachedJobs] = useState([]);
3233
const [loading, setLoading] = useState(true);
3334
const [error, setError] = useState(null);
3435
const [allNamespaces, setAllNamespaces] = useState([]);
@@ -53,7 +54,7 @@ const Jobs = () => {
5354
rowsPerPage: 10,
5455
});
5556
const [totalJobs, setTotalJobs] = useState(0);
56-
const [sortDirection, setSortDirection] = useState("desc");
57+
const [sortDirection, setSortDirection] = useState("");
5758

5859
const fetchJobs = useCallback(async () => {
5960
setLoading(true);
@@ -64,8 +65,6 @@ const Jobs = () => {
6465
`/api/jobs`,
6566
{
6667
params: {
67-
page: pagination.page,
68-
limit: pagination.rowsPerPage,
6968
search: searchText,
7069
namespace: filters.namespace,
7170
queue: filters.queue,
@@ -79,22 +78,28 @@ const Jobs = () => {
7978
}
8079

8180
const data = response.data;
82-
setJobs(data.items || []);
83-
setTotalJobs(data.totalCount || 0); // 更新 totalJobs
81+
setCachedJobs(data.items || []);
82+
setTotalJobs(data.totalCount || 0); // update totalJobs
8483
} catch (err) {
8584
setError("Failed to fetch jobs: " + err.message);
86-
setJobs([]);
85+
setCachedJobs([]);
8786
} finally {
8887
setLoading(false);
8988
}
90-
}, [pagination, searchText, filters]);
89+
}, [searchText, filters]);
9190

9291
useEffect(() => {
9392
fetchJobs();
9493
fetchAllNamespaces().then(setAllNamespaces);
9594
fetchAllQueues().then(setAllQueues);
9695
}, [fetchJobs]);
9796

97+
useEffect(() => {
98+
const startIndex = (pagination.page - 1) * pagination.rowsPerPage;
99+
const endIndex = startIndex + pagination.rowsPerPage;
100+
setJobs(cachedJobs.slice(startIndex, endIndex));
101+
}, [cachedJobs, pagination]);
102+
98103
const handleSearch = (event) => {
99104
setSearchText(event.target.value);
100105
setPagination((prev) => ({...prev, page: 1}));
@@ -179,7 +184,6 @@ const Jobs = () => {
179184
setFilters((prev) => ({...prev, [filterType]: value}));
180185
setAnchorEl((prev) => ({...prev, [filterType]: null}));
181186
setPagination((prev) => ({...prev, page: 1}));
182-
fetchJobs();
183187
}, [fetchJobs]);
184188

185189
const uniqueStatuses = useMemo(() => {
@@ -202,7 +206,7 @@ const Jobs = () => {
202206
}, [filteredJobs, sortDirection]);
203207

204208
const toggleSortDirection = useCallback(() => {
205-
setSortDirection((prev) => (prev === "desc" ? "asc" : "desc"));
209+
setSortDirection((prev) => (prev === "asc" ? "desc" : "asc"));
206210
}, []);
207211

208212
return (
@@ -323,7 +327,15 @@ const Jobs = () => {
323327
<Button
324328
size="small"
325329
onClick={toggleSortDirection}
326-
startIcon={sortDirection === "desc" ? <ArrowDownward/> : <ArrowUpward/>}
330+
startIcon={
331+
sortDirection === "desc" ? (
332+
<ArrowDownward/>
333+
) : sortDirection === "asc" ? (
334+
<ArrowUpward/>
335+
) : (
336+
<UnfoldMore/>
337+
)
338+
}
327339
sx={{textTransform: "none", padding: 0, minWidth: "auto"}}
328340
>
329341
Sort

frontend/src/components/Pods.jsx

+22-11
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ import {
2323
Typography,
2424
useTheme,
2525
} from "@mui/material";
26-
import {ArrowDownward, ArrowUpward, Clear, Error, FilterList, Refresh, Search} from "@mui/icons-material";
26+
import {ArrowDownward, ArrowUpward, Clear, Error, FilterList, Refresh, Search, UnfoldMore} from "@mui/icons-material";
2727
import axios from "axios";
2828
import {calculateAge, fetchAllNamespaces} from "./utils";
2929

3030
const Pods = () => {
3131
const [pods, setPods] = useState([]);
32+
const [cachedPods, setCachedPods] = useState([]);
3233
const [loading, setLoading] = useState(true);
3334
const [error, setError] = useState(null);
3435
const [allNamespaces, setAllNamespaces] = useState([]);
@@ -50,7 +51,7 @@ const Pods = () => {
5051
rowsPerPage: 10,
5152
});
5253
const [totalPods, setTotalPods] = useState(0);
53-
const [sortDirection, setSortDirection] = useState("desc");
54+
const [sortDirection, setSortDirection] = useState("");
5455

5556
const fetchPods = useCallback(async () => {
5657
setLoading(true);
@@ -61,11 +62,8 @@ const Pods = () => {
6162
`/api/pods`,
6263
{
6364
params: {
64-
page: pagination.page,
65-
limit: pagination.rowsPerPage,
6665
search: searchText,
6766
namespace: filters.namespace,
68-
queue: filters.queue,
6967
status: filters.status,
7068
},
7169
}
@@ -76,21 +74,27 @@ const Pods = () => {
7674
}
7775

7876
const data = response.data;
79-
setPods(data.items || []);
77+
setCachedPods(data.items || []);
8078
setTotalPods(data.totalCount || 0); // 更新 totalPods
8179
} catch (err) {
8280
setError("Failed to fetch pods: " + err.message);
83-
setPods([]);
81+
setCachedPods([]);
8482
} finally {
8583
setLoading(false);
8684
}
87-
}, [pagination, searchText, filters]);
85+
}, [searchText, filters]);
8886

8987
useEffect(() => {
9088
fetchPods();
9189
fetchAllNamespaces().then(setAllNamespaces);
9290
}, [fetchPods]);
9391

92+
useEffect(() => {
93+
const startIndex = (pagination.page - 1) * pagination.rowsPerPage;
94+
const endIndex = startIndex + pagination.rowsPerPage;
95+
setPods(cachedPods.slice(startIndex, endIndex));
96+
}, [cachedPods, pagination]);
97+
9498
const handleSearch = (event) => {
9599
setSearchText(event.target.value);
96100
setPagination((prev) => ({...prev, page: 1}));
@@ -175,7 +179,6 @@ const Pods = () => {
175179
setFilters((prev) => ({...prev, [filterType]: value}));
176180
setAnchorEl((prev) => ({...prev, [filterType]: null}));
177181
setPagination((prev) => ({...prev, page: 1}));
178-
fetchPods();
179182
}, [fetchPods]);
180183

181184
const uniqueStatuses = useMemo(() => {
@@ -198,7 +201,7 @@ const Pods = () => {
198201
}, [filteredPods, sortDirection]);
199202

200203
const toggleSortDirection = useCallback(() => {
201-
setSortDirection((prev) => (prev === "desc" ? "asc" : "desc"));
204+
setSortDirection((prev) => (prev === "asc" ? "desc" : "asc"));
202205
}, []);
203206

204207
return (
@@ -293,7 +296,15 @@ const Pods = () => {
293296
<Button
294297
size="small"
295298
onClick={toggleSortDirection}
296-
startIcon={sortDirection === "desc" ? <ArrowDownward/> : <ArrowUpward/>}
299+
startIcon={
300+
sortDirection === "desc" ? (
301+
<ArrowDownward/>
302+
) : sortDirection === "asc" ? (
303+
<ArrowUpward/>
304+
) : (
305+
<UnfoldMore/>
306+
)
307+
}
297308
sx={{textTransform: "none", padding: 0, minWidth: "auto"}}
298309
>
299310
Sort

frontend/src/components/Queues.jsx

-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ const Queues = () => {
172172
setFilters((prev) => ({...prev, [filterType]: value}));
173173
setAnchorEl((prev) => ({...prev, [filterType]: null}));
174174
setPagination((prev) => ({...prev, page: 1}));
175-
fetchQueues();
176175
}, [fetchQueues]);
177176

178177
const uniqueStates = useMemo(() => {

frontend/src/components/utils.js

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import {Error} from "@mui/icons-material";
2-
31
export const fetchAllNamespaces = async () => {
42
try {
53
const response = await fetch(`/api/namespaces`);

0 commit comments

Comments
 (0)