From 187c19f3b283944a125da65445dd047b563ce259 Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Sun, 27 Mar 2022 09:10:47 -0400 Subject: [PATCH] Continued work on publishing from the web app --- web/src/app/Api.js | 23 ++--- web/src/components/ActionBar.js | 6 +- web/src/components/App.js | 65 ++++++------- web/src/components/Notifications.js | 3 +- web/src/components/SendDialog.js | 136 ++++++++++++++++++++++++++++ web/src/img/priority-3.svg | 1 + 6 files changed, 182 insertions(+), 52 deletions(-) create mode 100644 web/src/components/SendDialog.js create mode 100644 web/src/img/priority-3.svg diff --git a/web/src/app/Api.js b/web/src/app/Api.js index 096f375..dcf09ea 100644 --- a/web/src/app/Api.js +++ b/web/src/app/Api.js @@ -26,23 +26,18 @@ class Api { return messages; } - async publish(baseUrl, topic, message, title, priority, tags) { + async publish(baseUrl, topic, message, options) { const user = await userManager.get(baseUrl); - const url = topicUrl(baseUrl, topic); - console.log(`[Api] Publishing message to ${url}`); + console.log(`[Api] Publishing message to ${topicUrl(baseUrl, topic)}`); const headers = {}; - if (title) { - headers["X-Title"] = title; - } - if (priority !== 3) { - headers["X-Priority"] = `${priority}`; - } - if (tags.length > 0) { - headers["X-Tags"] = tags.join(","); - } - await fetch(url, { + const body = { + topic: topic, + message: message, + ...options + }; + await fetch(baseUrl, { method: 'PUT', - body: message, + body: JSON.stringify(body), headers: maybeWithBasicAuth(headers, user) }); } diff --git a/web/src/components/ActionBar.js b/web/src/components/ActionBar.js index 1f9ca7b..878f7fe 100644 --- a/web/src/components/ActionBar.js +++ b/web/src/components/ActionBar.js @@ -135,7 +135,11 @@ const SettingsIcons = (props) => { `I'm really excited that you're trying out ntfy. Did you know that there are a few public topics, such as ntfy.sh/stats and ntfy.sh/announcements.`, `It's interesting to hear what people use ntfy for. I've heard people talk about using it for so many cool things. What do you use it for?` ])[0]; - api.publish(baseUrl, topic, message, title, priority, tags); + api.publish(baseUrl, topic, message, { + title: title, + priority: priority, + tags: tags + }); setOpen(false); } diff --git a/web/src/components/App.js b/web/src/components/App.js index 7637f15..94dbce0 100644 --- a/web/src/components/App.js +++ b/web/src/components/App.js @@ -14,7 +14,7 @@ import {useLiveQuery} from "dexie-react-hooks"; import subscriptionManager from "../app/SubscriptionManager"; import userManager from "../app/UserManager"; import {BrowserRouter, Outlet, Route, Routes, useOutletContext, useParams} from "react-router-dom"; -import {expandUrl} from "../app/utils"; +import {expandUrl, topicUrl} from "../app/utils"; import ErrorBoundary from "./ErrorBoundary"; import routes from "./routes"; import {useAutoSubscribe, useConnectionListeners, useLocalStorageMigration} from "./hooks"; @@ -22,7 +22,6 @@ import {Backdrop, ListItemIcon, ListItemText, Menu} from "@mui/material"; import Paper from "@mui/material/Paper"; import IconButton from "@mui/material/IconButton"; import {MoreVert} from "@mui/icons-material"; -import InsertEmoticonIcon from "@mui/icons-material/InsertEmoticon"; import MenuItem from "@mui/material/MenuItem"; import TextField from "@mui/material/TextField"; import SendIcon from "@mui/icons-material/Send"; @@ -30,6 +29,8 @@ import priority1 from "../img/priority-1.svg"; import priority2 from "../img/priority-2.svg"; import priority4 from "../img/priority-4.svg"; import priority5 from "../img/priority-5.svg"; +import api from "../app/Api"; +import SendDialog from "./SendDialog"; // TODO add drag and drop // TODO races when two tabs are open @@ -102,7 +103,7 @@ const Layout = () => { - + ); } @@ -128,23 +129,17 @@ const Main = (props) => { ); }; -const priorityFiles = { - 1: priority1, - 2: priority2, - 4: priority4, - 5: priority5 -}; - const Sender = (props) => { - const [priority, setPriority] = useState(5); - const [priorityAnchorEl, setPriorityAnchorEl] = React.useState(null); - const priorityMenuOpen = Boolean(priorityAnchorEl); - - const handlePriorityClick = (p) => { - setPriority(p); - setPriorityAnchorEl(null); + const [message, setMessage] = useState(""); + const [sendDialogOpen, setSendDialogOpen] = useState(false); + const subscription = props.selected; + const handleSendClick = () => { + api.publish(subscription.baseUrl, subscription.topic, message); + setMessage(""); }; - + if (!props.selected) { + return null; + } return ( { backgroundColor: (theme) => theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900] }} > - {false && + setSendDialogOpen(true)}> - } - {false && setPriorityAnchorEl(ev.currentTarget)}> - - } - setPriorityAnchorEl(null)} - > - {[5,4,2,1].map(p => handlePriorityClick(p)}> - - Priority {p} - )} - + { type="text" fullWidth variant="standard" - multiline + value={message} + onChange={ev => setMessage(ev.target.value)} + onKeyPress={(ev) => { + if (ev.key === 'Enter') { + ev.preventDefault(); + handleSendClick(); + } + }} /> - + + setSendDialogOpen(false)} + topicUrl={topicUrl(subscription.baseUrl, subscription.topic)} + message={message} + /> ); }; diff --git a/web/src/components/Notifications.js b/web/src/components/Notifications.js index 08b3d8a..f0987a6 100644 --- a/web/src/components/Notifications.js +++ b/web/src/components/Notifications.js @@ -120,13 +120,12 @@ const NotificationList = (props) => { const NotificationItem = (props) => { const notification = props.notification; - const subscriptionId = notification.subscriptionId; const attachment = notification.attachment; const date = formatShortDateTime(notification.time); const otherTags = unmatchedTags(notification.tags); const tags = (otherTags.length > 0) ? otherTags.join(', ') : null; const handleDelete = async () => { - console.log(`[Notifications] Deleting notification ${notification.id} from ${subscriptionId}`); + console.log(`[Notifications] Deleting notification ${notification.id}`); await subscriptionManager.deleteNotification(notification.id) } const handleCopy = (s) => { diff --git a/web/src/components/SendDialog.js b/web/src/components/SendDialog.js new file mode 100644 index 0000000..9a38865 --- /dev/null +++ b/web/src/components/SendDialog.js @@ -0,0 +1,136 @@ +import * as React from 'react'; +import {useState} from 'react'; +import {NotificationItem} from "./Notifications"; +import theme from "./theme"; +import {Link, Rating, useMediaQuery} from "@mui/material"; +import TextField from "@mui/material/TextField"; +import priority1 from "../img/priority-1.svg"; +import priority2 from "../img/priority-2.svg"; +import priority3 from "../img/priority-3.svg"; +import priority4 from "../img/priority-4.svg"; +import priority5 from "../img/priority-5.svg"; +import Dialog from "@mui/material/Dialog"; +import DialogTitle from "@mui/material/DialogTitle"; +import DialogContent from "@mui/material/DialogContent"; +import DialogActions from "@mui/material/DialogActions"; +import Button from "@mui/material/Button"; +import Typography from "@mui/material/Typography"; + +const priorityFiles = { + 1: priority1, + 2: priority2, + 3: priority3, + 4: priority4, + 5: priority5 +}; + +function IconContainer(props) { + const { value, ...other } = props; + return ; +} + +const PrioritySelect = () => { + return ( + + ); +} + +const SendDialog = (props) => { + const [topicUrl, setTopicUrl] = useState(props.topicUrl); + const [message, setMessage] = useState(props.message || ""); + const [title, setTitle] = useState(""); + const [tags, setTags] = useState(""); + const [click, setClick] = useState(""); + const [email, setEmail] = useState(""); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + const sendButtonEnabled = (() => { + return true; + })(); + const handleSubmit = async () => { + props.onSubmit({ + baseUrl: "xx", + username: username, + password: password + }) + }; + return ( + + Publish notification + + setTopicUrl(ev.target.value)} + type="text" + variant="standard" + fullWidth + required + /> + setMessage(ev.target.value)} + type="text" + variant="standard" + fullWidth + required + autoFocus + multiline + /> + setTitle(ev.target.value)} + type="text" + fullWidth + variant="standard" + /> + setTags(ev.target.value)} + type="text" + fullWidth + variant="standard" + /> + setClick(ev.target.value)} + type="url" + fullWidth + variant="standard" + /> + setEmail(ev.target.value)} + type="email" + fullWidth + variant="standard" + /> + + + For details on what these fields mean, please check out the + {" "}documentation. + + + + + + + + ); +}; + +export default SendDialog; diff --git a/web/src/img/priority-3.svg b/web/src/img/priority-3.svg new file mode 100644 index 0000000..fc65f66 --- /dev/null +++ b/web/src/img/priority-3.svg @@ -0,0 +1 @@ + \ No newline at end of file