Web: Fix clear=true on action buttons not clearing the notification
This commit is contained in:
@@ -1688,6 +1688,7 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release
|
|||||||
|
|
||||||
**Bug fixes + maintenance:**
|
**Bug fixes + maintenance:**
|
||||||
|
|
||||||
|
* Web: Fix `clear=true` on action buttons not clearing the notification ([#1029](https://github.com/binwiederhier/ntfy/issues/1029), thanks to [@ElFishi](https://github.com/ElFishi) for reporting)
|
||||||
* Fix crash when commit string is shorter than 7 characters in non-GitHub-Action builds ([#1493](https://github.com/binwiederhier/ntfy/issues/1493), thanks to [@cyrinux](https://github.com/cyrinux) for reporting)
|
* Fix crash when commit string is shorter than 7 characters in non-GitHub-Action builds ([#1493](https://github.com/binwiederhier/ntfy/issues/1493), thanks to [@cyrinux](https://github.com/cyrinux) for reporting)
|
||||||
* Fix log spam from `http: response.WriteHeader on hijacked connection` for WebSocket errors ([#1362](https://github.com/binwiederhier/ntfy/issues/1362), thanks to [@bonfiresh](https://github.com/bonfiresh) for reporting)
|
* Fix log spam from `http: response.WriteHeader on hijacked connection` for WebSocket errors ([#1362](https://github.com/binwiederhier/ntfy/issues/1362), thanks to [@bonfiresh](https://github.com/bonfiresh) for reporting)
|
||||||
* Web: Fix Markdown message line height to match plain text (1.5 instead of 1.2) ([#1139](https://github.com/binwiederhier/ntfy/issues/1139), thanks to [@etfz](https://github.com/etfz) for reporting)
|
* Web: Fix Markdown message line height to match plain text (1.5 instead of 1.2) ([#1139](https://github.com/binwiederhier/ntfy/issues/1139), thanks to [@etfz](https://github.com/etfz) for reporting)
|
||||||
|
|||||||
@@ -237,8 +237,24 @@ const handleClick = async (event) => {
|
|||||||
if (event.action) {
|
if (event.action) {
|
||||||
const action = event.notification.data.message.actions.find(({ label }) => event.action === label);
|
const action = event.notification.data.message.actions.find(({ label }) => event.action === label);
|
||||||
|
|
||||||
|
// Helper to clear notification and mark as read
|
||||||
|
const clearNotification = async () => {
|
||||||
|
event.notification.close();
|
||||||
|
const { subscriptionId, message: msg } = event.notification.data;
|
||||||
|
const seqId = msg.sequence_id || msg.id;
|
||||||
|
if (subscriptionId && seqId) {
|
||||||
|
const db = await dbAsync();
|
||||||
|
await db.notifications.where({ subscriptionId, sequenceId: seqId }).modify({ new: 0 });
|
||||||
|
const badgeCount = await db.notifications.where({ new: 1 }).count();
|
||||||
|
self.navigator.setAppBadge?.(badgeCount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (action.action === "view") {
|
if (action.action === "view") {
|
||||||
self.clients.openWindow(action.url);
|
self.clients.openWindow(action.url);
|
||||||
|
if (action.clear) {
|
||||||
|
await clearNotification();
|
||||||
|
}
|
||||||
} else if (action.action === "http") {
|
} else if (action.action === "http") {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(action.url, {
|
const response = await fetch(action.url, {
|
||||||
@@ -250,6 +266,11 @@ const handleClick = async (event) => {
|
|||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP ${response.status} ${response.statusText}`);
|
throw new Error(`HTTP ${response.status} ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only clear on success
|
||||||
|
if (action.clear) {
|
||||||
|
await clearNotification();
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[ServiceWorker] Error performing http action", e);
|
console.error("[ServiceWorker] Error performing http action", e);
|
||||||
self.registration.showNotification(`${t("notifications_actions_failed_notification")}: ${action.label} (${action.action})`, {
|
self.registration.showNotification(`${t("notifications_actions_failed_notification")}: ${action.label} (${action.action})`, {
|
||||||
@@ -259,10 +280,6 @@ const handleClick = async (event) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.clear) {
|
|
||||||
event.notification.close();
|
|
||||||
}
|
|
||||||
} else if (message.click) {
|
} else if (message.click) {
|
||||||
self.clients.openWindow(message.click);
|
self.clients.openWindow(message.click);
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export const toNotificationParams = ({ message, defaultTitle, topicRoute, baseUr
|
|||||||
const image = isImage(message.attachment) ? message.attachment.url : undefined;
|
const image = isImage(message.attachment) ? message.attachment.url : undefined;
|
||||||
const sequenceId = message.sequence_id || message.id;
|
const sequenceId = message.sequence_id || message.id;
|
||||||
const tag = notificationTag(baseUrl, topic, sequenceId);
|
const tag = notificationTag(baseUrl, topic, sequenceId);
|
||||||
|
const subscriptionId = `${baseUrl}/${topic}`;
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API
|
// https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API
|
||||||
return [
|
return [
|
||||||
@@ -75,6 +76,7 @@ export const toNotificationParams = ({ message, defaultTitle, topicRoute, baseUr
|
|||||||
silent: false,
|
silent: false,
|
||||||
// This is used by the notification onclick event
|
// This is used by the notification onclick event
|
||||||
data: {
|
data: {
|
||||||
|
subscriptionId,
|
||||||
message,
|
message,
|
||||||
topicRoute,
|
topicRoute,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import {
|
|||||||
import { formatMessage, formatTitle, isImage } from "../app/notificationUtils";
|
import { formatMessage, formatTitle, isImage } from "../app/notificationUtils";
|
||||||
import { LightboxBackdrop, Paragraph, VerticallyCenteredContainer } from "./styles";
|
import { LightboxBackdrop, Paragraph, VerticallyCenteredContainer } from "./styles";
|
||||||
import subscriptionManager from "../app/SubscriptionManager";
|
import subscriptionManager from "../app/SubscriptionManager";
|
||||||
|
import notifier from "../app/Notifier";
|
||||||
import priority1 from "../img/priority-1.svg";
|
import priority1 from "../img/priority-1.svg";
|
||||||
import priority2 from "../img/priority-2.svg";
|
import priority2 from "../img/priority-2.svg";
|
||||||
import priority4 from "../img/priority-4.svg";
|
import priority4 from "../img/priority-4.svg";
|
||||||
@@ -508,6 +509,15 @@ const updateActionStatus = (notification, action, progress, error) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const clearNotification = async (notification) => {
|
||||||
|
console.log(`[Notifications] Clearing notification ${notification.id}`);
|
||||||
|
const subscription = await subscriptionManager.get(notification.subscriptionId);
|
||||||
|
if (subscription) {
|
||||||
|
await notifier.cancel(subscription, notification);
|
||||||
|
}
|
||||||
|
await subscriptionManager.markNotificationRead(notification.id);
|
||||||
|
};
|
||||||
|
|
||||||
const performHttpAction = async (notification, action) => {
|
const performHttpAction = async (notification, action) => {
|
||||||
console.log(`[Notifications] Performing HTTP user action`, action);
|
console.log(`[Notifications] Performing HTTP user action`, action);
|
||||||
try {
|
try {
|
||||||
@@ -523,6 +533,9 @@ const performHttpAction = async (notification, action) => {
|
|||||||
const success = response.status >= 200 && response.status <= 299;
|
const success = response.status >= 200 && response.status <= 299;
|
||||||
if (success) {
|
if (success) {
|
||||||
updateActionStatus(notification, action, ACTION_PROGRESS_SUCCESS, null);
|
updateActionStatus(notification, action, ACTION_PROGRESS_SUCCESS, null);
|
||||||
|
if (action.clear) {
|
||||||
|
await clearNotification(notification);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
updateActionStatus(notification, action, ACTION_PROGRESS_FAILED, `${action.label}: Unexpected response HTTP ${response.status}`);
|
updateActionStatus(notification, action, ACTION_PROGRESS_FAILED, `${action.label}: Unexpected response HTTP ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -548,10 +561,16 @@ const UserAction = (props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (action.action === "view") {
|
if (action.action === "view") {
|
||||||
|
const handleClick = () => {
|
||||||
|
openUrl(action.url);
|
||||||
|
if (action.clear) {
|
||||||
|
clearNotification(notification);
|
||||||
|
}
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<Tooltip title={t("notifications_actions_open_url_title", { url: action.url })}>
|
<Tooltip title={t("notifications_actions_open_url_title", { url: action.url })}>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => openUrl(action.url)}
|
onClick={handleClick}
|
||||||
aria-label={t("notifications_actions_open_url_title", {
|
aria-label={t("notifications_actions_open_url_title", {
|
||||||
url: action.url,
|
url: action.url,
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in New Issue
Block a user