Home page; "all notifications"
parent
1d2f3f72e4
commit
5bed926323
|
@ -38,6 +38,14 @@ class SubscriptionManager {
|
||||||
async getNotifications(subscriptionId) {
|
async getNotifications(subscriptionId) {
|
||||||
return db.notifications
|
return db.notifications
|
||||||
.where({ subscriptionId: subscriptionId })
|
.where({ subscriptionId: subscriptionId })
|
||||||
|
.reverse()
|
||||||
|
.sortBy("time"); // Inefficient, but there is no other way (see docs)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllNotifications() {
|
||||||
|
return db.notifications
|
||||||
|
.orderBy("time") // Efficient, see docs
|
||||||
|
.reverse()
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import connectionManager from "../app/ConnectionManager";
|
||||||
import Navigation from "./Navigation";
|
import Navigation from "./Navigation";
|
||||||
import ActionBar from "./ActionBar";
|
import ActionBar from "./ActionBar";
|
||||||
import notifier from "../app/Notifier";
|
import notifier from "../app/Notifier";
|
||||||
import NoTopics from "./NoTopics";
|
|
||||||
import Preferences from "./Preferences";
|
import Preferences from "./Preferences";
|
||||||
import {useLiveQuery} from "dexie-react-hooks";
|
import {useLiveQuery} from "dexie-react-hooks";
|
||||||
import poller from "../app/Poller";
|
import poller from "../app/Poller";
|
||||||
|
@ -56,7 +55,6 @@ const Root = () => {
|
||||||
}, [subscriptions, users]); // Dangle!
|
}, [subscriptions, users]); // Dangle!
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(`hello ${newNotificationsCount}`)
|
|
||||||
document.title = (newNotificationsCount > 0) ? `(${newNotificationsCount}) ntfy web` : "ntfy web";
|
document.title = (newNotificationsCount > 0) ? `(${newNotificationsCount}) ntfy web` : "ntfy web";
|
||||||
}, [newNotificationsCount]);
|
}, [newNotificationsCount]);
|
||||||
|
|
||||||
|
@ -81,10 +79,10 @@ const Root = () => {
|
||||||
<Main>
|
<Main>
|
||||||
<Toolbar/>
|
<Toolbar/>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<NoTopics />} />
|
|
||||||
<Route path="settings" element={<Preferences />} />
|
<Route path="settings" element={<Preferences />} />
|
||||||
<Route path=":baseUrl/:topic" element={<Notifications subscription={selectedSubscription}/>} />
|
<Route path="/" element={<Notifications mode="all" subscriptions={subscriptions} />} />
|
||||||
<Route path=":topic" element={<Notifications subscription={selectedSubscription}/>} />
|
<Route path=":baseUrl/:topic" element={<Notifications mode="one" subscription={selectedSubscription}/>} />
|
||||||
|
<Route path=":topic" element={<Notifications mode="one" subscription={selectedSubscription}/>} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Main>
|
</Main>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
@ -133,9 +133,10 @@ const SubscriptionList = (props) => {
|
||||||
const SubscriptionItem = (props) => {
|
const SubscriptionItem = (props) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const subscription = props.subscription;
|
const subscription = props.subscription;
|
||||||
|
const iconBadge = (subscription.new <= 99) ? subscription.new : "99+";
|
||||||
const icon = (subscription.state === ConnectionState.Connecting)
|
const icon = (subscription.state === ConnectionState.Connecting)
|
||||||
? <CircularProgress size="24px"/>
|
? <CircularProgress size="24px"/>
|
||||||
: <Badge badgeContent={subscription.new} invisible={subscription.new === 0} color="primary"><ChatBubbleOutlineIcon/></Badge>;
|
: <Badge badgeContent={iconBadge} invisible={subscription.new === 0} color="primary"><ChatBubbleOutlineIcon/></Badge>;
|
||||||
const label = (subscription.baseUrl === window.location.origin)
|
const label = (subscription.baseUrl === window.location.origin)
|
||||||
? subscription.topic
|
? subscription.topic
|
||||||
: topicShortUrl(subscription.baseUrl, subscription.topic);
|
: topicShortUrl(subscription.baseUrl, subscription.topic);
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
import {Link} from "@mui/material";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import * as React from "react";
|
|
||||||
import {Paragraph, VerticallyCenteredContainer} from "./styles";
|
|
||||||
|
|
||||||
const NoTopics = (props) => {
|
|
||||||
return (
|
|
||||||
<VerticallyCenteredContainer maxWidth="xs">
|
|
||||||
<Typography variant="h5" align="center" sx={{ paddingBottom: 1 }}>
|
|
||||||
<img src="static/img/ntfy-outline.svg" height="64" width="64" alt="No topics"/><br />
|
|
||||||
It looks like you don't have any subscriptions yet.
|
|
||||||
</Typography>
|
|
||||||
<Paragraph>
|
|
||||||
Click the "Add subscription" link to create or subscribe to a topic. After that, you can send messages
|
|
||||||
via PUT or POST and you'll receive notifications here.
|
|
||||||
</Paragraph>
|
|
||||||
<Paragraph>
|
|
||||||
For more information, check out the <Link href="https://ntfy.sh" target="_blank" rel="noopener">website</Link> or
|
|
||||||
{" "}<Link href="https://ntfy.sh/docs" target="_blank" rel="noopener">documentation</Link>.
|
|
||||||
</Paragraph>
|
|
||||||
</VerticallyCenteredContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default NoTopics;
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Container from "@mui/material/Container";
|
import Container from "@mui/material/Container";
|
||||||
import {ButtonBase, CardActions, CardContent, Fade, Link, Modal, Stack} from "@mui/material";
|
import {ButtonBase, CardActions, CardContent, CircularProgress, Fade, Link, Modal, Stack} from "@mui/material";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
@ -22,28 +22,43 @@ import Button from "@mui/material/Button";
|
||||||
import subscriptionManager from "../app/SubscriptionManager";
|
import subscriptionManager from "../app/SubscriptionManager";
|
||||||
|
|
||||||
const Notifications = (props) => {
|
const Notifications = (props) => {
|
||||||
const subscription = props.subscription;
|
if (props.mode === "all") {
|
||||||
if (!subscription) {
|
return (props.subscriptions) ? <AllSubscriptions subscriptions={props.subscriptions}/> : <Loading/>;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return <NotificationList subscription={subscription}/>;
|
return (props.subscription) ? <SingleSubscription subscription={props.subscription}/> : <Loading/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AllSubscriptions = () => {
|
||||||
|
const notifications = useLiveQuery(() => subscriptionManager.getAllNotifications(), []);
|
||||||
|
if (notifications === null || notifications === undefined) {
|
||||||
|
return <Loading/>;
|
||||||
|
} else if (notifications.length === 0) {
|
||||||
|
return <NoSubscriptions/>;
|
||||||
|
}
|
||||||
|
return <NotificationList notifications={notifications}/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SingleSubscription = (props) => {
|
||||||
|
const subscription = props.subscription;
|
||||||
|
const notifications = useLiveQuery(() => subscriptionManager.getNotifications(subscription.id), [subscription]);
|
||||||
|
if (notifications === null || notifications === undefined) {
|
||||||
|
return <Loading/>;
|
||||||
|
} else if (notifications.length === 0) {
|
||||||
|
return <NoNotifications subscription={subscription}/>;
|
||||||
|
}
|
||||||
|
return <NotificationList notifications={notifications}/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NotificationList = (props) => {
|
const NotificationList = (props) => {
|
||||||
const subscription = props.subscription;
|
const sortedNotifications = props.notifications;
|
||||||
const notifications = useLiveQuery(() => subscriptionManager.getNotifications(subscription.id), [subscription]);
|
/*const sortedNotifications = Array.from(props.notifications)
|
||||||
if (!notifications || notifications.length === 0) {
|
.sort((a, b) => a.time < b.time ? 1 : -1);*/
|
||||||
return <NothingHereYet subscription={subscription}/>;
|
|
||||||
}
|
|
||||||
const sortedNotifications = Array.from(notifications)
|
|
||||||
.sort((a, b) => a.time < b.time ? 1 : -1);
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="md" sx={{marginTop: 3, marginBottom: 3}}>
|
<Container maxWidth="md" sx={{marginTop: 3, marginBottom: 3}}>
|
||||||
<Stack spacing={3}>
|
<Stack spacing={3}>
|
||||||
{sortedNotifications.map(notification =>
|
{sortedNotifications.map(notification =>
|
||||||
<NotificationItem
|
<NotificationItem
|
||||||
key={notification.id}
|
key={notification.id}
|
||||||
subscriptionId={subscription.id}
|
|
||||||
notification={notification}
|
notification={notification}
|
||||||
/>)}
|
/>)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -52,8 +67,8 @@ const NotificationList = (props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const NotificationItem = (props) => {
|
const NotificationItem = (props) => {
|
||||||
const subscriptionId = props.subscriptionId;
|
|
||||||
const notification = props.notification;
|
const notification = props.notification;
|
||||||
|
const subscriptionId = notification.subscriptionId;
|
||||||
const attachment = notification.attachment;
|
const attachment = notification.attachment;
|
||||||
const date = formatShortDateTime(notification.time);
|
const date = formatShortDateTime(notification.time);
|
||||||
const otherTags = unmatchedTags(notification.tags);
|
const otherTags = unmatchedTags(notification.tags);
|
||||||
|
@ -250,7 +265,7 @@ const Icon = (props) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const NothingHereYet = (props) => {
|
const NoNotifications = (props) => {
|
||||||
const shortUrl = topicShortUrl(props.subscription.baseUrl, props.subscription.topic);
|
const shortUrl = topicShortUrl(props.subscription.baseUrl, props.subscription.topic);
|
||||||
return (
|
return (
|
||||||
<VerticallyCenteredContainer maxWidth="xs">
|
<VerticallyCenteredContainer maxWidth="xs">
|
||||||
|
@ -275,4 +290,34 @@ const NothingHereYet = (props) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NoSubscriptions = () => {
|
||||||
|
return (
|
||||||
|
<VerticallyCenteredContainer maxWidth="xs">
|
||||||
|
<Typography variant="h5" align="center" sx={{ paddingBottom: 1 }}>
|
||||||
|
<img src="/static/img/ntfy-outline.svg" height="64" width="64" alt="No topics"/><br />
|
||||||
|
It looks like you don't have any subscriptions yet.
|
||||||
|
</Typography>
|
||||||
|
<Paragraph>
|
||||||
|
Click the "Add subscription" link to create or subscribe to a topic. After that, you can send messages
|
||||||
|
via PUT or POST and you'll receive notifications here.
|
||||||
|
</Paragraph>
|
||||||
|
<Paragraph>
|
||||||
|
For more information, check out the <Link href="https://ntfy.sh" target="_blank" rel="noopener">website</Link> or
|
||||||
|
{" "}<Link href="https://ntfy.sh/docs" target="_blank" rel="noopener">documentation</Link>.
|
||||||
|
</Paragraph>
|
||||||
|
</VerticallyCenteredContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loading = () => {
|
||||||
|
return (
|
||||||
|
<VerticallyCenteredContainer>
|
||||||
|
<Typography variant="h5" color="text.secondary" align="center" sx={{ paddingBottom: 1 }}>
|
||||||
|
<CircularProgress disableShrink sx={{marginBottom: 1}}/><br />
|
||||||
|
Loading notifications ...
|
||||||
|
</Typography>
|
||||||
|
</VerticallyCenteredContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Notifications;
|
export default Notifications;
|
||||||
|
|
Loading…
Reference in New Issue