Skip to content

Commit 64ed1e1

Browse files
authored
[grid] UI Overview add sort by Platform, Status, ID in oder ASC|DESC (SeleniumHQ#14571)
1 parent a12b597 commit 64ed1e1

File tree

2 files changed

+127
-66
lines changed

2 files changed

+127
-66
lines changed

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

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,49 +24,48 @@ import OsLogo from '../common/OsLogo'
2424

2525
function Node (props) {
2626
const { node } = props
27-
const nodeStatusDown = node.status === 'DOWN'
27+
const getCardStyle = (status: string) => ({
28+
height: '100%',
29+
flexGrow: 1,
30+
opacity: status === 'DOWN' ? 0.25 : 1,
31+
bgcolor: (status === 'DOWN' || status === 'DRAINING') ? 'grey.A100' : ''
32+
})
2833

2934
return (
30-
<Card
31-
sx={{
32-
height: '100%',
33-
flexGrow: 1,
34-
bgcolor: nodeStatusDown ? 'grey.A100' : ''
35-
}}
36-
>
35+
<Card sx={getCardStyle(node.status)}>
3736
<CardContent sx={{ pl: 2, pr: 1 }}>
3837
<Grid
3938
container
40-
justifyContent='space-between'
39+
justifyContent="space-between"
4140
spacing={1}
4241
>
4342
<Grid item xs={10}>
4443
<Typography
45-
color='textPrimary'
44+
color="textPrimary"
4645
gutterBottom
47-
variant='h6'
46+
variant="h6"
4847
>
49-
<Box fontWeight='fontWeightBold' mr={1} display='inline'>
48+
<Box fontWeight="fontWeightBold" mr={1} display="inline">
5049
URI:
5150
</Box>
5251
{node.uri}
5352
</Typography>
5453
</Grid>
5554
<Grid item xs={2}>
5655
<Typography
57-
color='textPrimary'
56+
color="textPrimary"
5857
gutterBottom
59-
variant='h6'
58+
variant="h6"
6059
>
61-
<OsLogo osName={node.osInfo.name} />
62-
<NodeDetailsDialog node={node} />
60+
<OsLogo osName={node.osInfo.name}/>
61+
<NodeDetailsDialog node={node}/>
6362
</Typography>
6463
</Grid>
6564
<Grid item xs={12}>
66-
<Stereotypes stereotypes={node.slotStereotypes} />
65+
<Stereotypes stereotypes={node.slotStereotypes}/>
6766
</Grid>
6867
<Grid item xs={12}>
69-
<NodeLoad node={node} />
68+
<NodeLoad node={node}/>
7069
</Grid>
7170
</Grid>
7271
</CardContent>

javascript/grid-ui/src/screens/Overview/Overview.tsx

Lines changed: 110 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ import Grid from '@mui/material/Grid'
1919
import Paper from '@mui/material/Paper'
2020
import { loader } from 'graphql.macro'
2121
import React from 'react'
22+
import { useState, useEffect, useMemo } from 'react'
23+
import {
24+
Box,
25+
Checkbox,
26+
FormControl,
27+
FormControlLabel,
28+
InputLabel,
29+
MenuItem,
30+
Select
31+
} from '@mui/material'
2232
import Node from '../../components/Node/Node'
2333
import { useQuery } from '@apollo/client'
2434
import NodeInfo from '../../models/node-info'
@@ -30,85 +40,137 @@ import StereotypeInfo from '../../models/stereotype-info'
3040
import browserVersion from '../../util/browser-version'
3141
import Capabilities from '../../models/capabilities'
3242
import { GridConfig } from '../../config'
33-
import {NODES_QUERY} from "../../graphql/nodes";
43+
import { NODES_QUERY } from '../../graphql/nodes'
3444

3545
function Overview (): JSX.Element {
3646
const { loading, error, data } = useQuery(NODES_QUERY, {
3747
pollInterval: GridConfig.status.xhrPollingIntervalMillis,
3848
fetchPolicy: 'network-only'
3949
})
4050

51+
const [sortOption, setSortOption] = useState('osInfo.name')
52+
const [sortOrder, setSortOrder] = useState(1)
53+
const [sortedNodes, setSortedNodes] = useState<NodeInfo[]>([])
54+
const [isDescending, setIsDescending] = useState(false)
55+
56+
const handleSortChange = (event: React.ChangeEvent<{ value: unknown }>) => {
57+
setSortOption(event.target.value as string)
58+
}
59+
60+
const handleOrderChange = (event: React.ChangeEvent<HTMLInputElement>) => {
61+
setIsDescending(event.target.checked)
62+
setSortOrder(event.target.checked ? -1 : 1)
63+
}
64+
65+
const sortProperties = {
66+
'osInfo.name': (a, b) => a.osInfo.name.localeCompare(b.osInfo.name),
67+
'status': (a, b) => a.status.localeCompare(b.status),
68+
'id': (a, b) => (a.id < b.id ? -1 : 1)
69+
}
70+
71+
const sortNodes = useMemo(() => {
72+
return (nodes: NodeInfo[], option: string, order: number) => {
73+
const sortFn = sortProperties[option] || (() => 0)
74+
return nodes.sort((a, b) => order * sortFn(a, b))
75+
}
76+
}, [sortOption, sortOrder])
77+
78+
useEffect(() => {
79+
if (data) {
80+
const unSortedNodes = data.nodesInfo.nodes.map((node) => {
81+
const osInfo: OsInfo = {
82+
name: node.osInfo.name,
83+
version: node.osInfo.version,
84+
arch: node.osInfo.arch
85+
}
86+
87+
interface StereoTypeData {
88+
stereotype: Capabilities;
89+
slots: number;
90+
}
91+
92+
const slotStereotypes = (JSON.parse(
93+
node.stereotypes) as StereoTypeData[]).map((item) => {
94+
const slotStereotype: StereotypeInfo = {
95+
browserName: item.stereotype.browserName ?? '',
96+
browserVersion: browserVersion(
97+
item.stereotype.browserVersion ?? item.stereotype.version),
98+
platformName: (item.stereotype.platformName
99+
?? item.stereotype.platform) ?? '',
100+
slotCount: item.slots,
101+
rawData: item
102+
}
103+
return slotStereotype
104+
})
105+
106+
const newNode: NodeInfo = {
107+
uri: node.uri,
108+
id: node.id,
109+
status: node.status,
110+
maxSession: node.maxSession,
111+
slotCount: node.slotCount,
112+
version: node.version,
113+
osInfo: osInfo,
114+
sessionCount: node.sessionCount ?? 0,
115+
slotStereotypes: slotStereotypes
116+
}
117+
return newNode
118+
})
119+
120+
setSortedNodes(sortNodes(unSortedNodes, sortOption, sortOrder))
121+
}
122+
}, [data, sortOption, sortOrder])
123+
41124
if (error !== undefined) {
42125
const message = 'There has been an error while loading the Nodes from the Grid.'
43126
const errorMessage = error?.networkError?.message
44127
return (
45128
<Grid container spacing={3}>
46-
<Error message={message} errorMessage={errorMessage} />
129+
<Error message={message} errorMessage={errorMessage}/>
47130
</Grid>
48131
)
49132
}
50133

51134
if (loading) {
52135
return (
53136
<Grid container spacing={3}>
54-
<Loading />
137+
<Loading/>
55138
</Grid>
56139
)
57140
}
58141

59-
const unSortedNodes = data.nodesInfo.nodes.map((node) => {
60-
const osInfo: OsInfo = {
61-
name: node.osInfo.name,
62-
version: node.osInfo.version,
63-
arch: node.osInfo.arch
64-
}
65-
66-
interface StereoTypeData {
67-
stereotype: Capabilities
68-
slots: number
69-
}
70-
71-
const slotStereotypes = (JSON.parse(
72-
node.stereotypes) as StereoTypeData[]).map((item) => {
73-
const slotStereotype: StereotypeInfo = {
74-
browserName: item.stereotype.browserName ?? '',
75-
browserVersion: browserVersion(
76-
item.stereotype.browserVersion ?? item.stereotype.version),
77-
platformName: (item.stereotype.platformName ??
78-
item.stereotype.platform) ?? '',
79-
slotCount: item.slots,
80-
rawData: item
81-
}
82-
return slotStereotype
83-
})
84-
const newNode: NodeInfo = {
85-
uri: node.uri,
86-
id: node.id,
87-
status: node.status,
88-
maxSession: node.maxSession,
89-
slotCount: node.slotCount,
90-
version: node.version,
91-
osInfo: osInfo,
92-
sessionCount: node.sessionCount ?? 0,
93-
slotStereotypes: slotStereotypes
94-
}
95-
return newNode
96-
})
97-
98-
const nodes = unSortedNodes.sort((a, b) => (a.id < b.id ? -1 : 1))
99-
if (nodes.length === 0) {
142+
if (sortedNodes.length === 0) {
100143
const shortMessage = 'The Grid has no registered Nodes yet.'
101144
return (
102145
<Grid container spacing={3}>
103-
<NoData message={shortMessage} />
146+
<NoData message={shortMessage}/>
104147
</Grid>
105148
)
106149
}
107150

108151
return (
109152
<Grid container>
110-
{/* Nodes */}
111-
{nodes.map((node, index) => {
153+
<Grid item xs={12}
154+
style={{ display: 'flex', justifyContent: 'flex-start' }}>
155+
<FormControl variant="outlined" style={{ marginBottom: '16px' }}>
156+
<InputLabel>Sort By</InputLabel>
157+
<Box display="flex" alignItems="center">
158+
<Select value={sortOption} onChange={handleSortChange}
159+
label="Sort By" style={{ minWidth: '150px' }}>
160+
<MenuItem value="osInfo.name">Platform</MenuItem>
161+
<MenuItem value="status">Status</MenuItem>
162+
<MenuItem value="id">ID</MenuItem>
163+
</Select>
164+
<FormControlLabel
165+
control={<Checkbox checked={isDescending}
166+
onChange={handleOrderChange}/>}
167+
label="Descending"
168+
style={{ marginLeft: '8px' }}
169+
/>
170+
</Box>
171+
</FormControl>
172+
</Grid>
173+
{sortedNodes.map((node, index) => {
112174
return (
113175
<Grid
114176
item
@@ -127,7 +189,7 @@ function Overview (): JSX.Element {
127189
flexDirection: 'column'
128190
}}
129191
>
130-
<Node node={node} />
192+
<Node node={node}/>
131193
</Paper>
132194
</Grid>
133195
)

0 commit comments

Comments
 (0)