diff --git a/circuit-laundry-notifier/circuit_scraper.py b/circuit-laundry-notifier/circuit_scraper.py
index 86cafdb..6b265fb 100644
--- a/circuit-laundry-notifier/circuit_scraper.py
+++ b/circuit-laundry-notifier/circuit_scraper.py
@@ -4,6 +4,7 @@ from typing import *
import requests
from bs4 import BeautifulSoup
+from cachetools import cached, TTLCache
class ScraperError(ValueError):
@@ -52,6 +53,7 @@ class CircuitScraper:
return CircuitScraper._base_url + f"/?site={site_id}"
@staticmethod
+ @cached(cache=TTLCache(maxsize=64, ttl=30))
def get_site_machine_states(site_id: str) -> List[Machine]:
site_url = CircuitScraper._get_site_url(site_id)
@@ -120,3 +122,13 @@ class CircuitScraper:
machines.append(machine)
return machines
+
+ @staticmethod
+ def get_machine(site_id: str, machine_number: str) -> Optional[Machine]:
+ all_machines = CircuitScraper.get_site_machine_states(site_id)
+ res: Optional[Machine] = None
+ for machine in all_machines:
+ if machine.number == machine_number:
+ res = machine
+ break
+ return res
diff --git a/circuit-laundry-notifier/static/main.js b/circuit-laundry-notifier/static/main.js
new file mode 100644
index 0000000..fa9aa7e
--- /dev/null
+++ b/circuit-laundry-notifier/static/main.js
@@ -0,0 +1,26 @@
+const show = (e) => { e.style.display = "block" }
+const hide = (e) => { e.style.display = "none" }
+
+const workingIndicator = document.getElementById("working")
+
+const successIndicator = document.getElementById("success")
+const errorIndicator = document.getElementById("error")
+const errorIndicatorText = document.getElementById("error_text")
+
+function showError(text) {
+ errorIndicatorText.innerText = text
+ show(errorIndicator)
+}
+
+function showSuccessHTML(html) {
+ const elem = document.createElement("p")
+ elem.innerHTML = html
+ showSuccessElement(elem)
+}
+
+function showSuccessElement(elem) {
+ successIndicator.appendChild(elem)
+ show(successIndicator)
+}
+
+const state = {}
\ No newline at end of file
diff --git a/circuit-laundry-notifier/static/selectMachine.js b/circuit-laundry-notifier/static/selectMachine.js
new file mode 100644
index 0000000..3261c07
--- /dev/null
+++ b/circuit-laundry-notifier/static/selectMachine.js
@@ -0,0 +1,19 @@
+const selectMachineBlock = document.getElementById("select_machine")
+const selectMachineSelection = document.getElementById("select_machine__selection")
+
+function addMachineToSelection(machineObject) {
+ const elem = document.createElement("option")
+ elem.value = machineObject["number"]
+ elem.innerText = `${machineObject["type"]} ${machineObject["number"]}`
+ selectMachineSelection.appendChild(elem)
+}
+
+{
+ const nextButton = document.getElementById("select_machine__next_button")
+
+ nextButton.addEventListener("click", () => {
+ state.machine = selectMachineSelection.options[selectMachineSelection.selectedIndex].value
+ hide(selectMachineBlock)
+ show(submitBlock)
+ })
+}
\ No newline at end of file
diff --git a/circuit-laundry-notifier/static/selectSite.js b/circuit-laundry-notifier/static/selectSite.js
new file mode 100644
index 0000000..59e0336
--- /dev/null
+++ b/circuit-laundry-notifier/static/selectSite.js
@@ -0,0 +1,51 @@
+const selectSiteBlock = document.getElementById("select_site");
+
+{
+ const nextButton = document.getElementById("select_site__next_button")
+ const siteIDInput = document.getElementById("select_site__site_id_input")
+
+ nextButton.addEventListener("click", () => {
+ hide(errorIndicator)
+ hide(selectSiteBlock)
+
+ if (siteIDInput.value === "") {
+ showError("Missing site ID")
+ show(selectSiteBlock)
+ return
+ }
+
+ show(workingIndicator)
+ hide(selectSiteBlock)
+
+ fetch(`/api/v1/machines/${siteIDInput.value.trim()}`)
+ .then(async (response) => {
+ hide(workingIndicator)
+
+ const responseBody = await response.json()
+ if (!response.ok) {
+ showError(responseBody.message)
+ show(selectSiteBlock)
+ return
+ }
+
+ let numberInUse = 0
+ for (let i = 0; i < responseBody.length; i += 1) {
+ const machineObject = responseBody[i]
+ if (machineObject["state"] === "IN_USE") {
+ addMachineToSelection(machineObject)
+ numberInUse += 1
+ }
+ }
+
+ if (numberInUse === 0) {
+ showError("No machines in use.")
+ return
+ }
+
+ state.siteID = siteIDInput.value.trim()
+
+ hide(selectSiteBlock)
+ show(selectMachineBlock)
+ })
+ })
+}
\ No newline at end of file
diff --git a/circuit-laundry-notifier/static/siteSelect.js b/circuit-laundry-notifier/static/siteSelect.js
deleted file mode 100644
index 62c3a17..0000000
--- a/circuit-laundry-notifier/static/siteSelect.js
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- const block = document.getElementById("select_site");
- const nextButton = document.getElementById("select_site__next_button")
- const siteIDInput = document.getElementById("select_site__site_id_input")
-
- nextButton.addEventListener("click", function () {
- hideErrorIndicator()
-
- if (siteIDInput.value === "") {
- showError("Missing site ID")
- return
- }
-
- showWorkingIndicator()
- hideWorkingIndicator()
- })
-}
\ No newline at end of file
diff --git a/circuit-laundry-notifier/static/submit.js b/circuit-laundry-notifier/static/submit.js
new file mode 100644
index 0000000..7f0121a
--- /dev/null
+++ b/circuit-laundry-notifier/static/submit.js
@@ -0,0 +1,44 @@
+const submitBlock = document.getElementById("submit")
+
+{
+ const nextButton = document.getElementById("submit__next_button")
+ const ntfyTopicInput = document.getElementById("submit__ntfy_topic")
+
+ nextButton.addEventListener("click", () => {
+ hide(errorIndicator)
+ hide(submitBlock)
+ show(workingIndicator)
+
+ const formValues = new FormData()
+ formValues.set("machine_number", state.machine)
+
+ {
+ const v = ntfyTopicInput.value.trim()
+ if (v !== "") {
+ formValues.set("ntfy_topic", ntfyTopicInput.value.trim())
+ }
+ }
+
+ fetch(`/api/v1/machines/${state.siteID}/watch`, {
+ method: "POST",
+ body: formValues,
+ })
+ .then(async (response) => {
+ hide(workingIndicator)
+
+ const responseBody = await response.json()
+ if (!response.ok) {
+ showError(responseBody.message)
+ show(submitBlock)
+ return
+ }
+
+ showSuccessHTML(`Successfully registered using ntfy topic ${responseBody["ntfy_topic"]}
`)
+ const anchor = document.createElement("a")
+ anchor.href = `https://ntfy.sh/${responseBody["ntfy_topic"]}`
+ anchor.innerText = "Click here to go to the ntfy topic"
+ anchor.target = "_blank"
+ showSuccessElement(anchor)
+ })
+ })
+}
\ No newline at end of file
diff --git a/circuit-laundry-notifier/static/util.js b/circuit-laundry-notifier/static/util.js
deleted file mode 100644
index 8f04e17..0000000
--- a/circuit-laundry-notifier/static/util.js
+++ /dev/null
@@ -1,25 +0,0 @@
-const workingIndicator = document.getElementById("working")
-
-function showWorkingIndicator() {
- workingIndicator.style.display = "block";
-}
-
-function hideWorkingIndicator() {
- workingIndicator.style.display = "none";
-}
-
-const errorIndicator = document.getElementById("error")
-const errorIndicatorText = document.getElementById("error_text")
-
-function showErrorIndicator() {
- errorIndicator.style.display = "block"
-}
-
-function hideErrorIndicator() {
- errorIndicator.style.display = "none"
-}
-
-function showError(text) {
- errorIndicatorText.innerText = text
- showErrorIndicator()
-}
\ No newline at end of file
diff --git a/circuit-laundry-notifier/templates/index.html b/circuit-laundry-notifier/templates/index.html
index 300be6e..ae2e7d8 100644
--- a/circuit-laundry-notifier/templates/index.html
+++ b/circuit-laundry-notifier/templates/index.html
@@ -9,12 +9,6 @@