mirror of
https://github.com/binwiederhier/ntfy.git
synced 2024-11-04 19:04:15 +01:00
Fix UI bugs
This commit is contained in:
parent
79f9e78c37
commit
5724bdf436
5 changed files with 54 additions and 28 deletions
|
@ -34,6 +34,7 @@ import (
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
- MEDIUM fail2ban to work with ntfy log not nginx log
|
||||||
- HIGH Docs
|
- HIGH Docs
|
||||||
- tiers
|
- tiers
|
||||||
- api
|
- api
|
||||||
|
|
|
@ -26,7 +26,7 @@ import {Logout, Person, Settings} from "@mui/icons-material";
|
||||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||||
import accountApi from "../app/AccountApi";
|
import accountApi from "../app/AccountApi";
|
||||||
import PopupMenu from "./PopupMenu";
|
import PopupMenu from "./PopupMenu";
|
||||||
import SubscriptionPopup from "./SubscriptionPopup";
|
import { SubscriptionPopup } from "./SubscriptionPopup";
|
||||||
|
|
||||||
const ActionBar = (props) => {
|
const ActionBar = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
|
@ -11,9 +11,8 @@ import Divider from "@mui/material/Divider";
|
||||||
import List from "@mui/material/List";
|
import List from "@mui/material/List";
|
||||||
import SettingsIcon from "@mui/icons-material/Settings";
|
import SettingsIcon from "@mui/icons-material/Settings";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import VisibilityIcon from '@mui/icons-material/Visibility';
|
|
||||||
import SubscribeDialog from "./SubscribeDialog";
|
import SubscribeDialog from "./SubscribeDialog";
|
||||||
import {Alert, AlertTitle, Badge, CircularProgress, Link, ListSubheader, Menu, Portal, Tooltip} from "@mui/material";
|
import {Alert, AlertTitle, Badge, CircularProgress, Link, ListSubheader, Portal, Tooltip} from "@mui/material";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import {openUrl, topicDisplayName, topicUrl} from "../app/utils";
|
import {openUrl, topicDisplayName, topicUrl} from "../app/utils";
|
||||||
|
@ -21,16 +20,7 @@ import routes from "./routes";
|
||||||
import {ConnectionState} from "../app/Connection";
|
import {ConnectionState} from "../app/Connection";
|
||||||
import {useLocation, useNavigate} from "react-router-dom";
|
import {useLocation, useNavigate} from "react-router-dom";
|
||||||
import subscriptionManager from "../app/SubscriptionManager";
|
import subscriptionManager from "../app/SubscriptionManager";
|
||||||
import {
|
import {ChatBubble, MoreVert, NotificationsOffOutlined, Send} from "@mui/icons-material";
|
||||||
ChatBubble,
|
|
||||||
Lock, Logout,
|
|
||||||
MoreHoriz, MoreVert,
|
|
||||||
NotificationsOffOutlined,
|
|
||||||
Public,
|
|
||||||
PublicOff,
|
|
||||||
Send,
|
|
||||||
Settings
|
|
||||||
} from "@mui/icons-material";
|
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import notifier from "../app/Notifier";
|
import notifier from "../app/Notifier";
|
||||||
import config from "../app/config";
|
import config from "../app/config";
|
||||||
|
@ -43,9 +33,7 @@ import UpgradeDialog from "./UpgradeDialog";
|
||||||
import {AccountContext} from "./App";
|
import {AccountContext} from "./App";
|
||||||
import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons";
|
import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import { SubscriptionPopup } from "./SubscriptionPopup";
|
||||||
import PopupMenu from "./PopupMenu";
|
|
||||||
import SubscriptionPopup from "./SubscriptionPopup";
|
|
||||||
|
|
||||||
const navWidth = 280;
|
const navWidth = 280;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import Dialog from '@mui/material/Dialog';
|
||||||
import DialogContent from '@mui/material/DialogContent';
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
import DialogContentText from '@mui/material/DialogContentText';
|
import DialogContentText from '@mui/material/DialogContentText';
|
||||||
import DialogTitle from '@mui/material/DialogTitle';
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
import {Autocomplete, Checkbox, Chip, FormControlLabel, FormGroup, useMediaQuery} from "@mui/material";
|
import {Autocomplete, Checkbox, FormControlLabel, FormGroup, useMediaQuery} from "@mui/material";
|
||||||
import theme from "./theme";
|
import theme from "./theme";
|
||||||
import api from "../app/Api";
|
import api from "../app/Api";
|
||||||
import {randomAlphanumericString, topicUrl, validTopic, validUrl} from "../app/utils";
|
import {randomAlphanumericString, topicUrl, validTopic, validUrl} from "../app/utils";
|
||||||
|
@ -21,6 +21,7 @@ import accountApi, {Role} from "../app/AccountApi";
|
||||||
import ReserveTopicSelect from "./ReserveTopicSelect";
|
import ReserveTopicSelect from "./ReserveTopicSelect";
|
||||||
import {AccountContext} from "./App";
|
import {AccountContext} from "./App";
|
||||||
import {TopicReservedError, UnauthorizedError} from "../app/errors";
|
import {TopicReservedError, UnauthorizedError} from "../app/errors";
|
||||||
|
import {ReserveLimitChip} from "./SubscriptionPopup";
|
||||||
|
|
||||||
const publicBaseUrl = "https://ntfy.sh";
|
const publicBaseUrl = "https://ntfy.sh";
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ const SubscribeDialog = (props) => {
|
||||||
const handleSuccess = async () => {
|
const handleSuccess = async () => {
|
||||||
console.log(`[SubscribeDialog] Subscribing to topic ${topic}`);
|
console.log(`[SubscribeDialog] Subscribing to topic ${topic}`);
|
||||||
const actualBaseUrl = (baseUrl) ? baseUrl : config.base_url;
|
const actualBaseUrl = (baseUrl) ? baseUrl : config.base_url;
|
||||||
const subscription = subscribeTopic(actualBaseUrl, topic);
|
const subscription = await subscribeTopic(actualBaseUrl, topic);
|
||||||
poller.pollInBackground(subscription); // Dangle!
|
poller.pollInBackground(subscription); // Dangle!
|
||||||
props.onSuccess(subscription);
|
props.onSuccess(subscription);
|
||||||
}
|
}
|
||||||
|
@ -73,6 +74,7 @@ const SubscribePage = (props) => {
|
||||||
const existingBaseUrls = Array
|
const existingBaseUrls = Array
|
||||||
.from(new Set([publicBaseUrl, ...props.subscriptions.map(s => s.baseUrl)]))
|
.from(new Set([publicBaseUrl, ...props.subscriptions.map(s => s.baseUrl)]))
|
||||||
.filter(s => s !== config.base_url);
|
.filter(s => s !== config.base_url);
|
||||||
|
const showReserveTopicCheckbox = config.enable_reservations && session.exists() && !anotherServerVisible;
|
||||||
const reserveTopicEnabled = session.exists() && account?.role === Role.USER && (account?.stats.reservations_remaining || 0) > 0;
|
const reserveTopicEnabled = session.exists() && account?.role === Role.USER && (account?.stats.reservations_remaining || 0) > 0;
|
||||||
|
|
||||||
const handleSubscribe = async () => {
|
const handleSubscribe = async () => {
|
||||||
|
@ -163,7 +165,7 @@ const SubscribePage = (props) => {
|
||||||
{t("subscribe_dialog_subscribe_button_generate_topic_name")}
|
{t("subscribe_dialog_subscribe_button_generate_topic_name")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{config.enable_reservations && session.exists() && !anotherServerVisible &&
|
{showReserveTopicCheckbox &&
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
variant="standard"
|
variant="standard"
|
||||||
|
@ -181,7 +183,7 @@ const SubscribePage = (props) => {
|
||||||
label={
|
label={
|
||||||
<>
|
<>
|
||||||
{t("reserve_dialog_checkbox_label")}
|
{t("reserve_dialog_checkbox_label")}
|
||||||
<Chip label={t("action_bar_reservation_limit_reached")} variant="outlined" color="primary" sx={{ opacity: 0.8, borderWidth: "2px", height: "24px", marginLeft: "5px" }}/>
|
<ReserveLimitChip/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -24,9 +24,8 @@ import {Clear} from "@mui/icons-material";
|
||||||
import {AccountContext} from "./App";
|
import {AccountContext} from "./App";
|
||||||
import {ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog} from "./ReserveDialogs";
|
import {ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog} from "./ReserveDialogs";
|
||||||
import {UnauthorizedError} from "../app/errors";
|
import {UnauthorizedError} from "../app/errors";
|
||||||
import Box from "@mui/material/Box";
|
|
||||||
|
|
||||||
const SubscriptionPopup = (props) => {
|
export const SubscriptionPopup = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { account } = useContext(AccountContext);
|
const { account } = useContext(AccountContext);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
@ -39,10 +38,10 @@ const SubscriptionPopup = (props) => {
|
||||||
const placement = props.placement ?? "left";
|
const placement = props.placement ?? "left";
|
||||||
const reservations = account?.reservations || [];
|
const reservations = account?.reservations || [];
|
||||||
|
|
||||||
const showReservationAdd = !subscription?.reservation && account?.stats.reservations_remaining > 0;
|
const showReservationAdd = config.enable_reservations && !subscription?.reservation && account?.stats.reservations_remaining > 0;
|
||||||
const showReservationAddDisabled = !subscription?.reservation && account?.stats.reservations_remaining === 0;
|
const showReservationAddDisabled = config.enable_reservations && !subscription?.reservation && (config.enable_payments || account?.stats.reservations_remaining === 0);
|
||||||
const showReservationEdit = !!subscription?.reservation;
|
const showReservationEdit = config.enable_reservations && !!subscription?.reservation;
|
||||||
const showReservationDelete = !!subscription?.reservation;
|
const showReservationDelete = config.enable_reservations && !!subscription?.reservation;
|
||||||
|
|
||||||
const handleChangeDisplayName = async () => {
|
const handleChangeDisplayName = async () => {
|
||||||
setDisplayNameDialogOpen(true);
|
setDisplayNameDialogOpen(true);
|
||||||
|
@ -141,7 +140,7 @@ const SubscriptionPopup = (props) => {
|
||||||
{showReservationAddDisabled &&
|
{showReservationAddDisabled &&
|
||||||
<MenuItem sx={{ cursor: "default" }}>
|
<MenuItem sx={{ cursor: "default" }}>
|
||||||
<span style={{ opacity: 0.3 }}>{t("action_bar_reservation_add")}</span>
|
<span style={{ opacity: 0.3 }}>{t("action_bar_reservation_add")}</span>
|
||||||
<Chip label={t("action_bar_reservation_limit_reached")} variant="outlined" color="primary" sx={{ opacity: 0.8, borderWidth: "2px", height: "24px", marginLeft: "5px" }}/>
|
<ReserveLimitChip/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
}
|
}
|
||||||
{showReservationEdit && <MenuItem onClick={handleReserveEdit}>{t("action_bar_reservation_edit")}</MenuItem>}
|
{showReservationEdit && <MenuItem onClick={handleReserveEdit}>{t("action_bar_reservation_edit")}</MenuItem>}
|
||||||
|
@ -254,4 +253,40 @@ const DisplayNameDialog = (props) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SubscriptionPopup;
|
export const ReserveLimitChip = () => {
|
||||||
|
const { account } = useContext(AccountContext);
|
||||||
|
if (account?.stats.reservations_remaining > 0) {
|
||||||
|
return <></>;
|
||||||
|
} else if (config.enable_payments) {
|
||||||
|
return <ProChip/>;
|
||||||
|
} else if (account) {
|
||||||
|
return <LimitReachedChip/>;
|
||||||
|
}
|
||||||
|
return <></>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const LimitReachedChip = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
label={t("action_bar_reservation_limit_reached")}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
sx={{ opacity: 0.8, borderWidth: "2px", height: "24px", marginLeft: "5px" }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProChip = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
label={"ntfy Pro"}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
sx={{ opacity: 0.8, borderWidth: "2px", height: "24px", marginLeft: "5px" }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue