Merge pull request #37524 from TITANiumRox/dialog-primary-button-spinner

This commit is contained in:
Suraj Shetty 2026-02-26 15:08:47 +05:30 committed by GitHub
commit 6e974833f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 76 additions and 59 deletions

View file

@ -211,8 +211,7 @@ frappe.ui.form.on("Communication", {
],
primary_action_label: __("Move"),
primary_action(values) {
d.hide();
frappe.call({
return frappe.call({
method: "frappe.email.inbox.move_email",
args: {
communication: frm.doc.name,
@ -220,6 +219,7 @@ frappe.ui.form.on("Communication", {
},
freeze: true,
callback: function () {
d.hide();
window.history.back();
},
});

View file

@ -103,7 +103,7 @@ frappe.listview_settings["DocType"] = {
primary_action_label: __("Create & Continue"),
primary_action(values) {
if (!values.istable) values.editable_grid = 0;
frappe.db
return frappe.db
.insert({
doctype: "DocType",
...values,

View file

@ -201,18 +201,19 @@ frappe.ui.form.on("User", {
},
],
primary_action: (values) => {
d.hide();
if (values.new_password !== values.confirm_password) {
frappe.throw(__("Passwords do not match!"));
}
frappe.call(
"frappe.integrations.doctype.ldap_settings.ldap_settings.reset_password",
{
user: frm.doc.email,
password: values.new_password,
logout: values.logout_sessions,
}
);
return frappe
.call(
"frappe.integrations.doctype.ldap_settings.ldap_settings.reset_password",
{
user: frm.doc.email,
password: values.new_password,
logout: values.logout_sessions,
}
)
.then(() => d.hide());
},
});
d.show();

View file

@ -25,7 +25,7 @@ frappe.query_reports["Database Storage Usage By Tables"] = {
size: "small",
primary_action_label: "Optimize",
primary_action(values) {
frappe.call({
return frappe.call({
method: "frappe.core.report.database_storage_usage_by_tables.database_storage_usage_by_tables.optimize_doctype",
args: {
doctype_name: values.doctype_name,
@ -38,9 +38,9 @@ frappe.query_reports["Database Storage Usage By Tables"] = {
)
);
}
d.hide();
},
});
d.hide();
},
});
d.show();

View file

@ -514,22 +514,7 @@ function check_restrictions(file) {
return is_correct_type && valid_file_size;
}
function set_loading_state(dialog, loading) {
let $btn = dialog?.get_primary_btn();
if (loading) {
$btn?.css("width", $btn.outerWidth());
$btn?.html(`<i class="fa fa-spinner fa-spin"></i>`);
$btn?.prop("disabled", true);
dialog?.get_secondary_btn().prop("disabled", true);
} else {
$btn?.css("width", "");
$btn?.html(__("Upload"));
$btn?.prop("disabled", false);
dialog?.get_secondary_btn().prop("disabled", false);
}
}
function upload_files(dialog) {
set_loading_state(dialog, true);
function upload_files() {
if (show_file_browser.value) {
promise = upload_via_file_browser();
} else if (show_web_link.value) {
@ -542,7 +527,7 @@ function upload_files(dialog) {
} else {
promise = frappe.run_serially(files.value.map((file, i) => () => upload_file(file, i)));
}
return promise.finally(() => set_loading_state(dialog, false));
return promise;
}
function upload_via_file_browser() {
let selected_file = file_browser.value.selected_node;

View file

@ -151,6 +151,7 @@ class FileUploader {
const dialog_opts = {
title: title || __("Upload"),
primary_action_label: __("Upload"),
primary_action_loading_label: __("Uploading"),
primary_action: () => this.upload_files(),
on_page_show: () => {
this.uploader.wrapper_ready = true;

View file

@ -48,8 +48,7 @@ export class ReminderManager {
],
primary_action_label: __("Create"),
primary_action: () => {
this.create_reminder();
this.dialog.hide();
return this.create_reminder().then(() => this.dialog.hide());
},
secondary_action_label: __("Cancel"),
secondary_action: () => {
@ -84,7 +83,7 @@ export class ReminderManager {
}
create_reminder() {
frappe
return frappe
.xcall("frappe.automation.doctype.reminder.reminder.create_new_reminder", {
remind_at: this.dialog.get_value("remind_at"),
description: this.dialog.get_value("description"),

View file

@ -114,9 +114,7 @@ frappe.ui.form.AssignToDialog = class AssignToDialog {
let args = me.dialog.get_values();
if (args && args.assign_to) {
me.dialog.set_message("Assigning...");
frappe.call({
return frappe.call({
method: me.method,
args: $.extend(args, {
doctype: me.doctype,
@ -125,15 +123,12 @@ frappe.ui.form.AssignToDialog = class AssignToDialog {
bulk_assign: me.bulk_assign || false,
re_assign: me.re_assign || false,
}),
btn: me.dialog.get_primary_btn(),
callback: function (r) {
if (!r.exc) {
if (me.callback) {
me.callback(r);
}
me.dialog && me.dialog.hide();
} else {
me.dialog.clear_message();
}
},
});

View file

@ -452,9 +452,7 @@ export default class BulkOperations {
primary_action: () => {
let args = dialog.get_values();
if (args && args.tags) {
dialog.set_message("Adding Tags...");
frappe.call({
return frappe.call({
method: "frappe.desk.doctype.tag.tag.add_tags",
args: {
tags: args.tags,

View file

@ -120,7 +120,7 @@ export default class ListFilter {
fields: fields,
primary_action_label: __("Create"),
primary_action: (values) => {
this.bind_save_filter(dialog, values.filter_name, values?.is_global);
return this.bind_save_filter(dialog, values.filter_name, values?.is_global);
},
});
dialog.show();
@ -138,7 +138,7 @@ export default class ListFilter {
dialog.fields_dict.filter_name.set_description(__("Duplicate Filter Name"));
return;
}
this.save_filter(value, is_global).then(() => {
return this.save_filter(value, is_global).then(() => {
this.refresh_list_filter();
dialog.hide();
});

View file

@ -48,9 +48,6 @@ frappe.ui.AddressAutocompleteDialog = class AddressAutocompleteDialog {
],
primary_action_label: __("Create Address"),
primary_action: () => {
// Insert the address into the database
dialog.hide();
const address = this.parse_selected_value();
address["doctype"] = "Address";
address["links"] = [
@ -59,7 +56,8 @@ frappe.ui.AddressAutocompleteDialog = class AddressAutocompleteDialog {
link_name: this.link_name,
},
];
frappe.db.insert(address).then((doc) => {
return frappe.db.insert(address).then((doc) => {
dialog.hide();
this.after_insert && this.after_insert(doc);
});
},

View file

@ -207,6 +207,7 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup {
this.has_primary_action = true;
var me = this;
const primary_btn = this.get_primary_btn().removeClass("hide").html(label);
const spinner = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" style="width: 13px; height: 13px; animation: spin 1s linear infinite;"><circle opacity=".25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/><path opacity=".25" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/></svg>`;
if (typeof click == "function") {
primary_btn.off("click").on("click", function () {
me.primary_action_fulfilled = true;
@ -215,7 +216,35 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup {
// if no values then return
var values = me.get_values();
if (!values) return;
click && click.apply(me, [values]);
const action = click.apply(me, [values]);
if (action && typeof action.then === "function") {
const loading_label = me.primary_action_loading_label;
primary_btn
.css({
"min-width": primary_btn.outerWidth(),
"min-height": primary_btn.outerHeight(),
})
.prop("disabled", true)
.addClass("btn-primary-dark")
.html(
`<div class="d-flex align-items-center justify-content-center" style="gap: 0.45rem;">
${spinner}
${
loading_label
? `<span class="text-muted" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">${loading_label}</span>`
: ""
}
</div>`
);
Promise.resolve(action).finally(() => {
primary_btn
.css({ "min-width": "", "min-height": "" })
.prop("disabled", false)
.removeClass("btn-primary-dark")
.html(label);
});
}
});
}
return primary_btn;

View file

@ -206,7 +206,7 @@ frappe.msgprint = function (msg, title, is_minimizable, re_route) {
typeof data.primary_action.server_action === "string"
) {
data.primary_action.action = () => {
frappe.call({
return frappe.call({
method: data.primary_action.server_action,
args: data.primary_action.args,
callback() {

View file

@ -264,7 +264,7 @@ frappe.dashboard_utils = {
primary_action: (values) => {
values.name = docname;
values.set_standard = frappe.boot.developer_mode;
frappe.xcall(method, { args: values }).then(() => {
return frappe.xcall(method, { args: values }).then(() => {
let dashboard_route_html = `<a href = "/desk/dashboard/${values.dashboard}">${values.dashboard}</a>`;
let message = __("{0} {1} added to Dashboard {2}", [
doctype,
@ -273,9 +273,8 @@ frappe.dashboard_utils = {
]);
frappe.msgprint(message);
dialog.hide();
});
dialog.hide();
},
});

View file

@ -449,7 +449,7 @@ frappe.views.DashboardView = class DashboardView extends frappe.views.ListView {
: chart.chart_type;
chart.document_type = this.doctype;
chart.filters_json = "[]";
frappe
return frappe
.xcall(
"frappe.desk.doctype.dashboard_chart.dashboard_chart.create_dashboard_chart",
{ args: chart }
@ -460,6 +460,7 @@ frappe.views.DashboardView = class DashboardView extends frappe.views.ListView {
name: doc.chart_name,
label: chart.label,
});
dialog.hide();
});
} else {
this.chart_group.new_widget.on_create({
@ -467,8 +468,8 @@ frappe.views.DashboardView = class DashboardView extends frappe.views.ListView {
label: __(chart.chart),
name: chart.chart,
});
dialog.hide();
}
dialog.hide();
},
});
dialog.show();

View file

@ -17,7 +17,7 @@ frappe.views.InteractionComposer = class InteractionComposer {
fields: me.get_fields(),
primary_action_label: __("Create"),
primary_action: function () {
me.create_action();
return me.create_action();
},
});

View file

@ -2109,7 +2109,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
},
],
primary_action: (values) => {
frappe.call({
return frappe.call({
method: "frappe.desk.query_report.save_report",
args: {
reference_report: this.report_name,

View file

@ -2,6 +2,12 @@ h5.modal-title {
margin: 0px !important;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
// Hack to fix incorrect padding applied by Bootstrap
body.modal-open[style^="padding-right"] {
padding-right: 12px !important;
@ -103,6 +109,11 @@ body.modal-open[style^="padding-right"] {
button:not(:last-child) {
margin-right: var(--margin-xs);
}
.btn-primary-dark {
min-width: 80px;
max-width: 200px;
}
}
& > * {

View file

@ -31,7 +31,7 @@ frappe.ui.form.on("Website Slideshow", {
],
primary_action_label: __("Add to table"),
primary_action: ({ reference_doctype, reference_name }) => {
frappe.db
return frappe.db
.get_list("File", {
fields: ["file_url"],
filters: {