From afed0c93747365dcd01ca468408cf73869b56ad7 Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Mon, 3 Jul 2017 18:15:40 +0530 Subject: [PATCH] Setup wizard refactor (#3548) * [wizard] refactor and UI cleanups * [wip] attach image control cleanup * try and detect lang, country, gravatar * password control * frappe.wiz to frappe.setup * cleaned up slides, yet to decide on master data * Add function to add dynamic fields in layout * [fix] independent slide fields numbering by deep-cloning initial fields * refresh only appended fields, autofill user_details * [wizard] UI test * [wizard] frappe icon, reuse get_geo_ip_country, cleanups --- frappe/build.js | 1 + .../desk/page/setup_wizard/setup_wizard.css | 120 +++- frappe/desk/page/setup_wizard/setup_wizard.js | 531 +++++++++++------- frappe/desk/page/setup_wizard/setup_wizard.py | 18 +- .../page/setup_wizard/setup_wizard_page.html | 12 +- frappe/public/css/form.css | 12 + frappe/public/js/frappe/form/control.js | 90 ++- frappe/public/js/frappe/form/layout.js | 45 +- frappe/public/js/frappe/misc/common.js | 6 +- frappe/public/js/frappe/ui/field_group.js | 6 +- frappe/public/less/form.less | 15 + frappe/tests/ui/setup_wizard.js | 43 ++ 12 files changed, 664 insertions(+), 235 deletions(-) create mode 100644 frappe/tests/ui/setup_wizard.js diff --git a/frappe/build.js b/frappe/build.js index 50e3d7ee8c..be24a6b0cd 100644 --- a/frappe/build.js +++ b/frappe/build.js @@ -272,6 +272,7 @@ function watch_js(ondirty) { if (sources.includes(filename)) { pack(target, sources); ondirty && ondirty(target); + // break; } } }); diff --git a/frappe/desk/page/setup_wizard/setup_wizard.css b/frappe/desk/page/setup_wizard/setup_wizard.css index 55cbd56153..f96c923337 100644 --- a/frappe/desk/page/setup_wizard/setup_wizard.css +++ b/frappe/desk/page/setup_wizard/setup_wizard.css @@ -1,3 +1,22 @@ +.setup-wizard-brand { + margin: 40px; + text-align: center; + display: flex; + justify-content: center; + align-items: center +} + +.setup-wizard-brand .brand-icon { + width: 36px; + height: 36px; +} + +.setup-wizard-brand .brand-name { + font-size: 20px; + margin-left: 8px; + color: #36414C; +} + .setup-wizard-slide { padding-left: 0px; padding-right: 0px; @@ -14,22 +33,67 @@ } .setup-wizard-slide .lead { - margin-bottom: 10px; + margin: 40px; + color: #777777; + text-align: center; + font-size: 30px; +} + +.setup-wizard-slide .col-sm-12 { + padding: 0px; +} + +.setup-wizard-slide .section-body .col-sm-6:first-child { + padding-left: 0px; +} + +.setup-wizard-slide .section-body .col-sm-6:last-child { + padding-right: 0px; +} + +.setup-wizard-slide .form-control { + height: 35px; font-weight: 500; } +.setup-wizard-slide .has-error .control-label { + color: #ffa00a; +} + +.setup-wizard-slide .has-error .form-control{ + border-color: #ffa00a; +} + +.setup-wizard-slide .form-control.bold { + background-color: #fff; +} + .setup-wizard-slide.with-form { margin: 40px auto; + padding: 10px 50px; border: 1px solid #d1d8dd; box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1); } .setup-wizard-slide .footer { - padding: 30px; + padding: 30px 0px; +} + +.setup-wizard-slide a.next-btn, +.setup-wizard-slide a.complete-btn { + font-size: 14px; + padding: 7px 25px; +} + +.setup-wizard-slide a.next-btn.disabled, +.setup-wizard-slide a.complete-btn.disabled { + background-color: #b1bdca; + color: #fff; + border-color: #b1bdca; } .setup-wizard-progress { - padding: 15px; + padding: 15px; } .setup-wizard-slide .fa-fw { @@ -50,16 +114,28 @@ } .setup-wizard-slide .frappe-control[data-fieldtype="Attach Image"] { + width: 140px; + height: 180px; /*depends on presence of heading*/ text-align: center; + margin-left: 33%; +} + +.setup-wizard-slide .frappe-control[data-fieldtype="Attach Image"] .form-group, +.setup-wizard-slide .frappe-control[data-fieldtype="Attach Image"] .clearfix { + display: none; } .setup-wizard-slide .missing-image, .setup-wizard-slide .attach-image-display { display: block; position: relative; - left: 50%; - transform: translate(-50%, 0); - -webkit-transform: translate(-50%, 0); + border-radius: 4px; +} + +.setup-wizard-slide .missing-image { + border: 1px solid #d1d8dd; + border-radius: 6px; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); } .setup-wizard-slide .missing-image .octicon { @@ -69,6 +145,38 @@ -webkit-transform: translate(0px, -50%); } + +.setup-wizard-slide .img-container { + height: 100%; + width: 100%; + padding: 2px; + display: flex; + align-items: center; + justify-content: center; + position: relative; + border: 1px solid #d1d8dd; + border-radius: 6px; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} + +.setup-wizard-slide .img-overlay { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + width: 100%; + height: 100%; + color: #777777; + background-color: rgba(255, 255, 255, 0.7); + opacity: 0; +} + +.setup-wizard-slide .img-overlay:hover { + opacity: 1; + cursor: pointer; +} + + .setup-wizard-message-image { margin: 15px auto; } diff --git a/frappe/desk/page/setup_wizard/setup_wizard.js b/frappe/desk/page/setup_wizard/setup_wizard.js index 28ac0bf48c..a8bc1acc31 100644 --- a/frappe/desk/page/setup_wizard/setup_wizard.js +++ b/frappe/desk/page/setup_wizard/setup_wizard.js @@ -1,22 +1,25 @@ frappe.provide("frappe.wiz"); -frappe.provide("frappe.wiz.events"); +frappe.provide("frappe.setup.events"); -frappe.wiz = { +frappe.setup = { slides: [], events: {}, + data: {}, + utils: {}, + remove_app_slides: [], on: function(event, fn) { - if(!frappe.wiz.events[event]) { - frappe.wiz.events[event] = []; + if(!frappe.setup.events[event]) { + frappe.setup.events[event] = []; } - frappe.wiz.events[event].push(fn); + frappe.setup.events[event].push(fn); }, add_slide: function(slide) { - frappe.wiz.slides.push(slide); + frappe.setup.slides.push(slide); }, run_event: function(event) { - $.each(frappe.wiz.events[event] || [], function(i, fn) { + $.each(frappe.setup.events[event] || [], function(i, fn) { fn(); }); } @@ -25,21 +28,21 @@ frappe.wiz = { frappe.pages['setup-wizard'].on_page_load = function(wrapper) { // setup page ui $(".navbar:first").toggle(false); - $("body").css({"padding-top":"30px"}); var requires = ["/assets/frappe/css/animate.min.css"].concat(frappe.boot.setup_wizard_requires || []); frappe.require(requires, function() { - frappe.wiz.run_event("before_load"); + frappe.setup.run_event("before_load"); + var wizard_settings = { page_name: "setup-wizard", parent: wrapper, - slides: frappe.wiz.slides, + slides: frappe.setup.slides, title: __("Welcome") } - frappe.wizard = new frappe.wiz.Wizard(wizard_settings); - frappe.wiz.run_event("after_load"); + frappe.wizard = new frappe.setup.Wizard(wizard_settings); + frappe.setup.run_event("after_load"); // frappe.wizard.values = test_values_edu; @@ -56,7 +59,7 @@ frappe.pages['setup-wizard'].on_page_show = function(wrapper) { } } -frappe.wiz.Wizard = Class.extend({ +frappe.setup.Wizard = Class.extend({ init: function(opts) { $.extend(this, opts); this.make(); @@ -75,6 +78,7 @@ frappe.wiz.Wizard = Class.extend({ ', {html:html})) }, show_working: function() { + $('header').find('.setup-wizard-brand').hide(); this.hide_current_slide(); frappe.set_route(this.page_name); this.current_slide = {"$wrapper": this.get_message(this.working_html()).appendTo(this.parent)}; @@ -96,7 +100,7 @@ frappe.wiz.Wizard = Class.extend({ this.update_values(); if(!this.slide_dict[id]) { - this.slide_dict[id] = new frappe.wiz.WizardSlide($.extend(this.slides[id], {wiz:this, id:id})); + this.slide_dict[id] = new frappe.setup.WizardSlide($.extend(this.slides[id], {wiz:this, id:id})); this.slide_dict[id].make(); } @@ -147,8 +151,8 @@ frappe.wiz.Wizard = Class.extend({ args: {args: this.values}, callback: function(r) { me.show_complete(); - if(frappe.wiz.welcome_page) { - localStorage.setItem("session_last_route", frappe.wiz.welcome_page); + if(frappe.setup.welcome_page) { + localStorage.setItem("session_last_route", frappe.setup.welcome_page); } setTimeout(function() { window.location = "/desk"; @@ -181,26 +185,27 @@ frappe.wiz.Wizard = Class.extend({ this.update_values(); - frappe.wiz.slides = []; - frappe.wiz.run_event("before_load"); + frappe.setup.slides = []; + frappe.setup.run_event("before_load"); // remove slides listed in remove_app_slides var new_slides = []; - frappe.wiz.slides.forEach(function(slide) { - if(frappe.wiz.domain) { + frappe.setup.slides.forEach(function(slide) { + if(frappe.setup.domain) { var domains = slide.domains; if (domains.indexOf('all') !== -1 || - domains.indexOf(frappe.wiz.domain.toLowerCase()) !== -1) { + domains.indexOf(frappe.setup.domain.toLowerCase()) !== -1) { new_slides.push(slide); } } else { new_slides.push(slide); } }) - frappe.wiz.slides = new_slides; - this.slides = frappe.wiz.slides; - frappe.wiz.run_event("after_load"); + frappe.setup.slides = new_slides; + + this.slides = frappe.setup.slides; + frappe.setup.run_event("after_load"); // re-render all slides this.slide_dict = {}; @@ -213,7 +218,7 @@ frappe.wiz.Wizard = Class.extend({ } }); -frappe.wiz.WizardSlide = Class.extend({ +frappe.setup.WizardSlide = Class.extend({ init: function(opts) { $.extend(this, opts); this.$wrapper = $('') @@ -224,6 +229,17 @@ frappe.wiz.WizardSlide = Class.extend({ var me = this; if(this.$body) this.$body.remove(); + var fields = JSON.parse(JSON.stringify(this.fields)); + + if(this.add_more) { + this.count = 1; + fields = fields.map(field => { + if(field.fieldname) field.fieldname += '_1'; + if(field.label) field.label += ' 1'; + return field; + }); + } + if(this.before_load) { this.before_load(this); } @@ -234,7 +250,6 @@ frappe.wiz.WizardSlide = Class.extend({ main_title:__(this.wiz.title), step: this.id + 1, name: this.name, - css_class: this.css_class || "", slides_count: this.wiz.slides.length })).appendTo(this.$wrapper); @@ -242,7 +257,7 @@ frappe.wiz.WizardSlide = Class.extend({ if(this.fields) { this.form = new frappe.ui.FieldGroup({ - fields: this.fields, + fields: fields, body: this.body, no_submit_on_enter: true }); @@ -251,18 +266,33 @@ frappe.wiz.WizardSlide = Class.extend({ $(this.body).html(this.html); } + this.set_reqd_fields(); this.set_init_values(); this.make_prev_next_buttons(); + if(this.add_more) this.bind_more_button(); + + var $primary_btn = this.$next ? this.$next : this.$complete; + + this.bind_fields_to_next($primary_btn); if(this.onload) { this.onload(this); } + this.reset_next($primary_btn); this.focus_first_input(); - + }, + set_reqd_fields: function() { + var dict = this.form.fields_dict; + this.reqd_fields = []; + Object.keys(dict).map(key => { + if(dict[key].df.reqd) { + this.reqd_fields.push(dict[key]); + } + }); }, set_init_values: function() { var me = this; - // set values from frappe.wiz.values + // set values from frappe.setup.values if(frappe.wizard.values && this.fields) { this.fields.forEach(function(f) { var value = frappe.wizard.values[f.fieldname]; @@ -284,6 +314,23 @@ frappe.wiz.WizardSlide = Class.extend({ return true; }, + bind_more_button: function() { + this.$more = this.$body.find('.more-btn'); + this.$more.removeClass('hide') + .on('click', () => { + this.count++; + var fields = JSON.parse(JSON.stringify(this.fields)); + this.form.add_fields(fields.map(field => { + if(field.fieldname) field.fieldname += '_' + this.count; + if(field.label) field.label += ' ' + this.count; + return field; + })); + if(this.count === this.max_count) { + this.$more.addClass('hide'); + } + }); + }, + make_prev_next_buttons: function() { var me = this; @@ -311,7 +358,7 @@ frappe.wiz.WizardSlide = Class.extend({ .click(this.next_or_complete.bind(this)); } - //setup mousefree navigation + // setup mousefree navigation this.$body.on('keypress', function(e) { if(e.which === 13) { var $target = $(e.target); @@ -326,6 +373,14 @@ frappe.wiz.WizardSlide = Class.extend({ } }); }, + bind_fields_to_next: function($primary_btn) { + var me = this; + this.reqd_fields.map((field) => { + field.$wrapper.on('change input', () => { + me.reset_next($primary_btn); + }); + }); + }, next_or_complete: function() { if(this.set_values()) { if(this.id+1 < this.wiz.slides.length) { @@ -335,6 +390,17 @@ frappe.wiz.WizardSlide = Class.extend({ } } }, + reset_next: function($primary_btn) { + var empty_fields = this.reqd_fields.filter((field) => { + return !field.get_value(); + }) + + if(empty_fields.length) { + $primary_btn.addClass('disabled'); + } else { + $primary_btn.removeClass('disabled'); + } + }, focus_first_input: function() { setTimeout(function() { this.$body.find('.form-control').first().focus(); @@ -360,233 +426,302 @@ frappe.wiz.WizardSlide = Class.extend({ }, }); -function load_frappe_slides() { - // language selection - frappe.wiz.welcome = { +var frappe_slides = [ + { + // Welcome (language) slide name: "welcome", domains: ["all"], - title: __("Welcome"), + title: __("Hello!"), icon: "fa fa-world", help: __("Let's prepare the system for first use."), fields: [ - { fieldname: "language", label: __("Select Your Language"), reqd:1, - fieldtype: "Select", "default": "english" }, + { fieldname: "language", label: __("Your Language"), + fieldtype: "Select", "default": "English" } ], onload: function(slide) { - if (!frappe.wiz.welcome.data) { - frappe.wiz.welcome.load_languages(slide); + if (frappe.setup.data.lang) { + this.setup_fields(slide); } else { - frappe.wiz.welcome.setup_fields(slide); + utils.load_languages(slide, this.setup_fields); } }, - css_class: "single-column", - load_languages: function(slide) { - frappe.call({ - method: "frappe.desk.page.setup_wizard.setup_wizard.load_languages", - freeze: true, - callback: function(r) { - frappe.wiz.welcome.data = r.message; - frappe.wiz.welcome.setup_fields(slide); - - var language_field = slide.get_field("language"); - language_field.set_input(frappe.wiz.welcome.data.default_language || "english"); - - if (!frappe.wiz._from_load_messages) { - language_field.$input.trigger("change"); - } - - delete frappe.wiz._from_load_messages; - - moment.locale("en"); - } - }); - }, - setup_fields: function(slide) { - var select = slide.get_field("language"); - select.df.options = frappe.wiz.welcome.data.languages; - select.refresh(); - frappe.wiz.welcome.bind_events(slide); + utils.setup_language_field(slide); + utils.bind_language_events(slide); }, - - bind_events: function(slide) { - slide.get_input("language").unbind("change").on("change", function() { - var lang = $(this).val() || "english"; - frappe._messages = {}; - frappe.call({ - method: "frappe.desk.page.setup_wizard.setup_wizard.load_messages", - freeze: true, - args: { - language: lang - }, - callback: function(r) { - frappe.wiz._from_load_messages = true; - frappe.wizard.refresh_slides(); - } - }); - }); - } }, - // region selection - frappe.wiz.region = { + { + // Region slide + name: 'region', domains: ["all"], - title: __("Region"), + title: __("Select Your Region"), icon: "fa fa-flag", help: __("Select your Country, Time Zone and Currency"), fields: [ - { fieldname: "country", label: __("Country"), reqd:1, + { fieldname: "country", label: __("Your Country"), reqd:1, fieldtype: "Select" }, + { fieldtype: "Section Break" }, { fieldname: "timezone", label: __("Time Zone"), reqd:1, fieldtype: "Select" }, + { fieldtype: "Column Break" }, { fieldname: "currency", label: __("Currency"), reqd:1, - fieldtype: "Select" }, + fieldtype: "Select" } ], onload: function(slide) { - var _setup = function() { - frappe.wiz.region.setup_fields(slide); - frappe.wiz.region.bind_events(slide); - }; - - if(frappe.wiz.regional_data) { - _setup(); + if(frappe.setup.data.regional_data) { + this.setup_fields(slide); } else { - frappe.call({ - method:"frappe.geo.country_info.get_country_timezone_info", - callback: function(data) { - frappe.wiz.regional_data = data.message; - _setup(); - } - }); + utils.load_regional_data(slide, this.setup_fields); } }, - css_class: "single-column", + setup_fields: function(slide) { - var data = frappe.wiz.regional_data; + utils.setup_region_fields(slide); + utils.bind_region_events(slide); + } + }, - slide.get_input("country").empty() - .add_options([""].concat(Object.keys(data.country_info).sort())); + { + // Profile slide + name: 'user', + domains: ["all"], + title: __("The First User: You"), + icon: "fa fa-user", + fields: [ + { "fieldtype":"Attach Image", "fieldname":"attach_user_image", + label: __("Attach Your Picture"), is_private: 0}, + { "fieldname": "full_name", "label": __("Full Name"), "fieldtype": "Data", + reqd:1}, + { "fieldname": "email", "label": __("Email Address") + ' (' + __("Will be your login ID") + ')', + "fieldtype": "Data", reqd:1, "options":"Email"}, + { "fieldname": "password", "label": __("Password"), "fieldtype": "Password", reqd:1 } + ], + help: __('The first user will become the System Manager (you can change this later).'), + onload: function(slide) { + if(frappe.session.user!=="Administrator") { + // remove password field + delete slide.form.fields_dict.password; + slide.form.fields_dict.email.$wrapper.toggle(false); + if(frappe.boot.user.first_name || frappe.boot.user.last_name) { + slide.form.fields_dict.full_name.set_input( + [frappe.boot.user.first_name, frappe.boot.user.last_name].join(' ').trim()); + } - slide.get_input("currency").empty() - .add_options(frappe.utils.unique([""].concat($.map(data.country_info, - function(opts, country) { return opts.currency; }))).sort()); + var user_image = frappe.get_cookie("user_image"); + var $attach_user_image = slide.form.fields_dict.attach_user_image.$wrapper; - slide.get_input("timezone").empty() - .add_options([""].concat(data.all_timezones)); + if(user_image) { + $attach_user_image.find(".missing-image").toggle(false); + $attach_user_image.find("img").attr("src", decodeURIComponent(user_image)).toggle(true); + } + delete slide.form.fields_dict.email; - // set values if present - if(frappe.wizard.values.country) { - slide.get_field("country").set_input(frappe.wizard.values.country); - } else if (data.default_country) { - slide.get_field("country").set_input(data.default_country); + } else { + utils.load_user_details(slide, this.setup_fields); } + }, - if(frappe.wizard.values.currency) { - slide.get_field("currency").set_input(frappe.wizard.values.currency); + setup_fields: function(slide) { + if(frappe.setup.data.full_name) { + slide.form.fields_dict.full_name.set_input(frappe.setup.data.full_name); } - - if(frappe.wizard.values.timezone) { - slide.get_field("timezone").set_input(frappe.wizard.values.timezone); + if(frappe.setup.data.email) { + let email = frappe.setup.data.email; + slide.form.fields_dict.email.set_input(email); + if (frappe.get_gravatar(email, 200)) { + var $attach_user_image = slide.form.fields_dict.attach_user_image.$wrapper; + $attach_user_image.find(".missing-image").toggle(false); + $attach_user_image.find("img").attr("src", frappe.get_gravatar(email, 200)); + $attach_user_image.find(".img-container").toggle(true); + } } - }, + }, +]; - bind_events: function(slide) { - slide.get_input("country").on("change", function() { - var country = slide.get_input("country").val(); - var $timezone = slide.get_input("timezone"); - var data = frappe.wiz.regional_data; +var utils = { + load_languages: function(slide, callback) { + frappe.call({ + method: "frappe.desk.page.setup_wizard.setup_wizard.load_languages", + freeze: true, + callback: function(r) { + frappe.setup.data.lang = r.message; + callback(slide); - $timezone.empty(); + var language_field = slide.get_field("language"); - // add country specific timezones first - if(country) { - var timezone_list = data.country_info[country].timezones || []; - $timezone.add_options(timezone_list.sort()); - slide.get_field("currency").set_input(data.country_info[country].currency); - slide.get_field("currency").$input.trigger("change"); + language_field.set_input(frappe.setup.data.default_language || "English"); + + if (!frappe.setup._from_load_messages) { + language_field.$input.trigger("change"); } + delete frappe.setup._from_load_messages; + moment.locale("en"); + } + }); + }, + + load_regional_data: function(slide, callback) { + frappe.call({ + method:"frappe.geo.country_info.get_country_timezone_info", + callback: function(data) { + frappe.setup.data.regional_data = data.message; + callback(slide); + } + }); + }, - // add all timezones at the end, so that user has the option to change it to any timezone - $timezone.add_options([""].concat(data.all_timezones)); + load_user_details: function(slide, callback) { + frappe.call({ + method: "frappe.desk.page.setup_wizard.setup_wizard.load_user_details", + freeze: true, + callback: function(r) { + frappe.setup.data.full_name = r.message.full_name; + frappe.setup.data.email = r.message.email; + callback(slide); + } + }) + }, - slide.get_field("timezone").set_input($timezone.val()); + setup_language_field: function(slide) { + var language_field = slide.get_field("language"); + language_field.df.options = frappe.setup.data.lang.languages; + language_field.refresh(); + }, - // temporarily set date format - frappe.boot.sysdefaults.date_format = (data.country_info[country].date_format - || "dd-mm-yyyy"); - }); + setup_region_fields: function(slide) { + /* + Set a slide's country, timezone and currency fields + */ + var data = frappe.setup.data.regional_data; - slide.get_input("currency").on("change", function() { - var currency = slide.get_input("currency").val(); - if (!currency) return; - frappe.model.with_doc("Currency", currency, function() { - frappe.provide("locals.:Currency." + currency); - var currency_doc = frappe.model.get_doc("Currency", currency); - var number_format = currency_doc.number_format; - if (number_format==="#.###") { - number_format = "#.###,##"; - } else if (number_format==="#,###") { - number_format = "#,###.##" - } - - frappe.boot.sysdefaults.number_format = number_format; - locals[":Currency"][currency] = $.extend({}, currency_doc); - }); - }); + var country_field = slide.get_field('country'); + + slide.get_input("country").empty() + .add_options([""].concat(Object.keys(data.country_info).sort())); + + slide.get_input("currency").empty() + .add_options(frappe.utils.unique([""].concat($.map(data.country_info, + function(opts, country) { return opts.currency; }))).sort()); + + slide.get_input("timezone").empty() + .add_options([""].concat(data.all_timezones)); + + // set values if present + if(frappe.wizard.values.country) { + country_field.set_input(frappe.wizard.values.country); + } else if (data.default_country) { + country_field.set_input(data.default_country); } - }, + if(frappe.wizard.values.currency) { + slide.get_field("currency").set_input(frappe.wizard.values.currency); + } - frappe.wiz.user = { - domains: ["all"], - title: __("The First User: You"), - icon: "fa fa-user", - fields: [ - {"fieldname": "full_name", "label": __("Full Name"), "fieldtype": "Data", - reqd:1}, - {"fieldname": "email", "label": __("Email Address"), "fieldtype": "Data", - reqd:1, "description": __("Login id"), "options":"Email"}, - {"fieldname": "password", "label": __("Password"), "fieldtype": "Password", - reqd:1}, - {fieldtype:"Attach Image", fieldname:"attach_user", - label: __("Attach Your Picture"), is_private: 0}, - ], - help: __('The first user will become the System Manager (you can change this later).'), - onload: function(slide) { - if(frappe.session.user!=="Administrator") { - slide.form.fields_dict.password.$wrapper.toggle(false); - slide.form.fields_dict.email.$wrapper.toggle(false); - if(frappe.boot.user.first_name || frappe.boot.user.last_name) { - slide.form.fields_dict.full_name.set_input( - [frappe.boot.user.first_name, frappe.boot.user.last_name].join(' ').trim()); + if(frappe.wizard.values.timezone) { + slide.get_field("timezone").set_input(frappe.wizard.values.timezone); + } + + country_field.df.description = 'fetching country...'; + country_field.set_description(); + + // get location from IP (unreliable) + frappe.call({ + method:"frappe.desk.page.setup_wizard.setup_wizard.load_country", + callback: function(r) { + if(r.message) { + slide.get_field("country").set_input(r.message); + slide.get_input("country").trigger('change'); } + country_field.df.description = ''; + country_field.set_description(); + } + }); + }, - var user_image = frappe.get_cookie("user_image"); - if(user_image) { - var $attach_user = slide.form.fields_dict.attach_user.$wrapper; - $attach_user.find(".missing-image").toggle(false); - $attach_user.find("img").attr("src", decodeURIComponent(user_image)).toggle(true); + bind_language_events: function(slide) { + slide.get_input("language").unbind("change").on("change", function() { + var lang = $(this).val() || "English"; + frappe._messages = {}; + frappe.call({ + method: "frappe.desk.page.setup_wizard.setup_wizard.load_messages", + freeze: true, + args: { + language: lang + }, + callback: function(r) { + frappe.setup._from_load_messages = true; + frappe.wizard.refresh_slides(); } + }); + }); + }, - delete slide.form.fields_dict.email; - delete slide.form.fields_dict.password; + bind_region_events: function(slide) { + /* + Bind a slide's country, timezone and currency fields + */ + slide.get_input("country").on("change", function() { + var country = slide.get_input("country").val(); + var $timezone = slide.get_input("timezone"); + var data = frappe.setup.data.regional_data; + + $timezone.empty(); + + // add country specific timezones first + if(country) { + var timezone_list = data.country_info[country].timezones || []; + $timezone.add_options(timezone_list.sort()); + slide.get_field("currency").set_input(data.country_info[country].currency); + slide.get_field("currency").$input.trigger("change"); } - }, - css_class: "single-column" - }; + + // add all timezones at the end, so that user has the option to change it to any timezone + $timezone.add_options([""].concat(data.all_timezones)); + + slide.get_field("timezone").set_input($timezone.val()); + + // temporarily set date format + frappe.boot.sysdefaults.date_format = (data.country_info[country].date_format + || "dd-mm-yyyy"); + }); + + slide.get_input("currency").on("change", function() { + var currency = slide.get_input("currency").val(); + if (!currency) return; + frappe.model.with_doc("Currency", currency, function() { + frappe.provide("locals.:Currency." + currency); + var currency_doc = frappe.model.get_doc("Currency", currency); + var number_format = currency_doc.number_format; + if (number_format==="#.###") { + number_format = "#.###,##"; + } else if (number_format==="#,###") { + number_format = "#,###.##" + } + + frappe.boot.sysdefaults.number_format = number_format; + locals[":Currency"][currency] = $.extend({}, currency_doc); + }); + }); + }, + } -frappe.wiz.on("before_load", function() { - load_frappe_slides(); +frappe.setup.on("before_load", function() { + // load slides + frappe_slides.map(frappe.setup.add_slide); - // add welcome slide - frappe.wiz.add_slide(frappe.wiz.welcome); - frappe.wiz.add_slide(frappe.wiz.region); - frappe.wiz.add_slide(frappe.wiz.user); + // set header image + let $icon = $('header .setup-wizard-brand'); + if($icon.length === 0) { + $('header').append(`
+
`); + } }); diff --git a/frappe/desk/page/setup_wizard/setup_wizard.py b/frappe/desk/page/setup_wizard/setup_wizard.py index 9a11894ce0..8e8fef3359 100755 --- a/frappe/desk/page/setup_wizard/setup_wizard.py +++ b/frappe/desk/page/setup_wizard/setup_wizard.py @@ -179,11 +179,27 @@ def load_messages(language): @frappe.whitelist() def load_languages(): + language_codes = frappe.db.sql('select language_code, language_name from tabLanguage order by name', as_dict=True) + codes_to_names = {} + for d in language_codes: + codes_to_names[d.language_code] = d.language_name return { "default_language": frappe.db.get_value('Language', frappe.local.lang, 'language_name') or frappe.local.lang, - "languages": sorted(frappe.db.sql_list('select language_name from tabLanguage order by name')) + "languages": sorted(frappe.db.sql_list('select language_name from tabLanguage order by name')), + "codes_to_names": codes_to_names } +@frappe.whitelist() +def load_country(): + from frappe.sessions import get_geo_ip_country + return get_geo_ip_country(frappe.local.request_ip) if frappe.local.request_ip else None + +@frappe.whitelist() +def load_user_details(): + return { + "full_name": frappe.cache().hget("full_name", "signup"), + "email": frappe.cache().hget("email", "signup") + } def prettify_args(args): # remove attachments diff --git a/frappe/desk/page/setup_wizard/setup_wizard_page.html b/frappe/desk/page/setup_wizard/setup_wizard_page.html index f52301b149..565dab563a 100644 --- a/frappe/desk/page/setup_wizard/setup_wizard_page.html +++ b/frappe/desk/page/setup_wizard/setup_wizard_page.html @@ -1,14 +1,18 @@ -
+
{% for (var i=0; i < slides_count; i++) { %} - + + + + {% } %}
-

{%= title %}

+

{%= title %}

-