@ant-design/icons#MinusCircleOutlined JavaScript Examples

The following examples show how to use @ant-design/icons#MinusCircleOutlined. 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: edit.js    From FP with MIT License 6 votes vote down vote up
MutiFormBox = (props) => {
  const { option, value, onChange } = props;
  const [opts, setOpts] = useState(option || []);
  const tpl = [...value];
  const addRow = () => {
    let base = {label: '', value: ''}
    setOpts(prev => [...prev, base])
    onChange([...tpl, base])
  }
  const delRow = (index) => {
    opts.splice(index, 1)
    setOpts([...opts])
  }
  const handleChange = (index, e) => {
    // console.log(index, e.target.value)
    tpl[index].label = tpl[index].value = e.target.value
    onChange(tpl)
  }
  return <div className={styles.mutiRow}>
    {
      opts.map((item, i) => {
        return <div key={i} className={styles.mutiItem}>
                <span className={styles.label}>{`选项${i}:`}</span>
                <div className={styles.formItem}><Input defaultValue={value[i] ? value[i].label : ''} onChange={handleChange.bind(this, i)} /><MinusCircleOutlined onClick={delRow.bind(this, i)} /></div>
               </div>
      })
    }
    <Button type="primary" onClick={addRow} block>
      <PlusOutlined />
    </Button>
  </div>
}
Example #2
Source File: baseForm.js    From FP with MIT License 6 votes vote down vote up
BaseFormEl = (props) => {
  const {isEdit, onEdit, onDel, onAdd} = props
  const handleEdit = (v) => {
    onEdit && onEdit(v)
  }
  return <div className={styles.formControl} style={{border: `1px solid ${isEdit ? 'red' : 'transparent'}`}}>
    <div className={styles.formItem}>{ props.children }</div>
    <div className={styles.actionBar}>
      <span className={styles.actionItem} onClick={onDel}><MinusCircleOutlined /></span>
      <span className={styles.actionItem} onClick={onAdd}><PlusCircleOutlined /></span>
      <span className={styles.actionItem} onClick={handleEdit}><EditOutlined /></span>
    </div>
  </div>
}
Example #3
Source File: status.jsx    From virtuoso-design-system with MIT License 6 votes vote down vote up
storiesOf('antd/tag', module).add('status', () => 
  <>
    <Divider orientation="left">Without icon</Divider>
    <div>
      <Tag color="success">success</Tag>
      <Tag color="processing">processing</Tag>
      <Tag color="error">error</Tag>
      <Tag color="warning">warning</Tag>
      <Tag color="default">default</Tag>
    </div>
    <Divider orientation="left">With icon</Divider>
    <div>
      <Tag icon={<CheckCircleOutlined />} color="success">
        success
      </Tag>
      <Tag icon={<SyncOutlined spin />} color="processing">
        processing
      </Tag>
      <Tag icon={<CloseCircleOutlined />} color="error">
        error
      </Tag>
      <Tag icon={<ExclamationCircleOutlined />} color="warning">
        warning
      </Tag>
      <Tag icon={<ClockCircleOutlined />} color="default">
        waiting
      </Tag>
      <Tag icon={<MinusCircleOutlined />} color="default">
        stop
      </Tag>
    </div>
  </>,
  { docs: { page: () => (<><h1 id="enus">en-US</h1>
<p>We preset five different colors, you can set color property such as <code>success</code>,<code>processing</code>,<code>error</code>,<code>default</code> and <code>warning</code> to indicate specific status.</p></>) } });
Example #4
Source File: dynamic-form-items-complex.jsx    From virtuoso-design-system with MIT License 5 votes vote down vote up
Demo = () => {
  const [form] = Form.useForm();

  const onFinish = values => {
    console.log('Received values of form:', values);
  };

  const handleChange = () => {
    form.setFieldsValue({ sights: [] });
  };

  return (
    <Form form={form} name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
      <Form.Item name="area" label="Area" rules={[{ required: true, message: 'Missing area' }]}>
        <Select options={areas} onChange={handleChange} />
      </Form.Item>
      <Form.List name="sights">
        {(fields, { add, remove }) => (
          <>
            {fields.map(field => (
              <Space key={field.key} align="baseline">
                <Form.Item
                  noStyle
                  shouldUpdate={(prevValues, curValues) =>
                    prevValues.area !== curValues.area || prevValues.sights !== curValues.sights
                  }
                >
                  {() => (
                    <Form.Item
                      {...field}
                      label="Sight"
                      name={[field.name, 'sight']}
                      fieldKey={[field.fieldKey, 'sight']}
                      rules={[{ required: true, message: 'Missing sight' }]}
                    >
                      <Select disabled={!form.getFieldValue('area')} style={{ width: 130 }}>
                        {(sights[form.getFieldValue('area')] || []).map(item => (
                          <Option key={item} value={item}>
                            {item}
                          </Option>
                        ))}
                      </Select>
                    </Form.Item>
                  )}
                </Form.Item>
                <Form.Item
                  {...field}
                  label="Price"
                  name={[field.name, 'price']}
                  fieldKey={[field.fieldKey, 'price']}
                  rules={[{ required: true, message: 'Missing price' }]}
                >
                  <Input />
                </Form.Item>

                <MinusCircleOutlined onClick={() => remove(field.name)} />
              </Space>
            ))}

            <Form.Item>
              <Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
                Add sights
              </Button>
            </Form.Item>
          </>
        )}
      </Form.List>
      <Form.Item>
        <Button type="primary" htmlType="submit">
          Submit
        </Button>
      </Form.Item>
    </Form>
  );
}
Example #5
Source File: dynamic-form-items.jsx    From virtuoso-design-system with MIT License 5 votes vote down vote up
Demo = () => {
  const onFinish = values => {
    console.log('Received values of form:', values);
  };

  return (
    <Form name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
      <Form.List name="users">
        {(fields, { add, remove }) => (
          <>
            {fields.map(({ key, name, fieldKey, ...restField }) => (
              <Space key={key} style={{ display: 'flex', marginBottom: 8 }} align="baseline">
                <Form.Item
                  {...restField}
                  name={[name, 'first']}
                  fieldKey={[fieldKey, 'first']}
                  rules={[{ required: true, message: 'Missing first name' }]}
                >
                  <Input placeholder="First Name" />
                </Form.Item>
                <Form.Item
                  {...restField}
                  name={[name, 'last']}
                  fieldKey={[fieldKey, 'last']}
                  rules={[{ required: true, message: 'Missing last name' }]}
                >
                  <Input placeholder="Last Name" />
                </Form.Item>
                <MinusCircleOutlined onClick={() => remove(name)} />
              </Space>
            ))}
            <Form.Item>
              <Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
                Add field
              </Button>
            </Form.Item>
          </>
        )}
      </Form.List>
      <Form.Item>
        <Button type="primary" htmlType="submit">
          Submit
        </Button>
      </Form.Item>
    </Form>
  );
}
Example #6
Source File: adminChallengeCreate.js    From ctf_platform with MIT License 4 votes vote down vote up
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 #7
Source File: adminChallengeEdit.js    From ctf_platform with MIT License 4 votes vote down vote up
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 #8
Source File: adminUsers.js    From ctf_platform with MIT License 4 votes vote down vote up
render() {
        return (

            <Layout style={{ height: "100%", width: "100%", backgroundColor: "rgba(0, 0, 0, 0)" }}>

                <Modal
                    title={<span>Change User Permissions <ClusterOutlined /></span>}
                    visible={this.state.permissionModal}
                    onOk={this.changePermissions}
                    onCancel={() => { this.setState({ permissionModal: false }) }}
                    confirmLoading={this.state.modalLoading}
                >
                    <Select size="large" value={this.state.permissionChangeTo} style={{ width: "30ch" }} onSelect={(value) => { this.setState({ permissionChangeTo: value }) }}>
                        <Option value="0">0 - Normal User</Option>
                        <Option value="1">1 - Challenge Creator User</Option>
                        <Option value="2">2 - Admin User</Option>
                    </Select>
                    <br />
                    <br />

                    <ul>
                        <li><b>0 - Normal User</b>: Has access to the basic functions and nothing else</li>
                        <li><b>1 - Challenge Creator User</b>: Has the additional power of submitting new challenges, but not modifying existing ones</li>
                        <li><b>2 - Admin User</b>: Has full access to the platform via the admin panel.</li>
                    </ul>
                </Modal>

                <Modal
                    title="Create New Account"
                    visible={this.state.createUserModal}
                    footer={null}
                    onCancel={() => { this.setState({ createUserModal: false }) }}
                >

                    <RegisterForm createAccount={this.createAccount.bind(this)} setState={this.setState.bind(this)} />
                </Modal>

                <Modal
                    title={"Changing Account Password For: " + this.state.username}
                    visible={this.state.passwordResetModal}
                    footer={null}
                    onCancel={() => { this.setState({ passwordResetModal: false }) }}
                >

                    <ChangePasswordForm username={this.state.username} setState={this.setState.bind(this)} />
                </Modal>

                <Modal
                    title={"Changing Category For: " + this.state.username}
                    visible={this.state.categoryChangeModal}
                    footer={null}
                    onCancel={() => { this.setState({ categoryChangeModal: false }) }}
                >

                    <SelectParticipantCategoryForm fillTableData={this.fillTableData.bind(this)} categoryList={this.state.categoryList} username={this.state.username} participantCategory={this.state.participantCategory} />
                </Modal>

                <Modal
                    title={"Changing Email For: " + this.state.username}
                    visible={this.state.emailChangeModal}
                    footer={null}
                    onCancel={() => { this.setState({ emailChangeModal: false }) }}
                >

                    <ChangeEmailForm fillTableData={this.fillTableData.bind(this)} username={this.state.username} setState={this.setState.bind(this)} />
                </Modal>


                <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={<UserOutlined />} onClick={() => { this.setState({ createUserModal: true }) }}>Create New User</Button>
                        {this.state.loading && (
                            <div style={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
                                <Ellipsis color="#177ddc" size={60} ></Ellipsis>
                                <h1>Loading Users</h1>
                            </div>
                        )}
                    </div>
                    <Button loading={this.state.loading} type="primary" shape="circle" size="large" style={{ marginBottom: "2vh", maxWidth: "25ch" }} icon={<RedoOutlined />} onClick={async () => { await Promise.all([this.fillTableData(), this.getDisableStates()]); message.success("Users list refreshed.") }} />
                </div>
                <div style={{ display: "flex", alignItems: "center" }}>
                    <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 user(s) (' + this.state.selectedTableKeys.join(", ") + ')? This action is irreversible.',
                            icon: <ExclamationCircleOutlined />,
                            onOk: (close) => { this.deleteAccounts(close.bind(this), this.state.selectedTableKeys) },
                            onCancel: () => { },
                        });
                    }}>Delete Users</Button>
                    <Button type="default" disabled={this.state.disableEditButtons} style={{ marginBottom: "2vh", marginRight: "1ch", backgroundColor: "#6e6e6e" }} icon={<CheckOutlined style={{ color: "#49aa19" }} />} onClick={() => {
                        confirm({
                            confirmLoading: this.state.disableEditButtons,
                            title: 'Are you sure you want to verify the user(s) (' + this.state.selectedTableKeys.join(", ") + ')?',
                            icon: <ExclamationCircleOutlined />,
                            onOk: (close) => { this.verifyAccounts(close.bind(this), this.state.selectedTableKeys) },
                            onCancel: () => { },
                        });
                    }}>Verify Users</Button>
                    <Button type="default" disabled={this.state.disableEditButtons} style={{ marginBottom: "2vh", marginRight: "1ch", backgroundColor: "#6e6e6e" }} icon={<CloseOutlined style={{ color: "#a61d24" }} />} onClick={() => {
                        confirm({
                            confirmLoading: this.state.disableEditButtons,
                            title: 'Are you sure you want to un-verify the user(s) (' + this.state.selectedTableKeys.join(", ") + ')?',
                            content: 'Please note that this action will send a new email per user asking them to re-verify.',
                            icon: <ExclamationCircleOutlined />,
                            onOk: (close) => { this.unverifyAccounts(close.bind(this), this.state.selectedTableKeys) },
                            onCancel: () => { },
                        });
                    }}>Un-Verify Users</Button>
                </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 users found/created</h1>
                        </div>
                    )
                }}>
                    <Column title="Username" dataIndex="username" key="username"
                        render={(text, row, index) => {
                            return <Link to={"/Profile/" + text}><a style={{ fontWeight: 700 }}>{text}</a></Link>;
                        }}
                        filterDropdown={({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
                            <div style={{ padding: 8 }}>
                                <Input
                                    placeholder="Search Username"
                                    value={selectedKeys[0]}
                                    onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
                                    onPressEnter={() => confirm()}
                                    style={{ marginBottom: 8, display: 'block' }}
                                    autoFocus
                                />
                                <Space>
                                    <Button
                                        type="primary"
                                        onClick={() => { confirm() }}
                                        icon={<SearchOutlined />}
                                    >
                                        Search
                                    </Button>
                                    <Button onClick={() => clearFilters()}>
                                        Reset
                                    </Button>
                                </Space>
                            </div>
                        )}
                        onFilter={(value, record) => record.username.toLowerCase().trim().includes(value.toLowerCase())}
                        filterIcon={filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />}
                        sorter={(a, b) => {
                            if (a.username < b.username) return -1
                            else return 1
                        }}
                    />
                    <Column title="Email" dataIndex="email" key="email"
                        filterDropdown={({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
                            <div style={{ padding: 8 }}>
                                <Input
                                    placeholder="Search Email"
                                    value={selectedKeys[0]}
                                    onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
                                    onPressEnter={() => confirm()}
                                    style={{ marginBottom: 8, display: 'block' }}
                                    autoFocus
                                />
                                <Space>
                                    <Button
                                        type="primary"
                                        onClick={() => { confirm() }}
                                        icon={<SearchOutlined />}
                                    >
                                        Search
                                    </Button>
                                    <Button onClick={() => clearFilters()}>
                                        Reset
                                    </Button>
                                </Space>
                            </div>
                        )}
                        onFilter={(value, record) => record.email.toLowerCase().trim().includes(value.toLowerCase())}
                        filterIcon={filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />}
                    />
                    <Column title="Permissions" dataIndex="type" key="type" filters={[{ text: "Normal User (0)", value: 0 }, { text: "Challenge Creator (1)", value: 1 }, { text: "Admin (2)", value: 2 }]} onFilter={(value, record) => { return value === record.type }} />
                    <Column title="Team" dataIndex="team" key="team"
                        render={(text, row, index) => {
                            if (text != "N/A") return <Link to={"/Team/" + text}><a style={{ fontWeight: 700 }}>{text}</a></Link>;
                            else return text;
                        }}
                        filterDropdown={({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
                            <div style={{ padding: 8 }}>
                                <Input
                                    placeholder="Search Team"
                                    value={selectedKeys[0]}
                                    onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
                                    onPressEnter={() => confirm()}
                                    style={{ marginBottom: 8, display: 'block' }}
                                    autoFocus
                                />
                                <Space>
                                    <Button
                                        type="primary"
                                        onClick={() => { confirm() }}
                                        icon={<SearchOutlined />}
                                    >
                                        Search
                                    </Button>
                                    <Button onClick={() => clearFilters()}>
                                        Reset
                                    </Button>
                                </Space>
                            </div>
                        )}
                        onFilter={(value, record) => record.team.toLowerCase().trim().includes(value.toLowerCase())}
                        filterIcon={filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />}
                    />
                    <Column title="Category" dataIndex="category" key="category" filters={
                        this.state.categoryList.map((category) => {
                            return { text: category, value: category }
                        })} onFilter={(value, record) => { return value === record.category }} />
                    <Column title="Verified" dataIndex="verified" key="verified" filters={[{ text: "Verified", value: "True" }, { text: "Unverified", value: "False" }]} onFilter={(value, record) => { return value === record.verified }} />
                    <Column
                        title=""
                        key="action"
                        render={(text, record) => (
                            <Dropdown trigger={['click']} overlay={
                                <Menu>
                                    <Menu.Item onClick={() => {
                                        this.setState({ permissionModal: true, username: record.username, permissionChangeTo: record.type.toString() })
                                    }}>
                                        <span>
                                            Change Permissions <ClusterOutlined />
                                        </span>
                                    </Menu.Item>
                                    <Menu.Item onClick={() => {
                                        this.setState({ passwordResetModal: true, username: record.username })
                                    }}>
                                        <span>
                                            Change Password <KeyOutlined />
                                        </span>
                                    </Menu.Item>
                                    <Menu.Item onClick={() => {
                                        this.setState({ emailChangeModal: true, username: record.username })
                                    }}>
                                        <span>
                                            Change Email <MailOutlined />
                                        </span>
                                    </Menu.Item>
                                    <Menu.Item onClick={() => {
                                        this.setState({ categoryChangeModal: true, username: record.username, participantCategory: record.category })
                                    }}>
                                        <span>
                                            Change Category <ApartmentOutlined />
                                        </span>
                                    </Menu.Item>
                                </Menu>
                            } placement="bottomCenter">
                                <Button>Actions</Button>
                            </Dropdown>
                        )}
                    />
                </Table>

                <Divider />

                <div className="settings-responsive2" style={{ display: "flex", justifyContent: "space-around" }}>

                    <Card className="settings-card">
                        <h3>Disable User Registration:  <Switch disabled={this.state.disableLoading} onClick={(value) => this.disableSetting("registerDisable", value)} checked={this.state.registerDisable} /></h3>
                        <p>Disables user registration for unregistered users. Admins can still create users from this page.</p>
                    </Card>

                    <Divider type="vertical" style={{ height: "inherit" }} />

                    <Card className="settings-card">
                        <h3>Disable User Logins:  <Switch disabled={this.state.disableLoading2} onClick={(value) => this.disableSetting("loginDisable", value)} checked={this.state.loginDisable} /></h3>
                        <p>Disables user login except for admin users. <br /><b>Note:</b> Users already logged into the platform will remain authenticated as tokens cannot be revoked. If you want to restrict a user from accessing the platform anymore, simply delete their account.</p>
                    </Card>

                    <Divider type="vertical" style={{ height: "inherit" }} />

                    <Card className="settings-card">
                        <h3>Disable Admin Scores:  <Switch disabled={this.state.disableLoading2} onClick={(value) => this.disableSetting("adminShowDisable", value)} checked={this.state.adminShowDisable} /></h3>
                        <p>Prevents admin scores from showing up on scoreboards and profile pages. Admin solves will still appear under the solve list in challenges. <br /> Please note that disabling/enabling this will require users to reopen ctfx to resync the scoreboard.</p>
                    </Card>
                </div>

                <Divider />

                <div className="settings-responsive2" style={{ display: "flex", justifyContent: "space-around" }}>

                    <Card className="settings-card">
                        <h3>Profile Picture Max Upload Size: <InputNumber
                            formatter={value => `${value}B`}
                            parser={value => value.replace('B', '')}
                            value={this.state.uploadSize}
                            disabled={this.state.uploadLoading}
                            onChange={(value) => this.setState({ uploadSize: value })}
                            onPressEnter={(e) => { this.changeSetting("uploadSize", this.state.uploadSize) }} /></h3>

                        <p>Sets the maximum file upload size for profile pictures (in Bytes). Press <b>Enter</b> to save</p>
                    </Card>

                    <Divider type="vertical" style={{ height: "inherit" }} />

                    <Card className="settings-card">
                        <h3>Disable Category Switches:  <Switch disabled={this.state.disableLoading2} onClick={(value) => this.disableSetting("categorySwitchDisable", value)} checked={this.state.categorySwitchDisable} /></h3>
                        <p>Prevents users from switching their scoreboard category. Useful during competitions where you want to lock the user into a category</p>
                    </Card>

                    <Divider type="vertical" style={{ height: "inherit" }} />

                    <Card className="settings-card">
                        <h3>User Category Management <UserOutlined /></h3>
                        <Space direction="vertical">
                            {this.state.categoryList.map((category) => {
                                return (
                                    <div style={{ display: 'flex', alignItems: "center" }}>
                                        <Input disabled value={category} />
                                         <MinusCircleOutlined onClick={() => { this.removeCategory(category) }} style={{ cursor: "pointer", marginLeft: "1ch", color: "#f5222d" }} />
                                    </div>
                                )
                            })}
                            <div style={{ display: "flex" }}>
                                <Input value={this.state.newCategoryValue} onChange={(e) => { this.setState({ newCategoryValue: e.target.value }) }} />
                                <Button
                                    loading={this.state.addCategoryLoading}
                                    style={{ marginLeft: "1ch" }}
                                    type="dashed"
                                    onClick={() => {
                                        this.addCategory()
                                    }}
                                >
                                    <PlusOutlined /> Add Category
                                </Button>
                            </div>
                        </Space>
                    </Card>
                </div>

                <Divider />

                <div className="settings-responsive2" style={{ display: "flex", justifyContent: "space-around" }}>

                    <Card className="settings-card">
                        <h3>Max Team Size: <InputNumber
                            value={this.state.teamMaxSize}
                            onChange={(value) => this.setState({ teamMaxSize: value })}
                            onPressEnter={(e) => { this.changeSetting("teamMaxSize", this.state.teamMaxSize) }} />
                        </h3>
                        <p>Sets the maximum number of members in a team. Press <b>Enter</b> to save</p>
                    </Card>

                    <Divider type="vertical" style={{ height: "inherit" }} />

                    <Card className="settings-card">
                        <h3>Enable Teams:  <Switch disabled={this.state.disableLoading3} onClick={(value) => this.disableSetting("teamMode", value)} checked={this.state.teamMode} /></h3>
                        <p>Enable teams for the platform. Users in a team will have their scores combined on the scoreboard <br /> Please note that disabling/enabling this will require users to reopen ctfx to resync the scoreboard.</p>
                    </Card>

                    <Divider type="vertical" style={{ height: "inherit" }} />

                    <Card className="settings-card">
                        <h3>Disable Team Switching:  <Switch disabled={this.state.disableLoading3} onClick={(value) => this.disableSetting("teamChangeDisable", value)} checked={this.state.teamChangeDisable} /></h3>
                        <p>Prevents users from leaving, joining & creating a team. Enable this option if you want to prevent any team changes during a competition</p>
                    </Card>
                </div>

                <Divider />

                <div className="settings-responsive2" style={{ display: "flex", justifyContent: "space-around" }}>

                    <Card className="settings-card">
                        <h3>Enable Password Reset  <Switch disabled={this.state.disableLoading2} onClick={(value) => this.disableSetting("forgotPass", value)} checked={this.state.forgotPass} /></h3>
                        <p>Allow users to use the "Forgot Password" option to reset their password. <br />Please ensure that you have connected to an SMTP server correctly in the "Email" tab</p>
                    </Card>

                    <Divider type="vertical" style={{ height: "inherit" }} />

                    <Card className="settings-card">
                        <h3>Enable Email Verification  <Switch disabled={this.state.disableLoading2} onClick={(value) => this.disableSetting("emailVerify", value)} checked={this.state.emailVerify} /></h3>
                        <p>Forces newly registered users to <b>verify their email</b> before being able to access the site.</p>
                    </Card>

                    <Divider type="vertical" style={{ height: "inherit" }} />

                    <Card className="settings-card">
                        <h3>Profile Picture Upload Path
                            <Input
                                value={this.state.uploadPath}
                                onChange={(e) => this.setState({ uploadPath: e.target.value })}
                                onPressEnter={(e) => { this.changeSetting("uploadPath", this.state.uploadPath) }} /></h3>
                        <p>Sets the file upload path for profile pictures. Please ensure that the folder has the appropriate permissions <br />set for the Node process to save the file there. Press <b>Enter</b> to save</p>
                    </Card>
                </div>

            </Layout>
        );
    }
Example #9
Source File: userChallengeCreate.js    From ctf_platform with MIT License 4 votes vote down vote up
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 #10
Source File: ChannelSetting.js    From network-rc with Apache License 2.0 4 votes vote down vote up
export default function ChannelSetting({
  saveServerConfig,
  serverConfig,
  resetChannel,
}) {
  const [form] = Form.useForm();

  useEffect(() => {
    form.resetFields();
  }, [serverConfig, form]);

  const ui = (index, fields, { add, remove }) => {
    return (
      <Space align="baseline" split={<Divider type="vertical" />} wrap>
        {fields.map((field) => {
          const uiId = form.getFieldValue([
            "channelList",
            index,
            "ui",
            field.name,
            "id",
          ]);
          const uiComponent = serverConfig.uiComponentList.find(
            (i) => i.id === uiId
          );
          return (
            <Space key={field.key} align="baseline">
              <Form.Item
                label="UI"
                {...field}
                name={[field.name, "id"]}
                fieldKey={[field.fieldKey, "id"]}
                rules={[{ required: true, message: "客官!选一个!" }]}
              >
                <Select style={{ width: 80 }}>
                  {serverConfig.uiComponentList.map(({ id, name }) => (
                    <Option value={id}> {name} </Option>
                  ))}
                </Select>
              </Form.Item>
              {uiComponent && uiComponent.type === "joystick" && (
                <Form.Item
                  label="轴"
                  {...field}
                  name={[field.name, "axis"]}
                  fieldKey={[field.fieldKey, "axis"]}
                  rules={[{ required: true, message: "客官!选一个!" }]}
                >
                  <Select style={{ width: 80 }}>
                    <Option value="x">x</Option>
                    <Option value="y">y</Option>
                  </Select>
                </Form.Item>
              )}
              <Form.Item
                label="控制方向"
                {...field}
                name={[field.name, "positive"]}
                fieldKey={[field.fieldKey, "positive"]}
                valuePropName="checked"
              >
                <Switch checkedChildren="正向" unCheckedChildren="反向" />
              </Form.Item>
              <Form.Item
                label="控制方式"
                {...field}
                name={[field.name, "method"]}
                fieldKey={[field.fieldKey, "method"]}
              >
                <Select style={{ width: 80 }}>
                  <Option value="default">默认</Option>
                  <Option value="step">步进</Option>
                </Select>
              </Form.Item>
              <Form.Item
                label="步进速度"
                {...field}
                name={[field.name, "speed"]}
                fieldKey={[field.fieldKey, "speed"]}
                initialValue={0.5}
              >
                <InputNumber
                  step={0.1}
                  min={0}
                  disabled={
                    "step" !==
                    form.getFieldValue([
                      "channelList",
                      index,
                      "ui",
                      field.name,
                      "method",
                    ])
                  }
                />
              </Form.Item>
              <MinusCircleOutlined onClick={() => remove(field.name)} />
            </Space>
          );
        })}
        <PlusCircleOutlined
          onClick={() =>
            add({
              positive: true,
              method: "default",
            })
          }
        />
      </Space>
    );
  };

  const keyboard = (index, fields, { add, remove }) => {
    const type = form.getFieldValue(["channelList", index, "type"]);
    return (
      <Space align="baseline" direction="vertical">
        {fields.map((field) => {
          const method = form.getFieldValue([
            "channelList",
            index,
            "keyboard",
            field.name,
            "method",
          ]);

          return (
            <Space key={field.key} align="baseline">
              <Form.Item
                {...field}
                name={[field.name, "name"]}
                fieldKey={[field.fieldKey, "name"]}
                rules={[{ required: true, message: "客官!选一个按键!" }]}
                extra="键盘按键"
              >
                <Input style={{ width: 80 }} />
              </Form.Item>

              {type === "pwm" && (
                <Form.Item
                  {...field}
                  name={[field.name, "method"]}
                  fieldKey={[field.fieldKey, "method"]}
                  defaultValue="default"
                  extra="控制方式"
                >
                  <Radio.Group size="middle">
                    <Radio.Button value="default">默认</Radio.Button>
                    <Radio.Button value="step">步进</Radio.Button>
                  </Radio.Group>
                </Form.Item>
              )}

              {type === "pwm" && (
                <Form.Item
                  {...field}
                  name={[field.name, "speed"]}
                  fieldKey={[field.fieldKey, "speed"]}
                  extra={
                    method === "default"
                      ? "-1 ~ 1, 0 为归位"
                      : "每秒步进速度系数"
                  }
                >
                  <InputNumber max={1} min={-1} step={0.1} />
                </Form.Item>
              )}

              {/* {type === "switch" && (
                <Form.Item
                  {...field}
                  name={[field.name, "speed"]}
                  fieldKey={[field.fieldKey, "speed"]}
                  extra="高低电平"
                >
                  <Radio.Group size="middle">
                    <Radio.Button value={1}>高</Radio.Button>
                    <Radio.Button value={-1}>低</Radio.Button>
                  </Radio.Group>
                </Form.Item>
              )} */}

              {(method === "default" || type === "switch") && (
                <Form.Item
                  {...field}
                  name={[field.name, "autoReset"]}
                  fieldKey={[field.fieldKey, "autoReset"]}
                  extra="释放键盘是否复位"
                  valuePropName="checked"
                  defaultValue={true}
                >
                  <Switch />
                </Form.Item>
              )}

              <MinusCircleOutlined onClick={() => remove(field.name)} />
            </Space>
          );
        })}
        <PlusCircleOutlined
          onClick={() =>
            add({
              speed: 1,
              autoReset: true,
              method: "default",
            })
          }
        />
      </Space>
    );
  };

  const gamepad = (index, fields, { add, remove }) => {
    const type = form.getFieldValue(["channelList", index, "type"]);

    return (
      <Space align="baseline" split={<Divider type="vertical" />} wrap>
        {fields.map((field) => {
          // const method = form.getFieldValue([
          //   "channelList",
          //   index,
          //   "gamepad",
          //   field.name,
          //   "method",
          // ]);
          return (
            <Space key={field.key} align="baseline">
              <Form.Item
                {...field}
                name={[field.name, "name"]}
                fieldKey={[field.fieldKey, "name"]}
                rules={[{ required: true, message: "客官!选一个!" }]}
                extra="摇杆轴或按键"
              >
                <Select style={{ width: 100 }}>
                  {gamePadInputList.map(({ value, name }) => (
                    <Option value={value}> {name} </Option>
                  ))}
                </Select>
              </Form.Item>

              {type === "pwm" && (
                <Form.Item
                  {...field}
                  name={[field.name, "method"]}
                  fieldKey={[field.fieldKey, "method"]}
                  defaultValue="default"
                  extra="控制方式"
                >
                  <Radio.Group size="middle">
                    <Radio.Button value="default">默认</Radio.Button>
                    <Radio.Button value="step">步进</Radio.Button>
                  </Radio.Group>
                </Form.Item>
              )}

              {type === "pwm" && (
                <Form.Item
                  {...field}
                  name={[field.name, "speed"]}
                  fieldKey={[field.fieldKey, "speed"]}
                  extra="控制系数,-1 ~ 1"
                >
                  <InputNumber min={-1} max={1} step={0.1} />
                </Form.Item>
              )}

              {/* {method === "default" && (
                <Form.Item
                  {...field}
                  name={[field.name, "autoReset"]}
                  fieldKey={[field.fieldKey, "autoReset"]}
                  extra="释放按钮是否复位"
                  valuePropName="checked"
                  defaultValue={true}
                >
                  <Switch />
                </Form.Item>
              )} */}

              {/* {type === "switch" && (
                <Form.Item
                  {...field}
                  name={[field.name, "speed"]}
                  fieldKey={[field.fieldKey, "speed"]}
                  extra="高低电平"
                >
                  <Radio.Group size="middle">
                    <Radio.Button value={1}>高</Radio.Button>
                    <Radio.Button value={-1}>低</Radio.Button>
                  </Radio.Group>
                </Form.Item>
              )} */}

              <MinusCircleOutlined onClick={() => remove(field.name)} />
            </Space>
          );
        })}
        <PlusCircleOutlined
          onClick={() =>
            add({
              speed: 1,
              autoReset: true,
              method: "default",
            })
          }
        />
      </Space>
    );
  };

  return (
    <Form form={form} onFinish={saveServerConfig} initialValues={serverConfig}>
      <Form.List name="channelList">
        {(fields, { add, remove }) => (
          <Space
            key={fields.key}
            direction="vertical"
            style={{ width: "100%" }}
          >
            {fields.map((field) => (
              <Card
                key={field.key}
                title={
                  <Space key={field.key} align="baseline" wrap>
                    <Form.Item
                      {...field}
                      name={[field.name, "enabled"]}
                      fieldKey={[field.fieldKey, "enabled"]}
                      valuePropName="checked"
                    >
                      <Switch checkedChildren="开启" unCheckedChildren="禁用" />
                    </Form.Item>
                    <Form.Item
                      {...field}
                      label="名称"
                      name={[field.name, "name"]}
                      fieldKey={[field.fieldKey, "name"]}
                    >
                      <Input style={{ width: 80 }} />
                    </Form.Item>
                    <Button danger onClick={() => remove(field.name)}>
                      <DeleteOutlined />
                    </Button>
                  </Space>
                }
              >
                <Row>
                  <Space key={field.key} align="baseline" wrap>
                    <Form.Item
                      {...field}
                      label="GPIO"
                      name={[field.name, "pin"]}
                      fieldKey={[field.fieldKey, "pin"]}
                      rules={[{ required: true, message: "仔细想想" }]}
                    >
                      <Select style={{ width: 60 }}>
                        {pins.map((pin) => (
                          <Option key={pin} value={pin}>
                            {pin}
                          </Option>
                        ))}
                      </Select>
                    </Form.Item>
                    <Form.Item
                      {...field}
                      label="类型"
                      name={[field.name, "type"]}
                      fieldKey={[field.fieldKey, "type"]}
                      rules={[{ required: true, message: "你不能没有我!" }]}
                    >
                      <Select style={{ width: 80 }}>
                        {types.map(({ value, label }) => (
                          <Option key={value} value={value}>
                            {label}
                          </Option>
                        ))}
                      </Select>
                    </Form.Item>
                    {form.getFieldValue([
                      "channelList",
                      field.fieldKey,
                      "type",
                    ]) === "pwm" && (
                      <>
                        <Form.Item
                          {...field}
                          label="最大值"
                          name={[field.name, "valuePostive"]}
                          fieldKey={[field.fieldKey, "valuePostive"]}
                        >
                          <InputNumber
                            step={0.1}
                            max={2}
                            min={form.getFieldValue([
                              "channelList",
                              field.fieldKey,
                              "valueReset",
                            ])}
                          />
                        </Form.Item>
                        <Form.Item
                          {...field}
                          label="复位值"
                          name={[field.name, "valueReset"]}
                          fieldKey={[field.fieldKey, "valueReset"]}
                          shouldUpdate
                        >
                          <InputNumber
                            step={0.1}
                            min={form.getFieldValue([
                              "channelList",
                              field.fieldKey,
                              "valueNegative",
                            ])}
                            max={form.getFieldValue([
                              "channelList",
                              field.fieldKey,
                              "valuePostive",
                            ])}
                          />
                        </Form.Item>
                        <Form.Item
                          {...field}
                          label="最小值"
                          name={[field.name, "valueNegative"]}
                          fieldKey={[field.fieldKey, "valueNegative"]}
                        >
                          <InputNumber
                            step={0.1}
                            min={-2}
                            max={form.getFieldValue([
                              "channelList",
                              field.fieldKey,
                              "valueReset",
                            ])}
                          />
                        </Form.Item>
                      </>
                    )}
                  </Space>
                </Row>

                <Collapse align="start">
                  <Panel header="UI 控件" size="small">
                    <Form.List name={[field.name, "ui"]}>
                      {(...props) => ui(field.fieldKey, ...props)}
                    </Form.List>
                  </Panel>
                  <Panel header="键盘" size="small">
                    <Form.List name={[field.name, "keyboard"]}>
                      {(...props) => keyboard(field.fieldKey, ...props)}
                    </Form.List>
                  </Panel>
                  <Panel header="手柄" size="small">
                    <Form.List name={[field.name, "gamepad"]}>
                      {(...props) => gamepad(field.fieldKey, ...props)}
                    </Form.List>
                  </Panel>
                  <Panel header="手机重力感应" size="small">
                    <Form.Item
                      {...field}
                      label="方向"
                      name={[field.name, "orientation", "axis"]}
                      fieldKey={[field.fieldKey, "orientation", "axis"]}
                    >
                      <Select style={{ width: 80 }} allowClear>
                        {[
                          { name: "水平", value: "x" },
                          { name: "垂直", value: "y" },
                        ].map((i) => (
                          <Option key={i.value} value={i.value}>
                            {i.name}
                          </Option>
                        ))}
                      </Select>
                    </Form.Item>
                    <Form.Item
                      {...field}
                      label="系数"
                      name={[field.name, "orientation", "coefficient"]}
                      fieldKey={[field.fieldKey, "orientation", "coefficient"]}
                    >
                      <Slider defaultValue={1} max={2} min={-2} step={0.01} />
                    </Form.Item>
                  </Panel>
                </Collapse>
              </Card>
            ))}

            <Form.Item>
              <Button
                onClick={() =>
                  add({
                    id: uuid(),
                    enabled: true,
                    valuePostive: 1,
                    valueNegative: -1,
                    valueReset: 0,
                  })
                }
                block
                icon={<PlusOutlined />}
              >
                添加通道
              </Button>
            </Form.Item>
          </Space>
        )}
      </Form.List>

      <Form.Item>
        <Space>
          <Button type="primary" htmlType="submit">
            保存
          </Button>
          <Button
            type="danger"
            onClick={() => {
              resetChannel();
              store.remove("ui-position");
            }}
          >
            恢复默认通道设置
          </Button>
        </Space>
      </Form.Item>
    </Form>
  );
}
Example #11
Source File: SoundSetting.js    From network-rc with Apache License 2.0 4 votes vote down vote up
export default function SoundSetting({
  micVolume,
  audioList,
  saveServerConfig,
  host,
}) {
  const [form] = Form.useForm();

  const { data: currentSpeaker = {} } = useRequest(
    `${protocol}//${host}/api/speaker/current`,
    {
      onSuccess: () => {
        form.resetFields();
      },
    }
  );

  const { data: speakerList = [] } = useRequest(
    `${protocol}//${host}/api/speaker`
  );

  const { run: setSpeaker } = useRequest(
    () => ({
      url: `${protocol}//${host}/api/speaker/set`,
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ name: form.getFieldValue("currentSpeakerName") }),
    }),
    {
      manual: true,
    }
  );

  const { run: setSpeakerVolume } = useRequest(
    () => ({
      url: `${protocol}//${host}/api/speaker/volume`,
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        name: form.getFieldValue("currentSpeakerName"),
        volume: form.getFieldValue("currentSpeakerVolume"),
      }),
    }),
    {
      manual: true,
    }
  );

  const { data: currentMic = {} } = useRequest(
    `${protocol}//${host}/api/mic/current`,
    {
      onSuccess: () => {
        form.resetFields();
      },
    }
  );

  const { data: micList = [] } = useRequest(`${protocol}//${host}/api/mic`);

  const { run: setMic } = useRequest(
    () => ({
      url: `${protocol}//${host}/api/mic/set`,
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ name: form.getFieldValue("currentMicName") }),
    }),
    {
      manual: true,
    }
  );

  const { run: setMicVolume } = useRequest(
    () => ({
      url: `${protocol}//${host}/api/mic/volume`,
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        name: form.getFieldValue("currentMicName"),
        volume: form.getFieldValue("currentMicVolume"),
      }),
    }),
    {
      manual: true,
    }
  );

  return (
    <Form
      form={form}
      {...layout}
      initialValues={{
        audioList,
        currentSpeakerName: currentSpeaker?.name,
        currentSpeakerVolume: currentSpeaker?.volume || 0,
        currentMicName: currentMic?.name,
        currentMicVolume: currentMic?.volume || 0,
      }}
    >
      <Form.Item label="喇叭音量" name="currentSpeakerVolume">
        <Slider
          min={0}
          max={100}
          value={currentSpeaker?.volume}
          onAfterChange={setSpeakerVolume}
        />
      </Form.Item>
      <Form.Item label="输出设备" name="currentSpeakerName">
        <Select onChange={setSpeaker}>
          {speakerList.map(({ name, displayName, volume }) => (
            <Option key={name} value={name}>
              {`${displayName}(${volume}%)`}
            </Option>
          ))}
        </Select>
      </Form.Item>

      <Form.Item label="麦克风音量" name="currentMicVolume">
        <Slider
          min={0}
          max={100}
          value={micVolume}
          onAfterChange={setMicVolume}
        />
      </Form.Item>
      <Form.Item label="选择麦克风" name="currentMicName">
        <Select onChange={setMic}>
          {micList.map(({ name, displayName, volume }) => (
            <Option key={name} value={name}>
              {`${displayName}(${volume}%)`}
            </Option>
          ))}
        </Select>
      </Form.Item>
      <Form.Item label="快捷播放">
        <Form.List name="audioList">
          {(fields, { add, remove }) => (
            <>
              {fields.map(({ key, name, ...restField }) => (
                <Space
                  key={key}
                  style={{ display: "flex", marginBottom: 8 }}
                  align="baseline"
                >
                  <Form.Item {...restField} name={[name, "type"]} extra="类型">
                    <Select onChange={setSpeaker}>
                      <Option key="audio" value="audio">
                        文件
                      </Option>
                      <Option key="test" value="text">
                        语音
                      </Option>
                      <Option key="stop" value="stop">
                        停止
                      </Option>
                    </Select>
                  </Form.Item>

                  {form.getFieldValue(["audioList", name, "type"]) ===
                    "audio" && (
                    <>
                      <Form.Item
                        {...restField}
                        name={[name, "name"]}
                        rules={[
                          { required: true, message: "写个名字日后好相见" },
                        ]}
                        style={{ width: 80 }}
                        extra="名称"
                      >
                        <Input placeholder="写个名字日后好相见" />
                      </Form.Item>
                      <Form.Item
                        {...restField}
                        name={[name, "path"]}
                        extra="文件在树莓派上完整路径"
                      >
                        <Input placeholder="文件路径" />
                        {/* <Upload /> */}
                      </Form.Item>
                    </>
                  )}

                  {form.getFieldValue(["audioList", name, "type"]) ===
                    "text" && (
                    <>
                      <Form.Item
                        {...restField}
                        name={[name, "text"]}
                        extra="语音播报文本"
                      >
                        <Input placeholder="语音播报文本" allowClear />
                      </Form.Item>
                    </>
                  )}

                  <Form.Item
                    {...restField}
                    name={[name, "keyboard"]}
                    style={{ width: 80 }}
                    extra="⌨️ 按键"
                  >
                    <Input placeholder="键盘" prefix="⌨️" />
                  </Form.Item>
                  <Form.Item
                    {...restField}
                    name={[name, "gamepadButton"]}
                    extra={
                      <span>
                        ? 编号
                        <a
                          href="https://gamepad-tester.com"
                          target="_blank"
                          rel="noreferrer"
                        >
                          测试网页
                        </a>
                      </span>
                    }
                  >
                    <InputNumber min={0} max={99} />
                  </Form.Item>
                  <Form.Item
                    {...restField}
                    name={[name, "showFooter"]}
                    extra="在底部显示"
                    valuePropName="checked"
                  >
                    <Switch />
                  </Form.Item>
                  <Button
                    icon={<MinusCircleOutlined />}
                    type="dashed"
                    onClick={() => remove(name)}
                  ></Button>
                </Space>
              ))}
              <Form.Item>
                <Space>
                  <Button
                    icon={<PlusCircleOutlined />}
                    type="dashed"
                    onClick={() => add({ showFooter: false })}
                  ></Button>
                  <Button
                    type="primary"
                    onClick={() => {
                      saveServerConfig({
                        audioList: form.getFieldValue("audioList"),
                      });
                    }}
                  >
                    保存
                  </Button>
                </Space>
              </Form.Item>
            </>
          )}
        </Form.List>
      </Form.Item>
    </Form>
  );
}
Example #12
Source File: UISetting.js    From network-rc with Apache License 2.0 4 votes vote down vote up
export default function UISetting({ saveServerConfig, serverConfig }) {
  const [form] = Form.useForm();
  return (
    <Form form={form} onFinish={saveServerConfig} initialValues={serverConfig}>
      <Form.List name="uiComponentList">
        {(fields, { add, remove }) => (
          <>
            {fields.map((field) => (
              <Row>
                <Space key={field.key} align="baseline">
                  <Form.Item
                    {...field}
                    name={[field.name, "enabled"]}
                    fieldKey={[field.fieldKey, "enabled"]}
                    valuePropName="checked"
                  >
                    <Switch checkedChildren="显示" unCheckedChildren="隐藏" />
                  </Form.Item>
                  <Form.Item
                    {...field}
                    label="名称"
                    name={[field.name, "name"]}
                    fieldKey={[field.fieldKey, "name"]}
                  >
                    <Input style={{ width: 80 }} />
                  </Form.Item>
                  <Form.Item
                    {...field}
                    label="类型"
                    name={[field.name, "type"]}
                    fieldKey={[field.fieldKey, "type"]}
                    rules={[{ required: true, message: "你还没选" }]}
                  >
                    <Select style={{ width: 72 }}>
                      {types.map(({ value, label }) => (
                        <Option key={value} value={value}>
                          {label}
                        </Option>
                      ))}
                    </Select>
                  </Form.Item>
                  <Form.Item
                    {...field}
                    label="释放归位"
                    name={[field.name, "autoReset"]}
                    fieldKey={[field.fieldKey, "autoReset"]}
                    valuePropName="checked"
                    extra="释放 UI 控件是否自动归位"
                  >
                    <Switch />
                  </Form.Item>
                  {form.getFieldValue([
                    "uiComponentList",
                    field.fieldKey,
                    "type",
                  ]) === "slider" && (
                    <Form.Item
                      {...field}
                      label="方向"
                      name={[field.name, "vertical"]}
                      fieldKey={[field.fieldKey, "vertical"]}
                      shouldUpdate
                      rules={[{ required: true, message: "你还没选" }]}
                    >
                      <Select style={{ width: 80 }}>
                        <Option value={false}> 横向 </Option>
                        <Option value={true}> 垂直 </Option>
                      </Select>
                    </Form.Item>
                  )}
                  <MinusCircleOutlined onClick={() => remove(field.name)} />
                </Space>
              </Row>
            ))}

            <Form.Item>
              <Button
                type="dashed"
                onClick={() =>
                  add({
                    id: uuid(),
                    enabled: true,
                  })
                }
                block
                icon={<PlusOutlined />}
              >
                添加控制组件
              </Button>
            </Form.Item>
          </>
        )}
      </Form.List>
      <Form.Item>
        <Button type="primary" htmlType="submit">
          保存
        </Button>
      </Form.Item>
    </Form>
  );
}
Example #13
Source File: dynamic-form-item.jsx    From virtuoso-design-system with MIT License 4 votes vote down vote up
DynamicFieldSet = () => {
  const onFinish = values => {
    console.log('Received values of form:', values);
  };

  return (
    <Form name="dynamic_form_item" {...formItemLayoutWithOutLabel} onFinish={onFinish}>
      <Form.List
        name="names"
        rules={[
          {
            validator: async (_, names) => {
              if (!names || names.length < 2) {
                return Promise.reject(new Error('At least 2 passengers'));
              }
            },
          },
        ]}
      >
        {(fields, { add, remove }, { errors }) => (
          <>
            {fields.map((field, index) => (
              <Form.Item
                {...(index === 0 ? formItemLayout : formItemLayoutWithOutLabel)}
                label={index === 0 ? 'Passengers' : ''}
                required={false}
                key={field.key}
              >
                <Form.Item
                  {...field}
                  validateTrigger={['onChange', 'onBlur']}
                  rules={[
                    {
                      required: true,
                      whitespace: true,
                      message: "Please input passenger's name or delete this field.",
                    },
                  ]}
                  noStyle
                >
                  <Input placeholder="passenger name" style={{ width: '60%' }} />
                </Form.Item>
                {fields.length > 1 ? (
                  <MinusCircleOutlined
                    className="dynamic-delete-button"
                    onClick={() => remove(field.name)}
                  />
                ) : null}
              </Form.Item>
            ))}
            <Form.Item>
              <Button
                type="dashed"
                onClick={() => add()}
                style={{ width: '60%' }}
                icon={<PlusOutlined />}
              >
                Add field
              </Button>
              <Button
                type="dashed"
                onClick={() => {
                  add('The head item', 0);
                }}
                style={{ width: '60%', marginTop: '20px' }}
                icon={<PlusOutlined />}
              >
                Add field at head
              </Button>
              <Form.ErrorList errors={errors} />
            </Form.Item>
          </>
        )}
      </Form.List>
      <Form.Item>
        <Button type="primary" htmlType="submit">
          Submit
        </Button>
      </Form.Item>
    </Form>
  );
}