Moortiii icon

Fuck Autocomplete

Moortiii | PRO | 03/04/20 04:44:36 PM UTC | 0 ⭐ | 262 👁️ | Never ⏰ | []
JavaScript |

12.36 KB

|

None

|

0 👍

/

0 👎

import 'index.css'
import 'react-quill/dist/quill.snow.css';
import "react-mde/lib/styles/css/react-mde-all.css";
 
import React, { useState, useEffect } from 'react'
 
import { RootState } from "../../app/rootReducer"
import { useParams } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { useSelector, useDispatch } from 'react-redux'
 
// @ts-ignore
import renderHTML from 'react-render-html';
import ReactQuill from 'react-quill';
 
import ReferenceList from './ReferenceList';
import VulnerabilityList from './VulnerabilityList';
import DeleteModal from './DeleteModal'
 
import {
    fetchArticle,
    addReference,
    addVulnerability,
    removeReference,
    removeVulnerability,
    fetchAutocompleteSuggestions
} from "./ArticleSlice"
 
import {
    Grid, Container, Button,
    Form, Input, Select,
    Header, Message, Dropdown
} from 'semantic-ui-react'
 
interface Suggestion {
    description: string,
    id: string
}
 
interface Option {
    key: string,
    value: string,
    text: string
}
 
interface Reference {
    id: number,
    text: string
}
 
interface Vulnerability {
    identifier: string,
    id: number
}
 
interface FormState {
    title: string,
    severity: number,
    summary: string,
    type: string,
    references: Array<Reference>,
    reference: string,
    vulnerability: string,
    vulnerabilities: Array<Vulnerability>,
    autocompleteOptions: Array<Option>
}
 
