(undefined);
const listWebhooks = async () => {
if (!currentUser) return [];
@@ -30,16 +33,22 @@ const WebhookSection = () => {
const handleCreateWebhookDialogConfirm = async () => {
const webhooks = await listWebhooks();
+ const name = webhooks[webhooks.length - 1]?.displayName || "";
setWebhooks(webhooks);
setIsCreateWebhookDialogOpen(false);
+ toast.success(t("setting.webhook-section.create-dialog.create-webhook-success", { name }));
};
const handleDeleteWebhook = async (webhook: UserWebhook) => {
- const confirmed = window.confirm(`Are you sure to delete webhook \`${webhook.displayName}\`? You cannot undo this action.`);
- if (confirmed) {
- await userServiceClient.deleteUserWebhook({ name: webhook.name });
- setWebhooks(webhooks.filter((item) => item.name !== webhook.name));
- }
+ setDeleteTarget(webhook);
+ };
+
+ const confirmDeleteWebhook = async () => {
+ if (!deleteTarget) return;
+ await userServiceClient.deleteUserWebhook({ name: deleteTarget.name });
+ setWebhooks(webhooks.filter((item) => item.name !== deleteTarget.name));
+ setDeleteTarget(undefined);
+ toast.success(t("setting.webhook-section.delete-dialog.delete-webhook-success", { name: deleteTarget.displayName }));
};
return (
@@ -79,12 +88,7 @@ const WebhookSection = () => {
{webhook.url}
- |
@@ -118,6 +122,16 @@ const WebhookSection = () => {
onOpenChange={setIsCreateWebhookDialogOpen}
onSuccess={handleCreateWebhookDialogConfirm}
/>
+ !open && setDeleteTarget(undefined)}
+ title={t("setting.webhook-section.delete-dialog.delete-webhook-title", { name: deleteTarget?.displayName || "" })}
+ description={t("setting.webhook-section.delete-dialog.delete-webhook-description")}
+ confirmLabel={t("common.delete")}
+ cancelLabel={t("common.cancel")}
+ onConfirm={confirmDeleteWebhook}
+ confirmVariant="destructive"
+ />
);
};
diff --git a/web/src/locales/en.json b/web/src/locales/en.json
index d3833b9a6..7f001d02e 100644
--- a/web/src/locales/en.json
+++ b/web/src/locales/en.json
@@ -143,7 +143,8 @@
},
"copy-link": "Copy Link",
"count-memos-in-date": "{{count}} {{memos}} in {{date}}",
- "delete-confirm": "Are you sure you want to delete this memo? THIS ACTION IS IRREVERSIBLE",
+ "delete-confirm": "Are you sure you want to delete this memo?",
+ "delete-confirm-description": "This action is irreversible. Attachments, links, and references will also be removed.",
"direction": "Direction",
"direction-asc": "Ascending",
"direction-desc": "Descending",
@@ -174,7 +175,7 @@
"archived-successfully": "Archived successfully",
"change-memo-created-time": "Change memo created time",
"copied": "Copied",
- "deleted-successfully": "Deleted successfully",
+ "deleted-successfully": "Memo deleted successfully",
"description-is-required": "Description is required",
"failed-to-embed-memo": "Failed to embed memo",
"fill-all": "Please fill in all fields.",
@@ -219,6 +220,8 @@
},
"delete-resource": "Delete Resource",
"delete-selected-resources": "Delete Selected Resources",
+ "delete-all-unused": "Delete all unused",
+ "delete-all-unused-confirm": "Are you sure you want to delete all unused resources? THIS ACTION IS IRREVERSIBLE",
"fetching-data": "Fetching data…",
"file-drag-drop-prompt": "Drag and drop your file here to upload file",
"linked-amount": "Linked amount",
@@ -226,7 +229,7 @@
"no-resources": "No resources.",
"no-unused-resources": "No unused resources",
"reset-link": "Reset Link",
- "reset-link-prompt": "Are you sure to reset the link? This will break all current link usages. THIS ACTION IS IRREVERSIBLE",
+ "reset-link-prompt": "Are you sure you want to reset the link? This will break all current link usages. THIS ACTION IS IRREVERSIBLE",
"reset-resource-link": "Reset Resource Link",
"unused-resources": "Unused resources"
},
@@ -237,8 +240,11 @@
"setting": {
"access-token-section": {
"access-token-copied-to-clipboard": "Access token copied to clipboard",
- "access-token-deletion": "Are you sure to delete access token {{accessToken}}? THIS ACTION IS IRREVERSIBLE.",
+ "access-token-deletion": "Are you sure you want to delete access token `{{description}}`?",
+ "access-token-deletion-description": "This action is irreversible. You will need to update any services using this token to use a new token.",
+ "access-token-deleted": "Access token `{{description}}` deleted",
"create-dialog": {
+ "access-token-created": "Access token `{{description}}` created",
"create-access-token": "Create Access Token",
"created-at": "Created At",
"description": "Description",
@@ -262,9 +268,11 @@
"expires": "Expires",
"current": "Current",
"never": "Never",
- "session-revocation": "Are you sure to revoke session {{sessionId}}? You will need to sign in again on that device.",
+ "session-revocation": "Are you sure you want to revoke session `{{sessionId}}`?",
+ "session-revocation-description": "You will need to sign in again on that device.",
"session-revoked": "Session revoked successfully",
"revoke-session": "Revoke session",
+ "revoke-session-button": "Revoke",
"cannot-revoke-current": "Cannot revoke current session",
"no-sessions": "No active sessions found"
},
@@ -286,10 +294,15 @@
"member-section": {
"admin": "Admin",
"archive-member": "Archive member",
- "archive-warning": "Are you sure to archive {{username}}?",
+ "archive-warning": "Are you sure you want to archive {{username}}?",
+ "archive-warning-description": "Archiving disables the account. You can restore or delete it later.",
+ "archive-success": "{{username}} archived successfully",
+ "restore-success": "{{username}} restored successfully",
"create-a-member": "Create a member",
"delete-member": "Delete Member",
- "delete-warning": "Are you sure to delete {{username}}? THIS ACTION IS IRREVERSIBLE",
+ "delete-warning": "Are you sure you want to delete {{username}}?",
+ "delete-warning-description": "THIS ACTION IS IRREVERSIBLE",
+ "delete-success": "{{username}} deleted successfully",
"user": "User"
},
"memo-related": "Memo",
@@ -309,12 +322,16 @@
"default-memo-visibility": "Default memo visibility",
"theme": "Theme"
},
+ "shortcut": {
+ "delete-confirm": "Are you sure you want to delete shortcut `{{title}}`?",
+ "delete-success": "Shortcut `{{title}}` deleted successfully"
+ },
"sso": "SSO",
"sso-section": {
"authorization-endpoint": "Authorization endpoint",
"client-id": "Client ID",
"client-secret": "Client secret",
- "confirm-delete": "Are you sure to delete \"{{name}}\" SSO configuration? THIS ACTION IS IRREVERSIBLE",
+ "confirm-delete": "Are you sure you want to delete `{{name}}` SSO configuration? THIS ACTION IS IRREVERSIBLE",
"create-sso": "Create SSO",
"custom": "Custom",
"delete-sso": "Confirm delete",
@@ -367,7 +384,7 @@
"url-prefix-placeholder": "Custom URL prefix, optional",
"url-suffix": "URL suffix",
"url-suffix-placeholder": "Custom URL suffix, optional",
- "warning-text": "Are you sure to delete storage service \"{{name}}\"? THIS ACTION IS IRREVERSIBLE"
+ "warning-text": "Are you sure you want to delete storage service `{{name}}`? THIS ACTION IS IRREVERSIBLE"
},
"system": "System",
"system-section": {
@@ -384,7 +401,7 @@
},
"disable-markdown-shortcuts-in-editor": "Disable Markdown shortcuts in editor",
"disable-password-login": "Disable password login",
- "disable-password-login-final-warning": "Please type \"CONFIRM\" if you know what you are doing.",
+ "disable-password-login-final-warning": "Please type `CONFIRM` if you know what you are doing.",
"disable-password-login-warning": "This will disable password login for all users. It is not possible to log in without reverting this setting in the database if your configured identity providers fail. You’ll also have to be extra careful when removing an identity provider",
"disable-public-memos": "Disable public memos",
"display-with-updated-time": "Display with updated time",
@@ -403,11 +420,17 @@
"create-dialog": {
"an-easy-to-remember-name": "An easy-to-remember name",
"create-webhook": "Create webhook",
+ "create-webhook-success": "Webhook `{{name}}` created",
"edit-webhook": "Edit webhook",
"payload-url": "Payload URL",
"title": "Title",
"url-example-post-receive": "https://example.com/postreceive"
},
+ "delete-dialog": {
+ "delete-webhook-description": "This action is irreversible.",
+ "delete-webhook-title": "Are you sure you want to delete webhook `{{name}}`?",
+ "delete-webhook-success": "Webhook `{{name}}` deleted successfully"
+ },
"no-webhooks-found": "No webhooks found.",
"title": "Webhooks",
"url": "URL"
@@ -427,8 +450,9 @@
"all-tags": "All Tags",
"create-tag": "Create Tag",
"create-tags-guide": "You can create tags by inputting `#tag`.",
- "delete-confirm": "Are you sure to delete this tag? All related memos will be archived.",
+ "delete-confirm": "Are you sure you want to delete this tag? All related memos will be archived.",
"delete-tag": "Delete Tag",
+ "delete-success": "Tag deleted successfully",
"new-name": "New Name",
"no-tag-found": "No tag found",
"old-name": "Old Name",
diff --git a/web/src/pages/Attachments.tsx b/web/src/pages/Attachments.tsx
index f8bafcdd5..7e6d33e40 100644
--- a/web/src/pages/Attachments.tsx
+++ b/web/src/pages/Attachments.tsx
@@ -1,15 +1,13 @@
import dayjs from "dayjs";
import { includes } from "lodash-es";
-import { PaperclipIcon, SearchIcon, TrashIcon } from "lucide-react";
+import { PaperclipIcon, SearchIcon } from "lucide-react";
import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react";
import AttachmentIcon from "@/components/AttachmentIcon";
import Empty from "@/components/Empty";
import MobileHeader from "@/components/MobileHeader";
-import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
-import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { attachmentServiceClient } from "@/grpcweb";
import useLoading from "@/hooks/useLoading";
import useResponsiveWidth from "@/hooks/useResponsiveWidth";
@@ -56,16 +54,6 @@ const Attachments = observer(() => {
});
}, []);
- const handleDeleteUnusedAttachments = async () => {
- const confirmed = window.confirm("Are you sure to delete all unused attachments? This action cannot be undone.");
- if (confirmed) {
- for (const attachment of unusedAttachments) {
- await attachmentServiceClient.deleteAttachment({ name: attachment.name });
- }
- setAttachments(attachments.filter((attachment) => attachment.memo));
- }
- };
-
return (
{!md && }
@@ -138,18 +126,6 @@ const Attachments = observer(() => {
{t("resource.unused-resources")}
({unusedAttachments.length})
-
-
-
-
-
-
-
-
- Delete all
-
-
-
{unusedAttachments.map((attachment) => {
return (