Migrated Heal and Watch pages to mds (#3016)
Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
@@ -16,116 +16,48 @@
|
||||
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import {
|
||||
FormControl,
|
||||
Grid,
|
||||
InputBase,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { IMessageEvent, w3cwebsocket as W3CWebSocket } from "websocket";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { Button, HealIcon, PageLayout } from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import { wsProtocol } from "../../../utils/wsUtils";
|
||||
import { colorH, HealStatus } from "./types";
|
||||
import { niceBytes } from "../../../common/utils";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
inlineCheckboxes,
|
||||
searchField,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
CONSOLE_UI_RESOURCE,
|
||||
IAM_SCOPES,
|
||||
} from "../../../common/SecureComponent/permissions";
|
||||
import CheckboxWrapper from "../Common/FormComponents/CheckboxWrapper/CheckboxWrapper";
|
||||
import { SecureComponent } from "../../../common/SecureComponent";
|
||||
import DistributedOnly from "../Common/DistributedOnly/DistributedOnly";
|
||||
import { selDistSet, setHelpName } from "../../../systemSlice";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Grid,
|
||||
HealIcon,
|
||||
InputBox,
|
||||
InputLabel,
|
||||
PageLayout,
|
||||
Select,
|
||||
} from "mds";
|
||||
import {
|
||||
Bar,
|
||||
BarChart,
|
||||
CartesianGrid,
|
||||
Legend,
|
||||
ResponsiveContainer,
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis,
|
||||
} from "recharts";
|
||||
import { Legend } from "recharts";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
|
||||
import { api } from "api";
|
||||
import { Bucket } from "api/consoleApi";
|
||||
import { errorToHandler } from "api/errors";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
graphContainer: {
|
||||
backgroundColor: "#fff",
|
||||
border: "#EAEDEE 1px solid",
|
||||
borderRadius: 3,
|
||||
padding: "19px 38px",
|
||||
marginTop: 15,
|
||||
},
|
||||
scanInfo: {
|
||||
marginTop: 20,
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
scanData: {
|
||||
fontSize: 13,
|
||||
},
|
||||
formBox: {
|
||||
padding: 15,
|
||||
border: "1px solid #EAEAEA",
|
||||
},
|
||||
buttonBar: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
},
|
||||
bucketField: {
|
||||
flex: 1,
|
||||
},
|
||||
prefixField: {
|
||||
...searchField.searchField,
|
||||
marginLeft: 10,
|
||||
flex: 1,
|
||||
},
|
||||
actionsTray: {
|
||||
...actionsTray.actionsTray,
|
||||
marginBottom: 0,
|
||||
},
|
||||
...inlineCheckboxes,
|
||||
...searchField,
|
||||
...containerForHeader,
|
||||
}),
|
||||
);
|
||||
|
||||
const SelectStyled = withStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
lineHeight: "50px",
|
||||
marginRight: 15,
|
||||
"label + &": {
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
"& .MuiSelect-select:focus": {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
},
|
||||
}),
|
||||
)(InputBase);
|
||||
import { wsProtocol } from "../../../utils/wsUtils";
|
||||
import { colorH, HealStatus } from "./types";
|
||||
import { niceBytes } from "../../../common/utils";
|
||||
import { modalStyleUtils } from "../Common/FormComponents/common/styleLibrary";
|
||||
import {
|
||||
CONSOLE_UI_RESOURCE,
|
||||
IAM_SCOPES,
|
||||
} from "../../../common/SecureComponent/permissions";
|
||||
import { selDistSet, setHelpName } from "../../../systemSlice";
|
||||
import { SecureComponent } from "../../../common/SecureComponent";
|
||||
import { useAppDispatch } from "../../../store";
|
||||
import DistributedOnly from "../Common/DistributedOnly/DistributedOnly";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
|
||||
const Heal = () => {
|
||||
const classes = useStyles();
|
||||
const distributedSetup = useSelector(selDistSet);
|
||||
|
||||
const [start, setStart] = useState(false);
|
||||
@@ -166,13 +98,13 @@ const Heal = () => {
|
||||
|
||||
// forceStart and forceStop need to be mutually exclusive
|
||||
useEffect(() => {
|
||||
if (forceStart === true) {
|
||||
if (forceStart) {
|
||||
setForceStop(false);
|
||||
}
|
||||
}, [forceStart]);
|
||||
|
||||
useEffect(() => {
|
||||
if (forceStop === true) {
|
||||
if (forceStop) {
|
||||
setForceStart(false);
|
||||
}
|
||||
}, [forceStop]);
|
||||
@@ -285,84 +217,81 @@ const Heal = () => {
|
||||
scopes={[IAM_SCOPES.ADMIN_HEAL]}
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
>
|
||||
<Grid xs={12} item className={classes.formBox}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<FormControl variant="outlined" className={classes.bucketField}>
|
||||
<Box withBorders>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex" as const,
|
||||
alignItems: "center",
|
||||
marginBottom: 15,
|
||||
gap: 15,
|
||||
}}
|
||||
>
|
||||
<Box sx={{ flexGrow: 1, width: "100%" }}>
|
||||
<InputLabel>Bucket</InputLabel>
|
||||
<Select
|
||||
label="Bucket"
|
||||
id="bucket-name"
|
||||
name="bucket-name"
|
||||
value={bucketName}
|
||||
onChange={(e) => {
|
||||
setBucketName(e.target.value as string);
|
||||
onChange={(value) => {
|
||||
setBucketName(value as string);
|
||||
}}
|
||||
className={classes.searchField}
|
||||
input={<SelectStyled />}
|
||||
displayEmpty
|
||||
>
|
||||
<MenuItem value="" key={`select-bucket-name-default`}>
|
||||
Select Bucket
|
||||
</MenuItem>
|
||||
{bucketNames.map((option) => (
|
||||
<MenuItem
|
||||
value={option.value}
|
||||
key={`select-bucket-name-${option.label}`}
|
||||
>
|
||||
{option.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
label="Prefix"
|
||||
className={classes.prefixField}
|
||||
id="prefix-resource"
|
||||
disabled={false}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setPrefix(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.inlineCheckboxes}>
|
||||
<CheckboxWrapper
|
||||
name="recursive"
|
||||
id="recursive"
|
||||
value="recursive"
|
||||
checked={recursive}
|
||||
onChange={(e) => {
|
||||
setRecursive(e.target.checked);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Recursive"
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
name="forceStart"
|
||||
id="forceStart"
|
||||
value="forceStart"
|
||||
checked={forceStart}
|
||||
onChange={(e) => {
|
||||
setForceStart(e.target.checked);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Force Start"
|
||||
/>
|
||||
<CheckboxWrapper
|
||||
name="forceStop"
|
||||
id="forceStop"
|
||||
value="forceStop"
|
||||
checked={forceStop}
|
||||
onChange={(e) => {
|
||||
setForceStop(e.target.checked);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Force Stop"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.buttonBar}>
|
||||
options={bucketNames}
|
||||
placeholder={"Select Bucket"}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ flexGrow: 1, width: "100%" }}>
|
||||
<InputLabel>Prefix</InputLabel>
|
||||
<InputBox
|
||||
id="prefix-resource"
|
||||
disabled={false}
|
||||
onChange={(e) => {
|
||||
setPrefix(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", gap: 20 }}>
|
||||
<Box>
|
||||
<Checkbox
|
||||
name="recursive"
|
||||
id="recursive"
|
||||
value="recursive"
|
||||
checked={recursive}
|
||||
onChange={() => {
|
||||
setRecursive(!recursive);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Recursive"
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Checkbox
|
||||
name="forceStart"
|
||||
id="forceStart"
|
||||
value="forceStart"
|
||||
checked={forceStart}
|
||||
onChange={() => {
|
||||
setForceStart(!forceStart);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Force Start"
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Checkbox
|
||||
name="forceStop"
|
||||
id="forceStop"
|
||||
value="forceStop"
|
||||
checked={forceStop}
|
||||
onChange={() => {
|
||||
setForceStop(!forceStop);
|
||||
}}
|
||||
disabled={false}
|
||||
label="Force Stop"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box sx={modalStyleUtils.modalButtonBar}>
|
||||
<Button
|
||||
id={"start-heal"}
|
||||
type="submit"
|
||||
@@ -372,9 +301,18 @@ const Heal = () => {
|
||||
onClick={() => setStart(true)}
|
||||
label={"Start"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12} className={classes.graphContainer}>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
withBorders
|
||||
sx={{
|
||||
marginTop: 15,
|
||||
'& ul li:not([class*="Mui"])::before': {
|
||||
listStyle: "none",
|
||||
content: "' '",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ResponsiveContainer width={"90%"} height={400}>
|
||||
<BarChart
|
||||
width={600}
|
||||
@@ -391,34 +329,48 @@ const Heal = () => {
|
||||
<XAxis dataKey="name" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend verticalAlign={"top"} layout={"vertical"} />
|
||||
<Legend
|
||||
verticalAlign={"top"}
|
||||
layout={"horizontal"}
|
||||
className={"noLi"}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="ah"
|
||||
name={"After Healing"}
|
||||
fill="rgba(0, 0, 255, 0.2)"
|
||||
stroke="rgba(0, 0, 255, 1)"
|
||||
fill="#2781B060"
|
||||
stroke="#2781B0"
|
||||
/>
|
||||
<Bar
|
||||
dataKey="bh"
|
||||
name={"Before Healing"}
|
||||
fill="rgba(153, 102, 255, 0.2)"
|
||||
stroke="rgba(153, 102, 255, 1)"
|
||||
fill="#C83B5160"
|
||||
stroke="#C83B51"
|
||||
/>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
<Grid item xs={12} className={classes.scanInfo}>
|
||||
<div className={classes.scanData}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sx={{
|
||||
marginTop: 20,
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
"& .scanData": {},
|
||||
}}
|
||||
>
|
||||
<Box className={"scanData"}>
|
||||
<strong>Size scanned:</strong> {hStatus.sizeScanned}
|
||||
</div>
|
||||
<div className={classes.scanData}>
|
||||
</Box>
|
||||
<Box className={"scanData"}>
|
||||
<strong>Objects healed:</strong> {hStatus.objectsHealed} /{" "}
|
||||
{hStatus.objectsScanned}
|
||||
</div>
|
||||
<div className={classes.scanData}>
|
||||
</Box>
|
||||
<Box className={"scanData"}>
|
||||
<strong>Healing time:</strong> {hStatus.healDuration}s
|
||||
</div>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</SecureComponent>
|
||||
)}
|
||||
</PageLayout>
|
||||
|
||||
@@ -13,83 +13,33 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
FormControl,
|
||||
Grid,
|
||||
InputBase,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
|
||||
import React, { useEffect, useState, Fragment } from "react";
|
||||
import { IMessageEvent, w3cwebsocket as W3CWebSocket } from "websocket";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Theme } from "@mui/material/styles";
|
||||
import { Button, PageLayout } from "mds";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
DataTable,
|
||||
Grid,
|
||||
InputBox,
|
||||
InputLabel,
|
||||
PageLayout,
|
||||
Select,
|
||||
} from "mds";
|
||||
import { AppState, useAppDispatch } from "../../../store";
|
||||
import { Bucket, BucketList, EventInfo } from "./types";
|
||||
import { niceBytes, timeFromDate } from "../../../common/utils";
|
||||
import { wsProtocol } from "../../../utils/wsUtils";
|
||||
import {
|
||||
actionsTray,
|
||||
containerForHeader,
|
||||
searchField,
|
||||
tableStyles,
|
||||
} from "../Common/FormComponents/common/styleLibrary";
|
||||
import { ErrorResponseHandler } from "../../../common/types";
|
||||
import TableWrapper from "../Common/TableWrapper/TableWrapper";
|
||||
import api from "../../../common/api";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import { watchMessageReceived, watchResetMessages } from "./watchSlice";
|
||||
import { setHelpName } from "../../../systemSlice";
|
||||
import api from "../../../common/api";
|
||||
import PageHeaderWrapper from "../Common/PageHeaderWrapper/PageHeaderWrapper";
|
||||
import HelpMenu from "../HelpMenu";
|
||||
import { setHelpName } from "../../../systemSlice";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
searchPrefix: {
|
||||
flexGrow: 1,
|
||||
marginLeft: 15,
|
||||
},
|
||||
watchTableHeight: {
|
||||
height: "calc(100vh - 270px)",
|
||||
},
|
||||
bucketField: {
|
||||
flexGrow: 2,
|
||||
minWidth: 200,
|
||||
},
|
||||
...tableStyles,
|
||||
...actionsTray,
|
||||
...searchField,
|
||||
...containerForHeader,
|
||||
}),
|
||||
);
|
||||
|
||||
const SelectStyled = withStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
lineHeight: "50px",
|
||||
"label + &": {
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
"& .MuiSelect-select:focus": {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
},
|
||||
input: {
|
||||
height: 50,
|
||||
fontSize: 13,
|
||||
lineHeight: "50px",
|
||||
},
|
||||
}),
|
||||
)(InputBase);
|
||||
|
||||
const Watch = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const classes = useStyles();
|
||||
|
||||
const messages = useSelector((state: AppState) => state.watch.messages);
|
||||
|
||||
const [start, setStart] = useState(false);
|
||||
@@ -177,89 +127,83 @@ const Watch = () => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<PageHeaderWrapper label="Watch" actions={<HelpMenu />} />
|
||||
const optionsArray = bucketNames.map((option) => ({
|
||||
label: option.label,
|
||||
value: option.value,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeaderWrapper label="Watch" actions={<HelpMenu />} />
|
||||
<PageLayout>
|
||||
<Grid container spacing={1} item xs={12}>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
<FormControl variant="outlined" className={classes.bucketField}>
|
||||
<Grid container>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: 10,
|
||||
marginBottom: 15,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<InputLabel>Bucket</InputLabel>
|
||||
<Select
|
||||
id="bucket-name"
|
||||
name="bucket-name"
|
||||
value={bucketName}
|
||||
onChange={(e) => {
|
||||
setBucketName(e.target.value as string);
|
||||
onChange={(value) => {
|
||||
setBucketName(value as string);
|
||||
}}
|
||||
className={classes.searchField}
|
||||
disabled={start}
|
||||
input={<SelectStyled />}
|
||||
>
|
||||
<MenuItem
|
||||
value={bucketName}
|
||||
key={`select-bucket-name-default`}
|
||||
disabled={true}
|
||||
>
|
||||
Select Bucket
|
||||
</MenuItem>
|
||||
{bucketNames.map((option) => (
|
||||
<MenuItem
|
||||
value={option.value}
|
||||
key={`select-bucket-name-${option.label}`}
|
||||
>
|
||||
{option.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
className={`${classes.searchField} ${classes.searchPrefix}`}
|
||||
id="prefix-resource"
|
||||
label="Prefix"
|
||||
disabled={start}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setPrefix(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
<TextField
|
||||
className={`${classes.searchField} ${classes.searchPrefix}`}
|
||||
id="suffix-resource"
|
||||
label="Suffix"
|
||||
disabled={start}
|
||||
InputProps={{
|
||||
disableUnderline: true,
|
||||
}}
|
||||
onChange={(e) => {
|
||||
setSuffix(e.target.value);
|
||||
}}
|
||||
variant="standard"
|
||||
/>
|
||||
{start ? (
|
||||
<Button
|
||||
id={"stop-watch"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
onClick={() => setStart(false)}
|
||||
label={"Stop"}
|
||||
options={optionsArray}
|
||||
placeholder={"Select Bucket"}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
id={"start-watch"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
onClick={() => setStart(true)}
|
||||
label={"Start"}
|
||||
</Box>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<InputLabel>Prefix</InputLabel>
|
||||
<InputBox
|
||||
id="prefix-resource"
|
||||
disabled={start}
|
||||
onChange={(e) => {
|
||||
setPrefix(e.target.value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<InputLabel>Suffix</InputLabel>
|
||||
<InputBox
|
||||
id="suffix-resource"
|
||||
disabled={start}
|
||||
onChange={(e) => {
|
||||
setSuffix(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ alignSelf: "flex-end", paddingBottom: 4 }}>
|
||||
{start ? (
|
||||
<Button
|
||||
id={"stop-watch"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
onClick={() => setStart(false)}
|
||||
label={"Stop"}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
id={"start-watch"}
|
||||
type="submit"
|
||||
variant="callAction"
|
||||
onClick={() => setStart(true)}
|
||||
label={"Start"}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} className={classes.tableBlock}>
|
||||
<TableWrapper
|
||||
<Grid item xs={12}>
|
||||
<DataTable
|
||||
columns={[
|
||||
{
|
||||
label: "Time",
|
||||
@@ -279,12 +223,12 @@ const Watch = () => {
|
||||
customEmptyMessage={"No Changes at this time"}
|
||||
idField={"watch_table"}
|
||||
isLoading={false}
|
||||
customPaperHeight={classes.watchTableHeight}
|
||||
customPaperHeight={"calc(100vh - 270px)"}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</PageLayout>
|
||||
</React.Fragment>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ export const deleteAllVersions =
|
||||
//----------------------------------------------------
|
||||
// Inputs
|
||||
//----------------------------------------------------
|
||||
export const bucketNameInput = Selector("#bucket-name");
|
||||
export const bucketNameInput = Selector("#bucket-name-select");
|
||||
export const bucketsPrefixInput = Selector("#prefix");
|
||||
export const bucketsAccessInput = Selector("div.selectContainer");
|
||||
export const bucketsAccessReadOnlyInput = Selector("li").withText("readonly");
|
||||
@@ -85,8 +85,7 @@ export const groupUserCheckbox = Selector(".ReactVirtualized__Table__row input")
|
||||
// Dropdowns and options
|
||||
//----------------------------------------------------
|
||||
export const bucketDropdownOptionFor = (modifier) => {
|
||||
return Selector("li").withAttribute(
|
||||
"data-value",
|
||||
return Selector("#bucket-name-options-selector li").withText(
|
||||
`${constants.TEST_BUCKET_NAME}-${modifier}`,
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user