@ant-design/icons#EyeInvisibleOutlined JavaScript Examples
The following examples show how to use
@ant-design/icons#EyeInvisibleOutlined.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Relations.js From label-studio-frontend with Apache License 2.0 | 6 votes |
RelationsComponent = ({ store }) => {
const annotation = store.annotationStore.selected;
const { relations } = annotation.relationStore;
const hasRelations = relations.length > 0;
const relationsUIVisible = annotation.relationStore.showConnections;
return (
<Block name="relations">
{/* override LS styles' height */}
<Elem name="header">
<Elem name="title">Relations ({relations.length})</Elem>
{hasRelations && (
<Button
size="small"
type="link"
icon={relationsUIVisible ? <EyeInvisibleOutlined /> : <EyeOutlined />}
onClick={() => annotation.relationStore.toggleConnections()}
className={[relationsUIVisible ? styles.uihidden : styles.uivisible, globalStyles.link]}
/>
)}
</Elem>
<Elem name="content">
{hasRelations ? (
<List
size="small"
bordered
itemLayout="vertical"
className={styles.list}
dataSource={annotation.relationStore.relations}
renderItem={item => <ListItem item={item} />}
/>
) : (
<p>No Relations added yet</p>
)}
</Elem>
</Block>
);
}
Example #2
Source File: password-input.jsx From virtuoso-design-system with MIT License | 6 votes |
storiesOf('antd/Input', module).add('password-input', () =>
<Space direction="vertical">
<Input.Password placeholder="input password" />
<Input.Password
placeholder="input password"
iconRender={visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)}
/>
</Space>,
{ docs: { page: () => (<><h1 id="enus">en-US</h1>
<p>Input type of password.</p></>) } });
Example #3
Source File: Login.js From Peppermint with GNU General Public License v3.0 | 5 votes |
Login = () => {
const history = useHistory();
const [password, setPassword] = useState("");
const [email, setEmail] = useState("");
const { signin } = useContext(GlobalContext);
const onSubmit = async () => {
signin(email, password);
};
return (
<div>
<Form
style={{ position: "absolute" }}
name="normal_login"
className="login-form"
initialValues={{
remember: true,
}}
>
<div className="logo-login">
<Image alt="logo" src={logo} width={300} preview={false} />
</div>
<Form.Item
name="username"
rules={[
{
required: true,
message: "Please input your Email!",
},
]}
>
<Input
style={{ width: 300 }}
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
/>
</Form.Item>
<Form.Item
name="password"
rules={[
{
required: true,
message: "Please input your Password!",
},
]}
>
<Input.Password
style={{ width: 300 }}
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Password"
iconRender={(visible) =>
visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />
}
onChange={(e) => setPassword(e.target.value)}
/>
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
className="login-form-button"
onClick={() => {
onSubmit();
setTimeout(() => history.push("/"), 1000);
}}
>
Log in
</Button>
</Form.Item>
</Form>
</div>
);
}
Example #4
Source File: Predictions.js From label-studio-frontend with Apache License 2.0 | 5 votes |
Prediction = observer(({ item, store }) => {
const toggleVisibility = e => {
e.preventDefault();
e.stopPropagation();
item.toggleVisibility();
const c = document.getElementById(`c-${item.id}`);
if (c) c.style.display = item.hidden ? "none" : "unset";
};
const highlight = () => {
const c = document.getElementById(`c-${item.id}`);
if (c) c.classList.add("hover");
};
const unhighlight = () => {
const c = document.getElementById(`c-${item.id}`);
if (c) c.classList.remove("hover");
};
return (
<List.Item
key={item.id}
className={item.selected ? `${styles.annotation} ${styles.annotation_selected}` : styles.annotation}
onClick={() => {
!item.selected && store.annotationStore.selectPrediction(item.id);
}}
onMouseEnter={highlight}
onMouseLeave={unhighlight}
>
<div className={styles.itembtns}>
<div>
<div className={styles.title}>{item.createdBy ? `Model (${item.createdBy})` : null}</div>
Created
<i>{item.createdAgo ? ` ${item.createdAgo} ago` : ` ${Utils.UDate.prettyDate(item.createdDate)}`}</i>
</div>
<div className={styles.buttons}>
{item.selected && (
<Tooltip placement="topLeft" title="Add a new annotation based on this prediction">
<Button
size="small"
onClick={ev => {
ev.preventDefault();
const cs = store.annotationStore;
const p = cs.selected;
const c = cs.addAnnotationFromPrediction(p);
// this is here because otherwise React doesn't re-render the change in the tree
window.setTimeout(function() {
store.annotationStore.selectAnnotation(c.id);
}, 50);
}}
>
<CopyOutlined />
</Button>
</Tooltip>
)}
{store.annotationStore.viewingAllAnnotations && (
<Button size="small" type="primary" ghost onClick={toggleVisibility}>
{item.hidden ? <EyeInvisibleOutlined /> : <EyeOutlined />}
</Button>
)}
</div>
</div>
</List.Item>
);
})
Example #5
Source File: adminChallengeCreate.js From ctf_platform with MIT License | 4 votes |
CreateChallengeForm = (props) => {
const [form] = Form.useForm();
const [editorValue, setEditorValue] = React.useState("")
const [existingCats, setExistingCats] = React.useState([])
const [finalSortedChalls, setfinalSortedChalls] = React.useState([])
useEffect(() => {
var currentValues = form.getFieldsValue()
currentValues.flags = [""]
form.setFieldsValue(currentValues)
//Render existing categories select options
let existCats = []
for (let i = 0; i < props.allCat.length; i++) {
existCats.push(<Option key={props.allCat[i].key} value={props.allCat[i].key}>{props.allCat[i].key}</Option>)
}
setExistingCats(existCats)
//Render existing challenges select options
let existChalls = {}
for (let i = 0; i < props.challenges.length; i++) {
if (!(props.challenges[i].category in existChalls)) existChalls[props.challenges[i].category] = []
existChalls[props.challenges[i].category].push({
value: props.challenges[i]._id,
label: props.challenges[i].name
})
}
let finalChalls = []
for (const category in existChalls) {
finalChalls.push({
value: category,
label: category,
children: existChalls[category]
})
}
setfinalSortedChalls(finalChalls)
}, [])
return (
<Form
form={form}
name="create_challenge_form"
className="create_challenge_form"
onValuesChange={() => { if (props.state.edited === false) props.setState({ edited: true }) }}
onFinish={async (values) => {
props.setState({ edited: false })
if (typeof values.flags === "undefined") {
message.warn("Please enter at least 1 flag")
}
else {
//console.log(values)
props.setState({ loading: true })
if (values.visibility === "false") {
values.visibility = false
}
else {
values.visibility = true
}
if (values.dynamic === "false") {
values.dynamic = false
}
else {
values.dynamic = true
}
if (typeof values.writeup !== "undefined") {
if (typeof values.writeupComplete === "undefined") {
values.writeupComplete = true
}
}
const category = (typeof values.category1 !== "undefined") ? values.category1 : values.category2
let requires = undefined
if (values.requires && values.requires.length > 0) requires = values.requires[1]
await fetch(window.ipAddress + "/v1/challenge/new", {
method: 'post',
headers: { 'Content-Type': 'application/json', "Authorization": window.IRSCTFToken },
body: JSON.stringify({
"name": values.name,
"category": category,
"description": values.description,
"points": values.points,
"flags": values.flags,
"tags": values.tags,
"hints": values.hints,
"max_attempts": values.max_attempts,
"visibility": values.visibility,
"writeup": values.writeup,
"writeupComplete": values.writeupComplete,
"requires": requires,
"dynamic": values.dynamic,
"initial": values.initial,
"minSolves": values.minSolves,
"minimum": values.minimum
})
}).then((results) => {
return results.json(); //return data in JSON (since its JSON data)
}).then((data) => {
//console.log(data)
if (data.success === true) {
message.success({ content: "Created challenge " + values.name + " successfully!" })
form.resetFields()
props.handleCreateBack()
}
else if (data.error === "exists") {
message.warn("A challenge with an existing name exists")
}
else {
message.error({ content: "Oops. Unknown error, please contact an admin." })
}
}).catch((error) => {
console.log(error)
message.error({ content: "Oops. Issue connecting with the server or client error, please check console and report the error. " });
})
props.setState({ loading: false })
}
}}
>
<Prompt
when={props.state.edited}
message='The challenge details you entered have not been saved. Are you sure you want to leave?'
/>
<h1>Challenge Name:</h1>
<Form.Item
name="name"
rules={[{ required: true, message: 'Please enter a challenge name' }]}
>
<Input allowClear placeholder="Challenge name" />
</Form.Item>
<Divider />
<h1>Challenge Category:</h1>
<h4>Select an Existing Category: </h4>
<Form.Item
name="category1"
rules={[{ required: !props.state.selectCatDisabled, message: 'Please enter a challenge category' }]}
>
<Select
disabled={props.state.selectCatDisabled}
allowClear
showSearch
placeholder="Select an existing Category"
onChange={(value) => {
if (value) {
props.setState({ inputCatDisabled: true })
}
else {
props.setState({ inputCatDisabled: false })
}
}}
>
{existingCats}
</Select>
</Form.Item>
<h4>Enter a New Category</h4>
<Form.Item
name="category2"
rules={[{ required: !props.state.inputCatDisabled, message: 'Please enter a challenge category' }]}
>
<Input onChange={(e) => {
e.target.value.length > 0 ? props.setState({ selectCatDisabled: true }) : props.setState({ selectCatDisabled: false })
}} disabled={props.state.inputCatDisabled} allowClear placeholder="Enter a new challenge category" />
</Form.Item>
<Divider />
<Suspense fallback={<div style={{ height: "100%", width: "100%", display: "flex", justifyContent: "center", alignItems: "center", zIndex: 15 }}>
<Ellipsis color="#177ddc" size={120} ></Ellipsis>
</div>}>
<h1>Challenge Description (Supports <a href="https://guides.github.com/features/mastering-markdown/" target="_blank" rel="noreferrer">Markdown</a> and <a href="https://github.com/rehypejs/rehype-raw" target="_blank" rel="noreferrer">HTML</a>):</h1>
<Form.Item
name="description"
rules={[{ required: true, message: 'Please enter a description' }]}
valuePropName={editorValue}
>
<MDEditor value={editorValue} onChange={(value) => { setEditorValue(value) }} preview="edit" />
</Form.Item>
<h3>Challenge Description Preview</h3>
<Card
type="inner"
bordered={true}
bodyStyle={{ backgroundColor: "#262626", textAlign: "center" }}
className="challengeModal"
>
<MarkdownRender>{editorValue}</MarkdownRender>
</Card>
</Suspense>
<Divider />
<div className="settings-responsive2" style={{ display: "flex", justifyContent: "space-around" }}>
<div style={{ display: "flex", flexDirection: "column", justifyContent: "center" }}>
<Card>
<h1>Challenge Points:</h1>
<Form.Item
name="points"
rules={[{ required: true, message: 'Please enter challenge points' }, {
type: 'integer',
message: "Please enter a valid integer between 0-100000",
},]}
initialValue={0}
>
<InputNumber disabled={props.state.dynamic} min={0} max={100000} style={{ width: "30ch" }} ></InputNumber>
</Form.Item>
</Card>
<Card>
<h1>Maximum Number of Attempts (Set to 0 for unlimited)</h1>
<Form.Item
name="max_attempts"
rules={[{ required: true, message: 'Please enter the maximum number of attempts' }, {
type: 'integer',
message: "Please enter a valid integer between 0-10000",
},]}
style={{ alignText: 'center' }}
initialValue={0}
>
<InputNumber min={0} max={10000} style={{ width: "30ch" }}></InputNumber>
</Form.Item>
</Card>
</div>
<Divider type="vertical" style={{ height: "inherit" }} />
<div style={{ display: "flex", flexDirection: "column" }}>
<Form.List name="flags" >
{(fields, { add, remove }) => {
return (
<Card>
<h1>Flags</h1>
{fields.map(field => (
<Space key={field.key} style={{ display: 'flex', marginBottom: 8 }} align="start">
<Form.Item
{...field}
name={[field.name]}
fieldKey={[field.fieldKey]}
rules={[{ required: true, message: 'Missing flag' }, { message: "Please enter a flag that is < 1000 characters", pattern: /^.{1,1000}$/ }]}
>
<Input style={{ width: "50ch" }} placeholder="Flag" />
</Form.Item>
{fields.length > 1 ? (
<MinusCircleOutlined
className="dynamic-delete-button"
style={{ margin: '0 8px', color: "red" }}
onClick={() => {
remove(field.name);
}}
/>
) : null}
</Space>
))}
<Form.Item>
<Button
type="dashed"
onLoad={() => { if (fields.length < 1) add() }}
onClick={() => {
add();
}}
block
style={{ width: "50ch" }}
>
<PlusOutlined /> Add Flag
</Button>
</Form.Item>
</Card>
);
}}
</Form.List>
<Form.List name="tags">
{(fields, { add, remove }) => {
return (
<Card>
<h1>Tags</h1>
{fields.map(field => (
<Space key={field.key} style={{ display: 'flex', marginBottom: 8 }} align="start">
<Form.Item
{...field}
name={[field.name]}
fieldKey={[field.fieldKey]}
rules={[{ required: true, message: 'Missing tag' }]}
>
<Input placeholder="Tag" style={{ width: "50ch" }} />
</Form.Item>
<MinusCircleOutlined
className="dynamic-delete-button"
style={{ margin: '0 8px', color: "red" }}
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
block
style={{ width: "50ch" }}
>
<PlusOutlined /> Add Tag
</Button>
</Form.Item>
</Card>
);
}}
</Form.List>
</div>
</div>
<Divider />
<div className="settings-responsive2" style={{ display: "flex", justifyContent: "space-around" }}>
<div style={{ display: "flex", flexDirection: "column" }}>
<Form.List name="hints" >
{(fields, { add, remove }) => {
return (
<Card>
<h1>Hints</h1>
{fields.map(field => (
<Space key={field.key} style={{ display: 'flex', marginBottom: 8 }} align="start">
<Form.Item
{...field}
name={[field.name, "hint"]}
fieldKey={[field.fieldKey, "hint"]}
rules={[{ required: true, message: 'Missing hint' }]}
>
<Input placeholder="Hint" style={{ width: "20vw" }} />
</Form.Item>
<Form.Item
{...field}
name={[field.name, "cost"]}
fieldKey={[field.fieldKey, "cost"]}
rules={[{ required: true, message: 'Missing cost for hint' }, {
type: 'integer',
message: "Please enter a valid integer between 0-10000",
},]}
>
<InputNumber min={0} max={10000} placeholder="Cost"></InputNumber>
</Form.Item>
<MinusCircleOutlined
style={{ color: "red" }}
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
block
style={{ width: "50ch" }}
>
<PlusOutlined /> Add Hint
</Button>
</Form.Item>
</Card>
);
}}
</Form.List>
<Card>
<h1>Writeup Link (Optional)</h1>
<Form.Item
name="writeup"
rules={[
{
type: 'url',
message: "Please enter a valid link",
}]}
>
<Input allowClear style={{ width: "50ch" }} placeholder="Enter a writeup link for this challenge" />
</Form.Item>
<div style={{ display: "flex", alignContent: "center" }}>
<h4 style={{ marginRight: "2ch" }}>Release Writeup Only After Completion: </h4>
<Form.Item
name="writeupComplete"
>
<Switch defaultChecked />
</Form.Item>
</div>
</Card>
<Card>
<h1>Visibility</h1>
<Form.Item
name="visibility"
rules={[{ required: true, message: 'Please set the challenge visibility' }]}
initialValue="false"
>
<Select style={{ width: "20ch" }}>
<Option value="false"><span style={{ color: "#d32029" }}>Hidden <EyeInvisibleOutlined /></span></Option>
<Option value="true"><span style={{ color: "#49aa19" }}>Visible <EyeOutlined /></span></Option>
</Select>
</Form.Item>
</Card>
</div>
<Divider type="vertical" style={{ height: "inherit" }} />
<div style={{ display: "flex", flexDirection: "column" }}>
<Card>
<h1>Challenge Required: </h1>
<Form.Item
name="requires"
>
<Cascader
options={finalSortedChalls}
allowClear
showSearch
placeholder="Select an existing challenge" />
</Form.Item>
<p>Locks this challenge until the provided challenge above has been solved.</p>
</Card>
<Card>
<h1>Dynamic Scoring</h1>
<Form.Item
name="dynamic"
rules={[{ required: true, message: 'Please set whether the challenge uses dynamic scoring' }]}
initialValue="false"
>
<Select onSelect={(option) => { option === "false" ? props.setState({ dynamic: false }) : props.setState({ dynamic: true }) }} style={{ width: "20ch" }}>
<Option value="false"><span style={{ color: "#d32029" }}>Disabled</span></Option>
<Option value="true"><span style={{ color: "#49aa19" }}>Enabled</span></Option>
</Select>
</Form.Item>
<h1>Initial Points:</h1>
<Form.Item
name="initial"
rules={[{ required: props.state.dynamic, message: 'Please enter the initial challenge points' }, {
type: 'integer',
message: "Please enter a valid integer between 1-100000",
},]}
initialValue={500}
>
<InputNumber disabled={!props.state.dynamic} min={1} max={100000} ></InputNumber>
</Form.Item>
<p>Initial number of points when there are 0/1 solves on a challenge</p>
<h1>Minimum Points:</h1>
<Form.Item
name="minimum"
rules={[{ required: props.state.dynamic, message: 'Please enter the minimum challenge points' }, {
type: 'integer',
message: "Please enter a valid integer between 0-100000",
},]}
initialValue={100}
>
<InputNumber disabled={!props.state.dynamic} min={0} max={100000} ></InputNumber>
</Form.Item>
<p>Minimum amount of points that the challenge can decay too</p>
<h1>Solves to Minimum:</h1>
<Form.Item
name="minSolves"
rules={[{ required: props.state.dynamic, message: 'Please enter the solves to minimum' }, {
type: 'integer',
message: "Please enter a valid integer between 1-100000",
},]}
initialValue={50}
>
<InputNumber disabled={!props.state.dynamic} min={1} max={100000} ></InputNumber>
</Form.Item>
<p>Number of solves on the challenge till it decays to the minimum point.</p>
</Card>
</div>
</div>
<Form.Item>
<div style={{ display: "flex", justifyContent: "space-between", flexDirection: "row", marginTop: "2vh" }}>
<div>
<Button style={{ marginBottom: "1.5vh", marginRight: "2vw", backgroundColor: "#d4b106", borderColor: "", color: "white" }} onClick={() => { props.previewChallenge(form.getFieldsValue()); }}>Preview</Button>
<Button loading={props.loadingStatus} type="primary" htmlType="submit" className="login-form-button" style={{ marginBottom: "1.5vh" }}>Create Challenge</Button>
</div>
<div>
<Button style={{ marginRight: "2vw" }} type="primary" danger onClick={() => { form.resetFields() }}>Clear</Button>
</div>
</div>
</Form.Item>
</Form>
);
}
Example #6
Source File: adminChallengeEdit.js From ctf_platform with MIT License | 4 votes |
CreateChallengeForm = (props) => {
const [form] = Form.useForm();
const [editorValue, setEditorValue] = React.useState("")
const [existingCats, setExistingCats] = React.useState([])
const [finalSortedChalls, setFinalSortedChalls] = React.useState([])
//Render existing categories select options
useEffect(() => {
let existingCats = []
for (let i = 0; i < props.allCat.length; i++) {
existingCats.push(<Option key={props.allCat[i].key} value={props.allCat[i].key}>{props.allCat[i].key}</Option>)
}
//Render existing challenges select options minus the challenge itself
let existingChalls = {}
for (let i = 0; i < props.challenges.length; i++) {
if (props.challenges[i].name !== props.initialData.name) {
if (!(props.challenges[i].category in existingChalls)) existingChalls[props.challenges[i].category] = []
existingChalls[props.challenges[i].category].push({
value: props.challenges[i]._id,
label: props.challenges[i].name
})
}
}
setExistingCats(existingCats)
let finalSortedChalls = []
for (const category in existingChalls) {
finalSortedChalls.push({
value: category,
label: category,
children: existingChalls[category]
})
}
setFinalSortedChalls(finalSortedChalls)
let initialData = JSON.parse(JSON.stringify(props.initialData))
if (props.initialData.visibility === false) {
initialData.visibility = "false"
}
else if (props.initialData.visibility === true) {
initialData.visibility = "true"
}
// if we put only props.initialData.requires, we are merely putting a reference to props.initialData.requires, which is this array, creating a "loop"
if (props.initialData.requires) initialData.requires = [props.IDNameMapping[props.initialData.requires], props.initialData.requires]
if (props.initialData.dynamic === false) {
initialData.dynamic = "false"
}
else if (props.initialData.dynamic === true) {
initialData.dynamic = "true"
props.setState({ dynamic: true })
}
else {
initialData.dynamic = "false"
}
initialData.category1 = initialData.category
form.setFieldsValue(initialData)
setEditorValue(initialData.description)
}, [])
return (
<Form
form={form}
name="create_challenge_form"
className="create_challenge_form"
onValuesChange={() => { if (props.state.edited === false) props.setState({ edited: true }) }}
onFinish={async (values) => {
props.setState({ edited: false })
if (typeof values.flags === "undefined") {
message.warn("Please enter at least 1 flag")
}
else {
if (values.visibility === "false") {
values.visibility = false
}
else {
values.visibility = true
}
if (values.dynamic === "false") {
values.dynamic = false
}
else {
values.dynamic = true
}
if (typeof values.writeup !== "undefined") {
if (typeof values.writeupComplete === "undefined") {
values.writeupComplete = true
}
}
const category = (typeof values.category1 !== "undefined") ? values.category1 : values.category2
props.setState({ editLoading: true })
let requires = ""
if (values.requires && values.requires.length > 0) requires = values.requires[1]
await fetch(window.ipAddress + "/v1/challenge/edit", {
method: 'post',
headers: { 'Content-Type': 'application/json', "Authorization": window.IRSCTFToken },
body: JSON.stringify({
"id": props.initialData._id,
"name": values.name,
"category": category,
"description": values.description,
"points": values.points,
"flags": values.flags,
"tags": values.tags,
"hints": values.hints,
"max_attempts": values.max_attempts,
"visibility": values.visibility,
"writeup": values.writeup,
"writeupComplete": values.writeupComplete,
"requires": requires,
"dynamic": values.dynamic,
"initial": values.initial,
"minSolves": values.minSolves,
"minimum": values.minimum
})
}).then((results) => {
return results.json(); //return data in JSON (since its JSON data)
}).then((data) => {
if (data.success === true) {
message.success({ content: "Edited challenge \"" + props.initialData.name + "\" successfully!" })
props.handleEditChallBack()
setEditorValue("")
form.resetFields()
}
else if (data.error === "exists") {
message.warn("A challenge with an existing name exists")
}
else {
message.error({ content: "Oops. Unknown error" })
}
}).catch((error) => {
console.log(error)
message.error({ content: "Oops. There was an issue connecting with the server" });
})
props.setState({ editLoading: false })
}
}}
>
<Prompt
when={props.state.edited}
message='The challenge details you modified have not been saved. Are you sure you want to leave?'
/>
<p><b><u>ID:</u></b> <code>{props.initialData._id}</code></p>
<h1>Challenge Name:</h1>
<Form.Item
name="name"
rules={[{ required: true, message: 'Please enter a challenge name' }]}
>
<Input allowClear placeholder="Challenge name" />
</Form.Item>
<Divider />
<h1>Challenge Category:</h1>
<h4>Select an Existing Category: </h4>
<Form.Item
name="category1"
initialValue={""}
rules={[{ required: !props.state.selectCatDisabled, message: 'Please enter a challenge category' }]}
>
<Select
disabled={props.state.selectCatDisabled}
allowClear
showSearch
placeholder="Select an existing Category"
onChange={(value) => {
if (value) {
props.setState({ inputCatDisabled: true })
}
else {
props.setState({ inputCatDisabled: false })
}
}}
>
{existingCats}
</Select>
</Form.Item>
<h4>Enter a New Category</h4>
<Form.Item
name="category2"
rules={[{ required: !props.state.inputCatDisabled, message: 'Please enter a challenge category' }]}
>
<Input onChange={(e) => {
e.target.value.length > 0 ? props.setState({ selectCatDisabled: true }) : props.setState({ selectCatDisabled: false })
}} disabled={props.state.inputCatDisabled} allowClear placeholder="Enter a new challenge category" />
</Form.Item>
<Divider />
<h1>Challenge Description (Supports <a href="https://guides.github.com/features/mastering-markdown/" target="_blank" rel="noreferrer">Markdown</a> and <a href="https://github.com/rehypejs/rehype-raw" target="_blank" rel="noreferrer">HTML</a>)):</h1>
<Suspense fallback={<div style={{ height: "100%", width: "100%", display: "flex", justifyContent: "center", alignItems: "center", zIndex: 15 }}>
<Ellipsis color="#177ddc" size={120} ></Ellipsis>
</div>}>
<Form.Item
name="description"
rules={[{ required: true, message: 'Please enter a description' }]}
valuePropName={editorValue}
>
<MDEditor value={editorValue} onChange={(value) => { setEditorValue(value) }} preview="edit" />
</Form.Item>
<h3>Challenge Description Preview</h3>
<Card
type="inner"
bordered={true}
bodyStyle={{ backgroundColor: "#262626", textAlign: "center" }}
className="challengeModal"
>
<MarkdownRender>{editorValue}</MarkdownRender>
</Card>
</Suspense>
<Divider />
<div className="settings-responsive2" style={{ display: "flex", justifyContent: "space-around" }}>
<div style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignContent: "center" }}>
<Card className="settings-card">
<h1>Challenge Points:</h1>
<Form.Item
name="points"
rules={[{ required: true, message: 'Please enter challenge points' }, {
type: 'integer',
message: "Please enter a valid integer between 0-100000",
},]}
initialValue={0}
>
<InputNumber disabled={props.state.dynamic} min={0} max={100000} style={{ width: "30ch" }} ></InputNumber>
</Form.Item>
</Card>
<Card className="settings-card">
<h1>Maximum Number of Attempts (Set to 0 for unlimited)</h1>
<Form.Item
name="max_attempts"
rules={[{ required: true, message: 'Please enter the maximum number of attempts' }, {
type: 'integer',
message: "Please enter a valid integer between 0-10000",
},]}
style={{ alignText: 'center' }}
initialValue={0}
>
<InputNumber min={0} max={10000} style={{ width: "30ch" }}></InputNumber>
</Form.Item>
</Card>
</div>
<Divider type="vertical" style={{ height: "inherit" }}></Divider>
<div style={{ display: "flex", flexDirection: "column" }}>
<Form.List name="flags" >
{(fields, { add, remove }) => {
return (
<Card className="settings-card">
<h1>Flags</h1>
{fields.map(field => (
<Space key={field.key} style={{ display: 'flex', marginBottom: 8 }} align="start">
<Form.Item
{...field}
name={[field.name]}
fieldKey={[field.fieldKey]}
rules={[{ required: true, message: 'Missing flag' }, { message: "Please enter a flag that is < 1000 characters", pattern: /^.{1,1000}$/ }]}
>
<Input style={{ width: "50ch" }} placeholder="Flag" />
</Form.Item>
{fields.length > 1 ? (
<MinusCircleOutlined
className="dynamic-delete-button"
style={{ margin: '0 8px', color: "red" }}
onClick={() => {
remove(field.name);
}}
/>
) : null}
</Space>
))}
<Form.Item>
<Button
type="dashed"
onLoad={() => { if (fields.length < 1) add() }}
onClick={() => {
add();
}}
block
style={{ width: "50ch" }}
>
<PlusOutlined /> Add Flag
</Button>
</Form.Item>
</Card>
);
}}
</Form.List>
<Form.List name="tags">
{(fields, { add, remove }) => {
return (
<Card className="settings-card">
<h1>Tags</h1>
{fields.map(field => (
<Space key={field.key} style={{ display: 'flex', marginBottom: 8 }} align="start">
<Form.Item
{...field}
name={[field.name]}
fieldKey={[field.fieldKey]}
rules={[{ required: true, message: 'Missing tag' }]}
>
<Input placeholder="Tag" style={{ width: "50ch" }} />
</Form.Item>
<MinusCircleOutlined
className="dynamic-delete-button"
style={{ margin: '0 8px', color: "red" }}
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
block
style={{ width: "50ch" }}
>
<PlusOutlined /> Add Tag
</Button>
</Form.Item>
</Card>
);
}}
</Form.List>
</div>
</div>
<Divider />
<div className="settings-responsive2" style={{ display: "flex", justifyContent: "space-around" }}>
<div style={{ display: "flex", flexDirection: "column" }}>
<Form.List name="hints" >
{(fields, { add, remove }) => {
return (
<Card className="settings-card">
<h1>Hints</h1>
{fields.map(field => (
<Space key={field.key} style={{ display: 'flex', marginBottom: 8 }} align="start">
<Form.Item
{...field}
name={[field.name, "hint"]}
fieldKey={[field.fieldKey, "hint"]}
rules={[{ required: true, message: 'Missing hint' }]}
>
<Input placeholder="Hint" style={{ width: "20vw" }} />
</Form.Item>
<Form.Item
{...field}
name={[field.name, "cost"]}
fieldKey={[field.fieldKey, "cost"]}
rules={[{ required: true, message: 'Missing cost for hint' }, {
type: 'integer',
message: "Please enter a valid integer between 0-10000",
},]}
>
<InputNumber min={0} max={10000} placeholder="Cost"></InputNumber>
</Form.Item>
<MinusCircleOutlined
style={{ color: "red" }}
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
block
style={{ width: "50ch" }}
>
<PlusOutlined /> Add Hint
</Button>
</Form.Item>
</Card>
);
}}
</Form.List>
<Card className="settings-card">
<h1>Writeup Link (Optional)</h1>
<Form.Item
name="writeup"
rules={[
{
type: 'url',
message: "Please enter a valid link",
}]}
>
<Input allowClear style={{ width: "50ch" }} placeholder="Enter a writeup link for this challenge" />
</Form.Item>
<div style={{ display: "flex", alignContent: "center" }}>
<h4 style={{ marginRight: "2ch" }}>Release Writeup Only After Completion: </h4>
<Form.Item
name="writeupComplete"
>
<Switch defaultChecked />
</Form.Item>
</div>
</Card>
<Card className="settings-card">
<h1>Visibility</h1>
<Form.Item
name="visibility"
rules={[{ required: true, message: 'Please set the challenge visibility' }]}
initialValue="false"
>
<Select style={{ width: "20ch" }}>
<Option value="false"><span style={{ color: "#d32029" }}>Hidden <EyeInvisibleOutlined /></span></Option>
<Option value="true"><span style={{ color: "#49aa19" }}>Visible <EyeOutlined /></span></Option>
</Select>
</Form.Item>
</Card>
</div>
<Divider type="vertical" style={{ height: "inherit" }} />
<div style={{ display: "flex", flexDirection: "column" }}>
<Card>
<h1>Challenge Required: </h1>
<Form.Item
name="requires"
>
{/*
The issue with this is that displayRender is supposed to return an array,
but setting a value causes it to become a string and error out
*/}
<Cascader
options={finalSortedChalls}
allowClear
showSearch
placeholder="Select an existing challenge" />
</Form.Item>
<p>Locks this challenge until the provided challenge above has been solved.</p>
</Card>
<Card className="settings-card">
<h1>Dynamic Scoring</h1>
<Form.Item
name="dynamic"
rules={[{ required: props.state.dynamic, message: 'Please set whether the challenge uses dynamic scoring' }]}
initialValue="false"
>
<Select style={{ width: "20ch" }} onSelect={(option) => { option === "false" ? props.setState({ dynamic: false }) : props.setState({ dynamic: true }) }}>
<Option value="false"><span style={{ color: "#d32029" }}>Disabled</span></Option>
<Option value="true"><span style={{ color: "#49aa19" }}>Enabled</span></Option>
</Select>
</Form.Item>
<h1>Initial Points:</h1>
<Form.Item
name="initial"
rules={[{ required: props.state.dynamic, message: 'Please enter the initial challenge points' }, {
type: 'integer',
message: "Please enter a valid integer between 1-100000",
},]}
initialValue={500}
>
<InputNumber disabled={!props.state.dynamic} min={1} max={100000} ></InputNumber>
</Form.Item>
<p>Initial number of points when there are 0/1 solves on a challenge</p>
<h1>Minimum Points:</h1>
<Form.Item
name="minimum"
rules={[{ required: props.state.dynamic, message: 'Please enter the minimum challenge points' }, {
type: 'integer',
message: "Please enter a valid integer between 0-100000",
},]}
initialValue={100}
>
<InputNumber disabled={!props.state.dynamic} min={0} max={100000} ></InputNumber>
</Form.Item>
<p>Minimum amount of points that the challenge can decay too</p>
<h1>Solves to Minimum:</h1>
<Form.Item
name="minSolves"
rules={[{ required: props.state.dynamic, message: 'Please enter the solves to minimum' }, {
type: 'integer',
message: "Please enter a valid integer between 1-100000",
},]}
initialValue={50}
>
<InputNumber disabled={!props.state.dynamic} min={1} max={100000} ></InputNumber>
</Form.Item>
<p>Number of solves on the challenge till it decays to the minimum point.</p>
</Card>
</div>
</div>
<Form.Item>
<div style={{ display: "flex", justifyContent: "space-between", flexDirection: "row", marginTop: "3ch" }}>
<div>
<Button style={{ marginBottom: "1.5vh", marginRight: "2vw", backgroundColor: "#d4b106", borderColor: "", color: "white" }} onClick={() => { props.previewChallenge(form.getFieldsValue()) }}>Preview</Button>
<Button type="primary" htmlType="submit" className="login-form-button" style={{ marginBottom: "1.5vh" }} loading={props.editLoading}>Edit Challenge</Button>
</div>
<div>
<Button style={{ marginRight: "2vw" }} type="primary" danger onClick={() => { form.resetFields() }}>Clear</Button>
</div>
</div>
</Form.Item>
</Form>
);
}
Example #7
Source File: adminChallenges.js From ctf_platform with MIT License | 4 votes |
render() {
return (
<Layout style={{ height: "100%", width: "100%", backgroundColor: "rgba(0, 0, 0, 0)" }}>
<Modal title={<span><UploadOutlined/> Upload Challenges</span>} visible={this.state.uploadModalVisible} footer={null} onCancel={() => {this.setState({uploadModalVisible: false})}}>
<UploadChallengesForm handleRefresh={this.handleRefresh.bind(this)} closeUploadChallenges={() => {this.setState({uploadModalVisible: false})}}/>
</Modal>
<div style={{ display: (!this.state.challengeCreate && !this.state.editChallenge) ? "initial" : "none" }}>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<div style={{ display: "flex", alignItems: "center", height: "2ch" }}>
<Button type="primary" style={{ marginBottom: "2vh", marginRight: "1ch" }} icon={<FlagOutlined />} onClick={() => { this.setState({ challengeCreate: true }, this.props.history.push("/Admin/Challenges/Create")) }}>Create New Challenge</Button>
<Button type="primary" style={{ marginBottom: "2vh", marginRight: "1ch" }} icon={<UploadOutlined />} onClick={() => { this.setState({uploadModalVisible: true}) }}>Upload Challenges</Button>
{this.state.loading && (
<div style={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
<Ellipsis color="#177ddc" size={60} />
<h1>Loading Challenges</h1>
</div>
)}
</div>
<Button loading={this.state.loading} type="primary" shape="circle" size="large" style={{ marginBottom: "2vh", maxWidth: "25ch" }} icon={<RedoOutlined />} onClick={async () => { await this.handleRefresh(); message.success("Challenge list refreshed.") }} />
</div>
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<div style={{ display: "flex", alignItems: "center" }}>
<Button disabled={this.state.disableEditButtons} type="default" style={{ marginBottom: "2vh", marginRight: "1ch", backgroundColor: "#6e6e6e" }} icon={<EyeOutlined style={{ color: "#49aa19" }} />} onClick={() => { this.editChallengeVisibility(true, this.state.selectedTableKeys, this.state.selectedRows) }}>Show</Button>
<Button disabled={this.state.disableEditButtons} type="default" style={{ marginBottom: "2vh", marginRight: "1ch", backgroundColor: "#6e6e6e" }} icon={<EyeInvisibleOutlined style={{ color: "#d32029" }} />} onClick={() => { this.editChallengeVisibility(false, this.state.selectedTableKeys, this.state.selectedRows) }}>Hide</Button>
<Button disabled={this.state.disableEditButtons} style={{ marginBottom: "2vh", marginRight: "1ch", backgroundColor: "#a61d24" }} icon={<DeleteOutlined />} onClick={() => {
confirm({
confirmLoading: this.state.disableEditButtons,
title: 'Are you sure you want to delete the challenge(s) (' + this.state.selectedTableKeys.join(", ") + ')? This action is irreversible.',
icon: <ExclamationCircleOutlined />,
onOk: (close) => { this.deleteChallenge(close.bind(this), this.state.selectedTableKeys, this.state.selectedRows) },
onCancel: () => { },
});
}}>Delete Challenges</Button>
</div>
<div>
<Button disabled={this.state.disableEditButtons} type="primary" style={{ marginBottom: "2vh", marginRight: "1ch" }} icon={<DownloadOutlined />} onClick={() => { this.downloadChallenges(this.state.selectedRows) }}>Download</Button>
</div>
</div>
<Table rowSelection={{ selectedRowKeys: this.state.selectedTableKeys, onChange: this.handleTableSelect.bind(this) }} style={{ overflow: "auto" }} dataSource={this.state.dataSource} locale={{
emptyText: (
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", marginTop: "10vh" }}>
<FileUnknownTwoTone style={{ color: "#177ddc", fontSize: "400%", zIndex: 1 }} />
<h1 style={{ fontSize: "200%" }}>No Challenges Found/Created</h1>
</div>
)
}}>
<Column title="Name" dataIndex="name" key="name"
render={(text, row, index) => {
return <Link to={"/Challenges/" + row._id}><a style={{ fontWeight: 700 }}>{text}</a></Link>;
}}
filterDropdown={({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
autoFocus
placeholder="Search Challenge Name"
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => confirm()}
style={{ marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => { confirm() }}
icon={<SearchOutlined />}
>
Search
</Button>
<Button onClick={() => clearFilters()}>
Reset
</Button>
</Space>
</div>
)}
onFilter={(value, record) => record.name.toLowerCase().trim().includes(value.toLowerCase())}
filterIcon={filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />}
sorter={(a, b) => {
if (a.name < b.name) return -1
else return 1
}}
/>
<Column filters={this.state.allCat.map(value => { return { text: value.key, value: value.key } })} onFilter={(value, record) => value === record.category} title="Category" dataIndex="category" key="category" render={(text, row, index) => {
return <Link to={"/Challenges/" + row.category}><a style={{ fontWeight: 700 }}>{text}</a></Link>;
}} />
<Column sorter={(a, b) => a.points - b.points} title="Points" dataIndex="points" key="points" />
<Column sorter={(a, b) => a.points - b.points} title="Initial Points" dataIndex="initial" key="initial" />
<Column sorter={(a, b) => a.points - b.points} title="Solves to Min." dataIndex="minSolves" key="minSolves" />
<Column sorter={(a, b) => a.points - b.points} title="Min. Points" dataIndex="minimum" key="minimum" />
<Column filters={[{ text: "Visible", value: "true" }, { text: "Hidden", value: "false" }]} onFilter={(value, record) => { return value === record.visibility.props.visibility }} title="Visbility" dataIndex="visibility" key="visibility" />
<Column title="Required Challenge" dataIndex="requires" key="requires"
render={(text, row, index) => {
return <Link to={"/Challenges/" + text}><a style={{ fontWeight: 700 }}>{this.state.IDNameMapping[text]}</a></Link>;
}}
filterDropdown={({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
autoFocus
placeholder="Search Challenge Name"
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => confirm()}
style={{ marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => { confirm() }}
icon={<SearchOutlined />}
>
Search
</Button>
<Button onClick={() => clearFilters()}>
Reset
</Button>
</Space>
</div>
)}
onFilter={(value, record) => { if (record.requires) return this.state.IDNameMapping[record.requires].toLowerCase().includes(value) }}
filterIcon={filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />}
sorter={(a, b) => {
if (!a.requires) return -1
if (!b.requires) return 1
if (this.state.IDNameMapping[a.requires] < this.state.IDNameMapping[b.requires]) return -1
else return 1
}}
/>
<Column
title=""
key="edit"
render={(text, record) => (
<Button icon={<EditOutlined />} onClick={() => { this.setState({ editChallenge: true, id: record._id }); this.props.history.push("/Admin/Challenges/Edit") }}> Edit</Button>
)}
/>
</Table>
<Divider />
<div style={{ display: "flex", alignItems: "center" }}>
<h1 style={{ fontSize: "150%" }}>Category Management </h1>{this.state.transferDisabled && (<Ellipsis color="#177ddc" size={50} />)}
</div>
<Card className="settings-card">
<h3>Category Meta Information Editor <EyeOutlined /></h3>
<p>Select a category to edit info such as Name, Cover Pictures etc.</p>
<Select style={{ width: "30ch" }} value={this.state.categorySelect} onChange={this.openCategoryEditor.bind(this)}>
{this.state.categoryOptions}
</Select>
{this.state.currentEditCategory && (
<div style={{ padding: "10px", marginTop: "20px", backgroundColor: "rgba(0, 0, 0, 0.3)", border: "5px solid transparent", borderRadius: "10px" }}>
<EditCategoryForm initialData={this.state.currentEditCategory} handleEditCategoryDone={this.handleEditCategoryDone.bind(this)} />
</div>
)}
</Card>
<Card className="settings-card">
<h3>Category Visibility <EyeOutlined /></h3>
<Transfer
dataSource={this.state.allCat}
titles={[<span style={{ color: "#49aa19" }}>Visible Categories <EyeOutlined /></span>, <span style={{ color: "#d32029" }} >Hidden Categories <EyeInvisibleOutlined /></span>]}
targetKeys={this.state.targetKeys}
selectedKeys={this.state.selectedKeys}
onChange={this.handleChange}
onSelectChange={this.handleSelectChange}
render={item => item.key}
pagination
disabled={this.state.transferDisabled}
/>
</Card>
<Divider />
<div className="settings-responsive2" style={{ display: "flex", justifyContent: "space-around" }}>
<Card className="settings-card">
<h3>Disable Submissions: <AntdSwitch disabled={this.state.disableLoading} onClick={(value) => this.disableSetting("submissionDisabled", value)} checked={this.state.submissionDisabled} /></h3>
<p>Prevents users from submitting any new submissions for all challenges. Hints can still be bought</p>
</Card>
<Divider type="vertical" style={{ height: "inherit" }} />
<Card className="settings-card">
<h3>Set Socket Limit: <InputNumber
value={this.state.maxSockets}
disabled={this.state.disableLoading}
onChange={(value) => this.setState({ maxSockets: value })}
onPressEnter={(e) => { this.changeSetting("maxSockets", this.state.maxSockets) }} /></h3>
<p>Sets the maximum number of socket connections allowed <b>per account</b> to connect to the live scoreboard. <br /> <b>Press "Enter" to save</b></p>
</Card>
<Divider type="vertical" style={{ height: "inherit" }} />
<Card className="settings-card">
<h3>Disable First Blood for No Category: <AntdSwitch disabled={this.state.disableLoading} onClick={(value) => this.disableSetting("disableNonCatFB", value)} checked={this.state.disableNonCatFB} /></h3>
<p>Prevents people with no categories from attaining first blood. Useful if you want to limit First Blood prizes to only eligible participants.</p>
</Card>
</div>
</div>
<Switch>
<Route exact path='/Admin/Challenges/Create' render={(props) => <AdminChallengeCreate {...props} challenges={this.state.dataSource} handleBack={this.handleBack.bind(this)} handleCreateBack={this.handleCreateBack.bind(this)} allCat={this.state.allCat} />} />
<Route exact path='/Admin/Challenges/Edit' render={(props) => <AdminChallengeEdit {...props} allCat={this.state.allCat} IDNameMapping={this.state.IDNameMapping} challenges={this.state.dataSource} id={this.state.id} handleEditBack={this.handleEditBack.bind(this)} handleEditChallBack={this.handleEditChallBack.bind(this)} />} />
</Switch>
</Layout>
);
}
Example #8
Source File: challenges.js From ctf_platform with MIT License | 4 votes |
render() {
return (
<Layout className="layout-style">
<div id="Header" className="challenge-header-style">
<h1 style={{
color: "white",
fontSize: "280%",
letterSpacing: ".3rem",
fontWeight: 300,
marginBottom: "10px"
}}> CHALLENGES
</h1>
{this.state.currentCategory && (<h4 className="category-header">{this.state.currentCategory}</h4>)}
</div>
<div style={{ display: "flex", justifyContent: "space-between", alignContent: "center", marginBottom: "10px", textAlign: "center" }}>
<Button size="large" disabled={!this.state.currentCategory} icon={<LeftCircleOutlined />} style={{ backgroundColor: "#1f1f1f" }} onClick={() => { this.props.history.push("/Challenges"); this.setState({ currentCategory: false, foundChallenge: false }) }}>Back</Button>
{this.state.currentCategory && this.state.countDownTimerStrings[this.state.currentCategory] && (
<h1 style={{
color: "white",
fontSize: "170%",
letterSpacing: ".3rem",
fontWeight: 300,
color: "#d89614",
}}>
{this.state.countDownTimerStrings[this.state.currentCategory]}
</h1>
)}
<div>
<Select disabled={!this.state.currentCategory} defaultValue="points" style={{ width: "20ch", backgroundColor: "#1f1f1f" }} onChange={this.sortCats.bind(this)}>
<Option value="points">Sort by ↑Points</Option>
<Option value="pointsrev">Sort by ↓Points</Option>
<Option value="abc">Sort A→Z</Option>
<Option value="abcrev">Sort Z→A</Option>
</Select>
</div>
</div>
<div>
<Transition
items={this.state.loadingChall}
from={{ opacity: 0 }}
enter={{ opacity: 1 }}
leave={{ opacity: 0 }}>
{(props, toggle) => {
if (toggle === true) {
return (<animated.div style={{ ...props, position: "absolute", left: "55%", transform: "translate(-55%, 0%)", zIndex: 10 }}>
<Ellipsis color="#177ddc" size={120} ></Ellipsis>
</animated.div>)
}
else {
return (<animated.div style={{ ...props }}>
{!this.state.currentCategory && (
<List
grid={{
xs: 1,
sm: 2,
md: 2,
lg: 3,
xl: 3,
xxl: 4,
gutter: 20
}}
dataSource={this.state.categories}
locale={{
emptyText: (
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", marginTop: "10vh" }}>
<FileUnknownTwoTone style={{ color: "#177ddc", fontSize: "400%", zIndex: 1 }} />
<h1 style={{ fontSize: "200%" }}>Oops, no challenges have been created.</h1>
</div>
)
}}
renderItem={item => {
return (
<List.Item key={item._id}>
<Link to={"/Challenges/" + item._id}>
<div onClick={() => {
this.setState({ currentCategory: item._id, currentSolvedStatus: item.challenges, currentCategoryChallenges: [this.state.originalData[item._id]] });
}}>
<Card
hoverable
type="inner"
bordered={true}
className="card-design hover"
cover={<img style={{ overflow: "hidden" }} alt="Category Card" src={"/static/category/" + item._id + ".webp"} />}
>
<Meta
title={
<div style={{ display: "flex", flexDirection: "column", textAlign: "center" }}>
<div id="Title" style={{ display: "flex", color: "#f5f5f5", alignItems: "center", marginBottom: "2ch" }}>
<h1 style={{ color: "white", fontSize: "2.5ch", width: "40ch", textOverflow: "ellipsis", overflow: "hidden" }}>{item._id}</h1>
<div style={{ display: "flex", justifyContent: "center", alignItems: "center", flexDirection: "column" }}>
<h2 style={{ fontSize: "2.5ch", marginLeft: "1vw", color: "#faad14", fontWeight: 700 }}>{item.challenges.solved}/{item.challenges.challenges}</h2>
<Progress type="circle" percent={item.challenges.percentage} width="7ch" strokeColor={{
'0%': '#177ddc',
'100%': '#49aa19',
}} style={{ marginLeft: "1vw", fontSize: "2ch" }} />
</div>
</div>
<div>
{"time" in item.meta && (
<span style={{
color: "#d89614",
letterSpacing: ".1rem",
fontWeight: 300,
whiteSpace: "initial"
}}>{this.state.countDownTimerStrings[item._id]}</span>
)}
{item.meta.visibility === false && (
<h4 style={{ color: "#d9d9d9" }}>Hidden Category <EyeInvisibleOutlined /></h4>
)}
</div>
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</Link>
</ List.Item>
)
}
}
/>
)}
{this.state.currentCategory && (
<ChallengesTagSort originalData={this.state.originalData} permissions={this.props.permissions} disableNonCatFB={this.state.disableNonCatFB} userCategories={this.state.userCategories} obtainScore={this.props.obtainScore.bind(this)} match={this.props.match} history={this.props.history} foundChallenge={this.state.foundChallenge} currentCategoryChallenges={this.state.currentCategoryChallenges} handleRefresh={this.handleRefresh.bind(this)} ref={this.tagSortRef} category={this.state.currentCategory}></ChallengesTagSort>
)}
</animated.div>)
}
}
}
</Transition>
</div>
</Layout>
);
}
Example #9
Source File: challengesTagSort.js From ctf_platform with MIT License | 4 votes |
render() {
return (
<Layout className="pageTransition" style={{ height: "100%", width: "100%", backgroundColor: "rgba(0, 0, 0, 0)" }}>
<Modal
title="Hint"
visible={this.state.hintModal}
onCancel={() => { this.setState({ hintModal: false }) }}
footer={null}
>
<p>{this.state.hintContent}</p>
</Modal>
<Modal
title={null}
visible={this.state.challengeModal}
footer={null}
bodyStyle={{ textAlign: "center" }}
onCancel={() => { this.setState({ challengeModal: false }); this.props.history.push("/Challenges/" + this.props.category); }}
>
<Tabs defaultActiveKey="challenge">
<TabPane
tab={<span><ProfileOutlined /> Challenge</span>}
key="challenge"
>
{this.state.challengeWriteup !== "" && this.state.challengeWriteup !== "CompleteFirst" && (
<Tooltip title="View writeups for this challenge">
<Button shape="circle" size="large" style={{ position: "absolute", right: "2ch" }} type="primary" icon={<SolutionOutlined />} onClick={() => { window.open(this.state.challengeWriteup) }} />
</Tooltip>
)}
{this.state.challengeWriteup === "" && (
<Tooltip title="Writeups are not available for this challenge">
<Button disabled shape="circle" size="large" style={{ position: "absolute", right: "2ch" }} type="primary" icon={<SolutionOutlined />} />
</Tooltip>
)}
{this.state.challengeWriteup === "CompleteFirst" && (
<Tooltip title="Writeups are available for this challenge but you must complete the challenge first to view it.">
<Button shape="circle" size="large" style={{ position: "absolute", right: "2ch", color: "#13a8a8" }} icon={<SolutionOutlined />} />
</Tooltip>
)}
<Suspense fallback={<div style={{ height: "100%", width: "100%", display: "flex", justifyContent: "center", alignItems: "center", zIndex: 15 }}>
<Ellipsis color="#177ddc" size={120} ></Ellipsis>
</div>}>
<div style={{ display: "flex", justifyContent: "center" }}>
<h1 style={{ fontSize: "150%", maxWidth: "35ch", whiteSpace: "initial" }}>{this.state.viewingChallengeDetails.name}
<Tooltip title="Copy challenge link to clipboard.">
<LinkOutlined style={{ color: "#1890ff", marginLeft: "0.5ch" }} onClick={
async () => {
await navigator.clipboard.writeText(window.location.href);
message.success("Challenge link copied to clipboard.")
}} /></Tooltip>
</h1>
</div>
<div>
{this.state.challengeTags}
</div>
<h2 style={{ color: "#1765ad", marginTop: "2vh", marginBottom: "6vh", fontSize: "200%" }}>{this.state.viewingChallengeDetails.points}</h2>
<div className="challengeModal">
<MarkdownRender >{this.state.viewingChallengeDetails.description}</MarkdownRender>
</div>
<div style={{ marginTop: "6vh", display: "flex", flexDirection: "column" }}>
{this.state.challengeHints}
</div>
</Suspense>
<div style={{ display: "flex" }}>
<SubmitFlagForm submitFlag={this.submitFlag.bind(this)} currentChallengeStatus={this.state.currentChallengeStatus} currentChallengeSolved={this.state.currentChallengeSolved}></SubmitFlagForm>
</div>
<div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", marginTop: "-1vh" }}>
<p>Challenge Author: <em>{this.state.viewingChallengeDetails.author}</em></p>
<p style={{ color: "#d87a16", fontWeight: 500 }}>Attempts Remaining: {this.state.viewingChallengeDetails.max_attempts}</p>
</div>
</TabPane>
<TabPane
tab={<span><UnlockOutlined /> Solves ({this.state.viewingChallengeDetails.solves.length}) </span>}
key="solves"
>
<List
itemLayout="horizontal"
dataSource={this.state.viewingChallengeDetails.solves}
locale={{
emptyText: (
<div>
<SmileOutlined style={{ fontSize: "500%" }} />
<br />
<br />
<p style={{ fontSize: "150%" }}>No solves yet. Maybe you can be the first!</p>
</div>
)
}}
renderItem={item => {
return (
<List.Item key={item}>
<List.Item.Meta
avatar={<Avatar src={"/static/profile/" + item + ".webp"} />}
title={<Link to={"/Profile/" + item}><a style={{ fontSize: "110%", fontWeight: 700 }} onClick={() => { this.setState({ challengeModal: false }) }}>{item}</a></Link>}
/>
</List.Item>
)
}
} />
</TabPane>
</Tabs>
</Modal>
<Divider style={{ marginTop: "0px" }}>Select Tags</Divider>
<span className="tag-holder" >
{Object.keys(this.state.tag).map((tag) => {
return (
<CheckableTag className="tag-select-style" key={tag} checked={this.state.selectedTags.indexOf(tag) !== -1}
onChange={(checked) => {
let selectedTags = this.state.selectedTags
if (!checked) selectedTags.splice(selectedTags.indexOf(tag), 1)
else selectedTags.push(tag)
if (selectedTags.length === 0) this.sortCats(this.state.sortType, true)
this.setState({ selectedTags: selectedTags })
}}>{tag} <span style={{ color: "#d89614" }}>({this.state.tag[tag].length})</span></CheckableTag>
)
})}
</span>
<Divider />
{this.state.tag && this.state.selectedTags.length > 0 ? (
<ChallengesTagSortList tag={this.state.tag} selectedTags={this.state.selectedTags} permissions={this.props.permissions} loadChallengeDetails={this.loadChallengeDetails.bind(this)} loadingChallenge={this.state.loadingChallenge} currentChallenge={this.state.currentChallenge} />
) : (
<List
grid={{
xs: 1,
sm: 2,
md: 2,
lg: 3,
xl: 4,
xxl: 5,
gutter: 20
}}
dataSource={this.state.challenges}
locale={{
emptyText: (
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", marginTop: "10vh" }}>
<FileUnknownTwoTone style={{ color: "#177ddc", fontSize: "400%", zIndex: 1 }} />
<h1 style={{ fontSize: "200%" }}>No challenges have been released yet</h1>
</div>
)
}}
renderItem={item => {
if (item.solves.length === 0) item.firstBlood = "No First Blood Yet!"
else {
if (this.props.disableNonCatFB) {
item.firstBlood = "No First blood Yet"
for (let i = 0; i < item.solves.length; i++) {
if (this.props.userCategories[item.solves[i]] !== "none") {
item.firstBlood = item.solves[i]
break
}
}
}
else item.firstBlood = item.solves[0]
}
if (item.requires && !item.requiresSolved && this.props.permissions < 2) {
return (
<List.Item key={item._id}>
<Tooltip title={<span>Please solve "<b><u>{item.requiresName}</u></b>" to unlock this challenge.</span>}>
<div id={item._id}>
<Card
type="inner"
bordered={true}
className="card-design"
>
<Meta
description={
<div className="card-design-body" >
<LockOutlined className="disabled-style" />
<h1 className="card-design-name" >{item.name}</h1>
<h1 className="card-design-points">{item.points}</h1>
<h1 className="card-design-firstblood"><img alt="First Blood" src={require("./../assets/blood.svg").default} /> {item.firstBlood}</h1>
{this.state.loadingChallenge && this.state.currentChallenge === item._id && (
<div style={{ width: "100%", height: "100%", backgroundColor: "red", zIndex: 1 }}>
<LoadingOutlined style={{ color: "#177ddc", fontSize: "500%", position: "absolute", zIndex: 1, left: "40%", top: "30%" }} />
</div>
)}
{item.visibility === false && (
<h1 style={{ color: "#d9d9d9" }}>Hidden Challenge <EyeInvisibleOutlined /></h1>
)}
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</Tooltip>
</List.Item>
)
}
else if (!item.solved) {
return (
<List.Item key={item._id}>
<div id={item._id} onClick={() => { this.loadChallengeDetails(item._id, item.solved, item.firstBlood) }}>
<Card
hoverable
type="inner"
bordered={true}
className="card-design hover"
>
<Meta
description={
<div className="card-design-body">
<h1 className="card-design-name">{item.name}</h1>
<h1 className="card-design-points">{item.points}</h1>
<h1 className="card-design-firstblood"><img alt="First Blood" src={require("./../assets/blood.svg").default} /> {item.firstBlood}</h1>
{this.state.loadingChallenge && this.state.currentChallenge === item._id && (
<div style={{ width: "100%", height: "100%", backgroundColor: "red", zIndex: 1 }}>
<LoadingOutlined style={{ color: "#177ddc", fontSize: "500%", position: "absolute", zIndex: 1, left: "40%", top: "30%" }} />
</div>
)}
{item.visibility === false && (
<h1 style={{ color: "#d9d9d9" }}>Hidden Challenge <EyeInvisibleOutlined /></h1>
)}
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</List.Item>
)
}
else {
return (
<List.Item key={item._id}>
<div id={item._id} onClick={() => { this.loadChallengeDetails(item._id, item.solved) }}>
<Card
hoverable
type="inner"
bordered={true}
className="card-design solved hover"
>
<Meta
description={
<div className="card-design-body">
<CheckOutlined className="correct-style" />
<h1 className="card-design-name">{item.name}</h1>
<h1 className="card-design-points">{item.points}</h1>
<h1 className="card-design-firstblood"><img alt="First Blood" src={require("./../assets/blood.svg").default} /> {item.firstBlood}</h1>
{this.state.loadingChallenge && this.state.currentChallenge === item._id && (
<div style={{ width: "100%", height: "100%", backgroundColor: "red", zIndex: 1 }}>
<LoadingOutlined style={{ color: "#177ddc", fontSize: "500%", position: "absolute", zIndex: 1, left: "40%", top: "30%" }} />
</div>
)}
{item.visibility === false && (
<h1 style={{ color: "#d9d9d9" }}>Hidden Challenge <EyeInvisibleOutlined /></h1>
)}
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</List.Item>
)
}
}
}
/>)}
</Layout>
);
}
Example #10
Source File: challengesTagSortList.js From ctf_platform with MIT License | 4 votes |
render() {
return (
<Collapse bordered={false} defaultActiveKey={Object.keys(this.props.tag)}>
{
this.props.selectedTags.map((category) => {
const key = category
const value = this.props.tag[category]
return (
<Panel header={<span style={{ color: "#177ddc", fontSize: "120%", textTransform: "capitalize", textAlign: "center", fontWeight: 700 }}>{key} - <span style={{ color: "#d89614" }}>{"(" + String(value.length) + ")"}</span> </span>} key={key}>
<List
grid={{
xs: 1,
sm: 2,
md: 2,
lg: 3,
xl: 4,
xxl: 5,
gutter: 20
}}
dataSource={value}
key={key + "cat"}
locale={{
emptyText: (
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", marginTop: "10vh" }}>
<FileUnknownTwoTone style={{ color: "#177ddc", fontSize: "400%", zIndex: 1 }} />
<h1 style={{ fontSize: "200%" }}>Oops, no challenges have been created.</h1>
</div>
)
}}
renderItem={item => {
if (!("firstBlood" in item)) {
item.firstBlood = "No Solves Yet!"
}
if (item.requires && !item.requiresSolved && this.props.permissions < 2) {
return (
<List.Item key={item._id}>
<Tooltip title={<span>Please solve "<b><u>{item.requiresName}</u></b>" to unlock this challenge.</span>}>
<div id={item._id}>
<Card
type="inner"
bordered={true}
className="card-design"
>
<Meta
description={
<div className="card-design-body" >
<LockOutlined className="disabled-style"/>
<h1 className="card-design-name" >{item.name}</h1>
<h1 className="card-design-points">{item.points}</h1>
<h1 className="card-design-firstblood"><img alt="First Blood" src={require("./../assets/blood.svg").default} /> {item.firstBlood}</h1>
{this.state.loadingChallenge && this.state.currentChallenge === item._id && (
<div style={{ width: "100%", height: "100%", backgroundColor: "red", zIndex: 1 }}>
<LoadingOutlined style={{ color: "#177ddc", fontSize: "500%", position: "absolute", zIndex: 1, left: "40%", top: "30%" }} />
</div>
)}
{item.visibility === false && (
<h1 style={{ color: "#d9d9d9" }}>Hidden Challenge <EyeInvisibleOutlined /></h1>
)}
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</Tooltip>
</List.Item>
)
}
else if (item.solved === false) {
return (
<List.Item key={item._id}>
<div id={item._id} onClick={() => { this.props.loadChallengeDetails(item._id, item.solved); }}>
<Card
hoverable
type="inner"
bordered={true}
className="card-design hover"
>
<Meta
description={
<div className="card-design-body">
<h1 className="card-design-name">{item.name}</h1>
<h1 className="card-design-points">{item.points}</h1>
<h1 className="card-design-firstblood"><img alt="First Blood" src={require("./../assets/blood.svg").default} /> {item.firstBlood}</h1>
{this.props.loadingChallenge && this.props.currentChallenge === item._id && (
<div style={{ width: "100%", height: "100%", backgroundColor: "red", zIndex: 1 }}>
<LoadingOutlined style={{ color: "#177ddc", fontSize: "500%", position: "absolute", zIndex: 1, left: "40%", top: "30%" }} />
</div>
)}
{item.visibility === false && (
<h1 style={{ color: "#d9d9d9" }}>Hidden Challenge <EyeInvisibleOutlined /></h1>
)}
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</List.Item>
)
}
else {
return (
<List.Item key={item._id}>
<div id={item._id} onClick={() => { this.props.loadChallengeDetails(item._id, item.solved);}}>
<Card
hoverable
type="inner"
bordered={true}
className="card-design solved hover"
>
<Meta
description={
<div className="card-design-body">
<CheckOutlined className="correct-style"/>
<h1 className="card-design-name">{item.name}</h1>
<h1 className="card-design-points">{item.points}</h1>
<h1 className="card-design-firstblood"><img alt="First Blood" src={require("./../assets/blood.svg").default} /> {item.firstBlood}</h1>
{this.props.loadingChallenge && this.props.currentChallenge === item._id && (
<div style={{ width: "100%", height: "100%", backgroundColor: "red", zIndex: 1 }}>
<LoadingOutlined style={{ color: "#177ddc", fontSize: "500%", position: "absolute", zIndex: 1, left: "40%", top: "30%" }} />
</div>
)}
{item.visibility === false && (
<h1 style={{ color: "#d9d9d9" }}>Hidden Challenge <EyeInvisibleOutlined /></h1>
)}
</div>
}
/>
</Card> {/*Pass entire datasource as prop*/}
</div>
</List.Item>
)
}
}
}
/>
</Panel>
)
})
}
</Collapse>
)
}
Example #11
Source File: userChallengeCreate.js From ctf_platform with MIT License | 4 votes |
CreateChallengeForm = (props) => {
const [form] = Form.useForm();
const [editorValue, setEditorValue] = React.useState("")
const [existingCats, setExistingCats] = React.useState([])
useEffect(() => {
var currentValues = form.getFieldsValue()
currentValues.flags = [""]
form.setFieldsValue(currentValues)
let existCats = []
for (let i = 0; i < props.allCat.length; i++) {
existCats.push(<Option key={props.allCat[i]} value={props.allCat[i]}>{props.allCat[i]}</Option>)
}
setExistingCats(existCats)
}, [])
return (
<Form
form={form}
name="create_challenge_form"
className="create_challenge_form"
onFinish={async (values) => {
props.setState({ edited: false })
//console.log(values)
if (typeof values.flags === "undefined") {
message.warn("Please enter at least 1 flag")
}
else {
//console.log(values)
props.setState({ loading: true })
if (values.visibility === "false") {
values.visibility = false
}
else {
values.visibility = true
}
const category = (typeof values.category1 !== "undefined") ? values.category1 : values.category2
if (typeof values.writeup !== "undefined") {
if (typeof values.writeupComplete === "undefined") {
values.writeupComplete = true
}
}
await fetch(window.ipAddress + "/v1/challenge/new", {
method: 'post',
headers: { 'Content-Type': 'application/json', "Authorization": window.IRSCTFToken },
body: JSON.stringify({
"name": values.name,
"category": category,
"description": values.description,
"points": values.points,
"flags": values.flags,
"tags": values.tags,
"hints": values.hints,
"max_attempts": values.max_attempts,
"visibility": values.visibility,
"writeup": values.writeup,
"writeupComplete": values.writeupComplete
})
}).then((results) => {
return results.json(); //return data in JSON (since its JSON data)
}).then((data) => {
//console.log(data)
if (data.success === true) {
message.success({ content: "Created challenge " + values.name + " successfully!" })
form.resetFields()
}
else {
message.error({ content: "Oops. Unknown error, please contact an admin." })
}
}).catch((error) => {
console.log(error)
message.error({ content: "Oops. Issue connecting with the server or client error, please check console and report the error. " });
})
props.setState({ loading: false })
}
}}
>
<h1>Challenge Name:</h1>
<Form.Item
name="name"
rules={[{ required: true, message: 'Please enter a challenge name' }]}
>
<Input allowClear placeholder="Challenge name" />
</Form.Item>
<Divider />
<h1>Challenge Category:</h1>
<h4>Select an Existing Category: </h4>
<Form.Item
name="category1"
rules={[{ required: !props.state.selectCatDisabled, message: 'Please enter a challenge category' }]}
>
<Select
disabled={props.state.selectCatDisabled}
allowClear
showSearch
placeholder="Select an existing Category"
onChange={(value) => {
if (value) {
props.setState({ inputCatDisabled: true })
}
else {
props.setState({ inputCatDisabled: false })
}
}}
>
{existingCats}
</Select>
</Form.Item>
<h4>Enter a New Category</h4>
<Form.Item
name="category2"
rules={[{ required: !props.state.inputCatDisabled, message: 'Please enter a challenge category' }]}
>
<Input onChange={(e) => {
e.target.value.length > 0 ? props.setState({ selectCatDisabled: true }) : props.setState({ selectCatDisabled: false })
}} disabled={props.state.inputCatDisabled} allowClear placeholder="Enter a new challenge category" />
</Form.Item>
<Divider />
<Suspense fallback={<div style={{ height: "100%", width: "100%", display: "flex", justifyContent: "center", alignItems: "center", zIndex: 15 }}>
<Ellipsis color="#177ddc" size={120} ></Ellipsis>
</div>}>
<h1>Challenge Description (Supports <a href="https://guides.github.com/features/mastering-markdown/" target="_blank" rel="noreferrer">Markdown</a> and <a href="https://github.com/rehypejs/rehype-raw" target="_blank" rel="noreferrer">HTML</a>)):</h1>
<Form.Item
name="description"
rules={[{ required: true, message: 'Please enter a description' }]}
valuePropName={editorValue}
>
<MDEditor value={editorValue} onChange={(value) => { setEditorValue(value) }} preview="edit" />
</Form.Item>
<h3>Challenge Description Preview</h3>
<Card
type="inner"
bordered={true}
bodyStyle={{ backgroundColor: "#262626", textAlign: "center" }}
className="challengeModal"
>
<MarkdownRender>{editorValue}</MarkdownRender>
</Card>
</Suspense>
<Divider />
<div style={{ display: "flex", flexDirection: "row", justifyItems: "space-evenly", marginLeft: "2vw" }}>
<div style={{ display: "flex", flexDirection: "column", justifyContent: "center", width: "35vw" }}>
<h1>Challenge Points:</h1>
<Form.Item
name="points"
rules={[{ required: true, message: 'Please enter challenge points' }, {
type: 'integer',
message: "Please enter a valid integer between 1-100000",
},]}
initialValue={1}
>
<InputNumber min={1} max={100000} style={{ width: "30ch" }} ></InputNumber>
</Form.Item>
<h1>Maximum Number of Attempts (Set to 0 for unlimited)</h1>
<Form.Item
name="max_attempts"
rules={[{ required: true, message: 'Please enter the maximum number of attempts' }, {
type: 'integer',
message: "Please enter a valid integer between 0-10000",
},]}
style={{ alignText: 'center' }}
initialValue={0}
>
<InputNumber min={0} max={10000} style={{ width: "30ch" }}></InputNumber>
</Form.Item>
</div>
<Divider type="vertical" style={{ height: "inherit" }}></Divider>
<div style={{ display: "flex", flexDirection: "column", width: "35vw", marginLeft: "2vw" }}>
<Form.List name="flags" >
{(fields, { add, remove }) => {
return (
<div>
<h1>Flags</h1>
{fields.map(field => (
<Space key={field.key} style={{ display: 'flex', marginBottom: 8 }} align="start">
<Form.Item
{...field}
name={[field.name]}
fieldKey={[field.fieldKey]}
rules={[{ required: true, message: 'Missing flag' }]}
>
<Input style={{ width: "50ch" }} placeholder="Flag" />
</Form.Item>
{fields.length > 1 ? (
<MinusCircleOutlined
className="dynamic-delete-button"
style={{ margin: '0 8px', color: "red" }}
onClick={() => {
remove(field.name);
}}
/>
) : null}
</Space>
))}
<Form.Item>
<Button
type="dashed"
onLoad={() => { if (fields.length < 1) add() }}
onClick={() => {
add();
}}
block
style={{ width: "50ch" }}
>
<PlusOutlined /> Add Flag
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
<Form.List name="tags">
{(fields, { add, remove }) => {
return (
<div>
<h1>Tags</h1>
{fields.map(field => (
<Space key={field.key} style={{ display: 'flex', marginBottom: 8 }} align="start">
<Form.Item
{...field}
name={[field.name]}
fieldKey={[field.fieldKey]}
rules={[{ required: true, message: 'Missing tag' }]}
>
<Input placeholder="Tag" style={{ width: "50ch" }} />
</Form.Item>
<MinusCircleOutlined
className="dynamic-delete-button"
style={{ margin: '0 8px', color: "red" }}
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
block
style={{ width: "50ch" }}
>
<PlusOutlined /> Add Tag
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
</div>
</div>
<Divider />
<h1>Hints</h1>
<Form.List name="hints" >
{(fields, { add, remove }) => {
return (
<div>
{fields.map(field => (
<Space key={field.key} style={{ display: 'flex', marginBottom: 8 }} align="start">
<Form.Item
{...field}
name={[field.name, "hint"]}
fieldKey={[field.fieldKey, "hint"]}
rules={[{ required: true, message: 'Missing hint' }]}
>
<Input placeholder="Hint" style={{ width: "20vw" }} />
</Form.Item>
<Form.Item
{...field}
name={[field.name, "cost"]}
fieldKey={[field.fieldKey, "cost"]}
rules={[{ required: true, message: 'Missing cost for hint' }, {
type: 'integer',
message: "Please enter a valid integer between 0-10000",
},]}
>
<InputNumber min={0} max={10000} placeholder="Cost"></InputNumber>
</Form.Item>
<MinusCircleOutlined
style={{ color: "red" }}
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
block
style={{ width: "50ch" }}
>
<PlusOutlined /> Add Hint
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
<h1>Writeup Link (Optional)</h1>
<Form.Item
name="writeup"
rules={[
{
type: 'url',
message: "Please enter a valid link",
}]}
>
<Input allowClear style={{ width: "50ch" }} placeholder="Enter a writeup link for this challenge" />
</Form.Item>
<div style={{ display: "flex", alignContent: "center" }}>
<h4 style={{ marginRight: "2ch" }}>Release Writeup Only After Completion: </h4>
<Form.Item
name="writeupComplete"
>
<Switch defaultChecked />
</Form.Item>
</div>
<h1>Visibility</h1>
<Form.Item
name="visibility"
rules={[{ required: true, message: 'Please set the challenge visibility' }]}
initialValue="false"
>
<Select style={{ width: "10vw" }}>
<Option value="false"><span style={{ color: "#d32029" }}>Hidden <EyeInvisibleOutlined /></span></Option>
<Option value="true"><span style={{ color: "#49aa19" }}>Visible <EyeOutlined /></span></Option>
</Select>
</Form.Item>
<Form.Item>
<div style={{ display: "flex", justifyContent: "space-between", flexDirection: "row" }}>
<div>
<Button style={{ marginBottom: "1.5vh", marginRight: "2vw", backgroundColor: "#d4b106", borderColor: "", color: "white" }} onClick={() => { props.previewChallenge(form.getFieldsValue()); }}>Preview</Button>
<Button loading={props.loadingStatus} type="primary" htmlType="submit" className="login-form-button" style={{ marginBottom: "1.5vh" }}>Create Challenge</Button>
</div>
<div>
<Button style={{ marginRight: "2vw" }} type="primary" danger onClick={() => { form.resetFields() }}>Clear</Button>
</div>
</div>
</Form.Item>
</Form>
);
}
Example #12
Source File: Reg.js From Peppermint with GNU General Public License v3.0 | 4 votes |
Reg = () => {
const history = useHistory();
const [password, setPassword] = useState("");
const [email, setEmail] = useState("");
const [name, setName] = useState("");
const PostData = async () => {
await fetch(`/api/v1/auth/Signup`, {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name,
email,
password,
}),
})
.then((res) => res.json())
.then((data) => {
if (!data.error) {
history.push("/login");
} else {
console.log(data.error);
}
});
};
return (
<div>
<div>
<Form
style={{ position: "absolute" }}
name="normal_login"
className="login-form"
initialValues={{
remember: true,
}}
>
<div className="logo-login">
<Image alt="logo" src={logo} width={300} preview={false} />
</div>
<Form.Item
name="username"
rules={[
{
required: true,
message: "Please input your Email!",
},
]}
>
<Input
style={{ width: 300 }}
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
/>
</Form.Item>
<Form.Item
name="name"
rules={[
{
required: true,
message: "Please input your name!",
},
]}
>
<Input
style={{ width: 300 }}
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="Name"
onChange={(e) => setName(e.target.value)}
/>
</Form.Item>
<Form.Item
name="password"
rules={[
{
required: true,
message: "Please input your Password!",
},
]}
>
<Input.Password
style={{ width: 300 }}
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Password"
iconRender={(visible) =>
visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />
}
onChange={(e) => setPassword(e.target.value)}
/>
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
className="login-form-button"
onClick={() => {
PostData();
setTimeout(() => history.push("/"), 4000);
}}
>
Log in
</Button>
</Form.Item>
</Form>
</div>
</div>
);
}
Example #13
Source File: OfflineSession.js From next-terminal with GNU Affero General Public License v3.0 | 4 votes |
render() { const columns = [{ title: '序号', dataIndex: 'id', key: 'id', render: (id, record, index) => { return index + 1; }, }, { title: '来源IP', dataIndex: 'clientIp', key: 'clientIp' }, { title: '接入方式', dataIndex: 'mode', key: 'mode', render: (text) => { return ( <Tag color={MODE_COLORS[text]}>{text}</Tag> ) } }, { title: '用户昵称', dataIndex: 'creatorName', key: 'creatorName' }, { title: '资产名称', dataIndex: 'assetName', key: 'assetName' }, { title: '连接协议', dataIndex: 'protocol', key: 'protocol', render: (text, record) => { const title = `${record.username}@${record.ip}:${record.port}`; return ( <Tooltip title={title}> <Tag color={PROTOCOL_COLORS[text]}>{text}</Tag> </Tooltip> ) } }, { title: '接入时间', dataIndex: 'connectedTime', key: 'connectedTime', render: (text, record) => { return ( <Tooltip title={text}> {dayjs(text).fromNow()} </Tooltip> ) } }, { title: '接入时长', dataIndex: 'connectedTime', key: 'connectedTime', render: (text, record) => { return differTime(new Date(record['connectedTime']), new Date(record['disconnectedTime'])); } }, { title: '操作', key: 'action', render: (text, record) => { let disabled = true; if (record['recording'] && record['recording'] === '1') { disabled = false } return ( <div> <Button type="link" size='small' disabled={disabled} onClick={() => this.showPlayback(record)}>回放</Button> <Button type="link" size='small' onClick={() => { confirm({ title: '您确定要禁止该IP访问本系统吗?', content: '', okText: '确定', okType: 'danger', cancelText: '取消', onOk: async () => { // 向后台提交数据 let formData = { ip: record['clientIp'], rule: 'reject', priority: 99, } const result = await request.post('/securities', formData); if (result.code === 1) { message.success('禁用成功'); } else { message.error(result.message, 10); } } }); }}>禁用IP</Button> <Button type="link" size='small' danger onClick={() => { confirm({ title: '您确定要删除此会话吗?', content: '', okText: '确定', okType: 'danger', cancelText: '取消', onOk: () => { this.del(record.id) } }); }}>删除</Button> </div> ) }, } ]; const selectedRowKeys = this.state.selectedRowKeys; const rowSelection = { selectedRowKeys: this.state.selectedRowKeys, onChange: (selectedRowKeys, selectedRows) => { this.setState({selectedRowKeys}); }, }; const hasSelected = selectedRowKeys.length > 0; const userOptions = this.state.users.map(d => <Select.Option key={d.id} value={d.id}>{d.nickname}</Select.Option>); const assetOptions = this.state.assets.map(d => <Select.Option key={d.id} value={d.id}>{d.name}</Select.Option>); return ( <> <Content className="site-layout-background page-content"> <div style={{marginBottom: 20}}> <Row justify="space-around" align="middle" gutter={24}> <Col span={4} key={1}> <Title level={3}>离线会话列表</Title> </Col> <Col span={20} key={2} style={{textAlign: 'right'}}> <Space> <Search ref={this.inputRefOfClientIp} placeholder="来源IP" allowClear onSearch={this.handleSearchByClientIp} /> <Select style={{width: 140}} showSearch value={this.state.queryParams.userId} placeholder='用户昵称' onSearch={this.handleSearchByNickname} onChange={this.handleChangeByUserId} filterOption={false} allowClear > {userOptions} </Select> <Select style={{width: 140}} showSearch value={this.state.queryParams.assetId} placeholder='资产名称' onSearch={this.handleSearchByAssetName} onChange={this.handleChangeByAssetId} filterOption={false} > {assetOptions} </Select> <Select onChange={this.handleChangeByRead} value={this.state.queryParams.reviewed ? this.state.queryParams.reviewed : ''} style={{width: 100}}> <Select.Option value="">全部会话</Select.Option> <Select.Option value="true">只看已读</Select.Option> <Select.Option value="false">只看未读</Select.Option> </Select> <Select onChange={this.handleChangeByProtocol} value={this.state.queryParams.protocol ? this.state.queryParams.protocol : ''} style={{width: 100}}> <Select.Option value="">全部协议</Select.Option> <Select.Option value="rdp">rdp</Select.Option> <Select.Option value="ssh">ssh</Select.Option> <Select.Option value="vnc">vnc</Select.Option> <Select.Option value="telnet">telnet</Select.Option> <Select.Option value="kubernetes">kubernetes</Select.Option> </Select> <Tooltip title='重置查询'> <Button icon={<UndoOutlined/>} onClick={() => { this.inputRefOfClientIp.current.setValue(''); this.loadTableData({ pageIndex: 1, pageSize: 10, protocol: '' }) }}> </Button> </Tooltip> <Divider type="vertical"/> <Tooltip title="刷新列表"> <Button icon={<SyncOutlined/>} onClick={() => { this.loadTableData(this.state.queryParams) }}> </Button> </Tooltip> <Tooltip title="全部标为已阅"> <Button icon={<CheckOutlined />} loading={this.state.reviewedAllBtnLoading} onClick={this.handleAllReviewed}> </Button> </Tooltip> <Tooltip title="标为已阅"> <Button disabled={!hasSelected} icon={<EyeOutlined />} loading={this.state.reviewedBtnLoading} onClick={this.handleReviewed}> </Button> </Tooltip> <Tooltip title="标为未阅"> <Button disabled={!hasSelected} icon={<EyeInvisibleOutlined />} loading={this.state.unreviewedBtnLoading} onClick={this.handleUnreviewed}> </Button> </Tooltip> <Tooltip title="批量删除"> <Button type="primary" danger disabled={!hasSelected} icon={<DeleteOutlined/>} loading={this.state.delBtnLoading} onClick={() => { const content = <div> 您确定要删除选中的<Text style={{color: '#1890FF'}} strong>{this.state.selectedRowKeys.length}</Text>条记录吗? </div>; confirm({ icon: <ExclamationCircleOutlined/>, content: content, onOk: () => { this.batchDelete() }, onCancel() { }, }); }}> </Button> </Tooltip> <Tooltip title="清空"> <Button type="primary" danger icon={<ClearOutlined/>} loading={this.state.clearBtnLoading} onClick={() => { const content = <Text style={{color: 'red'}} strong>您确定要清空全部的离线会话吗?</Text>; confirm({ icon: <ExclamationCircleOutlined/>, content: content, okType: 'danger', onOk: this.clearSession, onCancel() { }, }); }}> </Button> </Tooltip> </Space> </Col> </Row> </div> <Table rowSelection={rowSelection} dataSource={this.state.items} columns={columns} position={'both'} pagination={{ showSizeChanger: true, current: this.state.queryParams.pageIndex, pageSize: this.state.queryParams.pageSize, onChange: this.handleChangPage, total: this.state.total, showTotal: total => `总计 ${total} 条` }} loading={this.state.loading} rowClassName={(record, index) => { return record['reviewed'] ? '' : 'unreviewed'; }} /> { this.state.playbackVisible ? <Modal className='modal-no-padding' title={`会话回放 来源IP:${this.state.selectedRow['clientIp']} 用户昵称:${this.state.selectedRow['creatorName']} 资产名称:${this.state.selectedRow['assetName']} 网络:${this.state.selectedRow['username']}@${this.state.selectedRow['ip']}:${this.state.selectedRow['port']}`} centered={true} visible={this.state.playbackVisible} onCancel={this.hidePlayback} width={window.innerWidth * 0.8} footer={null} destroyOnClose maskClosable={false} > { this.state.selectedRow['mode'] === 'native' || this.state.selectedRow['mode'] === 'terminal' ? <iframe title='recording' style={{ width: '100%', // height: this.state.iFrameHeight, overflow: 'visible' }} onLoad={() => { // constant obj = ReactDOM.findDOMNode(this); // this.setState({ // "iFrameHeight": obj.contentWindow.document.body.scrollHeight + 'px' // }); }} ref="iframe" src={'./asciinema.html?sessionId=' + this.state.selectedRow['id']} width="100%" height={window.innerHeight * 0.8} frameBorder="0" /> : <Playback sessionId={this.state.selectedRow['id']}/> } </Modal> : undefined } </Content> </> ); }
Example #14
Source File: [id].js From zeroqueue with GNU General Public License v3.0 | 4 votes |
export default function Queue() {
const user = useUser({ redirectTo: '/' });
const router = useRouter();
const { id } = router.query;
const [queue, setQueue] = useState(null);
const [loadingQueue, setLoadingQueue] = useState(false);
useEffect(() => {
const fetchQueue = async () => {
try {
if (!user) return;
setLoadingQueue(true);
const res = await fetch(`/api/queue/${id}`);
const { data, error } = await res.json();
switch (res.status) {
case 200:
setQueue(data);
break;
default:
throw new Error(error);
}
} catch (error) {
message.error(error.message);
} finally {
setLoadingQueue(false);
}
};
fetchQueue();
}, [user]);
const [showNewJobsForm, setShowNewJobsForm] = useState(false);
const [jobs, setJobs] = useState(null);
const [loadingAddJobs, setLoadingAddJobs] = useState(false);
const onAddJob = async () => {
try {
if (!user) return;
setLoadingAddJobs(true);
const res = await fetch(`/api/queue/${id}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: jobs,
});
const { error } = await res.json();
switch (res.status) {
case 200:
location.reload();
break;
default:
throw new Error(error);
}
} catch (error) {
message.error(error.message);
} finally {
setLoadingAddJobs(false);
}
};
const [showWorkerCodeSample, setShowWorkerCodeSample] = useState(false);
const onDropdownClick = ({ key }) => {
switch (key) {
case DROPDOWN_KEYS.CODE_SAMPLE:
return setShowWorkerCodeSample(true);
default:
break;
}
};
const queueName = () => (queue && queue.name) || '...';
const [redis, setRedis] = useState(null);
const [loadingSecret, setLoadingSecret] = useState(null);
const onShowSecret = async (checked) => {
if (!checked) return setRedis(null);
try {
if (!user) return;
setLoadingSecret(true);
const res = await fetch(`/api/config`);
const { data, error } = await res.json();
switch (res.status) {
case 200:
setRedis(data.REDIS_URL);
break;
default:
throw new Error(error);
}
} catch (error) {
message.error(error.message);
} finally {
setLoadingSecret(false);
}
};
return (
<div>
<Head>
<title>Zero Queue</title>
<link rel="icon" href="/favicon.ico" />
</Head>
{user && (
<Layout className="dashboard-layout">
<Sidebar />
<Layout className="dashboard-layout">
<Header className="dashboard-header">
<div className="dashboard-header__space" />
<Button type="link" href="/api/auth/logout">
Logout
</Button>
</Header>
<Content className="dashboard-content">
<Breadcrumb className="dashboard-content__breadcrumb">
<Breadcrumb.Item>ZeroQueue</Breadcrumb.Item>
<Breadcrumb.Item>
<Link href={`/dashboard`}>
<a>Queue</a>
</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>{id}</Breadcrumb.Item>
</Breadcrumb>
<div className="dashboard-content__background">
<div className="dashboard-overview-header">
<Title className="dashboard-overview-header__title" level={3}>
{queueName()}
</Title>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() => setShowNewJobsForm(true)}
>
New Jobs
</Button>
<Dropdown
overlay={
<Menu onClick={onDropdownClick}>
<Menu.Item key={DROPDOWN_KEYS.CODE_SAMPLE}>
<ApiOutlined /> Code sample
</Menu.Item>
</Menu>
}
>
<Button className="dashboard-overview-header__last-button">
More <DownOutlined />
</Button>
</Dropdown>
</div>
<Table
rowKey="name"
loading={loadingQueue}
columns={columns(id)}
dataSource={(queue && queue.status) || []}
/>
</div>
</Content>
<Footer className="dashboard-footer">
<Button
type="link"
href="https://github.com/thezeroqueue/zeroqueue"
target="blank"
icon={<GithubFilled />}
/>
</Footer>
</Layout>
<Modal
title="Add new jobs"
visible={showNewJobsForm}
onCancel={() => setShowNewJobsForm(false)}
footer={null}
>
<Dragger {...uploadProps(setJobs)}>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text">Click or drag JSON file to this area to upload</p>
<p className="ant-upload-hint">See docs to learn more...</p>
</Dragger>
<br />
<Button
loading={loadingAddJobs}
disabled={!jobs}
type="primary"
block
onClick={onAddJob}
>
Add Jobs
</Button>
</Modal>
<Modal
title="Worker code sample"
width="45%"
visible={showWorkerCodeSample}
onCancel={() => setShowWorkerCodeSample(false)}
footer={null}
>
<p>Install dependencies:</p>
<InstallDependencies />
<div className="modal-inline-text">
<p>Use the following template:</p>
<p>
<Switch
unCheckedChildren={<EyeInvisibleOutlined />}
loading={loadingSecret}
onChange={onShowSecret}
/>
</p>
</div>
<Worker queue={queueName()} redis={redis} />
</Modal>
</Layout>
)}
</div>
);
}
Example #15
Source File: Annotations.js From label-studio-frontend with Apache License 2.0 | 4 votes |
Annotation = observer(({ item, store }) => {
const removeHoney = () => (
<Tooltip placement="topLeft" title="Unset this result as a ground truth">
<Button
size="small"
type="primary"
onClick={ev => {
ev.preventDefault();
item.setGroundTruth(false);
}}
>
<StarOutlined />
</Button>
</Tooltip>
);
const setHoney = () => {
const title = item.ground_truth
? "Unset this result as a ground truth"
: "Set this result as a ground truth";
return (
<Tooltip placement="topLeft" title={title}>
<Button
size="small"
look="link"
onClick={ev => {
ev.preventDefault();
item.setGroundTruth(!item.ground_truth);
}}
>
{item.ground_truth ? (
<StarFilled />
) : (
<StarOutlined />
)}
</Button>
</Tooltip>
);
};
const toggleVisibility = e => {
e.preventDefault();
e.stopPropagation();
item.toggleVisibility();
const c = document.getElementById(`c-${item.id}`);
if (c) c.style.display = item.hidden ? "none" : "unset";
};
const highlight = () => {
const c = document.getElementById(`c-${item.id}`);
if (c) c.classList.add("hover");
};
const unhighlight = () => {
const c = document.getElementById(`c-${item.id}`);
if (c) c.classList.remove("hover");
};
/**
* Default badge for saved annotations
*/
let badge = <Badge status="default" />;
/**
*
*/
let annotationID;
/**
* Title of card
*/
if (item.userGenerate && !item.sentUserGenerate) {
annotationID = <span className={styles.title}>Unsaved Annotation</span>;
} else {
if (item.pk) {
annotationID = <span className={styles.title}>ID {item.pk}</span>;
} else if (item.id) {
annotationID = <span className={styles.title}>ID {item.id}</span>;
}
}
/**
* Badge for processing of user generate annotation
*/
if (item.userGenerate) {
badge = <Badge status="processing" />;
}
/**
* Badge for complete of user generate annotation
*/
if (item.userGenerate && item.sentUserGenerate) {
badge = <Badge status="success" />;
}
const btnsView = () => {
const confirm = () => {
// ev.preventDefault();
// debugger;
item.list.deleteAnnotation(item);
};
return (
<div className={styles.buttons}>
{store.hasInterface("ground-truth") && (item.ground_truth ? removeHoney() : setHoney())}
{store.hasInterface("annotations:delete") && (
<Tooltip placement="topLeft" title="Delete selected annotation">
<Popconfirm
placement="bottomLeft"
title={"Please confirm you want to delete this annotation"}
onConfirm={confirm}
okText="Delete"
okType="danger"
cancelText="Cancel"
>
<Button size="small" danger style={{ background: "transparent" }}>
<DeleteOutlined />
</Button>
</Popconfirm>
</Tooltip>
)}
</div>
);
};
return (
<List.Item
key={item.id}
className={item.selected ? `${styles.annotation} ${styles.annotation_selected}` : styles.annotation}
onClick={() => {
!item.selected && store.annotationStore.selectAnnotation(item.id);
}}
onMouseEnter={highlight}
onMouseLeave={unhighlight}
>
<div className={styles.annotationcard}>
<div>
<div className={styles.title}>
{badge}
{annotationID}
</div>
{item.pk ? "Created" : "Started"}
<i>{item.createdAgo ? ` ${item.createdAgo} ago` : ` ${Utils.UDate.prettyDate(item.createdDate)}`}</i>
{item.createdBy && item.pk ? ` by ${item.createdBy}` : null}
<DraftPanel item={item} />
</div>
{/* platform uses was_cancelled so check both */}
{store.hasInterface("skip") && (item.skipped || item.was_cancelled) && (
<Tooltip placement="topLeft" title="Skipped annotation">
<StopOutlined className={styles.skipped} />
</Tooltip>
)}
{store.annotationStore.viewingAllAnnotations && (
<Button size="small" type="primary" ghost onClick={toggleVisibility}>
{item.hidden ? <EyeInvisibleOutlined /> : <EyeOutlined />}
</Button>
)}
{item.selected && btnsView()}
</div>
</List.Item>
);
})
Example #16
Source File: HeatmapMetadataTrackSettings.jsx From ui with MIT License | 4 votes |
HeatmapMetadataTrackSettings = (props) => {
const dispatch = useDispatch();
const { componentType } = props;
const hierarchy = useSelector(getCellSetsHierarchy());
const selectedTracks = useSelector(
(state) => state.componentConfig[componentType]?.config?.selectedTracks,
_.isEqual,
);
const [listData, setListData] = useState([]);
useEffect(() => {
if (hierarchy === null || _.isEmpty(hierarchy)) return;
const selectedTracksListData = convertToReorderableListData(
selectedTracks, true, hierarchy,
);
const unselectedTracks = _.difference(hierarchy.map(({ key }) => key), selectedTracks);
const unselectedTracksListData = convertToReorderableListData(
unselectedTracks, false, hierarchy,
);
setListData([...selectedTracksListData, ...unselectedTracksListData]);
}, [selectedTracks]);
const setTrackSelected = (selected, key) => {
const newSelectedTracks = [...selectedTracks];
if (selected) {
newSelectedTracks.push(key);
} else {
_.pull(newSelectedTracks, key);
}
dispatch(
updatePlotConfig(componentType, {
selectedTracks: newSelectedTracks,
}),
);
};
const setTrackOrder = (reorderedTracks) => {
const reorderedSelectedTrackKeys = reorderedTracks
.filter(({ disabledReorder }) => !disabledReorder)
.map(({ key }) => key);
dispatch(
updatePlotConfig(componentType, {
selectedTracks: reorderedSelectedTrackKeys,
}),
);
};
const leftItem = (trackDataItem) => (
<Switch
checkedChildren={<EyeOutlined />}
unCheckedChildren={<EyeInvisibleOutlined />}
value={trackDataItem.key}
checked={!trackDataItem.disabledReorder}
onChange={(selected) => {
setTrackSelected(selected, trackDataItem.key);
}}
/>
);
const rightItem = (trackDataItem) => (
hierarchy.filter((current) => current.key === trackDataItem.key)[0].name
);
return (
<div style={{ padding: '5px' }}>
<ReorderableList
onChange={setTrackOrder}
listData={listData}
leftItem={leftItem}
rightItem={rightItem}
/>
</div>
);
}