Skip to content

Commit 75d5c92

Browse files
committed
create dialogue box for jobs/pods/queue creation
Signed-off-by: Shrutim1505 <[email protected]> format check create dialogue box for jobs/pods/queue creation Signed-off-by: Shrutim1505 <[email protected]> changed fields in create functionality Signed-off-by: Shrutim1505 <[email protected]> create funtionality for queues Signed-off-by: Shrutim1505 <[email protected]>
1 parent 40ca5bb commit 75d5c92

File tree

4 files changed

+441
-78
lines changed

4 files changed

+441
-78
lines changed
Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
import React, { useState } from "react";
2+
import {
3+
Dialog,
4+
DialogTitle,
5+
DialogContent,
6+
DialogActions,
7+
TextField,
8+
Box,
9+
FormControlLabel,
10+
Checkbox,
11+
IconButton,
12+
} from "@mui/material";
13+
import { Button } from "react-bootstrap";
14+
import { Plus } from "lucide-react";
15+
16+
/**
17+
* CreateQueueDialog
18+
* - Namespace removed (Queue is cluster‑scoped)
19+
* - Users can add arbitrary scalar resources via “+” button
20+
* (saved in an array of { key, value })
21+
*/
22+
const CreateQueueDialog = ({ open, onClose, onCreate }) => {
23+
const [queueData, setQueueData] = useState({
24+
name: "",
25+
weight: 1,
26+
reclaimable: true,
27+
guaranteed: { cpu: "", memory: "" },
28+
capability: { cpu: "", memory: "" },
29+
deserved: { cpu: "", memory: "" },
30+
scalars: [], // [{ key:"nvidia.com/gpu", value:"1" }]
31+
});
32+
33+
const primaryColor = "#E34C26";
34+
35+
const handleChange = (field) => (event) => {
36+
setQueueData((prev) => ({
37+
...prev,
38+
[field]:
39+
field === "weight"
40+
? parseInt(event.target.value, 10)
41+
: event.target.value,
42+
}));
43+
};
44+
45+
const handleResourceChange = (section, key) => (event) => {
46+
setQueueData((prev) => ({
47+
...prev,
48+
[section]: {
49+
...prev[section],
50+
[key]: event.target.value,
51+
},
52+
}));
53+
};
54+
55+
const handleCheckboxChange = (event) => {
56+
setQueueData((prev) => ({
57+
...prev,
58+
reclaimable: event.target.checked,
59+
}));
60+
};
61+
62+
// Scalar resources handlers
63+
const addScalar = () => {
64+
setQueueData((prev) => ({
65+
...prev,
66+
scalars: [...prev.scalars, { key: "", value: "" }],
67+
}));
68+
};
69+
70+
const handleScalarChange = (index, field) => (event) => {
71+
const newScalars = [...queueData.scalars];
72+
newScalars[index][field] = event.target.value;
73+
setQueueData((prev) => ({ ...prev, scalars: newScalars }));
74+
};
75+
76+
const handleSubmit = () => {
77+
if (!queueData.name.trim()) {
78+
alert("Queue name is required.");
79+
return;
80+
}
81+
82+
const specSection = {
83+
weight: queueData.weight,
84+
reclaimable: queueData.reclaimable,
85+
};
86+
87+
["guaranteed", "capability", "deserved"].forEach((section) => {
88+
const cpu = queueData[section].cpu.trim();
89+
const memory = queueData[section].memory.trim();
90+
if (cpu || memory) {
91+
specSection[section] = {};
92+
if (cpu) specSection[section].cpu = cpu;
93+
if (memory) specSection[section].memory = memory;
94+
}
95+
});
96+
97+
// Add scalar resources if any key/value present
98+
queueData.scalars.forEach(({ key, value }) => {
99+
const k = key.trim();
100+
const v = value.trim();
101+
if (!k || !v) return; // skip empty rows
102+
if (!specSection.guaranteed) specSection.guaranteed = {};
103+
specSection.guaranteed[k] = v; // put scalars under guaranteed by convention
104+
});
105+
106+
const newQueue = {
107+
apiVersion: "scheduling.volcano.sh/v1beta1",
108+
kind: "Queue",
109+
metadata: { name: queueData.name.trim() },
110+
spec: specSection,
111+
};
112+
113+
onCreate(newQueue);
114+
// reset form
115+
setQueueData({
116+
name: "",
117+
weight: 1,
118+
reclaimable: true,
119+
guaranteed: { cpu: "", memory: "" },
120+
capability: { cpu: "", memory: "" },
121+
deserved: { cpu: "", memory: "" },
122+
scalars: [],
123+
});
124+
onClose();
125+
};
126+
127+
const tfStyle = {
128+
"& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline":
129+
{
130+
borderColor: primaryColor,
131+
},
132+
"& .MuiInputLabel-root.Mui-focused": { color: primaryColor },
133+
};
134+
135+
return (
136+
<Dialog
137+
open={open}
138+
onClose={onClose}
139+
maxWidth="sm"
140+
fullWidth
141+
PaperProps={{
142+
style: {
143+
borderRadius: "12px",
144+
boxShadow: "0 8px 16px rgba(0, 0, 0, 0.1)",
145+
},
146+
}}
147+
>
148+
<DialogTitle sx={{ color: "#212529", fontWeight: 500, pb: 1 }}>
149+
Create Queue
150+
</DialogTitle>
151+
<DialogContent>
152+
<Box
153+
sx={{
154+
display: "flex",
155+
flexDirection: "column",
156+
gap: 2,
157+
mt: 1,
158+
}}
159+
>
160+
<TextField
161+
required
162+
label="Queue Name"
163+
value={queueData.name}
164+
onChange={handleChange("name")}
165+
fullWidth
166+
sx={tfStyle}
167+
/>
168+
<TextField
169+
label="Weight"
170+
type="number"
171+
value={queueData.weight}
172+
onChange={handleChange("weight")}
173+
fullWidth
174+
sx={tfStyle}
175+
/>
176+
<FormControlLabel
177+
control={
178+
<Checkbox
179+
checked={queueData.reclaimable}
180+
onChange={handleCheckboxChange}
181+
sx={{
182+
color: primaryColor,
183+
"&.Mui-checked": { color: primaryColor },
184+
}}
185+
/>
186+
}
187+
label="Reclaimable"
188+
/>
189+
190+
{/* Standard resources */}
191+
{["guaranteed", "capability", "deserved"].map((section) => (
192+
<Box key={section}>
193+
<Box sx={{ fontWeight: 500, mb: 1, color: "#555" }}>
194+
{section.charAt(0).toUpperCase() +
195+
section.slice(1)}{" "}
196+
Resources
197+
</Box>
198+
<Box sx={{ display: "flex", gap: 2 }}>
199+
<TextField
200+
label="CPU"
201+
value={queueData[section].cpu}
202+
onChange={handleResourceChange(
203+
section,
204+
"cpu",
205+
)}
206+
fullWidth
207+
placeholder="e.g. 1000m"
208+
sx={tfStyle}
209+
/>
210+
<TextField
211+
label="Memory"
212+
value={queueData[section].memory}
213+
onChange={handleResourceChange(
214+
section,
215+
"memory",
216+
)}
217+
fullWidth
218+
placeholder="e.g. 1Gi"
219+
sx={tfStyle}
220+
/>
221+
</Box>
222+
</Box>
223+
))}
224+
225+
{/* Scalar resources */}
226+
<Box>
227+
<Box
228+
sx={{
229+
display: "flex",
230+
alignItems: "center",
231+
mb: 1,
232+
}}
233+
>
234+
<Box
235+
sx={{
236+
fontWeight: 500,
237+
color: "#555",
238+
flexGrow: 1,
239+
}}
240+
>
241+
Custom Scalar Resources
242+
</Box>
243+
<IconButton
244+
size="small"
245+
onClick={addScalar}
246+
sx={{ color: primaryColor }}
247+
>
248+
<Plus size={20} />
249+
</IconButton>
250+
</Box>
251+
{queueData.scalars.map((scalar, idx) => (
252+
<Box
253+
key={idx}
254+
sx={{ display: "flex", gap: 2, mb: 1 }}
255+
>
256+
<TextField
257+
label="Key"
258+
value={scalar.key}
259+
onChange={handleScalarChange(idx, "key")}
260+
fullWidth
261+
placeholder="e.g. nvidia.com/gpu"
262+
sx={tfStyle}
263+
/>
264+
<TextField
265+
label="Value"
266+
value={scalar.value}
267+
onChange={handleScalarChange(idx, "value")}
268+
fullWidth
269+
placeholder="e.g. 1"
270+
sx={tfStyle}
271+
/>
272+
</Box>
273+
))}
274+
</Box>
275+
</Box>
276+
</DialogContent>
277+
<DialogActions>
278+
<Button
279+
onClick={onClose}
280+
style={{ backgroundColor: primaryColor, color: "white" }}
281+
>
282+
Cancel
283+
</Button>
284+
<Button
285+
onClick={handleSubmit}
286+
style={{ backgroundColor: primaryColor, color: "white" }}
287+
>
288+
Create
289+
</Button>
290+
</DialogActions>
291+
</Dialog>
292+
);
293+
};
294+
295+
export default CreateQueueDialog;

0 commit comments

Comments
 (0)