From f0edf0610eb77562608cb65c67e59eaae05efe1a Mon Sep 17 00:00:00 2001
From: Philipp Heckel <pheckel@datto.com>
Date: Sun, 28 Nov 2021 19:03:15 -0500
Subject: [PATCH] Add priorities and tags to web UI

---
 server/index.gohtml                           |  2 +-
 server/static/css/app.css                     | 13 ++++-
 .../img/{close_black_24dp.svg => close.svg}   |  0
 server/static/img/priority-1.svg              | 47 +++++++++++++++++++
 server/static/img/priority-2.svg              | 43 +++++++++++++++++
 server/static/img/priority-4.svg              | 43 +++++++++++++++++
 server/static/img/priority-5.svg              | 47 +++++++++++++++++++
 .../img/{send_black_24dp.svg => send.svg}     |  0
 .../{clear_black_24dp.svg => unsubscribe.svg} |  0
 server/static/js/app.js                       | 35 +++++++++-----
 10 files changed, 216 insertions(+), 14 deletions(-)
 rename server/static/img/{close_black_24dp.svg => close.svg} (100%)
 create mode 100644 server/static/img/priority-1.svg
 create mode 100644 server/static/img/priority-2.svg
 create mode 100644 server/static/img/priority-4.svg
 create mode 100644 server/static/img/priority-5.svg
 rename server/static/img/{send_black_24dp.svg => send.svg} (100%)
 rename server/static/img/{clear_black_24dp.svg => unsubscribe.svg} (100%)

diff --git a/server/index.gohtml b/server/index.gohtml
index 9267cbf8..3c248729 100644
--- a/server/index.gohtml
+++ b/server/index.gohtml
@@ -381,7 +381,7 @@
 </div>
 <div id="detail"{{if not .Topic}} style="display: none"{{end}}>
     <div id="detailMain">
-        <button id="detailCloseButton"><img src="static/img/close_black_24dp.svg"/></button>
+        <button id="detailCloseButton"><img src="static/img/close.svg"/></button>
         <h1><span id="detailTitle"></span></h1>
         <p class="smallMarginBottom">
             <b>ntfy</b> is a simple HTTP-based pub-sub notification service. This is a ntfy topic.
diff --git a/server/static/css/app.css b/server/static/css/app.css
index 5a84c95c..4efcdb4d 100644
--- a/server/static/css/app.css
+++ b/server/static/css/app.css
@@ -377,18 +377,27 @@ li {
     display: none;
 }
 
-#detail .detailDate {
+#detail .detailEntry {
+    margin-bottom: 20px;
+}
+
+#detail .detailDate, #detail .detailTags {
     color: #888;
     font-size: 0.9em;
 }
 
+#detail .detailDate img {
+    width: 20px;
+    height: 20px;
+    vertical-align: bottom;
+}
+
 #detail .detailTitle {
     font-weight: bold;
     font-size: 1.1em;
 }
 
 #detail .detailMessage {
-    margin-bottom: 20px;
     font-size: 1.1em;
 }
 
