mirror of https://github.com/zulip/zulip.git
message_edit: Ask users to delete attachments after editing.
currently, after a user edits a message and removes an reference to the uploaded file, the uploaded file stays on the storage taking up space. We want to ask the user to possibly delete the removed attachments if they are no longer needed. These changes applies a modal that will appear prompting the user to delete the attachments. Fixes: #25525. Co-authored-by: brijsiyag Co-authored-by: wandrew0
This commit is contained in:
parent
5133f34a05
commit
5d3edf06c8
|
@ -53,6 +53,7 @@ EXEMPT_FILES = make_set(
|
||||||
"web/src/alert_words_ui.ts",
|
"web/src/alert_words_ui.ts",
|
||||||
"web/src/archive.js",
|
"web/src/archive.js",
|
||||||
"web/src/assets.d.ts",
|
"web/src/assets.d.ts",
|
||||||
|
"web/src/attachments.ts",
|
||||||
"web/src/attachments_ui.ts",
|
"web/src/attachments_ui.ts",
|
||||||
"web/src/audible_notifications.ts",
|
"web/src/audible_notifications.ts",
|
||||||
"web/src/avatar.ts",
|
"web/src/avatar.ts",
|
||||||
|
|
|
@ -20,3 +20,7 @@ export const attachment_api_response_schema = z.object({
|
||||||
attachments: attachments_schema,
|
attachments: attachments_schema,
|
||||||
upload_space_used: z.number(),
|
upload_space_used: z.number(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const detached_uploads_api_response_schema = z.object({
|
||||||
|
detached_uploads: attachments_schema,
|
||||||
|
});
|
||||||
|
|
|
@ -2,6 +2,7 @@ import $ from "jquery";
|
||||||
import type {z} from "zod";
|
import type {z} from "zod";
|
||||||
|
|
||||||
import render_confirm_delete_attachment from "../templates/confirm_dialog/confirm_delete_attachment.hbs";
|
import render_confirm_delete_attachment from "../templates/confirm_dialog/confirm_delete_attachment.hbs";
|
||||||
|
import render_confirm_delete_detached_attachments_modal from "../templates/confirm_dialog/confirm_delete_detached_attachments.hbs";
|
||||||
import render_settings_upload_space_stats from "../templates/settings/upload_space_stats.hbs";
|
import render_settings_upload_space_stats from "../templates/settings/upload_space_stats.hbs";
|
||||||
import render_uploaded_files_list from "../templates/settings/uploaded_files_list.hbs";
|
import render_uploaded_files_list from "../templates/settings/uploaded_files_list.hbs";
|
||||||
|
|
||||||
|
@ -205,3 +206,58 @@ export function set_up_attachments(): void {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function suggest_delete_detached_attachments(attachments_list: ServerAttachment[]): void {
|
||||||
|
const html_body = render_confirm_delete_detached_attachments_modal({
|
||||||
|
attachments_list,
|
||||||
|
realm_allow_edit_history: realm.realm_allow_edit_history,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Since we want to delete multiple attachments, we want to be
|
||||||
|
// able to keep track of attachments to delete and which ones to
|
||||||
|
// retry if it fails.
|
||||||
|
const attachments_map = new Map<number, ServerAttachment>();
|
||||||
|
for (const attachment of attachments_list) {
|
||||||
|
attachments_map.set(attachment.id, attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_delete_attachments(): void {
|
||||||
|
dialog_widget.show_dialog_spinner();
|
||||||
|
for (const [key, attachment] of attachments_map.entries()) {
|
||||||
|
const id = Number(key);
|
||||||
|
void channel.del({
|
||||||
|
url: "/json/attachments/" + attachment.id,
|
||||||
|
success() {
|
||||||
|
attachments_map.delete(id);
|
||||||
|
if (attachments_map.size === 0) {
|
||||||
|
dialog_widget.hide_dialog_spinner();
|
||||||
|
dialog_widget.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error() {
|
||||||
|
dialog_widget.hide_dialog_spinner();
|
||||||
|
ui_report.error(
|
||||||
|
$t_html({defaultMessage: "One or more files could not be deleted."}),
|
||||||
|
undefined,
|
||||||
|
$("#dialog_error"),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// This is to open "Manage uploaded files" link.
|
||||||
|
$("#confirm_delete_attachments_modal .uploaded_files_settings_link").on("click", (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
dialog_widget.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog_widget.launch({
|
||||||
|
id: "confirm_delete_attachments_modal",
|
||||||
|
html_heading: $t_html({defaultMessage: "Delete uploaded files?"}),
|
||||||
|
html_body,
|
||||||
|
html_submit_button: $t_html({defaultMessage: "Delete"}),
|
||||||
|
html_exit_button: $t_html({defaultMessage: "Don't delete"}),
|
||||||
|
loading_spinner: true,
|
||||||
|
on_click: do_delete_attachments,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import render_message_moved_widget_body from "../templates/message_moved_widget_
|
||||||
import render_resolve_topic_time_limit_error_modal from "../templates/resolve_topic_time_limit_error_modal.hbs";
|
import render_resolve_topic_time_limit_error_modal from "../templates/resolve_topic_time_limit_error_modal.hbs";
|
||||||
import render_topic_edit_form from "../templates/topic_edit_form.hbs";
|
import render_topic_edit_form from "../templates/topic_edit_form.hbs";
|
||||||
|
|
||||||
|
import {detached_uploads_api_response_schema} from "./attachments";
|
||||||
|
import * as attachments_ui from "./attachments_ui";
|
||||||
import * as blueslip from "./blueslip";
|
import * as blueslip from "./blueslip";
|
||||||
import * as channel from "./channel";
|
import * as channel from "./channel";
|
||||||
import * as compose_actions from "./compose_actions";
|
import * as compose_actions from "./compose_actions";
|
||||||
|
@ -1093,11 +1095,12 @@ export function save_message_row_edit($row: JQuery): void {
|
||||||
void channel.patch({
|
void channel.patch({
|
||||||
url: "/json/messages/" + message.id,
|
url: "/json/messages/" + message.id,
|
||||||
data: request,
|
data: request,
|
||||||
success() {
|
success(res) {
|
||||||
if (edit_locally_echoed) {
|
if (edit_locally_echoed) {
|
||||||
delete message.local_edit_timestamp;
|
delete message.local_edit_timestamp;
|
||||||
currently_echoing_messages.delete(message_id);
|
currently_echoing_messages.delete(message_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ordinarily, in a code path like this, we'd make
|
// Ordinarily, in a code path like this, we'd make
|
||||||
// a call to `hide_message_edit_spinner()`. But in
|
// a call to `hide_message_edit_spinner()`. But in
|
||||||
// this instance, we want to avoid a momentary flash
|
// this instance, we want to avoid a momentary flash
|
||||||
|
@ -1105,6 +1108,11 @@ export function save_message_row_edit($row: JQuery): void {
|
||||||
// re-renders. Note that any subsequent editing will
|
// re-renders. Note that any subsequent editing will
|
||||||
// create a fresh Save button, without the spinner
|
// create a fresh Save button, without the spinner
|
||||||
// class attached.
|
// class attached.
|
||||||
|
|
||||||
|
const {detached_uploads} = detached_uploads_api_response_schema.parse(res);
|
||||||
|
if (detached_uploads.length) {
|
||||||
|
attachments_ui.suggest_delete_detached_attachments(detached_uploads);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error(xhr) {
|
error(xhr) {
|
||||||
if (msg_list === message_lists.current) {
|
if (msg_list === message_lists.current) {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<div>
|
||||||
|
{{#if realm_allow_edit_history}}
|
||||||
|
{{#tr}}
|
||||||
|
The following <z-link>uploaded files</z-link> are no longer attached to any messages. They can still be accessed from this message's edit history. Would you like to delete them entirely?
|
||||||
|
{{#*inline "z-link"}}<a class="uploaded_files_settings_link" href="/#settings/uploaded-files">{{> @partial-block}}</a>{{/inline}}
|
||||||
|
{{/tr}}
|
||||||
|
{{else}}
|
||||||
|
{{#tr}}
|
||||||
|
The following <z-link>uploaded files</z-link> are no longer attached to any messages. Would you like to delete them entirely?
|
||||||
|
{{#*inline "z-link"}}<a class="uploaded_files_settings_link" href="/#settings/uploaded-files">{{> @partial-block}}</a>{{/inline}}
|
||||||
|
{{/tr}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
{{#each attachments_list}}
|
||||||
|
<li>
|
||||||
|
<a href="/user_uploads/{{this.path_id}}" rel="noopener noreferrer" target="_blank">{{this.name}}</a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</p>
|
Loading…
Reference in New Issue