mirror of
https://github.com/binwiederhier/ntfy.git
synced 2025-06-16 01:23:18 +02:00
WIP: DIsplay name for the web app
This commit is contained in:
parent
2d26a990a9
commit
4d6c147f24
9 changed files with 108 additions and 15 deletions
|
@ -1,13 +1,12 @@
|
|||
import {
|
||||
basicAuth,
|
||||
encodeBase64,
|
||||
fetchLinesIterator,
|
||||
maybeWithBasicAuth,
|
||||
topicShortUrl,
|
||||
topicUrl,
|
||||
topicUrlAuth,
|
||||
topicUrlJsonPoll,
|
||||
topicUrlJsonPollWithSince, userStatsUrl
|
||||
topicUrlJsonPollWithSince,
|
||||
userStatsUrl
|
||||
} from "./utils";
|
||||
import userManager from "./UserManager";
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {formatMessage, formatTitleWithDefault, openUrl, playSound, topicShortUrl} from "./utils";
|
||||
import {formatMessage, formatTitleWithDefault, openUrl, playSound, topicDisplayName, topicShortUrl} from "./utils";
|
||||
import prefs from "./Prefs";
|
||||
import subscriptionManager from "./SubscriptionManager";
|
||||
import logo from "../img/ntfy.png";
|
||||
|
@ -18,8 +18,9 @@ class Notifier {
|
|||
return;
|
||||
}
|
||||
const shortUrl = topicShortUrl(subscription.baseUrl, subscription.topic);
|
||||
const displayName = topicDisplayName(subscription);
|
||||
const message = formatMessage(notification);
|
||||
const title = formatTitleWithDefault(notification, shortUrl);
|
||||
const title = formatTitleWithDefault(notification, displayName);
|
||||
|
||||
// Show notification
|
||||
console.log(`[Notifier, ${shortUrl}] Displaying notification ${notification.id}: ${message}`);
|
||||
|
|
|
@ -133,6 +133,12 @@ class SubscriptionManager {
|
|||
});
|
||||
}
|
||||
|
||||
async setDisplayName(subscriptionId, displayName) {
|
||||
await db.subscriptions.update(subscriptionId, {
|
||||
displayName: displayName
|
||||
});
|
||||
}
|
||||
|
||||
async pruneNotifications(thresholdTimestamp) {
|
||||
await db.notifications
|
||||
.where("time").below(thresholdTimestamp)
|
||||
|
|
|
@ -38,6 +38,15 @@ export const disallowedTopic = (topic) => {
|
|||
return config.disallowedTopics.includes(topic);
|
||||
}
|
||||
|
||||
export const topicDisplayName = (subscription) => {
|
||||
if (subscription.displayName) {
|
||||
return subscription.displayName;
|
||||
} else if (subscription.baseUrl === window.location.origin) {
|
||||
return subscription.topic;
|
||||
}
|
||||
return topicShortUrl(subscription.baseUrl, subscription.topic);
|
||||
};
|
||||
|
||||
// Format emojis (see emoji.js)
|
||||
const emojis = {};
|
||||
rawEmojis.forEach(emoji => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import Typography from "@mui/material/Typography";
|
|||
import * as React from "react";
|
||||
import {useEffect, useRef, useState} from "react";
|
||||
import Box from "@mui/material/Box";
|
||||
import {formatShortDateTime, shuffle, topicShortUrl} from "../app/utils";
|
||||
import {formatShortDateTime, shuffle, topicDisplayName, topicShortUrl} from "../app/utils";
|
||||
import {useLocation, useNavigate} from "react-router-dom";
|
||||
import ClickAwayListener from '@mui/material/ClickAwayListener';
|
||||
import Grow from '@mui/material/Grow';
|
||||
|
@ -24,13 +24,14 @@ import subscriptionManager from "../app/SubscriptionManager";
|
|||
import logo from "../img/ntfy.svg";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {Portal, Snackbar} from "@mui/material";
|
||||
import SubscriptionSettingsDialog from "./SubscriptionSettingsDialog";
|
||||
|
||||
const ActionBar = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
let title = "ntfy";
|
||||
if (props.selected) {
|
||||
title = topicShortUrl(props.selected.baseUrl, props.selected.topic);
|
||||
title = topicDisplayName(props.selected);
|
||||
} else if (location.pathname === "/settings") {
|
||||
title = t("action_bar_settings");
|
||||
}
|
||||
|
@ -79,6 +80,7 @@ const SettingsIcons = (props) => {
|
|||
const navigate = useNavigate();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [snackOpen, setSnackOpen] = useState(false);
|
||||
const [subscriptionSettingsOpen, setSubscriptionSettingsOpen] = useState(false);
|
||||
const anchorRef = useRef(null);
|
||||
const subscription = props.subscription;
|
||||
|
||||
|
@ -116,6 +118,10 @@ const SettingsIcons = (props) => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleSubscriptionSettings = async () => {
|
||||
setSubscriptionSettingsOpen(true);
|
||||
}
|
||||
|
||||
const handleSendTestMessage = async () => {
|
||||
const baseUrl = props.subscription.baseUrl;
|
||||
const topic = props.subscription.topic;
|
||||
|
@ -201,6 +207,7 @@ const SettingsIcons = (props) => {
|
|||
<Paper>
|
||||
<ClickAwayListener onClickAway={handleClose}>
|
||||
<MenuList autoFocusItem={open} onKeyDown={handleListKeyDown}>
|
||||
<MenuItem onClick={handleSubscriptionSettings}>{t("action_bar_subscription_settings")}</MenuItem>
|
||||
<MenuItem onClick={handleSendTestMessage}>{t("action_bar_send_test_notification")}</MenuItem>
|
||||
<MenuItem onClick={handleClearAll}>{t("action_bar_clear_notifications")}</MenuItem>
|
||||
<MenuItem onClick={handleUnsubscribe}>{t("action_bar_unsubscribe")}</MenuItem>
|
||||
|
@ -218,6 +225,14 @@ const SettingsIcons = (props) => {
|
|||
message={t("message_bar_error_publishing")}
|
||||
/>
|
||||
</Portal>
|
||||
<Portal>
|
||||
<SubscriptionSettingsDialog
|
||||
key={`subscriptionSettingsDialog${subscription.id}`}
|
||||
open={subscriptionSettingsOpen}
|
||||
subscription={subscription}
|
||||
onClose={() => setSubscriptionSettingsOpen(false)}
|
||||
/>
|
||||
</Portal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ import SubscribeDialog from "./SubscribeDialog";
|
|||
import {Alert, AlertTitle, Badge, CircularProgress, Link, ListSubheader} from "@mui/material";
|
||||
import Button from "@mui/material/Button";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import {openUrl, topicShortUrl, topicUrl} from "../app/utils";
|
||||
import {openUrl, topicDisplayName, topicUrl} from "../app/utils";
|
||||
import routes from "./routes";
|
||||
import {ConnectionState} from "../app/Connection";
|
||||
import {useLocation, useNavigate} from "react-router-dom";
|
||||
|
@ -173,12 +173,10 @@ const SubscriptionItem = (props) => {
|
|||
const icon = (subscription.state === ConnectionState.Connecting)
|
||||
? <CircularProgress size="24px"/>
|
||||
: <Badge badgeContent={iconBadge} invisible={subscription.new === 0} color="primary"><ChatBubbleOutlineIcon/></Badge>;
|
||||
const label = (subscription.baseUrl === window.location.origin)
|
||||
? subscription.topic
|
||||
: topicShortUrl(subscription.baseUrl, subscription.topic);
|
||||
const displayName = topicDisplayName(subscription);
|
||||
const ariaLabel = (subscription.state === ConnectionState.Connecting)
|
||||
? `${label} (${t("nav_button_connecting")})`
|
||||
: label;
|
||||
? `${displayName} (${t("nav_button_connecting")})`
|
||||
: displayName;
|
||||
const handleClick = async () => {
|
||||
navigate(routes.forSubscription(subscription));
|
||||
await subscriptionManager.markNotificationsRead(subscription.id);
|
||||
|
@ -186,7 +184,7 @@ const SubscriptionItem = (props) => {
|
|||
return (
|
||||
<ListItemButton onClick={handleClick} selected={props.selected} aria-label={ariaLabel} aria-live="polite">
|
||||
<ListItemIcon>{icon}</ListItemIcon>
|
||||
<ListItemText primary={label}/>
|
||||
<ListItemText primary={displayName}/>
|
||||
{subscription.mutedUntil > 0 &&
|
||||
<ListItemIcon edge="end" aria-label={t("nav_button_muted")}><NotificationsOffOutlined /></ListItemIcon>}
|
||||
</ListItemButton>
|
||||
|
|
59
web/src/components/SubscriptionSettingsDialog.js
Normal file
59
web/src/components/SubscriptionSettingsDialog.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
import * as React from 'react';
|
||||
import {useState} from 'react';
|
||||
import Button from '@mui/material/Button';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import {Autocomplete, Checkbox, FormControlLabel, useMediaQuery} from "@mui/material";
|
||||
import theme from "./theme";
|
||||
import api from "../app/Api";
|
||||
import {topicUrl, validTopic, validUrl} from "../app/utils";
|
||||
import userManager from "../app/UserManager";
|
||||
import subscriptionManager from "../app/SubscriptionManager";
|
||||
import poller from "../app/Poller";
|
||||
import DialogFooter from "./DialogFooter";
|
||||
import {useTranslation} from "react-i18next";
|
||||
|
||||
const SubscriptionSettingsDialog = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const subscription = props.subscription;
|
||||
const [displayName, setDisplayName] = useState(subscription.displayName ?? "");
|
||||
const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const handleSave = async () => {
|
||||
await subscriptionManager.setDisplayName(subscription.id, displayName);
|
||||
props.onClose();
|
||||
}
|
||||
return (
|
||||
<Dialog open={props.open} onClose={props.onClose} fullScreen={fullScreen}>
|
||||
<DialogTitle>{t("subscription_settings_dialog_title")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
{t("subscription_settings_dialog_description")}
|
||||
</DialogContentText>
|
||||
<TextField
|
||||
autoFocus
|
||||
margin="dense"
|
||||
id="topic"
|
||||
placeholder={t("subscription_settings_dialog_display_name_placeholder")}
|
||||
value={displayName}
|
||||
onChange={ev => setDisplayName(ev.target.value)}
|
||||
type="text"
|
||||
fullWidth
|
||||
variant="standard"
|
||||
inputProps={{
|
||||
maxLength: 64,
|
||||
"aria-label": t("subscription_settings_dialog_display_name_placeholder")
|
||||
}}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogFooter>
|
||||
<Button onClick={props.onClose}>{t("subscription_settings_button_cancel")}</Button>
|
||||
<Button onClick={handleSave}>{t("subscription_settings_button_save")}</Button>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubscriptionSettingsDialog;
|
Loading…
Add table
Add a link
Reference in a new issue