diff --git a/server/static/img/close_black_24dp.svg b/server/static/img/close.svg
similarity index 100%
rename from server/static/img/close_black_24dp.svg
rename to server/static/img/close.svg
diff --git a/server/static/img/priority-1.svg b/server/static/img/priority-1.svg
new file mode 100644
index 00000000..df6a0a49
--- /dev/null
+++ b/server/static/img/priority-1.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   height="24px"
+   viewBox="0 0 24 24"
+   width="24px"
+   fill="#000000"
+   version="1.1"
+   id="svg1428"
+   sodipodi:docname="priority_1_24dp.svg"
+   inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs1432" />
+  <sodipodi:namedview
+     id="namedview1430"
+     pagecolor="#505050"
+     bordercolor="#eeeeee"
+     borderopacity="1"
+     inkscape:pageshadow="0"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="0"
+     showgrid="false"
+     inkscape:zoom="20.517358"
+     inkscape:cx="22.834324"
+     inkscape:cy="15.742768"
+     inkscape:window-width="1863"
+     inkscape:window-height="1025"
+     inkscape:window-x="57"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg1428" />
+  <path
+     style="color:#000000;fill:#999999;fill-opacity:1;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="m 12.195014,20.828316 a 1.2747098,1.2747098 0 0 0 0.661605,-0.185206 l 6.646593,-4.037178 a 1.2745823,1.2745823 0 0 0 0.427537,-1.751107 1.2745823,1.2745823 0 0 0 -1.750928,-0.427718 l -5.984807,3.635327 -5.9848086,-3.635327 a 1.2745823,1.2745823 0 0 0 -1.750927,0.427718 1.2745823,1.2745823 0 0 0 0.427536,1.751107 l 6.6464146,4.037178 a 1.2747098,1.2747098 0 0 0 0.661785,0.185206 z"
+     id="rect3554" />
+  <path
+     style="color:#000000;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="m 12.195014,15.694014 a 1.2747098,1.2747098 0 0 0 0.661605,-0.185206 l 6.646593,-4.037176 A 1.2745823,1.2745823 0 0 0 19.930749,9.7205243 1.2745823,1.2745823 0 0 0 18.179821,9.2928073 L 12.195014,12.928134 6.2102054,9.2928073 a 1.2745823,1.2745823 0 0 0 -1.750927,0.427717 1.2745823,1.2745823 0 0 0 0.427536,1.7511077 l 6.6464146,4.037176 a 1.2747098,1.2747098 0 0 0 0.661785,0.185206 z"
+     id="path9314" />
+  <path
+     style="color:#000000;fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="m 12.116784,10.426777 a 1.2747098,1.2747098 0 0 0 0.661606,-0.185205 l 6.646593,-4.0371767 a 1.2745823,1.2745823 0 0 0 0.427537,-1.751108 1.2745823,1.2745823 0 0 0 -1.750928,-0.427718 l -5.984808,3.635327 -5.9848066,-3.635327 a 1.2745823,1.2745823 0 0 0 -1.750928,0.427718 1.2745823,1.2745823 0 0 0 0.427537,1.751108 L 11.455,10.241572 a 1.2747098,1.2747098 0 0 0 0.661784,0.185205 z"
+     id="path9316" />
+</svg>
diff --git a/server/static/img/priority-2.svg b/server/static/img/priority-2.svg
new file mode 100644
index 00000000..10a89ad1
--- /dev/null
+++ b/server/static/img/priority-2.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   height="24px"
+   viewBox="0 0 24 24"
+   width="24px"
+   fill="#000000"
+   version="1.1"
+   id="svg1428"
+   sodipodi:docname="priority_2_24dp.svg"
+   inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs1432" />
+  <sodipodi:namedview
+     id="namedview1430"
+     pagecolor="#505050"
+     bordercolor="#eeeeee"
+     borderopacity="1"
+     inkscape:pageshadow="0"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="0"
+     showgrid="false"
+     inkscape:zoom="20.517358"
+     inkscape:cx="22.834324"
+     inkscape:cy="15.742768"
+     inkscape:window-width="1863"
+     inkscape:window-height="1025"
+     inkscape:window-x="57"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg1428" />
+  <path
+     style="color:#000000;fill:#999999;fill-opacity:1;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="m 12.172712,17.774352 a 1.2747098,1.2747098 0 0 0 0.661605,-0.185206 l 6.646593,-4.037178 a 1.2745823,1.2745823 0 0 0 0.427537,-1.751107 1.2745823,1.2745823 0 0 0 -1.750928,-0.427718 L 12.172712,15.00847 6.1879033,11.373143 a 1.2745823,1.2745823 0 0 0 -1.750927,0.427718 1.2745823,1.2745823 0 0 0 0.427536,1.751107 l 6.6464147,4.037178 a 1.2747098,1.2747098 0 0 0 0.661785,0.185206 z"
+     id="rect3554" />
+  <path
+     style="color:#000000;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="m 12.172712,12.64005 a 1.2747098,1.2747098 0 0 0 0.661605,-0.185206 L 19.48091,8.4176679 A 1.2745823,1.2745823 0 0 0 19.908447,6.6665602 1.2745823,1.2745823 0 0 0 18.157519,6.2388432 L 12.172712,9.8741699 6.1879033,6.2388432 a 1.2745823,1.2745823 0 0 0 -1.750927,0.427717 1.2745823,1.2745823 0 0 0 0.427536,1.7511077 l 6.6464147,4.0371761 a 1.2747098,1.2747098 0 0 0 0.661785,0.185206 z"
+     id="path9314" />
+</svg>
diff --git a/server/static/img/priority-4.svg b/server/static/img/priority-4.svg
new file mode 100644
index 00000000..a1723cf8
--- /dev/null
+++ b/server/static/img/priority-4.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   height="24px"
+   viewBox="0 0 24 24"
+   width="24px"
+   fill="#000000"
+   version="1.1"
+   id="svg1428"
+   sodipodi:docname="priority_4_24dp.svg"
+   inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs1432" />
+  <sodipodi:namedview
+     id="namedview1430"
+     pagecolor="#505050"
+     bordercolor="#eeeeee"
+     borderopacity="1"
+     inkscape:pageshadow="0"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="0"
+     showgrid="false"
+     inkscape:zoom="20.517358"
+     inkscape:cx="22.834324"
+     inkscape:cy="15.742768"
+     inkscape:window-width="1863"
+     inkscape:window-height="1025"
+     inkscape:window-x="57"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg1428" />
+  <path
+     style="color:#000000;fill:#c60000;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="M 12.116784,6.5394415 A 1.2747098,1.2747098 0 0 0 11.455179,6.724648 l -6.6465926,4.037176 a 1.2745823,1.2745823 0 0 0 -0.427537,1.751108 1.2745823,1.2745823 0 0 0 1.7509281,0.427717 l 5.9848065,-3.635327 5.984809,3.635327 A 1.2745823,1.2745823 0 0 0 19.85252,12.512932 1.2745823,1.2745823 0 0 0 19.424984,10.761824 L 12.778569,6.724648 A 1.2747098,1.2747098 0 0 0 12.116784,6.5394415 Z"
+     id="path9314" />
+  <path
+     style="color:#000000;fill:#de0000;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="m 12.195014,11.806679 a 1.2747098,1.2747098 0 0 0 -0.661606,0.185205 l -6.6465924,4.037177 a 1.2745823,1.2745823 0 0 0 -0.427537,1.751108 1.2745823,1.2745823 0 0 0 1.750928,0.427718 l 5.9848074,-3.635327 5.984807,3.635327 a 1.2745823,1.2745823 0 0 0 1.750928,-0.427718 1.2745823,1.2745823 0 0 0 -0.427537,-1.751108 l -6.646414,-4.037177 a 1.2747098,1.2747098 0 0 0 -0.661784,-0.185205 z"
+     id="path9316" />
+</svg>
diff --git a/server/static/img/priority-5.svg b/server/static/img/priority-5.svg
new file mode 100644
index 00000000..2e2c4447
--- /dev/null
+++ b/server/static/img/priority-5.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   height="24px"
+   viewBox="0 0 24 24"
+   width="24px"
+   fill="#000000"
+   version="1.1"
+   id="svg1428"
+   sodipodi:docname="priority_5_24dp.svg"
+   inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <defs
+     id="defs1432" />
+  <sodipodi:namedview
+     id="namedview1430"
+     pagecolor="#505050"
+     bordercolor="#eeeeee"
+     borderopacity="1"
+     inkscape:pageshadow="0"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="0"
+     showgrid="false"
+     inkscape:zoom="20.517358"
+     inkscape:cx="22.834323"
+     inkscape:cy="15.742767"
+     inkscape:window-width="1863"
+     inkscape:window-height="1025"
+     inkscape:window-x="57"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg1428" />
+  <path
+     style="color:#000000;fill:#aa0000;fill-opacity:1;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="M 12.116784,3.40514 A 1.2747098,1.2747098 0 0 0 11.455179,3.5903463 L 4.8085864,7.6275238 A 1.2745823,1.2745823 0 0 0 4.3810494,9.3786313 1.2745823,1.2745823 0 0 0 6.1319775,9.8063489 L 12.116784,6.1710217 18.101593,9.8063489 A 1.2745823,1.2745823 0 0 0 19.85252,9.3786313 1.2745823,1.2745823 0 0 0 19.424984,7.6275238 L 12.778569,3.5903463 A 1.2747098,1.2747098 0 0 0 12.116784,3.40514 Z"
+     id="rect3554" />
+  <path
+     style="color:#000000;fill:#c60000;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="M 12.116784,8.5394415 A 1.2747098,1.2747098 0 0 0 11.455179,8.724648 l -6.6465926,4.037176 a 1.2745823,1.2745823 0 0 0 -0.427537,1.751108 1.2745823,1.2745823 0 0 0 1.7509281,0.427717 l 5.9848065,-3.635327 5.984809,3.635327 A 1.2745823,1.2745823 0 0 0 19.85252,14.512932 1.2745823,1.2745823 0 0 0 19.424984,12.761824 L 12.778569,8.724648 A 1.2747098,1.2747098 0 0 0 12.116784,8.5394415 Z"
+     id="path9314" />
+  <path
+     style="color:#000000;fill:#de0000;fill-opacity:1;stroke:none;stroke-width:0.0919748;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none"
+     d="m 12.195014,13.806679 a 1.2747098,1.2747098 0 0 0 -0.661606,0.185205 l -6.6465924,4.037177 a 1.2745823,1.2745823 0 0 0 -0.427537,1.751108 1.2745823,1.2745823 0 0 0 1.750928,0.427718 l 5.9848074,-3.635327 5.984807,3.635327 a 1.2745823,1.2745823 0 0 0 1.750928,-0.427718 1.2745823,1.2745823 0 0 0 -0.427537,-1.751108 l -6.646414,-4.037177 a 1.2747098,1.2747098 0 0 0 -0.661784,-0.185205 z"
+     id="path9316" />
+</svg>
diff --git a/server/static/img/send_black_24dp.svg b/server/static/img/send.svg
similarity index 100%
rename from server/static/img/send_black_24dp.svg
rename to server/static/img/send.svg
diff --git a/server/static/img/clear_black_24dp.svg b/server/static/img/unsubscribe.svg
similarity index 100%
rename from server/static/img/clear_black_24dp.svg
rename to server/static/img/unsubscribe.svg
diff --git a/server/static/js/app.js b/server/static/js/app.js
index 270b6ca7..90901e88 100644
--- a/server/static/js/app.js
+++ b/server/static/js/app.js
@@ -60,7 +60,7 @@ const subscribeInternal = (topic, persist, delaySec) => {
         if (!topicEntry) {
             topicEntry = document.createElement('li');
             topicEntry.id = `topic-${topic}`;
-            topicEntry.innerHTML = `<a href="/${topic}" onclick="return showDetail('${topic}')">${topic}</a> <button onclick="test('${topic}'); return false;"> <img src="static/img/send_black_24dp.svg"> Test</button> <button onclick="unsubscribe('${topic}'); return false;"> <img src="static/img/clear_black_24dp.svg"> Unsubscribe</button>`;
+            topicEntry.innerHTML = `<a href="/${topic}" onclick="return showDetail('${topic}')">${topic}</a> <button onclick="test('${topic}'); return false;"> <img src="static/img/send.svg"> Test</button> <button onclick="unsubscribe('${topic}'); return false;"> <img src="static/img/unsubscribe.svg"> Unsubscribe</button>`;
             topicsList.appendChild(topicEntry);
         }
         topicsHeader.style.display = '';
@@ -68,7 +68,7 @@ const subscribeInternal = (topic, persist, delaySec) => {
         // Open event source
         let eventSource = new EventSource(`${topic}/sse`);
         eventSource.onopen = () => {
-            topicEntry.innerHTML = `<a href="/${topic}" onclick="return showDetail('${topic}')">${topic}</a> <button onclick="test('${topic}'); return false;"> <img src="static/img/send_black_24dp.svg"> Test</button> <button onclick="unsubscribe('${topic}'); return false;"> <img src="static/img/clear_black_24dp.svg"> Unsubscribe</button>`;
+            topicEntry.innerHTML = `<a href="/${topic}" onclick="return showDetail('${topic}')">${topic}</a> <button onclick="test('${topic}'); return false;"> <img src="static/img/send.svg"> Test</button> <button onclick="unsubscribe('${topic}'); return false;"> <img src="static/img/unsubscribe.svg"> Unsubscribe</button>`;
             delaySec = 0; // Reset on successful connection
         };
         eventSource.onerror = (e) => {
@@ -152,22 +152,35 @@ const rerenderDetailView = () => {
         detailEventsList.removeChild(detailEventsList.firstChild);
     }
     topics[currentTopic]['messages'].forEach(m => {
-        let dateDiv = document.createElement('div');
-        let titleDiv = document.createElement('div');
-        let messageDiv = document.createElement('div');
-        let eventDiv = document.createElement('div');
+        const entryDiv = document.createElement('div');
+        const dateDiv = document.createElement('div');
+        const titleDiv = document.createElement('div');
+        const messageDiv = document.createElement('div');
+        const tagsDiv = document.createElement('div');
+
+        entryDiv.classList.add('detailEntry');
         dateDiv.classList.add('detailDate');
-        dateDiv.innerHTML = new Date(m.time * 1000).toLocaleString();
+        const dateStr = new Date(m.time * 1000).toLocaleString();
+        if (m.priority && [1,2,4,5].includes(m.priority)) {
+            dateDiv.innerHTML = `${dateStr} <img src="static/img/priority-${m.priority}.svg"/>`;
+        } else {
+            dateDiv.innerHTML = `${dateStr}`;
+        }
         messageDiv.classList.add('detailMessage');
         messageDiv.innerText = m.message;
-        eventDiv.appendChild(dateDiv);
+        entryDiv.appendChild(dateDiv);
         if (m.title) {
             titleDiv.classList.add('detailTitle');
             titleDiv.innerText = m.title;
-            eventDiv.appendChild(titleDiv)
+            entryDiv.appendChild(titleDiv);
         }
-        eventDiv.appendChild(messageDiv);
-        detailEventsList.appendChild(eventDiv);
+        entryDiv.appendChild(messageDiv);
+        if (m.tags) {
+            tagsDiv.classList.add('detailTags');
+            tagsDiv.innerText = "Tags: " + m.tags.join(", ");
+            entryDiv.appendChild(tagsDiv);
+        }
+        detailEventsList.appendChild(entryDiv);
     })
     if (topics[currentTopic]['messages'].length === 0) {
         detailNoNotifications.style.display = '';