Changeset 92fafb3 for pages/dashboard/admin/+Page.tsx
- Timestamp:
- 02/19/26 20:33:50 (5 months ago)
- Branches:
- main
- Children:
- 2c7b9c8
- Parents:
- c586cbd (diff), 546a194 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - File:
-
- 1 edited
-
pages/dashboard/admin/+Page.tsx (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
pages/dashboard/admin/+Page.tsx
rc586cbd r92fafb3 1 1 import React, {useEffect, useState} from 'react'; 2 2 import { 3 Container, Grid,Paper, Typography, Box, Avatar, Divider, Button,3 Container, Paper, Typography, Box, Avatar, Divider, Button, 4 4 CircularProgress, Table, TableBody, TableCell, TableHead, TableRow, 5 5 Chip, IconButton, TextField, Dialog, DialogTitle, DialogContent, DialogActions … … 173 173 return ( 174 174 <Container maxWidth="xl" sx={{mt: 4, mb: 10}}> 175 <Grid container spacing={4}> 176 <Grid item xs={12} md={3}> 175 <Box sx={{ 176 display: 'grid', 177 gridTemplateColumns: { 178 xs: '1fr', 179 md: '300px 1fr' 180 }, 181 gap: 4 182 }}> 183 <Box> 177 184 <Paper elevation={3} sx={{ 178 185 p: 4, … … 216 223 </Box> 217 224 </Paper> 218 </Grid> 219 220 <Grid item xs={12} md={9}> 221 <Grid container spacing={4} direction="column"> 222 <Grid item xs={12}> 223 <Paper sx={{p: 3, borderLeft: '6px solid #9c27b0'}}> 224 <Box sx={{display: 'flex', alignItems: 'center', mb: 2}}> 225 <MemoryIcon color="secondary" sx={{mr: 1}}/> 226 <Typography variant="h6" fontWeight="bold"> 227 Component Suggestions ({data.componentSuggestions?.length || 0}) 228 </Typography> 229 </Box> 230 231 {data.componentSuggestions?.length === 0 ? ( 232 <Typography color="text.secondary">No suggestions.</Typography> 233 ) : ( 234 <Table size="small"> 235 <TableHead> 236 <TableRow> 237 <TableCell>Link/Description</TableCell> 238 <TableCell>Type</TableCell> 239 <TableCell>User</TableCell> 240 <TableCell>Status</TableCell> 241 <TableCell align="right">Actions</TableCell> 242 </TableRow> 243 </TableHead> 244 <TableBody> 245 {data.componentSuggestions?.map((sug: any) => ( 246 <TableRow key={sug.id}> 247 <TableCell sx={{maxWidth: 300}}> 248 <a 249 href={sug.link} 250 target="_blank" 251 rel="noopener noreferrer" 252 title={sug.link} 253 style={{textDecoration: 'none', color: 'inherit'}} 254 > 255 {sug.description || sug.link} 256 </a> 257 </TableCell> 258 <TableCell>{sug.componentType?.toUpperCase()}</TableCell> 259 <TableCell>{sug.userId}</TableCell> 260 <TableCell> 261 <Chip 262 label={sug.status || 'pending'} 225 </Box> 226 227 <Box sx={{ 228 display: 'flex', 229 flexDirection: 'column', 230 gap: 4 231 }}> 232 <Paper sx={{p: 3, borderLeft: '6px solid #9c27b0'}}> 233 <Box sx={{display: 'flex', alignItems: 'center', mb: 2}}> 234 <MemoryIcon color="secondary" sx={{mr: 1}}/> 235 <Typography variant="h6" fontWeight="bold"> 236 Component Suggestions ({data.componentSuggestions?.length || 0}) 237 </Typography> 238 </Box> 239 240 {data.componentSuggestions?.length === 0 ? ( 241 <Typography color="text.secondary">No suggestions.</Typography> 242 ) : ( 243 <Box sx={{width: '100%', overflowX: 'auto'}}> 244 <Table size="small"> 245 <TableHead> 246 <TableRow> 247 <TableCell>Link/Description</TableCell> 248 <TableCell>Type</TableCell> 249 <TableCell>User</TableCell> 250 <TableCell>Status</TableCell> 251 <TableCell align="right">Actions</TableCell> 252 </TableRow> 253 </TableHead> 254 <TableBody> 255 {data.componentSuggestions?.map((sug: any) => ( 256 <TableRow key={sug.id}> 257 <TableCell sx={{minWidth: 200, maxWidth: 300}}> 258 <a 259 href={sug.link} 260 target="_blank" 261 rel="noopener noreferrer" 262 title={sug.link} 263 style={{textDecoration: 'none', color: 'inherit'}} 264 > 265 {sug.description || sug.link} 266 </a> 267 </TableCell> 268 <TableCell sx={{minWidth: 80}}> 269 {sug.componentType?.toUpperCase()} 270 </TableCell> 271 <TableCell sx={{minWidth: 100}}> 272 {sug.user?.username || `${sug.userId}`} 273 </TableCell> 274 <TableCell sx={{minWidth: 100}}> 275 <Chip 276 label={sug.status || 'pending'} 277 size="small" 278 color={ 279 sug.status === 'approved' ? 'success' : 280 sug.status === 'rejected' ? 'error' : 281 'default' 282 } 283 /> 284 </TableCell> 285 <TableCell align="right" sx={{minWidth: 150}}> 286 {sug.status === 'pending' ? ( 287 <> 288 <IconButton 289 size="small" 290 color="success" 291 onClick={() => openSuggestionReview(sug.id, 'approved')} 292 > 293 <CheckCircleIcon/> 294 </IconButton> 295 <IconButton 296 size="small" 297 color="error" 298 onClick={() => openSuggestionReview(sug.id, 'rejected')} 299 > 300 <CancelIcon/> 301 </IconButton> 302 </> 303 ) : sug.status === 'approved' ? ( 304 <Button 263 305 size="small" 264 color={265 sug.status === 'approved' ? 'success' :266 sug.status === 'rejected' ? 'error' :267 'default'268 }269 />270 </TableCell>271 <TableCell align="right">272 {sug.status === 'pending' ? (273 <>274 <IconButton275 size="small"276 color="success"277 onClick={() => openSuggestionReview(sug.id, 'approved')}278 >279 <CheckCircleIcon/>280 </IconButton>281 <IconButton282 size="small"283 color="error"284 onClick={() => openSuggestionReview(sug.id, 'rejected')}285 >286 <CancelIcon/>287 </IconButton>288 </>289 ) : sug.status === 'approved' ? (290 <Button291 size="small"292 variant="contained"293 color="warning"294 startIcon={<AddIcon/>}295 onClick={() => setCreateComponentDialog({296 open: true,297 suggestion: sug298 })}299 >300 Create301 </Button>302 ) : (303 <Typography variant="caption" color="text.secondary">304 {sug.adminComment || 'Rejected'}305 </Typography>306 )}307 </TableCell>308 </TableRow>309 ))}310 </TableBody>311 </Table>312 )}313 </Paper>314 </Grid>315 316 <Grid item xs={12}>317 <Paper sx={{p: 3, borderLeft: '6px solid #ed6c02', bgcolor: '#121212'}}>318 <Box sx={{display: 'flex', alignItems: 'center', mb: 2}}>319 <BuildIcon color="warning" sx={{mr: 1}}/>320 <Typography variant="h6" fontWeight="bold">321 Builds Waiting for Approval ({data.pendingBuilds?.length || 0})322 </Typography>323 </Box>324 325 {data.pendingBuilds?.length === 0 ? (326 <Typography color="text.secondary">No pending builds.</Typography>327 ) : (328 <Grid container spacing={2}>329 {data.pendingBuilds.map((build: any) => (330 <Grid item xs={12} sm={6} md={4} lg={3} key={build.id}>331 <Box sx={{position: 'relative'}}>332 <BuildCard333 build={build}334 onClick={() => setSelectedBuildId(build.id)}335 />336 <Box sx={{337 mt: 1,338 display: 'flex',339 gap: 1,340 justifyContent: 'center'341 }}>342 <Button343 306 variant="contained" 344 307 color="warning" 345 size="small" 346 startIcon={<BuildIcon/>} 347 onClick={(e) => { 348 e.stopPropagation(); 349 openBuildApproval(build.id, build.name); 350 }} 308 startIcon={<AddIcon/>} 309 onClick={() => setCreateComponentDialog({ 310 open: true, 311 suggestion: sug 312 })} 351 313 > 352 Review314 Create 353 315 </Button> 354 </Box> 355 </Box> 356 </Grid> 316 ) : ( 317 <Typography variant="caption" color="text.secondary"> 318 {sug.adminComment || 'Rejected'} 319 </Typography> 320 )} 321 </TableCell> 322 </TableRow> 357 323 ))} 358 </Grid> 359 )} 360 </Paper> 361 </Grid> 362 363 <Grid item xs={12}> 364 <Paper sx={{p: 3, borderLeft: '6px solid #2e7d32'}}> 365 <Typography variant="h6" fontWeight="bold" gutterBottom> 366 My Builds / Sandbox 367 </Typography> 368 {data.userBuilds?.length === 0 ? ( 369 <Typography color="text.secondary">No builds created by admin.</Typography> 370 ) : ( 371 <Grid container spacing={2}> 372 {data.userBuilds.slice(0, 4).map((build: any) => ( 373 <Grid item xs={12} sm={6} md={4} lg={3} key={build.id}> 374 <Box sx={{position: 'relative'}}> 375 <BuildCard 376 build={build} 377 onClick={() => setSelectedBuildId(build.id)} 378 /> 379 <Box sx={{mt: 1, display: 'flex', justifyContent: 'center'}}> 380 <Button 381 variant="outlined" 382 color="error" 383 size="small" 384 startIcon={<DeleteIcon/>} 385 onClick={(e) => { 386 e.stopPropagation(); 387 openDeleteDialog(build.id, build.name); 388 }} 389 fullWidth 390 > 391 Delete 392 </Button> 393 </Box> 394 </Box> 395 </Grid> 396 ))} 397 </Grid> 398 )} 399 </Paper> 400 </Grid> 401 </Grid> 402 </Grid> 403 </Grid> 324 </TableBody> 325 </Table> 326 </Box> 327 )} 328 </Paper> 329 330 <Paper sx={{p: 3, borderLeft: '6px solid #ed6c02', bgcolor: '#121212'}}> 331 <Box sx={{display: 'flex', alignItems: 'center', mb: 2}}> 332 <BuildIcon color="warning" sx={{mr: 1}}/> 333 <Typography variant="h6" fontWeight="bold"> 334 Builds Waiting for Approval ({data.pendingBuilds?.length || 0}) 335 </Typography> 336 </Box> 337 338 {data.pendingBuilds?.length === 0 ? ( 339 <Typography color="text.secondary">No pending builds.</Typography> 340 ) : ( 341 <Box sx={{ 342 display: 'grid', 343 gridTemplateColumns: { 344 xs: '1fr', 345 sm: 'repeat(2, 1fr)', 346 lg: 'repeat(3, 1fr)', 347 xl: 'repeat(4, 1fr)' 348 }, 349 gap: 2 350 }}> 351 {data.pendingBuilds.map((build: any) => ( 352 <Box key={build.id}> 353 <BuildCard 354 build={build} 355 onClick={() => setSelectedBuildId(build.id)} 356 /> 357 <Box sx={{mt: 1, display: 'flex', gap: 1, justifyContent: 'center'}}> 358 <Button 359 variant="contained" 360 color="warning" 361 size="small" 362 startIcon={<BuildIcon/>} 363 onClick={(e) => { 364 e.stopPropagation(); 365 openBuildApproval(build.id, build.name); 366 }} 367 > 368 Review 369 </Button> 370 </Box> 371 </Box> 372 ))} 373 </Box> 374 )} 375 </Paper> 376 377 <Paper sx={{p: 3, borderLeft: '6px solid #2e7d32'}}> 378 <Typography variant="h6" fontWeight="bold" gutterBottom> 379 My Builds / Sandbox 380 </Typography> 381 {data.userBuilds?.length === 0 ? ( 382 <Typography color="text.secondary">No builds created by admin.</Typography> 383 ) : ( 384 <Box sx={{ 385 display: 'grid', 386 gridTemplateColumns: { 387 xs: '1fr', 388 sm: 'repeat(2, 1fr)', 389 lg: 'repeat(3, 1fr)', 390 xl: 'repeat(4, 1fr)' 391 }, 392 gap: 2 393 }}> 394 {data.userBuilds.slice(0, 4).map((build: any) => ( 395 <Box key={build.id}> 396 <BuildCard 397 build={build} 398 onClick={() => setSelectedBuildId(build.id)} 399 /> 400 <Box sx={{mt: 1, display: 'flex', justifyContent: 'center'}}> 401 <Button 402 variant="outlined" 403 color="error" 404 size="small" 405 startIcon={<DeleteIcon/>} 406 onClick={(e) => { 407 e.stopPropagation(); 408 openDeleteDialog(build.id, build.name); 409 }} 410 fullWidth 411 > 412 Delete 413 </Button> 414 </Box> 415 </Box> 416 ))} 417 </Box> 418 )} 419 </Paper> 420 </Box> 421 </Box> 404 422 405 423 <Dialog open={suggestionDialog.open} … … 520 538 <AddComponentDialog 521 539 open={createComponentDialog.open} 522 onClose={() => setCreateComponentDialog({ open: false, suggestion: null})}540 onClose={() => setCreateComponentDialog({open: false, suggestion: null})} 523 541 onSuccess={() => { 524 542 loadData(); 525 setCreateComponentDialog({ open: false, suggestion: null});543 setCreateComponentDialog({open: false, suggestion: null}); 526 544 }} 527 545 prefillData={createComponentDialog.suggestion ? {
Note:
See TracChangeset
for help on using the changeset viewer.
