Skip to content

Commit 71e6751

Browse files
committed
[grid] Displaying a message when no Sessions or Nodes are present (UI)
1 parent 57a4ac8 commit 71e6751

File tree

7 files changed

+217
-121
lines changed

7 files changed

+217
-121
lines changed

javascript/grid-ui/src/components/NavBar/NavBar.tsx

+42-25
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import {makeStyles} from '@material-ui/core/styles';
99
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
1010
import DashboardIcon from "@material-ui/icons/Dashboard";
1111
import AssessmentIcon from '@material-ui/icons/Assessment';
12+
import HelpIcon from '@material-ui/icons/Help';
1213
import clsx from 'clsx';
1314
import * as React from 'react';
1415
import {Box, CircularProgress, CircularProgressProps, Typography} from "@material-ui/core";
16+
import {useLocation} from "react-router-dom";
1517

1618
const drawerWidth = 240;
1719

@@ -82,9 +84,15 @@ function CircularProgressWithLabel(props: CircularProgressProps & { value: numbe
8284

8385
export default function NavBar(props) {
8486
const classes = useStyles();
85-
const {open, maxSession, sessionCount} = props;
87+
const {open, maxSession, sessionCount, nodeCount} = props;
8688
const currentLoad = Math.min(((sessionCount / maxSession) * 100), 100);
8789

90+
const location = useLocation();
91+
// Not showing the overall status when the user is on the Overview page and there is only one node, because polling
92+
// is not happening at the same time and it could be confusing for the user. So, displaying it when there is more
93+
// than one node, or when the user is on a different page and there is at least one node registered.
94+
const showOverallConcurrency = nodeCount > 1 || (location.pathname !== "/" && nodeCount > 0);
95+
8896
return (
8997
<Drawer
9098
variant="permanent"
@@ -113,36 +121,45 @@ export default function NavBar(props) {
113121
</ListItemIcon>
114122
<ListItemText primary="Sessions"/>
115123
</ListItemLink>
124+
<ListItemLink href={"#help"}>
125+
<ListItemIcon>
126+
<HelpIcon/>
127+
</ListItemIcon>
128+
<ListItemText primary="Help"/>
129+
</ListItemLink>
116130
</div>
117131
</List>
118132
<Box flexGrow={1}/>
119-
<Box
120-
p={2}
121-
m={2}
122-
className={classes.concurrencyBackground}
123-
>
124-
<Typography
125-
align="center"
126-
gutterBottom
127-
variant="h4"
128-
>
129-
Concurrency
130-
</Typography>
133+
{showOverallConcurrency && (
131134
<Box
132-
display="flex"
133-
justifyContent="center"
134-
mt={2}
135-
mb={2}
135+
p={2}
136+
m={2}
137+
className={classes.concurrencyBackground}
136138
>
137-
<CircularProgressWithLabel value={currentLoad}/>
139+
<Typography
140+
align="center"
141+
gutterBottom
142+
variant="h4"
143+
>
144+
Concurrency
145+
</Typography>
146+
<Box
147+
display="flex"
148+
justifyContent="center"
149+
mt={2}
150+
mb={2}
151+
>
152+
<CircularProgressWithLabel value={currentLoad}/>
153+
</Box>
154+
<Typography
155+
align="center"
156+
variant="h4"
157+
>
158+
{sessionCount} / {maxSession}
159+
</Typography>
138160
</Box>
139-
<Typography
140-
align="center"
141-
variant="h4"
142-
>
143-
{sessionCount} / {maxSession}
144-
</Typography>
145-
</Box>
161+
162+
)}
146163
</Drawer>
147164
);
148165
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as React from 'react';
2+
import {Box, Container, Link, Typography} from "@material-ui/core";
3+
import {makeStyles} from "@material-ui/core/styles";
4+
5+
const useStyles = makeStyles((theme) => ({
6+
root: {
7+
backgroundColor: theme.palette.secondary.main,
8+
height: '100%',
9+
paddingBottom: theme.spacing(3),
10+
paddingTop: theme.spacing(3),
11+
width: '100%',
12+
justifyContent: "center",
13+
},
14+
}));
15+
16+
export default function NoData(props) {
17+
const classes = useStyles();
18+
const {message} = props;
19+
20+
// noinspection HtmlUnknownAnchorTarget
21+
return (
22+
<div className={classes.root}>
23+
<Box
24+
display="flex"
25+
flexDirection="column"
26+
height="100%"
27+
justifyContent="center"
28+
>
29+
<Container maxWidth="md">
30+
<Typography
31+
align="center"
32+
color="textPrimary"
33+
variant="h1"
34+
>
35+
{message}
36+
</Typography>
37+
<Typography
38+
align="center"
39+
color="textPrimary"
40+
variant="h4"
41+
>
42+
More information about Selenium Grid can be found at the{' '}
43+
<Link href="#help">
44+
Help
45+
</Link>
46+
{' '}section.
47+
</Typography>
48+
</Container>
49+
</Box>
50+
</div>
51+
);
52+
}

javascript/grid-ui/src/components/RunningSessions/RunningSessions.tsx

+99-94
Original file line numberDiff line numberDiff line change
@@ -268,58 +268,43 @@ export default function RunningSessions(props) {
268268

269269
return (
270270
<div className={classes.root}>
271-
<Paper className={classes.paper}>
272-
<EnhancedTableToolbar title={"Running"}/>
273-
<TableContainer>
274-
<Table
275-
className={classes.table}
276-
aria-labelledby="tableTitle"
277-
size={dense ? 'small' : 'medium'}
278-
aria-label="enhanced table"
279-
>
280-
<EnhancedTableHead
281-
classes={classes}
282-
order={order}
283-
orderBy={orderBy}
284-
onRequestSort={handleRequestSort}
285-
/>
286-
<TableBody>
287-
{stableSort(rows, getComparator(order, orderBy))
288-
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
289-
.map((row, index) => {
290-
const isItemSelected = isSelected(row.id as string);
291-
const labelId = `enhanced-table-checkbox-${index}`;
292-
return (
293-
<TableRow
294-
hover
295-
onClick={(event) => handleClick(event, row.id as string)}
296-
role="checkbox"
297-
aria-checked={isItemSelected}
298-
tabIndex={-1}
299-
key={row.id}
300-
selected={isItemSelected}
301-
>
302-
<TableCell component="th" id={labelId} scope="row">
303-
{row.id}
304-
</TableCell>
305-
<TableCell align="right">
306-
<img
307-
src={osLogo(row.platformName as string)}
308-
className={classes.logo}
309-
alt="OS Logo"
310-
/>
311-
<img
312-
src={browserLogo(row.browserName as string)}
313-
className={classes.logo}
314-
alt="Browser Logo"
315-
/>
316-
{browserVersion(row.browserVersion as string)}
317-
<IconButton className={classes.buttonMargin} onClick={() => handleDialogOpen(row.id as string)}>
318-
<InfoIcon/>
319-
</IconButton>
320-
<Dialog onClose={handleDialogClose} aria-labelledby="session-info-dialog"
321-
open={rowOpen === row.id}>
322-
<DialogTitle id="session-info-dialog">
271+
{rows.length > 0 && (
272+
<div>
273+
<Paper className={classes.paper}>
274+
<EnhancedTableToolbar title={"Running"}/>
275+
<TableContainer>
276+
<Table
277+
className={classes.table}
278+
aria-labelledby="tableTitle"
279+
size={dense ? 'small' : 'medium'}
280+
aria-label="enhanced table"
281+
>
282+
<EnhancedTableHead
283+
classes={classes}
284+
order={order}
285+
orderBy={orderBy}
286+
onRequestSort={handleRequestSort}
287+
/>
288+
<TableBody>
289+
{stableSort(rows, getComparator(order, orderBy))
290+
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
291+
.map((row, index) => {
292+
const isItemSelected = isSelected(row.id as string);
293+
const labelId = `enhanced-table-checkbox-${index}`;
294+
return (
295+
<TableRow
296+
hover
297+
onClick={(event) => handleClick(event, row.id as string)}
298+
role="checkbox"
299+
aria-checked={isItemSelected}
300+
tabIndex={-1}
301+
key={row.id}
302+
selected={isItemSelected}
303+
>
304+
<TableCell component="th" id={labelId} scope="row">
305+
{row.id}
306+
</TableCell>
307+
<TableCell align="right">
323308
<img
324309
src={osLogo(row.platformName as string)}
325310
className={classes.logo}
@@ -331,52 +316,72 @@ export default function RunningSessions(props) {
331316
alt="Browser Logo"
332317
/>
333318
{browserVersion(row.browserVersion as string)}
334-
</DialogTitle>
335-
<DialogContent dividers>
336-
<Typography gutterBottom>
337-
Capabilities:
338-
</Typography>
339-
<Typography gutterBottom component={'span'}>
319+
<IconButton className={classes.buttonMargin}
320+
onClick={() => handleDialogOpen(row.id as string)}>
321+
<InfoIcon/>
322+
</IconButton>
323+
<Dialog onClose={handleDialogClose} aria-labelledby="session-info-dialog"
324+
open={rowOpen === row.id}>
325+
<DialogTitle id="session-info-dialog">
326+
<img
327+
src={osLogo(row.platformName as string)}
328+
className={classes.logo}
329+
alt="OS Logo"
330+
/>
331+
<img
332+
src={browserLogo(row.browserName as string)}
333+
className={classes.logo}
334+
alt="Browser Logo"
335+
/>
336+
{browserVersion(row.browserVersion as string)}
337+
</DialogTitle>
338+
<DialogContent dividers>
339+
<Typography gutterBottom>
340+
Capabilities:
341+
</Typography>
342+
<Typography gutterBottom component={'span'}>
340343
<pre>
341344
{JSON.stringify(JSON.parse(row.rawCapabilities as string), null, 2)}
342345
</pre>
343-
</Typography>
344-
</DialogContent>
345-
<DialogActions>
346-
<Button onClick={handleDialogClose} color="primary" variant="outlined">
347-
Close
348-
</Button>
349-
</DialogActions>
350-
</Dialog>
351-
</TableCell>
352-
<TableCell align="right">{row.startTime}</TableCell>
353-
<TableCell align="right">{row.sessionDurationMillis}</TableCell>
354-
<TableCell align="right">{row.nodeUri}</TableCell>
346+
</Typography>
347+
</DialogContent>
348+
<DialogActions>
349+
<Button onClick={handleDialogClose} color="primary" variant="outlined">
350+
Close
351+
</Button>
352+
</DialogActions>
353+
</Dialog>
354+
</TableCell>
355+
<TableCell align="right">{row.startTime}</TableCell>
356+
<TableCell align="right">{row.sessionDurationMillis}</TableCell>
357+
<TableCell align="right">{row.nodeUri}</TableCell>
358+
</TableRow>
359+
);
360+
})}
361+
{emptyRows > 0 && (
362+
<TableRow style={{height: (dense ? 33 : 53) * emptyRows}}>
363+
<TableCell colSpan={6}/>
355364
</TableRow>
356-
);
357-
})}
358-
{emptyRows > 0 && (
359-
<TableRow style={{height: (dense ? 33 : 53) * emptyRows}}>
360-
<TableCell colSpan={6}/>
361-
</TableRow>
362-
)}
363-
</TableBody>
364-
</Table>
365-
</TableContainer>
366-
<TablePagination
367-
rowsPerPageOptions={[5, 10, 15]}
368-
component="div"
369-
count={rows.length}
370-
rowsPerPage={rowsPerPage}
371-
page={page}
372-
onChangePage={handleChangePage}
373-
onChangeRowsPerPage={handleChangeRowsPerPage}
374-
/>
375-
</Paper>
376-
<FormControlLabel
377-
control={<Switch checked={dense} onChange={handleChangeDense}/>}
378-
label="Dense padding"
379-
/>
365+
)}
366+
</TableBody>
367+
</Table>
368+
</TableContainer>
369+
<TablePagination
370+
rowsPerPageOptions={[5, 10, 15]}
371+
component="div"
372+
count={rows.length}
373+
rowsPerPage={rowsPerPage}
374+
page={page}
375+
onChangePage={handleChangePage}
376+
onChangeRowsPerPage={handleChangeRowsPerPage}
377+
/>
378+
</Paper>
379+
<FormControlLabel
380+
control={<Switch checked={dense} onChange={handleChangeDense}/>}
381+
label="Dense padding"
382+
/>
383+
</div>
384+
)}
380385
</div>
381386
);
382387
}

javascript/grid-ui/src/components/TopBar/TopBar.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,9 @@ export default function TopBar() {
7171
if (error) return <p>`Error! ${error.message}`</p>;
7272

7373
const gridVersion = data.grid.version;
74-
const maxSession = data.grid.maxSession;
74+
const maxSession = data.grid.maxSession ?? 0;
7575
const sessionCount = data.grid.sessionCount ?? 0;
76+
const nodeCount = data.grid.nodeCount ?? 0;
7677

7778
return (
7879
<div className={classes.root}>
@@ -123,7 +124,7 @@ export default function TopBar() {
123124
</Box>
124125
</Toolbar>
125126
</AppBar>
126-
<NavBar open={open} maxSession={maxSession} sessionCount={sessionCount}/>
127+
<NavBar open={open} maxSession={maxSession} sessionCount={sessionCount} nodeCount={nodeCount}/>
127128
</div>
128129
);
129130
}

javascript/grid-ui/src/graphql/grid.gql

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ query Summary {
22
grid {
33
uri
44
totalSlots
5+
nodeCount
56
maxSession
67
sessionCount
78
sessionQueueSize

0 commit comments

Comments
 (0)