Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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
Add Comment
Please, Sign In to add comment