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}
-
+
)
}