diff --git a/nest_frontend/LocalizationStrings.js b/nest_frontend/LocalizationStrings.js index 9de817f..335e0a9 100644 --- a/nest_frontend/LocalizationStrings.js +++ b/nest_frontend/LocalizationStrings.js @@ -71,6 +71,11 @@ export default { alerts: "Allarmi", alertTitle: "I tuoi allarmi", alertCreate: "Crea un allarme", + alertName: "Nome allarme", // TODO: tradurre + createAlert: "Crea allarme", // TODO: tradurre + alertLimit: "Limite", // TODO: tradurre e migliorare? + alertWindow: "Finestra (in ore)", // TODO: tradurre + notImplemented: "🚧 Non implementato.", settings: "Impostazioni", diff --git a/nest_frontend/PageSwitcher.js b/nest_frontend/PageSwitcher.js index db7332f..41e3cb3 100644 --- a/nest_frontend/PageSwitcher.js +++ b/nest_frontend/PageSwitcher.js @@ -27,7 +27,7 @@ export default function PageSwitcher({ ...props }) { - + diff --git a/nest_frontend/components/interactive/BoxAlertCreate.js b/nest_frontend/components/interactive/BoxAlertCreate.js new file mode 100644 index 0000000..e97a7f2 --- /dev/null +++ b/nest_frontend/components/interactive/BoxAlertCreate.js @@ -0,0 +1,109 @@ +import React from "react" +import BoxFull from "../base/BoxFull" +import FormLabelled from "../base/FormLabelled" +import FormLabel from "../base/formparts/FormLabel" +import InputWithIcon from "../base/InputWithIcon" +import { + faBackward, faBell, + faFolder, + faPencilAlt, + faPlus, faStopwatch, + faThermometerThreeQuarters, +} from "@fortawesome/free-solid-svg-icons" +import Radio from "../base/Radio" +import Button from "../base/Button" +import useRepositoryEditor from "../../hooks/useRepositoryEditor" +import FormAlert from "../base/formparts/FormAlert" +import { useHistory } from "react-router" +import useStrings from "../../hooks/useStrings" + + +export default function BoxAlertCreate( + { + name, + setName, + evaluationMode, + setEvaluationMode, + limit, + setLimit, + windowSize, + setWindowSize, + running, + error, + save, + ...props + }) { + + const strings = useStrings() + + return ( + + { + e.preventDefault() + save() + }} + > + + setName(e.target.value)} + /> + + + +   + + + + setLimit(e.target.limit)} + /> + + + setWindowSize(e.target.limit)} + /> + + {error ? + + {strings[error.data.code]} + + : null} + + + + ) +} diff --git a/nest_frontend/components/providers/AlertEditor.js b/nest_frontend/components/providers/AlertEditor.js new file mode 100644 index 0000000..ab365a2 --- /dev/null +++ b/nest_frontend/components/providers/AlertEditor.js @@ -0,0 +1,145 @@ +import React, { useCallback, useState } from "react" +import ContextConditionEditor from "../../contexts/ContextConditionEditor" +import useArrayState from "../../hooks/useArrayState" +import Style from "./RepositoryEditor.module.css" +import BoxConditionLocation from "../interactive/BoxConditionLocation" +import BoxConditionHashtag from "../interactive/BoxConditionHashtag" +import BoxConditionUser from "../interactive/BoxConditionUser" +import BoxConditionDatetime from "../interactive/BoxConditionDatetime" +import BoxConditions from "../interactive/BoxConditions" +import classNames from "classnames" +import { Condition } from "../../objects/Condition" +import useBackendViewset from "../../hooks/useBackendViewset" +import { Redirect, useParams } from "react-router" +import BoxAlertCreate from "../interactive/BoxAlertCreate" + + +export default function AlertEditor({className}) { + /** The connected repository id. */ + const {id: repoId} = useParams() + + /** The alert name. */ + const [_name, setName] = useState("") + + /** The alert limit. */ + const [limit, setLimit] = useState(10) + + /** The window size. */ + const [windowSize, setWindowSize] = useState(24) + + /** The conditions of the data gathering. */ + const { + value: rawConditions, + setValue: setRawConditions, + appendValue: appendRawCondition, + removeValue: removeRawCondition, + spliceValue: spliceRawCondition, + } = useArrayState([]) + const _conditions = rawConditions.map(cond => Condition.fromRaw(cond)) + + /** The operator the conditions should be evaluated with. */ + const [_evaluationMode, setEvaluationMode] = useState(0) + + /** The backend viewset to use to create / edit the repository. */ + const {running, error, createResource} = useBackendViewset( + `/api/v1/repositories/${repoId}/alerts/`, + "name", + { + list: false, + create: true, + retrieve: false, + edit: false, + destroy: false, + command: false, + action: false, + } + ) + + /** If `true`, switches to the repository page on the next render. */ + const [switchPage, setSwitchPage] = useState(false) + + /** + * Save the current changes, creating or editing it as needed. + * + * @type {(function(): Promise)|*} + */ + const save = useCallback( + async () => { + const body = { + "repository_id": repoId, + "name": _name, + "window_size": windowSize, + "limit": limit, + "evaluation_mode": _evaluationMode, + "conditions": _conditions, + } + + console.info("Creating new alert with body: ", body) + await createResource(body) + setSwitchPage(true) + }, + [repoId, createResource, _conditions, _evaluationMode, _name, limit], + ) + + /** + * Try to add a new condition, logging a message to the console if something goes wrong. + * + * @type {(function(): void)|*} + */ + const addCondition = useCallback( + (newCond) => { + + // Check for duplicates + let duplicate = null + for(const oldCond of _conditions) { + if(newCond.type === oldCond.type && newCond.content === oldCond.content) { + duplicate = oldCond + break + } + } + if(duplicate) { + console.debug("Cannot add ", newCond, ": ", duplicate, " already exists.") + return + } + + console.debug("Adding ", newCond, " to the repository conditions") + appendRawCondition(newCond) + }, + [_conditions, appendRawCondition], + ) + + // Hack to switch page on success + if(!error && switchPage) { + return + } + + return ( + +
+ + + + + + +
+
+ ) +} diff --git a/nest_frontend/routes/PageRepositoriesList.js b/nest_frontend/routes/PageRepositoriesList.js index e2ac85a..840fde2 100644 --- a/nest_frontend/routes/PageRepositoriesList.js +++ b/nest_frontend/routes/PageRepositoriesList.js @@ -52,7 +52,7 @@ export default function PageRepositoriesList() { repositories={bv.resources.filter(r => r.is_active)} view={pk => history.push(`/repositories/${pk}`)} share={pk => history.push(`/repositories/${pk}/share`)} - alerts={pk => history.push(`/repositories/${pk}/alerts`)} + alerts={pk => history.push(`/repositories/${pk}/alerts/`)} archive={archive} edit={pk => history.push(`/repositories/${pk}/edit`)} /> diff --git a/nest_frontend/routes/PageRepositoryAlertsCreate.js b/nest_frontend/routes/PageRepositoryAlertsCreate.js index bd3ea08..6ecb44e 100644 --- a/nest_frontend/routes/PageRepositoryAlertsCreate.js +++ b/nest_frontend/routes/PageRepositoryAlertsCreate.js @@ -1,32 +1,15 @@ import React, { useContext } from "react" -import BoxFull from "../components/base/BoxFull" import ContextLanguage from "../contexts/ContextLanguage" import BoxHeader from "../components/base/BoxHeader" -import { useHistory, useParams } from "react-router" +import { useParams } from "react-router" import { faPlus } from "@fortawesome/free-solid-svg-icons" import PageWithHeader from "../components/base/layout/PageWithHeader" import makeIcon from "../utils/makeIcon" -import useBackendViewset from "../hooks/useBackendViewset" +import AlertEditor from "../components/providers/AlertEditor" export default function PageRepositoryAlertsCreate() { const { strings } = useContext(ContextLanguage) - const { id } = useParams() - const history = useHistory() - - const {createResource} = useBackendViewset( - `/api/v1/repositories/${id}/alerts/`, - "name", - { - list: false, - create: true, - retrieve: false, - edit: false, - destroy: false, - command: false, - action: false, - } - ) return ( } > - - {strings.notImplemented} - + ) }