drafts: Add confirmation banner and undo option for drafts deletion.

Previously, deleting drafts was too easy, which could result in
accidentally losing important information.

This commit adds a green confirmation banner showing "N drafts were
deleted" and "Undo" button to restore deleted drafts.

Fixes: #32995.
This commit is contained in:
Aditya Kumar Kasaudhan
2025-04-01 16:07:57 +05:30
committed by Tim Abbott
parent 9a4de8d9b8
commit a0d86aeca4
3 changed files with 74 additions and 0 deletions

View File

@@ -3,6 +3,7 @@ import $ from "jquery";
import _ from "lodash";
import assert from "minimalistic-assert";
import render_banner from "../templates/components/banner.hbs";
import render_draft_table_body from "../templates/draft_table_body.hbs";
import render_drafts_list from "../templates/drafts_list.hbs";
@@ -21,6 +22,55 @@ import {realm} from "./state_data.ts";
import * as user_card_popover from "./user_card_popover.ts";
import * as user_group_popover from "./user_group_popover.ts";
let draft_undo_delete_list: LocalStorageDraft[] = [];
function clear_undo_list(): void {
draft_undo_delete_list = [];
$("#draft_overlay_banner_container").empty();
}
function undo_draft_deletion(): void {
if (draft_undo_delete_list.length === 0) {
return;
}
for (const draft of draft_undo_delete_list) {
drafts.draft_model.addDraft(draft);
}
clear_undo_list();
rerender_drafts();
$(".select-drafts-button").show();
$(".delete-selected-drafts-button").show();
}
function show_delete_banner(): void {
const $banner_container = $("#draft_overlay_banner_container");
$banner_container.empty();
const banner_html = render_banner({
intent: "success",
label: $t(
{
defaultMessage:
"{N, plural, one {# draft was deleted.} other {# drafts were deleted.}}",
},
{N: draft_undo_delete_list.length},
),
buttons: [
{
attention: "quiet",
intent: "success",
label: $t({defaultMessage: "Undo"}),
custom_classes: "draft-delete-banner-undo-button",
},
],
close_button: true,
});
$banner_container.html(banner_html);
}
function restore_draft(draft_id: string): void {
const draft = drafts.draft_model.getDraft(draft_id);
if (!draft) {
@@ -66,8 +116,14 @@ function remove_draft($draft_row: JQuery): void {
// Deletes the draft and removes it from the list
const draft_id = $draft_row.attr("data-draft-id")!;
const draft = drafts.draft_model.getDraft(draft_id);
drafts.draft_model.deleteDraft(draft_id);
if (draft) {
draft_undo_delete_list.push(draft);
show_delete_banner();
}
$draft_row.remove();
if ($("#drafts_table .overlay-message-row").length === 0) {
@@ -304,6 +360,12 @@ function setup_bulk_actions_handlers(): void {
});
}
function rerender_drafts(): void {
const {narrow_drafts, other_drafts, narrow_drafts_header} = get_formatted_drafts_data();
render_widgets(narrow_drafts, other_drafts, narrow_drafts_header);
setup_event_handlers();
}
export function launch(): void {
const {narrow_drafts, other_drafts, narrow_drafts_header} = get_formatted_drafts_data();
@@ -359,6 +421,7 @@ export function open_overlay(): void {
on_close() {
browser_history.exit_overlay();
drafts.sync_count();
draft_undo_delete_list = [];
},
});
}
@@ -380,4 +443,10 @@ export function initialize(): void {
$("body").on("focus", "#drafts_table .overlay-message-info-box", function (this: HTMLElement) {
messages_overlay_ui.activate_element(this, keyboard_handling_context);
});
$("body").on(
"click",
"#draft_overlay_banner_container .draft-delete-banner-undo-button",
undo_draft_deletion,
);
$("body").on("click", "#draft_overlay_banner_container .banner-close-button", clear_undo_list);
}

View File

@@ -1,4 +1,8 @@
.drafts-container {
.banner-container {
margin: 0 25px 5px;
}
.header-body {
display: flex;
align-items: center;

View File

@@ -6,6 +6,7 @@
<div class="exit">
<span class="exit-sign">&times;</span>
</div>
<div id="draft_overlay_banner_container" class="banner-container"></div>
<div class="header-body">
<div class="drafts-header-note">
{{t "Drafts are not synced to other devices and browsers." }}