const Article = () => {
    let { id } = useParams();
    const { t } = useTranslation();
    const dispatch = useDispatch()
 
    const articleOptions = [
        { key: "article", text: t("article_options.news"), value: "article" },
        { key: "vulnerability", text: t("article_options.vulnerability"), value: "vulnerability" },
        { key: "update", text: t("article_options.update"), value: "update" }
    ]
 
    const severityOptions = [
        { key: "low", text: t("severity_options.low"), value: "1" },
        { key: "medium", text: t("severity_options.medium"), value: "2" },
        { key: "high", text: t("severity_options.high"), value: "3" },
        { key: "critical", text: t("severity_options.critical"), value: "4" }
    ]
 
    const { title, summary, severity, references, type, vulnerabilities } = useSelector(
        (state: RootState) => state.articles.article
    )
 
    const { error, autocompleteSuggestions } = useSelector(
        (state: RootState) => state.articles
    )
 
    useEffect(() => {
        if (id) {
            dispatch(fetchArticle(id))
        }
    }, [dispatch, title, summary, type, severity, id])
 
    const [form, setForm] = useState<FormState>({
        title: title,
        type: type,
        summary: summary,
        severity: severity,
        references: references,
        vulnerabilities: vulnerabilities,
        reference: "",
        vulnerability: "",
        autocompleteOptions: [] as Array<Option>
    })
 
    // Whenever the vulnerability search is updated, repopulate the dropdown options
    useEffect(() => {
        if (autocompleteSuggestions.length > 0) {
            const options = autocompleteSuggestions.reduce((options: Array<Option>, x: Suggestion) => {
 
                let option = {
                    key: x.id,
                    value: x.id,
                    text: x.id
                }
 
                options.push(option)
                return options
            }, [])
 
            setForm({
                ...form,
                autocompleteOptions: options
            })
        }
    }, [form.vulnerability])
 
    useEffect(() => {
        setForm({ ...form, references: references })
    }, [references])
 
    useEffect(() => {
        setForm({ ...form, vulnerabilities: vulnerabilities })
    }, [vulnerabilities])
 
    const handleFormChange = (event: any, { name, value }: any) => {
        setForm({
            ...form,
            [name]: value
        })
    }
 
    const handleAddReference = () => {
        if (form.reference) {
            dispatch(addReference(form.reference))
            setForm({ ...form, reference: "" })
        }
    }
 
    const handleRemoveReference = (reference: Reference) => {
        dispatch(removeReference(reference.id))
    }
 
    const handleAddVulnerability = () => {
        if(form.vulnerability) {
            dispatch(addVulnerability(form.vulnerability))
            setForm({...form, vulnerability: ""})
        }
    }
 
    const handleRemoveVulnerability = (vulnerability: Vulnerability) => {
        dispatch(removeVulnerability(vulnerability.id))
    }
 
    const handleQuillUpdate = (value: any) => {
        setForm({ ...form, summary: value })
    }
 
    const handleAutocompleteSearch = (event: any) => {
        const key = event.key
 
        if(key === "ArrowDown" || key === "ArrowUp" || key === "Enter") return
 
        if (event.target.value !== "")
            dispatch(fetchAutocompleteSuggestions(event.target.value))
        
        setForm({...form, vulnerability: event.target.value})
    }
 
    const [preview, setPreview] = useState("")
 
    // TODO: Cleanup or move elsewheres
    useEffect(() => {
        const headline = `<h3>${form.title}</h3>`
 
        // Combine the necessary fields for the preview
        let output = headline + form.summary
 
        for (let i = 0; i < form.references.length; i++) {
            output += `<a href="#">${form.references[i].text}</a><br>`
        }
 
        if (form.vulnerabilities.length > 0) {
            output += "<h3>Svakheter:</h3>"
 
            for (let i = 0; i < form.vulnerabilities.length; i++) {
                output += `<a href="#">${form.vulnerabilities[i].identifier}</a><br>`
            }
        }
 
        // Replace empty lines with a more sensible format
        output = output.replace(/<p><br><\/p>/g, "");
 
        setPreview(output)
    }, [form])
 
 
    const handleArticleDeletion = () => {
        alert("Article Deleted inside callback")
    }
 
    return (
        <Container>
            <Grid columns={2} divided>
                <Grid.Row>
                    <Grid.Column>
                        <Header as='h1'>{t("write")}</Header>
                        <Form error>
                            <Form.Field
                                autoComplete="off"
                                name="title"
                                value={form.title}
                                onChange={handleFormChange}
                                control={Input}
                                label={t('form.title')}
                                placeholder={t('form.title')}
                            />
                            <Form.Select
                                name="type"
                                value={form.type}
                                onChange={handleFormChange}
                                options={articleOptions}
                                label={t('form.article_type')}
                                placeholder={t('form.article_type')}
                                search
                            />
 
                            <Form.Input
                                fluid
                                action
                                label={t("form.CVE")}
                                placeholder={t("form.CVE")}
                            >
                                <Dropdown
                                    name="vulnerability"
                                    onKeyUp={handleAutocompleteSearch}
                                    options={form.autocompleteOptions}
                                    value={form.vulnerability}
                                    onChange={handleFormChange}
                                    selection
                                    search
                                    fluid
                                    style={{borderRadius: "4px 0px 0px 4px"}}
                                />
                                <Button attached="left" color="green" icon="add" content={t("form.add")} labelPosition="right" onClick={handleAddVulnerability} onKeyPress={handleAddVulnerability}/>
                            </Form.Input>
 
                            {error && (
                                <Message visible warning content="Fant ikke informasjon om gitt CVE" />
                            )}
 
                            <Form.Field
                                control={VulnerabilityList}
                                handleRemove={handleRemoveVulnerability}
                                vulnerabilities={form.vulnerabilities}
                            />
                            <Form.Field
                                name="summary"
                                control={ReactQuill}
                                value={form.summary}
                                onChange={handleQuillUpdate}
                                label={{ children: t("form.summary"), htmlFor: 'form-select-control-summary' }}
                                modules={{
                                    toolbar: [
                                        ['bold', 'italic', 'underline'],
                                        [{ 'list': 'ordered' }, { 'list': 'bullet' }],
                                        ['code', 'clean']
                                    ],
                                }}
                            />
 
 
                            <Form.Field
                                autoComplete="off"
                                control={Input}
                                name="reference"
                                value={form.reference}
                                onChange={handleFormChange}
                                action={
                                    <Button labelPosition='right'
                                        icon='add'
                                        content={t("form.add")}
                                        color='green'
                                        onClick={handleAddReference}
                                    >
                                    </Button>
                                }
                                label={t("form.reference")}
                                placeholder="URL"
                                onKeyPress={(event: any) => { if (event.key === "Enter") { handleAddReference() } }}
                            />
                            <Form.Field
                                control={ReferenceList}
                                references={form.references}
                                handleRemove={handleRemoveReference}
                            />
                            <Form.Field
                                control={Select}
                                name="severity"
                                value={form.severity}
                                onChange={handleFormChange}
                                options={severityOptions}
                                label={{ children: t("form.severity"), htmlFor: 'form-select-control-severity' }}
                                placeholder={t("form.severity")}
                                search
                                searchInput={{ id: 'form-select-control-severity' }}
                            />
                            <Form.Group>
                                <Form.Field
                                    id='form-button-control-public'
                                    control={Button}
                                    color="green"
                                    content={t("form.save")}
                                    onClick={() => { alert(JSON.stringify(form)) }}
                                />
                                <DeleteModal callback={handleArticleDeletion} />
                            </Form.Group>
                        </Form>
                    </Grid.Column>
                    <Grid.Column>
                        <Header as='h1'>{t("preview")}</Header>
                        <div>
                            {renderHTML(preview)}
                        </div>
                    </Grid.Column>
                </Grid.Row>
            </Grid>
        </Container>
    )
}
 
export default Article

Comments