Frappe Date controls, finalize progress bar, full message_log clear
Three UX fixes for the post-setup experience:
1. Native Frappe Date pickers on the company step
Replaces <input type="date"> for fy_start/fy_end with
frappe.ui.form.make_control({fieldtype:"Date"}). Same Flatpickr-
styled control the rest of the desk uses. Values come back as
YYYY-MM-DD via get_value(), matching the previous .val() contract.
2. Inline progress bar instead of the freeze overlay
finalize() now renders a status line + animated bar in place of
the wizard form, and drops freeze:true so the bar is visible.
Subscribes to the realtime "setup_task" channel that
process_setup_stages publishes — translates the [done, total]
tuples into a 5%→95% bar fill, finishes at 100% on success, and
handles the realtime "fail" case by switching to the error view.
3. Wipe all setup-time messages, not just alerts
_drop_alert_messages → frappe.clear_messages(). The old filter
missed non-alert msgprints, so HRMS Salary Component "Hesablar
təyin edilməyib" warnings and Frappe's "Employee Self Service rolu
silindi" note for the new admin user still surfaced as a modal.
Genuine failures raise; everything queued for the response by this
point is just noise for an automated run.
This commit is contained in:
parent
7a9c25ba35
commit
40f65ffd90
|
|
@ -1 +1 @@
|
|||
__version__ = "0.1.15"
|
||||
__version__ = "0.1.16"
|
||||
|
|
|
|||
|
|
@ -1103,24 +1103,22 @@ def _find_default_warehouse(company):
|
|||
|
||||
|
||||
def _drop_alert_messages():
|
||||
"""Remove every entry from frappe.local.message_log that was queued via
|
||||
frappe.msgprint(alert=True) (a.k.a. toast). Keeps non-alert msgprints so
|
||||
the user still sees real warnings.
|
||||
"""Wipe everything in frappe.local.message_log that piled up during the
|
||||
setup_complete request. We need the entire log gone, not just alerts:
|
||||
besides the az_locale rename toasts (alert=True), HRMS Salary Component
|
||||
warnings ("Hesablar təyin edilməyib") and Frappe's own user-creation
|
||||
notes ("Employee Self Service rolu silindi") come through plain
|
||||
msgprints — and they're noise for an automated setup. Genuine failures
|
||||
would have raised an exception and been handled separately, so blanket
|
||||
clearing is safe here.
|
||||
"""
|
||||
try:
|
||||
log = list(getattr(frappe.local, "message_log", []) or [])
|
||||
frappe.clear_messages()
|
||||
except Exception:
|
||||
return
|
||||
if not log:
|
||||
return
|
||||
def _is_alert(m):
|
||||
try:
|
||||
if isinstance(m, dict):
|
||||
return bool(m.get("alert"))
|
||||
return bool(getattr(m, "alert", 0))
|
||||
frappe.local.message_log = []
|
||||
except Exception:
|
||||
return False
|
||||
frappe.local.message_log = [m for m in log if not _is_alert(m)]
|
||||
pass
|
||||
|
||||
|
||||
def _only_admin():
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ frappe.provide("jey_wizard");
|
|||
// Bump this string in every commit that changes wizard code. Displayed in the badge so
|
||||
// we can tell at a glance which version is actually running on a given machine. Kept in
|
||||
// sync with __version__ in jey_wizard/__init__.py.
|
||||
const JEY_WIZARD_VERSION = "0.1.15";
|
||||
const JEY_WIZARD_VERSION = "0.1.16";
|
||||
|
||||
// Wipe Frappe + ERPNext default slides so their `before_load`/`after_load` listeners
|
||||
// don't try to mutate a wizard that isn't slide-based anymore.
|
||||
|
|
@ -415,11 +415,11 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
<div style="display:flex;gap:16px;max-width:420px">
|
||||
<div style="flex:1">
|
||||
<label style="display:block;margin-bottom:4px">${__("Start date")}</label>
|
||||
<input type="date" class="jey-fy-start form-control" />
|
||||
<div class="jey-fy-start"></div>
|
||||
</div>
|
||||
<div style="flex:1">
|
||||
<label style="display:block;margin-bottom:4px">${__("End date")}</label>
|
||||
<input type="date" class="jey-fy-end form-control" />
|
||||
<div class="jey-fy-end"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="color:#888;font-size:12px;margin-top:6px">${__("Default: current calendar year (Jan 1 – Dec 31).")}</div>
|
||||
|
|
@ -443,8 +443,25 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
</div>
|
||||
`);
|
||||
$body.find(".jey-company-name").val(this.data.company_name);
|
||||
$body.find(".jey-fy-start").val(this.data.fy_start_date);
|
||||
$body.find(".jey-fy-end").val(this.data.fy_end_date);
|
||||
|
||||
// Mount native Frappe Date controls (Flatpickr-styled) into the
|
||||
// jey-fy-start / jey-fy-end placeholders. Plain <input type="date">
|
||||
// looks dated and inconsistent with the rest of Frappe's UI. The
|
||||
// controls expose set_value / get_value; we wire those into the
|
||||
// usual data dict.
|
||||
this.fy_start_ctrl = frappe.ui.form.make_control({
|
||||
df: { fieldtype: "Date", fieldname: "fy_start_date", placeholder: "" },
|
||||
parent: $body.find(".jey-fy-start")[0],
|
||||
render_input: true,
|
||||
});
|
||||
this.fy_start_ctrl.set_value(this.data.fy_start_date || "");
|
||||
this.fy_end_ctrl = frappe.ui.form.make_control({
|
||||
df: { fieldtype: "Date", fieldname: "fy_end_date", placeholder: "" },
|
||||
parent: $body.find(".jey-fy-end")[0],
|
||||
render_input: true,
|
||||
});
|
||||
this.fy_end_ctrl.set_value(this.data.fy_end_date || "");
|
||||
|
||||
$body.find(".jey-valuation-method").val(this.data.valuation_method || "FIFO");
|
||||
$body.find(".jey-accounting-method").val(this.data.accounting_method || "Hesablama metodu");
|
||||
// Show why the default landed where it did, only when the auto-pick
|
||||
|
|
@ -676,8 +693,10 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
return false;
|
||||
}
|
||||
this.data.company_abbr = abbr;
|
||||
const fyStart = (this.$wrap.find(".jey-fy-start").val() || "").trim();
|
||||
const fyEnd = (this.$wrap.find(".jey-fy-end").val() || "").trim();
|
||||
// Frappe Date controls return the value as YYYY-MM-DD or "" when
|
||||
// blank. Mirrors the previous .val() contract on <input type="date">.
|
||||
const fyStart = String((this.fy_start_ctrl && this.fy_start_ctrl.get_value()) || "").trim();
|
||||
const fyEnd = String((this.fy_end_ctrl && this.fy_end_ctrl.get_value()) || "").trim();
|
||||
if (!fyStart || !fyEnd) {
|
||||
this.$wrap.find(".jey-status").text(__("Fiscal year start and end dates are required"));
|
||||
return false;
|
||||
|
|
@ -1322,35 +1341,75 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
}
|
||||
|
||||
finalize() {
|
||||
this.$wrap.find(".jey-body").html(
|
||||
`<p>${__("Setting up your system. This can take a minute...")}</p>`
|
||||
);
|
||||
// Render an inline progress UI in place of the wizard form. We don't
|
||||
// pass freeze:true to frappe.call — the freeze overlay would dim and
|
||||
// hide the bar. process_setup_stages publishes realtime "setup_task"
|
||||
// events with {progress: [idx, total], stage_status: "..."}; we
|
||||
// subscribe and translate those into bar width + status text.
|
||||
this.$wrap.find(".jey-body").html(`
|
||||
<h3 style="margin-bottom:12px">${__("Setting up your system")}</h3>
|
||||
<div class="jey-finalize-status" style="color:#666;margin-bottom:12px;min-height:1.4em">${__("Starting...")}</div>
|
||||
<div style="background:#eee;border-radius:6px;height:12px;overflow:hidden">
|
||||
<div class="jey-finalize-bar" style="background:#3b82f6;height:100%;width:5%;transition:width 0.4s ease"></div>
|
||||
</div>
|
||||
<div class="jey-finalize-pct" style="color:#888;font-size:12px;margin-top:6px;text-align:right">5%</div>
|
||||
`);
|
||||
this.$wrap.find(".jey-nav").empty();
|
||||
this.$wrap.find(".jey-status").empty();
|
||||
|
||||
const setProgress = (pct, status) => {
|
||||
pct = Math.max(0, Math.min(100, Math.round(pct)));
|
||||
this.$wrap.find(".jey-finalize-bar").css("width", pct + "%");
|
||||
this.$wrap.find(".jey-finalize-pct").text(pct + "%");
|
||||
if (status) this.$wrap.find(".jey-finalize-status").text(status);
|
||||
};
|
||||
|
||||
// Realtime subscription. Each "setup_task" event carries either a
|
||||
// progress tuple or a final status. Cap displayed pct at 95% during
|
||||
// the run so the bar visibly completes when the HTTP response lands.
|
||||
const onSetupTask = (data) => {
|
||||
if (!data) return;
|
||||
if (Array.isArray(data.progress)) {
|
||||
const [done, total] = data.progress;
|
||||
if (total > 0) {
|
||||
const ratio = Math.min(done / total, 0.95);
|
||||
setProgress(5 + ratio * 90, data.stage_status || __("Working..."));
|
||||
}
|
||||
}
|
||||
if (data.status === "fail") {
|
||||
this.show_error(
|
||||
data.fail_msg || __("Setup failed"),
|
||||
data.exc || data.exception || __("(check server logs)")
|
||||
);
|
||||
}
|
||||
};
|
||||
frappe.realtime.on("setup_task", onSetupTask);
|
||||
const cleanup = () => frappe.realtime.off("setup_task", onSetupTask);
|
||||
|
||||
const values = this.build_setup_args();
|
||||
|
||||
frappe.call({
|
||||
method: "frappe.desk.page.setup_wizard.setup_wizard.setup_complete",
|
||||
args: { args: values },
|
||||
freeze: true,
|
||||
callback: (r) => {
|
||||
const m = r.message || {};
|
||||
if (m.status === "ok") {
|
||||
this.$wrap.find(".jey-body").html(
|
||||
`<p>${__("Setup complete! Redirecting...")}</p>`
|
||||
);
|
||||
setProgress(100, __("Setup complete! Redirecting..."));
|
||||
cleanup();
|
||||
setTimeout(() => {
|
||||
window.location.href = "/app";
|
||||
}, 1500);
|
||||
}, 800);
|
||||
} else if (m.status === "registered") {
|
||||
cleanup();
|
||||
this.show_error(
|
||||
__("Setup is running in background mode, not supported by skeleton"),
|
||||
JSON.stringify(m, null, 2)
|
||||
);
|
||||
} else if (m.fail !== undefined) {
|
||||
cleanup();
|
||||
this.show_error(m.fail, JSON.stringify(m, null, 2));
|
||||
} else {
|
||||
cleanup();
|
||||
this.show_error(
|
||||
__("Setup returned unexpected response"),
|
||||
JSON.stringify(m, null, 2)
|
||||
|
|
@ -1358,6 +1417,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
}
|
||||
},
|
||||
error: () => {
|
||||
cleanup();
|
||||
const resp = frappe.last_response || {};
|
||||
this.show_error(
|
||||
resp.setup_wizard_failure_message || __("Setup failed"),
|
||||
|
|
|
|||
Loading…
Reference in New Issue