diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py
index fdebc17e76..7c18bdbc78 100644
--- a/frappe/commands/utils.py
+++ b/frappe/commands/utils.py
@@ -344,6 +344,26 @@ def run_ui_tests(context, app=None, test=False, profile=False):
if os.environ.get('CI'):
sys.exit(ret)
+@click.command('run-setup-wizard-ui-test')
+@click.option('--app', help="App to run tests on, leave blank for all apps")
+@click.option('--profile', is_flag=True, default=False)
+@pass_context
+def run_setup_wizard_ui_test(context, app=None, profile=False):
+ "Run setup wizard UI test"
+ import frappe.test_runner
+
+ site = get_site(context)
+ frappe.init(site=site)
+ frappe.connect()
+
+ ret = frappe.test_runner.run_setup_wizard_ui_test(app=app, verbose=context.verbose,
+ profile=profile)
+ if len(ret.failures) == 0 and len(ret.errors) == 0:
+ ret = 0
+
+ if os.environ.get('CI'):
+ sys.exit(ret)
+
@click.command('serve')
@click.option('--port', default=8000)
@click.option('--profile', is_flag=True, default=False)
@@ -485,6 +505,7 @@ commands = [
reset_perms,
run_tests,
run_ui_tests,
+ run_setup_wizard_ui_test,
serve,
set_config,
watch,
diff --git a/frappe/core/doctype/system_settings/system_settings.json b/frappe/core/doctype/system_settings/system_settings.json
index 6405a275bf..42f873509a 100644
--- a/frappe/core/doctype/system_settings/system_settings.json
+++ b/frappe/core/doctype/system_settings/system_settings.json
@@ -159,6 +159,36 @@
"set_only_once": 0,
"unique": 0
},
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_first_startup",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Is First Startup",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
@@ -1186,8 +1216,8 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-08-07 23:29:18.858797",
- "modified_by": "Administrator",
+ "modified": "2017-08-31 14:53:31.065925",
+ "modified_by": "ewfds@wfe.ef",
"module": "Core",
"name": "System Settings",
"name_case": "",
diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py
index d0ee87a209..07725423f4 100644
--- a/frappe/desk/notifications.py
+++ b/frappe/desk/notifications.py
@@ -156,7 +156,6 @@ def get_notifications_for_targets(config, notification_percent):
return doc_target_percents
-
def clear_notifications(user=None):
if frappe.flags.in_install:
return
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.css b/frappe/desk/page/setup_wizard/setup_wizard.css
deleted file mode 100644
index f61ea87863..0000000000
--- a/frappe/desk/page/setup_wizard/setup_wizard.css
+++ /dev/null
@@ -1,146 +0,0 @@
-#page-setup-wizard {
- margin-top: 30px;
-}
-
-.setup-wizard-slide {
- padding-left: 0px;
- padding-right: 0px;
-}
-
-@media (min-width: 768px) {
- .setup-wizard-slide {
- max-width: 500px;
- }
-}
-
-.setup-wizard-slide .lead {
- margin: 30px;
- color: #777777;
- text-align: center;
- font-size: 24px;
-}
-
-.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 {
- font-weight: 500;
-}
-
-.setup-wizard-slide .form-control.bold {
- background-color: #fff;
-}
-
-.setup-wizard-slide.with-form {
- margin: 60px 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 0px;
-}
-
-.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;
-}
-
-.setup-wizard-slide .fa-fw {
- vertical-align: middle;
- font-size: 10px;
-}
-
-.setup-wizard-slide .fa-fw.active {
- color: #5e64ff;
-}
-
-.setup-wizard-slide .icon-circle-blank {
- font-size: 7px;
-}
-
-.setup-wizard-slide .icon-circle {
- font-size: 10px;
-}
-
-.setup-wizard-slide .frappe-control[data-fieldtype="Attach Image"] {
- width: 140px;
- height: 180px; /*depends on presence of heading*/
- margin-top: 20px;
-}
-
-.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;
- 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 {
- position: relative;
- top: 50%;
- transform: translate(0px, -50%);
- -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 5ea6412977..ba481f9f18 100644
--- a/frappe/desk/page/setup_wizard/setup_wizard.js
+++ b/frappe/desk/page/setup_wizard/setup_wizard.js
@@ -1,5 +1,6 @@
-frappe.provide("frappe.wiz");
+frappe.provide("frappe.setup");
frappe.provide("frappe.setup.events");
+frappe.provide("frappe.ui");
frappe.setup = {
slides: [],
@@ -7,7 +8,6 @@ frappe.setup = {
data: {},
utils: {},
- remove_app_slides: [],
on: function(event, fn) {
if(!frappe.setup.events[event]) {
frappe.setup.events[event] = [];
@@ -29,277 +29,226 @@ frappe.pages['setup-wizard'].on_page_load = function(wrapper) {
// setup page ui
$(".navbar:first").toggle(false);
- var requires = ["/assets/frappe/css/animate.min.css"].concat(frappe.boot.setup_wizard_requires || []);
+ var requires = ["/assets/frappe/css/animate.min.css"].concat(
+ frappe.boot.setup_wizard_requires || []);
frappe.require(requires, function() {
frappe.setup.run_event("before_load");
-
var wizard_settings = {
- page_name: "setup-wizard",
parent: wrapper,
slides: frappe.setup.slides,
- title: __("Welcome")
+ slide_class: frappe.setup.SetupWizardSlide,
+ unidirectional: 1,
+ before_load: ($footer) => {
+ $footer.find('.next-btn').removeClass('btn-default')
+ .addClass('btn-primary');
+ $footer.find('.text-right').prepend(
+ $(`
+ ${__("Complete Setup")}`));
+
+ }
}
-
- frappe.wizard = new frappe.setup.Wizard(wizard_settings);
+ frappe.wizard = new frappe.setup.SetupWizard(wizard_settings);
frappe.setup.run_event("after_load");
-
// frappe.wizard.values = test_values_edu;
-
- var route = frappe.get_route();
+ let route = frappe.get_route();
if(route) {
- frappe.wizard.show(route[1]);
+ frappe.wizard.show_slide(route[1]);
}
});
-}
+};
frappe.pages['setup-wizard'].on_page_show = function(wrapper) {
if(frappe.get_route()[1]) {
- frappe.wizard && frappe.wizard.show(frappe.get_route()[1]);
+ frappe.wizard && frappe.wizard.show_slide(frappe.get_route()[1]);
}
-}
+};
+
+frappe.setup.on("before_load", function() {
+ // load slides
+ frappe.setup.slides_settings.map(frappe.setup.add_slide);
+});
+
+frappe.setup.SetupWizard = class SetupWizard extends frappe.ui.Slides {
+ constructor(args = {}) {
+ super(args);
+ $.extend(this, args);
-frappe.setup.Wizard = Class.extend({
- init: function(opts) {
- $.extend(this, opts);
- this.make();
- this.slides;
- this.slide_dict = {};
- this.values = {};
this.welcomed = true;
+ this.page_name = "setup-wizard";
frappe.set_route("setup-wizard/0");
- },
- make: function() {
- this.parent = $('
').appendTo(this.parent);
- },
- get_message: function(html) {
- return $(repl('
', {html:html}))
- },
- show_working: function() {
- this.hide_current_slide();
- frappe.set_route(this.page_name);
- this.current_slide = {"$wrapper": this.get_message(this.working_html()).appendTo(this.parent)};
- },
- show_complete: function() {
- this.hide_current_slide();
- this.current_slide = {"$wrapper": this.get_message(this.complete_html()).appendTo(this.parent)};
- },
- show: function(id) {
+ }
+
+ make() {
+ super.make();
+ this.container.addClass("container setup-wizard-slide with-form");
+ this.$next_btn.addClass('action');
+ this.$complete_btn = this.$footer.find('.complete-btn').addClass('action');
+ }
+
+ before_show_slide() {
if(!this.welcomed) {
frappe.set_route(this.page_name);
- return;
+ return false;
}
- id = cint(id);
- if(this.current_slide && this.current_slide.id===id) {
- return;
+ return true;
+ }
+
+ show_slide(id) {
+ super.show_slide(id);
+ frappe.set_route(this.page_name, id + "");
+ }
+
+ show_hide_prev_next(id) {
+ super.show_hide_prev_next(id);
+ if (id + 1 === this.slides.length){
+ this.$next_btn.removeClass("btn-primary").hide();
+ this.$complete_btn.addClass("btn-primary").show()
+ .on('click', this.action_on_complete.bind(this));
+
+ } else {
+ this.$next_btn.addClass("btn-primary").show();
+ this.$complete_btn.removeClass("btn-primary").hide();
}
+ }
- this.update_values();
-
- if(!this.slide_dict[id]) {
- this.slide_dict[id] = new frappe.setup.WizardSlide($.extend(this.slides[id], {wiz:this, id:id}));
- this.slide_dict[id].make();
- }
-
- this.hide_current_slide();
-
- this.current_slide = this.slide_dict[id];
- this.current_slide.$wrapper.removeClass("hidden");
- },
- hide_current_slide: function() {
- if(this.current_slide) {
- this.current_slide.$wrapper.addClass("hidden");
- this.current_slide = null;
- }
- },
- get_values: function() {
- var values = {};
- $.each(this.slide_dict, function(id, slide) {
- if(slide.values) {
- $.extend(values, slide.values);
- }
- });
- return values;
- },
- working_html: function() {
- var msg = $(frappe.render_template("setup_wizard_message", {
- image: "/assets/frappe/images/ui/bubble-tea-smile.svg",
- title: __("Setting Up"),
- message: __('Sit tight while your system is being setup. This may take a few moments.')
- }));
- msg.find(".setup-wizard-message-image").addClass("animated infinite bounce");
- return msg.html();
- },
-
- complete_html: function() {
- return frappe.render_template("setup_wizard_message", {
- image: "/assets/frappe/images/ui/bubble-tea-happy.svg",
- title: __('Setup Complete'),
- message: ""
- });
- },
-
- on_complete: function() {
- var me = this;
- this.update_values();
- this.show_working();
- return frappe.call({
- method: "frappe.desk.page.setup_wizard.setup_wizard.setup_complete",
- args: {args: this.values},
- callback: function(r) {
- me.show_complete();
- if(frappe.setup.welcome_page) {
- localStorage.setItem("session_last_route", frappe.setup.welcome_page);
- }
- setTimeout(function() {
- window.location = "/desk";
- }, 2000);
- },
- error: function(r) {
- var d = frappe.msgprint(__("There were errors."));
- d.custom_onhide = function() {
- frappe.set_route(me.page_name, me.slides.length - 1);
- };
- }
- });
- },
-
- update_values: function() {
- this.values = $.extend(this.values, this.get_values());
- },
-
- refresh_slides: function() {
- // reset all slides so that labels are translated
- var me = this;
- if(this.in_refresh_slides) {
+ refresh_slides() {
+ // For Translations, etc.
+ if(this.in_refresh_slides || !this.current_slide.set_values()) {
return;
}
this.in_refresh_slides = true;
- if(!this.current_slide.set_values()) {
- return;
- }
-
this.update_values();
-
frappe.setup.slides = [];
frappe.setup.run_event("before_load");
- // remove slides listed in remove_app_slides
- var new_slides = [];
+ frappe.setup.slides = this.get_setup_slides_filtered_by_domain();
+
+ this.slides = frappe.setup.slides;
+ frappe.setup.run_event("after_load");
+
+ // re-render all slide, only remake made slides
+ $.each(this.slide_dict, (id, slide) => {
+ if(slide.made) {
+ this.made_slide_ids.push(id);
+ }
+ });
+ this.made_slide_ids.push(this.current_id);
+ this.setup();
+
+ this.show_slide(this.current_id);
+ this.in_refresh_slides = false;
+ }
+
+ action_on_complete() {
+ var me = this;
+ if (!this.current_slide.set_values()) return;
+ this.update_values();
+ this.show_working_state();
+ return frappe.call({
+ method: "frappe.desk.page.setup_wizard.setup_wizard.setup_complete",
+ args: {args: this.values},
+ callback: function() {
+ me.show_setup_complete_state();
+ if(frappe.setup.welcome_page) {
+ localStorage.setItem("session_last_route", frappe.setup.welcome_page);
+ }
+ window.location = "/desk";
+ window.location.reload();
+ setTimeout(function() {
+ // frappe.ui.toolbar.clear_cache();
+ window.location = "/desk";
+ }, 2000);
+ setTimeout(()=> {
+ $('body').removeClass('setup-state');
+ }, 20000);
+ },
+ error: function() {
+ var d = frappe.msgprint(__("There were errors."));
+ d.custom_onhide = function() {
+ $(me.parent).find('.setup-state').remove();
+ $('body').removeClass('setup-state');
+ me.container.show();
+ frappe.set_route(me.page_name, me.slides.length - 1);
+ };
+ }
+ });
+ }
+
+ get_setup_slides_filtered_by_domain() {
+ var filtered_slides = [];
frappe.setup.slides.forEach(function(slide) {
if(frappe.setup.domain) {
var domains = slide.domains;
if (domains.indexOf('all') !== -1 ||
domains.indexOf(frappe.setup.domain.toLowerCase()) !== -1) {
- new_slides.push(slide);
+ filtered_slides.push(slide);
}
} else {
- new_slides.push(slide);
+ filtered_slides.push(slide);
}
})
-
- frappe.setup.slides = new_slides;
-
- this.slides = frappe.setup.slides;
- frappe.setup.run_event("after_load");
-
- // re-render all slides
- this.slide_dict = {};
-
- var current_id = this.current_slide.id;
- this.current_slide.destroy();
-
- this.show(current_id);
- this.in_refresh_slides = false;
+ return filtered_slides;
}
-});
-frappe.setup.WizardSlide = Class.extend({
- init: function(opts) {
- $.extend(this, opts);
- this.$wrapper = $('
')
- .appendTo(this.wiz.parent)
- .attr("data-slide-id", this.id);
- },
- make: function() {
- var me = this;
- if(this.$body) this.$body.remove();
+ show_working_state() {
+ this.container.hide();
+ $('body').addClass('setup-state');
+ frappe.set_route(this.page_name);
- var fields = JSON.parse(JSON.stringify(this.fields));
+ this.working_state_message = this.get_message(
+ __("Setting Up"),
+ __("Sit tight while your system is being setup. This may take a few moments."),
+ true
+ ).appendTo(this.parent);
- if(this.add_more) {
- this.count = 1;
- fields = fields.map((field, i) => {
- if(field.fieldname) {
- field.fieldname += '_1';
+ this.current_id = this.slides.length;
+ this.current_slide = null;
+ this.completed_state_message = this.get_message(
+ __("Setup Complete"),
+ __("You're all set!")
+ );
+ }
+
+ show_setup_complete_state() {
+ this.working_state_message.hide();
+ this.completed_state_message.appendTo(this.parent);
+ }
+
+ get_message(title, message="", loading=false) {
+ return $(`
+
+
+
+ ${title}
+
+
${message}
+
+ ${loading
+ ? '
'
+ : `
`
}
- if(i === 1 && this.mandatory_entry) {
- field.reqd = 1;
- }
- if(!field.static) {
- if(field.label) field.label += ' 1';
- }
- return field;
- });
- }
+
+
+
`);
+ }
+};
- if(this.before_load) {
- this.before_load(this);
- }
+frappe.setup.SetupWizardSlide = class SetupWizardSlide extends frappe.ui.Slide {
+ constructor(slide = null) {
+ super(slide);
+ }
- this.$body = $(frappe.render_template("setup_wizard_page", {
- help: __(this.help),
- title:__(this.title),
- main_title:__(this.wiz.title),
- step: this.id + 1,
- name: this.name,
- slides_count: this.wiz.slides.length
- })).appendTo(this.$wrapper);
-
- this.body = this.$body.find(".form")[0];
-
- if(this.fields) {
- this.form = new frappe.ui.FieldGroup({
- fields: fields,
- body: this.body,
- no_submit_on_enter: true
- });
- this.form.make();
- } else {
- $(this.body).html(this.html);
- }
-
- this.set_reqd_fields();
+ make() {
+ super.make();
this.set_init_values();
- this.make_prev_next_buttons();
- if(this.add_more) this.bind_more_button();
+ this.reset_action_button_state();
+ }
- var $primary_btn = this.$next ? this.$next : this.$complete;
-
- this.bind_fields_to_next($primary_btn);
-
- if(this.onload) {
- this.onload(this);
- }
- this.set_reqd_fields();
- this.bind_fields_to_next($primary_btn);
-
- 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() {
+ set_init_values () {
var me = this;
// set values from frappe.setup.values
if(frappe.wizard.values && this.fields) {
@@ -310,141 +259,21 @@ frappe.setup.WizardSlide = Class.extend({
}
});
}
- },
+ }
- set_values: function() {
- this.values = this.form.get_values();
- if(this.values===null) {
- return false;
- }
- if(this.validate && !this.validate()) {
- return false;
- }
- 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.static) {
- if(field.label) field.label += ' ' + this.count;
- }
- return field;
- }));
- if(this.count === this.max_count) {
- this.$more.addClass('hide');
- }
- });
- },
+// Frappe slides settings
+// ======================================================
- make_prev_next_buttons: function() {
- var me = this;
-
- // prev
- if(this.id > 0) {
- this.$prev = this.$body.find('.prev-btn')
- .removeClass("hide")
- .attr('tabIndex', 0)
- .click(function() {
- me.prev();
- })
- .css({"margin-right": "10px"});
- }
-
- // next or complete
- if(this.id+1 < this.wiz.slides.length) {
- this.$next = this.$body.find('.next-btn')
- .removeClass("hide")
- .attr('tabIndex', 0)
- .click(this.next_or_complete.bind(this));
- } else {
- this.$complete = this.$body.find('.complete-btn')
- .removeClass("hide")
- .attr('tabIndex', 0)
- .click(this.next_or_complete.bind(this));
- }
-
- // setup mousefree navigation
- this.$body.on('keypress', function(e) {
- if(e.which === 13) {
- var $target = $(e.target);
- if($target.hasClass('prev-btn')) {
- me.prev();
- } else if($target.hasClass('btn-attach')) {
- //do nothing
- } else {
- me.next_or_complete();
- e.preventDefault();
- }
- }
- });
- },
- 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) {
- this.next();
- } else {
- this.wiz.on_complete(this.wiz);
- }
- }
- },
- 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();
- }.bind(this), 0);
- },
- next: function() {
- frappe.set_route(this.wiz.page_name, this.id+1 + "");
- },
- prev: function() {
- frappe.set_route(this.wiz.page_name, this.id-1 + "");
- },
- get_input: function(fn) {
- return this.form.get_input(fn);
- },
- get_field: function(fn) {
- return this.form.get_field(fn);
- },
- destroy: function() {
- this.$body.remove();
- if(frappe.wizard.current_slide===this) {
- frappe.wizard.current_slide = null;
- }
- },
-});
-
-var frappe_slides = [
+frappe.setup.slides_settings = [
{
// Welcome (language) slide
name: "welcome",
domains: ["all"],
title: __("Hello!"),
icon: "fa fa-world",
- help: __("Let's prepare the system for first use."),
+ // help: __("Let's prepare the system for first use."),
fields: [
{ fieldname: "language", label: __("Your Language"),
@@ -455,13 +284,13 @@ var frappe_slides = [
if (frappe.setup.data.lang) {
this.setup_fields(slide);
} else {
- utils.load_languages(slide, this.setup_fields);
+ frappe.setup.utils.load_languages(slide, this.setup_fields);
}
},
setup_fields: function(slide) {
- utils.setup_language_field(slide);
- utils.bind_language_events(slide);
+ frappe.setup.utils.setup_language_field(slide);
+ frappe.setup.utils.bind_language_events(slide);
},
},
@@ -471,7 +300,7 @@ var frappe_slides = [
domains: ["all"],
title: __("Select Your Region"),
icon: "fa fa-flag",
- help: __("Select your Country, Time Zone and Currency"),
+ // help: __("Select your Country, Time Zone and Currency"),
fields: [
{ fieldname: "country", label: __("Your Country"), reqd:1,
fieldtype: "Select" },
@@ -487,13 +316,13 @@ var frappe_slides = [
if(frappe.setup.data.regional_data) {
this.setup_fields(slide);
} else {
- utils.load_regional_data(slide, this.setup_fields);
+ frappe.setup.utils.load_regional_data(slide, this.setup_fields);
}
},
setup_fields: function(slide) {
- utils.setup_region_fields(slide);
- utils.bind_region_events(slide);
+ frappe.setup.utils.setup_region_fields(slide);
+ frappe.setup.utils.bind_region_events(slide);
}
},
@@ -512,7 +341,7 @@ var frappe_slides = [
"fieldtype": "Data", "options":"Email"},
{ "fieldname": "password", "label": __("Password"), "fieldtype": "Password" }
],
- help: __('The first user will become the System Manager (you can change this later).'),
+ // 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.email.$wrapper.toggle(false);
@@ -542,7 +371,7 @@ var frappe_slides = [
slide.form.fields_dict.password.df.reqd = 1;
slide.form.fields_dict.password.refresh();
- utils.load_user_details(slide, this.setup_fields);
+ frappe.setup.utils.load_user_details(slide, this.setup_fields);
}
},
@@ -564,7 +393,7 @@ var frappe_slides = [
}
];
-var utils = {
+frappe.setup.utils = {
load_languages: function(slide, callback) {
frappe.call({
method: "frappe.desk.page.setup_wizard.setup_wizard.load_languages",
@@ -714,10 +543,4 @@ var utils = {
});
});
},
-
-}
-
-frappe.setup.on("before_load", function() {
- // load slides
- frappe_slides.map(frappe.setup.add_slide);
-});
+};
diff --git a/frappe/desk/page/setup_wizard/setup_wizard.py b/frappe/desk/page/setup_wizard/setup_wizard.py
index 87a574cba2..db9f29fc80 100755
--- a/frappe/desk/page/setup_wizard/setup_wizard.py
+++ b/frappe/desk/page/setup_wizard/setup_wizard.py
@@ -151,6 +151,7 @@ def add_all_roles_to(name):
def disable_future_access():
frappe.db.set_default('desktop:home_page', 'desktop')
frappe.db.set_value('System Settings', 'System Settings', 'setup_complete', 1)
+ frappe.db.set_value('System Settings', 'System Settings', 'is_first_startup', 1)
if not frappe.flags.in_test:
# remove all roles and add 'Administrator' to prevent future access
@@ -202,6 +203,10 @@ def load_user_details():
"email": frappe.cache().hget("email", "signup")
}
+@frappe.whitelist()
+def reset_is_first_startup():
+ frappe.db.set_value('System Settings', 'System Settings', 'is_first_startup', 0)
+
def prettify_args(args):
# remove attachments
for key, val in args.items():
diff --git a/frappe/desk/page/setup_wizard/setup_wizard_message.html b/frappe/desk/page/setup_wizard/setup_wizard_message.html
deleted file mode 100644
index e2f6bbc51d..0000000000
--- a/frappe/desk/page/setup_wizard/setup_wizard_message.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-

-
-
{%= title %}
-
-
{%= message %}
-
diff --git a/frappe/desk/page/setup_wizard/setup_wizard_page.html b/frappe/desk/page/setup_wizard/setup_wizard_page.html
deleted file mode 100644
index 565dab563a..0000000000
--- a/frappe/desk/page/setup_wizard/setup_wizard_page.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
diff --git a/frappe/desk/user_progress.py b/frappe/desk/user_progress.py
new file mode 100644
index 0000000000..f62bb2a29d
--- /dev/null
+++ b/frappe/desk/user_progress.py
@@ -0,0 +1,30 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe.utils import cint
+
+@frappe.whitelist()
+def get_user_progress_slides():
+ '''
+ Return user progress slides for the desktop (called via `get_user_progress_slides` hook)
+ '''
+ slides = []
+ if cint(frappe.db.get_single_value('System Settings', 'setup_complete')):
+ for fn in frappe.get_hooks('get_user_progress_slides'):
+ slides += frappe.get_attr(fn)()
+
+ return slides
+
+@frappe.whitelist()
+def update_and_get_user_progress():
+ '''
+ Return setup progress action states (called via `update_and_get_user_progress` hook)
+ '''
+ states = {}
+ for fn in frappe.get_hooks('update_and_get_user_progress'):
+ states.update(frappe.get_attr(fn)())
+
+ return states
diff --git a/frappe/public/build.json b/frappe/public/build.json
index 5035a1fec0..15dc9e313b 100755
--- a/frappe/public/build.json
+++ b/frappe/public/build.json
@@ -61,7 +61,6 @@
"public/js/frappe/form/link_selector.js",
"public/js/frappe/form/multi_select_dialog.js",
"public/js/frappe/ui/dialog.js",
-
"public/js/frappe/form/controls/base_control.js",
"public/js/frappe/form/controls/base_input.js",
"public/js/frappe/form/controls/data.js",
@@ -162,6 +161,7 @@
"public/js/frappe/ui/page.html",
"public/js/frappe/ui/page.js",
+ "public/js/frappe/ui/slides.js",
"public/js/frappe/ui/find.js",
"public/js/frappe/ui/iconbar.js",
"public/js/frappe/form/layout.js",
diff --git a/frappe/public/css/desk.css b/frappe/public/css/desk.css
index 22ecdb993b..f5193dac9d 100644
--- a/frappe/public/css/desk.css
+++ b/frappe/public/css/desk.css
@@ -441,7 +441,7 @@ fieldset[disabled] .form-control {
}
}
@media (min-width: 768px) {
- .video-modal {
+ .video-modal .modal-dialog {
width: 700px;
}
}
@@ -510,7 +510,7 @@ fieldset[disabled] .form-control {
margin-right: 10px;
}
a.progress-small .progress-chart {
- width: 60px;
+ width: 40px;
margin-top: 4px;
float: right;
}
@@ -518,6 +518,20 @@ a.progress-small .progress {
margin-bottom: 0;
}
a.progress-small .progress-bar {
+ transition: unset;
+ background-color: #98d85b;
+}
+li.user-progress .progress-chart {
+ width: 60px;
+ margin-top: 8px;
+}
+li.user-progress .progress {
+ margin-bottom: 0;
+ background-color: #fff;
+ border: 1px solid #e5e7e9;
+}
+li.user-progress .progress-bar {
+ transition: unset;
background-color: #98d85b;
}
/* on small screens, show only icons on top */
@@ -1070,3 +1084,69 @@ input[type="checkbox"]:checked:before {
margin: -2px 0 0 3px;
border: 1px solid rgba(0, 0, 0, 0.25);
}
+.slides-wrapper .fa-circle {
+ font-size: 10px;
+ margin: 0px 2px;
+}
+.slides-wrapper .fa-circle.active {
+ color: #5e64ff;
+}
+.slides-wrapper .fa-circle.link {
+ cursor: pointer;
+}
+.slides-wrapper .form {
+ margin-top: 30px;
+}
+.slides-wrapper .form .form-layout {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+.slides-wrapper .form .form-section {
+ padding: 0px 7px;
+ border: none;
+}
+.slides-wrapper .add-more {
+ margin-bottom: 30px;
+}
+.slides-wrapper .lead {
+ margin-top: 20px;
+}
+.slides-wrapper .success-state {
+ margin-bottom: 20px;
+}
+.slides-wrapper .next-steps-links .title {
+ text-transform: uppercase;
+ color: #8D99A6;
+ font-size: 11px;
+}
+.slides-wrapper .btn-primary {
+ font-weight: bold;
+}
+.slides-wrapper .footer {
+ margin-top: 15px;
+ padding: 0px 7px;
+}
+.slides-wrapper .footer .btn:not(:last-child) {
+ margin-right: 3px;
+}
+.slides-wrapper .footer a.btn.make-btn {
+ margin-right: 7px;
+}
+.slides-wrapper .footer a.make-btn.disabled {
+ background-color: #b1bdca;
+ color: #fff;
+ border-color: #b1bdca;
+}
+.user-progress-dialog .slides-progress {
+ margin-top: 15px;
+}
+.user-progress-dialog .done-state .check-container {
+ font-size: 64px;
+ margin: 40px;
+}
+.user-progress-dialog .done-state .title {
+ font-weight: normal;
+}
+.user-progress-dialog .done-state .help-links a {
+ margin: 0px 10px;
+}
diff --git a/frappe/public/css/page.css b/frappe/public/css/page.css
index 66a7bbd836..1f54563454 100644
--- a/frappe/public/css/page.css
+++ b/frappe/public/css/page.css
@@ -153,3 +153,200 @@ select.input-sm {
font-size: 18px;
}
}
+#page-setup-wizard {
+ margin-top: 30px;
+}
+.setup-wizard-slide {
+ padding-left: 0px;
+ padding-right: 0px;
+}
+@media (min-width: 768px) {
+ .setup-wizard-slide {
+ max-width: 500px;
+ }
+}
+.setup-wizard-slide .slides-progress {
+ margin-top: 20px;
+}
+.setup-wizard-slide .lead {
+ margin: 30px;
+ color: #777777;
+ text-align: center;
+ font-size: 24px;
+}
+.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 {
+ font-weight: 500;
+}
+.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 .add-more {
+ margin: 0px;
+}
+.setup-wizard-slide .footer {
+ padding: 30px 7px;
+}
+.setup-wizard-slide a.next-btn.disabled,
+.setup-wizard-slide a.complete-btn.disabled {
+ background-color: #b1bdca;
+ color: #fff;
+ border-color: #b1bdca;
+}
+.setup-wizard-slide .fa-fw {
+ vertical-align: middle;
+ font-size: 10px;
+}
+.setup-wizard-slide .fa-fw.active {
+ color: #5e64ff;
+}
+.setup-wizard-slide .icon-circle-blank {
+ font-size: 7px;
+}
+.setup-wizard-slide .icon-circle {
+ font-size: 10px;
+}
+.setup-wizard-slide .frappe-control[data-fieldtype="Attach Image"] {
+ width: 140px;
+ height: 180px;
+ /*depends on presence of heading*/
+ margin-top: 20px;
+}
+.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;
+ 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, 0.075);
+}
+.setup-wizard-slide .missing-image .octicon {
+ position: relative;
+ top: 50%;
+ transform: translate(0px, -50%);
+ -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, 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-state {
+ background-color: #f5f7fa;
+}
+.page-card {
+ max-width: 360px;
+ padding: 15px;
+ margin: 70px auto;
+ border: 1px solid #d1d8dd;
+ border-radius: 4px;
+ background-color: #fff;
+ box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.1);
+}
+.page-card .page-card-head {
+ padding: 10px 15px;
+ margin: -15px;
+ margin-bottom: 15px;
+ border-bottom: 1px solid #d1d8dd;
+}
+.state-icon-container {
+ display: flex;
+ justify-content: center;
+}
+.state-icon {
+ position: relative;
+ width: 100px !important;
+ height: 100px !important;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+@keyframes lds-rolling {
+ 0% {
+ -webkit-transform: translate(-50%, -50%) rotate(0deg);
+ transform: translate(-50%, -50%) rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: translate(-50%, -50%) rotate(360deg);
+ transform: translate(-50%, -50%) rotate(360deg);
+ }
+}
+@-webkit-keyframes lds-rolling {
+ 0% {
+ -webkit-transform: translate(-50%, -50%) rotate(0deg);
+ transform: translate(-50%, -50%) rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: translate(-50%, -50%) rotate(360deg);
+ transform: translate(-50%, -50%) rotate(360deg);
+ }
+}
+.lds-rolling {
+ -webkit-transform: translate(-100px, -100px) scale(1) translate(100px, 100px);
+ transform: translate(-100px, -100px) scale(1) translate(100px, 100px);
+}
+.lds-rolling div {
+ position: absolute;
+ width: 60px;
+ height: 60px;
+ border: 3px solid #d1d8dd;
+ border-top-color: transparent;
+ border-radius: 50%;
+ -webkit-animation: lds-rolling 1s linear infinite;
+ animation: lds-rolling 1s linear infinite;
+ top: 50px;
+ left: 50px;
+}
+.lds-rolling div:after {
+ position: absolute;
+ width: 60px;
+ height: 60px;
+ border: 3px solid #d1d8dd;
+ border-top-color: transparent;
+ border-radius: 50%;
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg);
+}
diff --git a/frappe/public/js/frappe/misc/help.js b/frappe/public/js/frappe/misc/help.js
index f67628142b..1d3402c216 100644
--- a/frappe/public/js/frappe/misc/help.js
+++ b/frappe/public/js/frappe/misc/help.js
@@ -24,9 +24,9 @@ frappe.help.show_video = function(youtube_id, title) {
var dialog = frappe.msgprint('
' + (frappe.help_feedback_link || ""),
- title || __("Help"));
+ title || __("Help"));
- dialog.$wrapper.find(".modal-content").addClass("video-modal");
+ dialog.$wrapper.addClass("video-modal");
}
$("body").on("click", "a.help-link", function() {
diff --git a/frappe/public/js/frappe/ui/dialog.js b/frappe/public/js/frappe/ui/dialog.js
index 8ab1019a54..8163cf5ec8 100644
--- a/frappe/public/js/frappe/ui/dialog.js
+++ b/frappe/public/js/frappe/ui/dialog.js
@@ -67,15 +67,6 @@ frappe.ui.Dialog = frappe.ui.FieldGroup.extend({
});
},
- focus_on_first_input: function() {
- if(this.no_focus) return;
- $.each(this.fields_list, function(i, f) {
- if(!in_list(['Date', 'Datetime', 'Time'], f.df.fieldtype) && f.set_focus) {
- f.set_focus();
- return false;
- }
- });
- },
get_primary_btn: function() {
return this.$wrapper.find(".modal-header .btn-primary");
},
diff --git a/frappe/public/js/frappe/ui/field_group.js b/frappe/public/js/frappe/ui/field_group.js
index 5df46c55ef..c2a21825b9 100644
--- a/frappe/public/js/frappe/ui/field_group.js
+++ b/frappe/public/js/frappe/ui/field_group.js
@@ -60,6 +60,15 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
});
},
first_button: false,
+ focus_on_first_input: function() {
+ if(this.no_focus) return;
+ $.each(this.fields_list, function(i, f) {
+ if(!in_list(['Date', 'Datetime', 'Time'], f.df.fieldtype) && f.set_focus) {
+ f.set_focus();
+ return false;
+ }
+ });
+ },
catch_enter_as_submit: function() {
var me = this;
$(this.body).find('input[type="text"], input[type="password"]').keypress(function(e) {
diff --git a/frappe/public/js/frappe/ui/slides.js b/frappe/public/js/frappe/ui/slides.js
new file mode 100644
index 0000000000..7d2fc295ac
--- /dev/null
+++ b/frappe/public/js/frappe/ui/slides.js
@@ -0,0 +1,393 @@
+// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+frappe.provide("frappe.ui");
+
+frappe.ui.Slide = class Slide {
+ constructor(slide = null) {
+ $.extend(this, slide);
+ this.setup();
+ }
+
+ setup() {
+ this.$wrapper = $('
')
+ .attr({"data-slide-id": this.id, "data-slide-name": this.name})
+ .appendTo(this.parent);
+ }
+
+ // Make has to be called manually, to account for on-demand use cases
+ make() {
+ if(this.before_load) { this.before_load(this); }
+
+ this.$body = $(`
`).appendTo(this.$wrapper);
+
+ this.$content = this.$body.find(".content");
+ this.$form = this.$body.find(".form");
+ this.$primary_btn = this.slides_footer.find('.primary');
+
+ if(this.help) this.$content.append($(`
${this.help}
`));
+ if(this.image_src) this.$content.append(
+ $(`

`));
+
+ this.reqd_fields = [];
+
+ this.refresh();
+ this.made = true;
+ }
+
+ refresh() {
+ this.render_parent_dots();
+ if(!this.done) {
+ this.setup_form();
+ } else {
+ this.setup_done_state();
+ }
+ }
+
+ setup_form() {
+ this.form = new frappe.ui.FieldGroup({
+ fields: this.get_atomic_fields(),
+ body: this.$form[0],
+ no_submit_on_enter: true
+ });
+ this.form.make();
+ if(this.add_more) this.bind_more_button();
+
+ this.set_reqd_fields();
+
+ if(this.onload) { this.onload(this); }
+ this.set_reqd_fields();
+ }
+
+ // Form methods
+ get_atomic_fields() {
+ var fields = JSON.parse(JSON.stringify(this.fields));
+ if(this.add_more) {
+ this.count = 1;
+ fields = fields.map((field, i) => {
+ if(field.fieldname) {
+ field.fieldname += '_1';
+ }
+ if(i === 1 && this.mandatory_entry) {
+ field.reqd = 1;
+ }
+ if(!field.static) {
+ if(field.label) field.label += ' 1';
+ }
+ return field;
+ });
+ }
+ return fields;
+ }
+
+ set_reqd_fields() {
+ 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_values() {
+ this.values = this.form.get_values();
+ if(this.values===null) {
+ return false;
+ }
+ if(this.validate && !this.validate()) {
+ return false;
+ }
+ return true;
+ }
+
+ bind_more_button() {
+ this.$more = this.$body.find('.form-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.static) {
+ if(field.label) field.label += ' ' + this.count;
+ }
+ return field;
+ }));
+ if(this.count === this.max_count) {
+ this.$more.addClass('hide');
+ }
+ });
+ }
+
+ // Primary button (outside of slide)
+ resetup_primary_button() {
+ this.unbind_primary_action();
+ this.bind_fields_to_action_btn();
+ this.reset_action_button_state();
+ this.bind_primary_action();
+ }
+
+ bind_fields_to_action_btn() {
+ var me = this;
+ this.reqd_fields.map((field) => {
+ field.$wrapper.on('change input', () => {
+ me.reset_action_button_state();
+ });
+ });
+ }
+
+ reset_action_button_state() {
+ var empty_fields = this.reqd_fields.filter((field) => {
+ return !field.get_value();
+ });
+ if(empty_fields.length) {
+ this.slides_footer.find('.action').addClass('disabled');
+ } else {
+ this.slides_footer.find('.action').removeClass('disabled');
+ }
+ }
+
+ unbind_primary_action() {
+ this.slides_footer.find(".primary").off();
+ }
+
+ bind_primary_action() {
+ this.slides_footer.find(".primary").on('click', () => {
+ this.primary_action();
+ });
+ }
+
+ before_show() { }
+
+ show_slide() {
+ this.$wrapper.removeClass("hidden");
+ this.before_show();
+ this.resetup_primary_button();
+ if(!this.done) {
+ this.$body.find('.form-control').first().focus();
+ this.$primary_btn.show();
+ } else {
+ this.$primary_btn.hide();
+ }
+ }
+
+ hide_slide() {
+ this.$wrapper.addClass("hidden");
+ }
+
+ get_input(fieldname) {
+ return this.form.get_input(fieldname);
+ }
+
+ get_field(fieldname) {
+ return this.form.get_field(fieldname);
+ }
+
+ destroy() {
+ this.$body.remove();
+ }
+
+ primary_action() { }
+};
+
+frappe.ui.Slides = class Slides {
+ constructor({
+ parent = null,
+ slides = [],
+ slide_class = null,
+ unidirectional = 0,
+ done_state = 0,
+ before_load = null,
+ on_update = null
+ }) {
+ this.parent = parent;
+ this.slides = slides;
+ this.slide_class = slide_class;
+ this.unidirectional = unidirectional;
+ this.done_state = done_state;
+ this.before_load = before_load;
+ this.on_update = on_update;
+
+ this.slide_dict = {};
+
+ //In case of refreshing
+ this.made_slide_ids = [];
+ this.values = {};
+ this.make();
+ }
+
+ make() {
+ this.container = $('
').addClass("slides-wrapper")
+ .appendTo(this.parent);
+ this.$slide_progress = $(`
`).addClass(`slides-progress text-center text-extra-muted`)
+ .appendTo(this.container);
+ this.$body = $(`
`).addClass(`slide-container`)
+ .appendTo(this.container);
+ this.$footer = $(`
`).addClass(`footer`)
+ .appendTo(this.container);
+
+ this.render_progress_dots();
+ this.make_prev_next_buttons();
+ if(this.before_load) { this.before_load(this.$footer); }
+
+ // can be on demand
+ this.setup();
+
+ // can be on demand
+ this.show_slide(0);
+ }
+
+ setup() {
+ this.slides.map((slide, id) => {
+ if(!this.slide_dict[id]) {
+ this.slide_dict[id] = new (this.slide_class)(
+ $.extend(this.slides[id], {
+ parent: this.$body,
+ slides_footer: this.$footer,
+ render_parent_dots: this.render_progress_dots.bind(this),
+ id: id,
+ })
+ );
+ if(!this.unidirectional) {
+ this.slide_dict[id].make();
+ }
+ } else {
+ if(this.made_slide_ids.includes(id+"")) {
+ this.slide_dict[id].destroy();
+ this.slide_dict[id].make();
+ }
+ }
+ });
+ }
+
+ refresh(id) {
+ this.render_progress_dots();
+ this.show_hide_prev_next(id);
+ this.$body.find('.form-control').first().focus();
+ }
+
+ render_progress_dots() {
+ // Depends on this.unidirectional and this.done_state
+ // Can be called by a slide to update states
+ this.$slide_progress.empty();
+
+ this.slides.map((slide, id) => {
+ let $dot = $(`
`)
+ .attr({'data-step-id': id});
+
+ if(this.done_state && (this.slide_dict[id] &&
+ this.slide_dict[id].done || slide.done)) {
+ $dot.addClass('text-success');
+ }
+ if((this.unidirectional && id <= this.current_id) ||
+ id === this.current_id) {
+ $dot.addClass('active');
+ }
+ // Add pointer event for non-unidirectional
+ this.$slide_progress.append($dot);
+ });
+
+ this.completed = 0;
+ this.slides.map((slide, i) => {
+ if(this.slide_dict[i]) {
+ if(this.slide_dict[i].done) this.completed++;
+ } else {
+ if(slide.done) this.completed++;
+ }
+ });
+ if(this.on_update) {this.on_update(this.completed, this.slides.length);}
+
+ if(!this.unidirectional) this.bind_progress_dots();
+ }
+
+ make_prev_next_buttons() {
+ $(`
`).appendTo(this.$footer);
+
+ this.$prev_btn = this.$footer.find('.prev-btn').attr('tabIndex', 0)
+ .on('click', () => { this.show_slide(this.current_id - 1); });
+
+ this.$next_btn = this.$footer.find('.next-btn').attr('tabIndex', 0)
+ .on('click', () => {
+ if (!this.unidirectional || (this.unidirectional && this.current_slide.set_values())) {
+ this.show_slide(this.current_id + 1);
+ }
+ });
+ }
+
+ bind_progress_dots() {
+ var me = this;
+ this.$slide_progress.find('.fa-circle').addClass('link').on('click', function() {
+ let id = $(this).attr('data-step-id');
+ me.show_slide(id);
+ });
+ }
+
+ before_show_slide() {
+ return true;
+ }
+
+ show_slide(id) {
+ id = cint(id);
+ if(!this.before_show_slide() ||
+ (this.current_slide && this.current_id===id)) {
+ return;
+ }
+
+ this.update_values();
+
+ if(this.current_slide) this.current_slide.hide_slide();
+ if(this.unidirectional && !this.slide_dict[id].made) {
+ this.slide_dict[id].make();
+ }
+ this.current_id = id;
+ this.current_slide = this.slide_dict[id];
+ this.current_slide.show_slide();
+ this.refresh(id);
+ }
+
+ destroy_slide(id) {
+ if(this.slide_dict[id]) this.slide_dict[id].destroy();
+ this.slide_dict[id] = null;
+ }
+
+ on_update(completed, total) {}
+
+ show_hide_prev_next(id) {
+ (id === 0) ?
+ this.$prev_btn.hide() : this.$prev_btn.show();
+ (id + 1 === this.slides.length) ?
+ this.$next_btn.hide() : this.$next_btn.show();
+ }
+
+ get_values() {
+ var values = {};
+ $.each(this.slide_dict, function(id, slide) {
+ if(slide.values) {
+ $.extend(values, slide.values);
+ }
+ });
+ return values;
+ }
+
+ update_values() {
+ this.values = $.extend(this.values, this.get_values());
+ }
+};
\ No newline at end of file
diff --git a/frappe/public/js/frappe/ui/toolbar/about.js b/frappe/public/js/frappe/ui/toolbar/about.js
index 3ef036ad5f..234c5ee5bf 100644
--- a/frappe/public/js/frappe/ui/toolbar/about.js
+++ b/frappe/public/js/frappe/ui/toolbar/about.js
@@ -35,10 +35,10 @@ frappe.ui.misc.about = function() {
var v = versions[key];
if(v.branch) {
var text = $.format('
{0}: v{1} ({2})
',
- [v.title, v.branch_version || v.version, v.branch])
+ [v.title, v.branch_version || v.version, v.branch])
} else {
var text = $.format('
{0}: v{1}
',
- [v.title, v.version])
+ [v.title, v.version])
}
$(text).appendTo($wrap);
});
diff --git a/frappe/public/js/frappe/ui/toolbar/navbar.html b/frappe/public/js/frappe/ui/toolbar/navbar.html
index fb49d558b3..4e92bc9ac5 100644
--- a/frappe/public/js/frappe/ui/toolbar/navbar.html
+++ b/frappe/public/js/frappe/ui/toolbar/navbar.html
@@ -11,6 +11,13 @@
+ -
+
+
+
+
-
diff --git a/frappe/public/js/frappe/ui/toolbar/toolbar.js b/frappe/public/js/frappe/ui/toolbar/toolbar.js
index 41a22ccd8c..474d00ccf5 100644
--- a/frappe/public/js/frappe/ui/toolbar/toolbar.js
+++ b/frappe/public/js/frappe/ui/toolbar/toolbar.js
@@ -6,26 +6,32 @@ frappe.provide('frappe.search');
frappe.ui.toolbar.Toolbar = Class.extend({
init: function() {
- var header = $('header').append(frappe.render_template("navbar", {
+ $('header').append(frappe.render_template("navbar", {
avatar: frappe.avatar(frappe.session.user)
}));
+ $('.dropdown-toggle').dropdown();
- this.setup_sidebar();
-
- var awesome_bar = new frappe.search.AwesomeBar();
+ let awesome_bar = new frappe.search.AwesomeBar();
awesome_bar.setup("#navbar-search");
awesome_bar.setup("#modal-search");
- this.setup_help();
+ this.make();
+ },
+ make: function() {
+ this.setup_sidebar();
+ this.setup_help();
+ this.setup_progress_dialog();
+ this.bind_events();
+
+ $(document).trigger('toolbar_setup');
+ },
+
+ bind_events: function() {
$(document).on("notification-update", function() {
frappe.ui.notifications.update_notifications();
});
- $('.dropdown-toggle').dropdown();
-
- $(document).trigger('toolbar_setup');
-
// clear all custom menus on page change
$(document).on("page-change", function() {
$("header .navbar .custom-menu").remove();
@@ -41,7 +47,6 @@ frappe.ui.toolbar.Toolbar = Class.extend({
},
setup_sidebar: function () {
-
var header = $('header');
header.find(".toggle-sidebar").on("click", function () {
var layout_side_section = $('.layout-side-section');
@@ -186,10 +191,44 @@ frappe.ui.toolbar.Toolbar = Class.extend({
});
}
}
+ },
+
+ setup_progress_dialog: function() {
+ var me = this;
+ $('.user-progress').hide();
+ frappe.call({
+ method: "frappe.desk.user_progress.get_user_progress_slides",
+ callback: function(r) {
+ if(r.message) {
+ let slides = r.message;
+ if(slides.length) {
+ frappe.require("assets/frappe/js/frappe/ui/toolbar/user_progress_dialog.js", function() {
+ me.progress_dialog = new frappe.setup.UserProgressDialog({
+ slides: slides
+ });
+ $('.user-progress').show();
+ $('.user-progress .dropdown-toggle').on('click', () => {
+ me.progress_dialog.show();
+ });
+
+ if (frappe.boot.is_first_startup) {
+ me.progress_dialog.show();
+ frappe.call({
+ method: "frappe.desk.page.setup_wizard.setup_wizard.reset_is_first_startup",
+ args: {},
+ callback: () => {}
+ });
+ }
+
+ });
+ }
+ }
+ },
+ freeze: false
+ });
}
});
-
$.extend(frappe.ui.toolbar, {
add_dropdown_button: function(parent, label, click, icon) {
var menu = frappe.ui.toolbar.get_menu(parent);
diff --git a/frappe/public/js/frappe/ui/toolbar/user_progress_dialog.js b/frappe/public/js/frappe/ui/toolbar/user_progress_dialog.js
new file mode 100644
index 0000000000..01b103956a
--- /dev/null
+++ b/frappe/public/js/frappe/ui/toolbar/user_progress_dialog.js
@@ -0,0 +1,210 @@
+// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+frappe.provide("frappe.setup");
+frappe.provide("frappe.ui");
+
+frappe.setup.UserProgressSlide = class UserProgressSlide extends frappe.ui.Slide {
+ constructor(slide = null) {
+ super(slide);
+ }
+
+ make() {
+ super.make();
+ }
+
+ setup_done_state() {
+ this.$body.find(".slide-help").hide();
+ this.$body.find(".form-wrapper").hide();
+ this.slides_footer.find('.next-btn').addClass('btn-primary');
+ this.slides_footer.find('.done-btn').hide();
+ this.$primary_btn.hide();
+ this.make_done_state();
+ }
+
+ make_done_state() {
+ this.$done_state = $(``).appendTo(this.$body);
+
+ this.$done_state_title = this.$done_state.find('.title');
+ this.$check = this.$done_state.find('.check');
+ this.$help_links = this.$done_state.find('.help-links');
+
+ if(this.done_state_title) {
+ $("" + this.done_state_title + "").appendTo(this.$done_state_title);
+ this.$done_state_title.on('click', () => {
+ frappe.set_route(this.done_state_title_route);
+ });
+ }
+
+ if(this.help_links) {
+ this.help_links.map(link => {
+ let $link = $(`${link.label}`);
+ if(link.url) {
+ $link.attr({"href": link.url});
+ } else if(link.video_id) {
+ $link.on('click', () => {
+ frappe.help.show_video(link.video_id, link.label);
+ })
+ }
+ this.$help_links.append($link);
+ });
+ }
+
+ }
+
+ before_show() {
+ if(this.done) {
+ this.slides_footer.find('.next-btn').addClass('btn-primary');
+ this.slides_footer.find('.done-btn').hide();
+ } else {
+ this.slides_footer.find('.next-btn').removeClass('btn-primary');
+ this.slides_footer.find('.done-btn').show();
+ }
+ if(this.dialog_dismissed) {
+ this.slides_footer.find('.next-btn').removeClass('btn-primary');
+ }
+ }
+
+ primary_action() {
+ var me = this;
+ if(this.set_values()) {
+ this.slides_footer.find('.make-btn').addClass('disabled');
+ frappe.call({
+ method: me.submit_method,
+ args: {args_data: me.values},
+ callback: function() {
+ me.done = 1;
+ me.refresh();
+ },
+ onerror: function() {
+ me.slides_footer.find('.make-btn').removeClass('disabled');
+ },
+ freeze: true
+ });
+ }
+ }
+};
+
+frappe.setup.UserProgressDialog = class UserProgressDialog {
+ constructor({
+ slides = []
+ }) {
+ this.slides = slides;
+ this.progress_state_dict = {};
+ this.slides.map(slide => {
+ this.progress_state_dict[slide.action_name] = slide.done || 0;
+ });
+ this.progress_percent = 0;
+ this.setup();
+ }
+
+ setup() {
+ this.dialog = new frappe.ui.Dialog({title: __("Complete Setup")});
+ this.$wrapper = $(this.dialog.$wrapper).addClass('user-progress-dialog');
+ this.slide_container = new frappe.ui.Slides({
+ parent: this.dialog.body,
+ slides: this.slides,
+ slide_class: frappe.setup.UserProgressSlide,
+ done_state: 1,
+ before_load: ($footer) => {
+ $footer.find('.text-right')
+ .prepend($(`
+ ${__("Mark as Done")}`))
+ .prepend($(`
+ ${__("Create")}`));
+ },
+ on_update: (completed, total) => {
+ let percent = completed * 100 / total;
+ $('.user-progress .progress-bar').css({'width': percent + '%'});
+ if(percent === 100) {
+ this.dismiss_progress();
+ }
+ }
+ });
+
+ this.$wrapper.find('.done-btn').on('click', () => {
+ this.mark_as_done();
+ });
+
+ this.get_and_update_progress_state();
+ this.check_for_updates();
+ }
+
+ mark_as_done() {
+ let me = this;
+ let current_slide = this.slide_container.current_slide;
+ frappe.call({
+ method: current_slide.mark_as_done_method,
+ args: {action_name: current_slide.action_name},
+ callback: function() {
+ current_slide.done = 1;
+ current_slide.refresh();
+ },
+ freeze: true
+ });
+ }
+
+ check_for_updates() {
+ this.updater = setInterval(() => {
+ this.get_and_update_progress_state();
+ }, 60000);
+ }
+
+ get_and_update_progress_state() {
+ var me = this;
+ frappe.call({
+ method: "frappe.desk.user_progress.update_and_get_user_progress",
+ callback: function(r) {
+ // console.log("states", r.message);
+ let states = r.message;
+ let changed = 0;
+ let completed = 0;
+ Object.keys(states).map(action_name => {
+ if(states[action_name]) {
+ completed ++;
+ }
+ if(me.progress_state_dict[action_name] != states[action_name]) {
+ changed = 1;
+ me.progress_state_dict[action_name] = states[action_name];
+ }
+ });
+
+ if(changed) {
+ Object.keys(me.slide_container.slide_dict).map((id) => {
+ let slide = me.slide_container.slide_dict[id];
+ if(me.progress_state_dict[slide.action_name]) {
+ if(!slide.done) {
+ slide.done = 1;
+ slide.refresh();
+ }
+ }
+ });
+
+ }
+ me.progress_percent = completed / Object.keys(states).length * 100;
+ me.update_progress();
+ },
+ freeze: false
+ });
+ }
+
+ update_progress() {
+ $('.user-progress .progress-bar').css({'width': this.progress_percent + '%'});
+ if(this.progress_percent === 100) {
+ this.dismiss_progress();
+ }
+ }
+
+ dismiss_progress() {
+ $('.user-progress').addClass('hide');
+ clearInterval(this.updater);
+ }
+
+ show() {
+ this.dialog.show();
+ }
+};
diff --git a/frappe/public/less/desk.less b/frappe/public/less/desk.less
index 9df1cab483..7272ff955f 100644
--- a/frappe/public/less/desk.less
+++ b/frappe/public/less/desk.less
@@ -246,7 +246,7 @@ textarea.form-control {
}
@media (min-width: 768px) {
- .video-modal {
+ .video-modal .modal-dialog {
width: 700px;
}
}
@@ -333,7 +333,7 @@ textarea.form-control {
a.progress-small {
.progress-chart {
- width: 60px;
+ width: 40px;
margin-top: 4px;
float: right;
}
@@ -343,6 +343,25 @@ a.progress-small {
}
.progress-bar {
+ transition: unset;
+ background-color: #98d85b;
+ }
+}
+
+li.user-progress {
+ .progress-chart {
+ width: 60px;
+ margin-top: 8px;
+ }
+
+ .progress {
+ margin-bottom: 0;
+ background-color: #fff;
+ border: 1px solid #e5e7e9;
+ }
+
+ .progress-bar {
+ transition: unset;
background-color: #98d85b;
}
}
@@ -1005,3 +1024,92 @@ input[type="checkbox"] {
}
}
+
+// Slides
+.slides-wrapper {
+ .fa-circle {
+ font-size: 10px;
+ margin: 0px 2px;
+ &.active {
+ color: #5e64ff;
+ }
+ &.link {
+ cursor: pointer;
+ }
+ }
+ .form {
+ margin-top: 30px;
+ .form-layout {
+ margin-top: 0px;
+ margin-bottom: 0px;
+ }
+ .form-section {
+ padding: 0px 7px;
+ border: none;
+ }
+ }
+ .add-more {
+ margin-bottom: 30px;
+ }
+ .lead {
+ margin-top: 20px;
+ }
+ .success-state {
+ margin-bottom: 20px;
+ }
+ .next-steps-links {
+ .title {
+ text-transform: uppercase;
+ color: #8D99A6;
+ font-size: 11px;
+ }
+
+ }
+ .btn-primary {
+ font-weight: bold;
+ }
+ .footer {
+ margin-top: 15px;
+ padding: 0px 7px;
+
+ .btn:not(:last-child) {
+ margin-right: 3px;
+ }
+
+ a.btn.make-btn {
+ margin-right: 7px;
+ }
+
+ a.make-btn.disabled {
+ background-color: #b1bdca;
+ color: #fff;
+ border-color: #b1bdca;
+ }
+ }
+}
+
+// User Progress Dialog
+.user-progress-dialog {
+ .slides-progress {
+ margin-top: 15px;
+ }
+
+ .done-state {
+ .check-container {
+ font-size: 64px;
+ margin: 40px;
+ }
+
+ .title {
+ font-weight: normal;
+ }
+
+ .help-links {
+
+ a {
+ margin: 0px 10px;
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/frappe/public/less/page.less b/frappe/public/less/page.less
index 5dc338d3ec..d768926525 100644
--- a/frappe/public/less/page.less
+++ b/frappe/public/less/page.less
@@ -187,3 +187,226 @@ select.input-sm {
font-size: 18px;
}
}
+
+#page-setup-wizard {
+ margin-top: 30px;
+}
+.setup-wizard-slide {
+ padding-left: 0px;
+ padding-right: 0px;
+
+ .slides-progress {
+ margin-top: 20px;
+ }
+
+ .lead {
+ margin: 30px;
+ color: #777777;
+ text-align: center;
+ font-size: 24px;
+ }
+
+ .col-sm-12 {
+ padding: 0px;
+ }
+
+ .section-body .col-sm-6 {
+ &:first-child {
+ padding-left: 0px;
+ }
+ &:last-child {
+ padding-right: 0px;
+ }
+ }
+
+ .form-control {
+ font-weight: 500;
+ }
+
+ .form-control.bold {
+ background-color: #fff;
+ }
+
+ .add-more {
+ margin: 0px;
+ }
+
+ .footer {
+ padding: 30px 7px;
+ }
+
+ a.next-btn.disabled {
+ background-color: #b1bdca;
+ color: #fff;
+ border-color: #b1bdca;
+ }
+
+ a.complete-btn.disabled {
+ background-color: #b1bdca;
+ color: #fff;
+ border-color: #b1bdca;
+ }
+
+ .fa-fw {
+ vertical-align: middle;
+ font-size: 10px;
+ }
+
+ .fa-fw.active {
+ color: #5e64ff;
+ }
+
+ .icon-circle-blank {
+ font-size: 7px;
+ }
+
+ .icon-circle {
+ font-size: 10px;
+ }
+
+ .frappe-control[data-fieldtype="Attach Image"] {
+ width: 140px;
+ height: 180px;
+ margin-top: 20px;
+ .form-group {
+ display: none;
+ }
+ .clearfix {
+ display: none;
+ }
+ }
+ }
+
+ .missing-image {
+ display: block;
+ position: relative;
+ border-radius: 4px;
+ border: 1px solid #d1d8dd;
+ border-radius: 6px;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+ .octicon {
+ position: relative;
+ top: 50%;
+ transform: translate(0px, -50%);
+ -webkit-transform: translate(0px, -50%);
+ }
+ }
+
+ .attach-image-display {
+ display: block;
+ position: relative;
+ border-radius: 4px;
+ }
+
+ .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);
+ }
+
+ .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;
+ &:hover {
+ opacity: 1;
+ cursor: pointer;
+ }
+ }
+}
+
+.setup-state {
+ background-color: #f5f7fa;
+}
+
+.page-card {
+ max-width: 360px;
+ padding: 15px;
+ margin: 70px auto;
+ border: 1px solid #d1d8dd;
+ border-radius: 4px;
+ background-color: #fff;
+ box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.1);
+
+ .page-card-head {
+ padding: 10px 15px;
+ margin: -15px;
+ margin-bottom: 15px;
+ border-bottom: 1px solid #d1d8dd;
+ }
+}
+
+.state-icon-container {
+ display: flex;
+ justify-content: center;
+}
+
+.state-icon {
+ position: relative;
+ width: 100px !important;
+ height: 100px !important;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+@keyframes lds-rolling {
+ 0% {
+ -webkit-transform: translate(-50%, -50%) rotate(0deg);
+ transform: translate(-50%, -50%) rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: translate(-50%, -50%) rotate(360deg);
+ transform: translate(-50%, -50%) rotate(360deg);
+ }
+}
+@-webkit-keyframes lds-rolling {
+ 0% {
+ -webkit-transform: translate(-50%, -50%) rotate(0deg);
+ transform: translate(-50%, -50%) rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: translate(-50%, -50%) rotate(360deg);
+ transform: translate(-50%, -50%) rotate(360deg);
+ }
+}
+
+.lds-rolling {
+ -webkit-transform: translate(-100px, -100px) scale(1) translate(100px, 100px);
+ transform: translate(-100px, -100px) scale(1) translate(100px, 100px);
+ div {
+ position: absolute;
+ width: 60px;
+ height: 60px;
+ border: 3px solid #d1d8dd;
+ border-top-color: transparent;
+ border-radius: 50%;
+ -webkit-animation: lds-rolling 1s linear infinite;
+ animation: lds-rolling 1s linear infinite;
+ top: 50px;
+ left: 50px;
+ &:after {
+ position: absolute;
+ width: 60px;
+ height: 60px;
+ border: 3px solid #d1d8dd;
+ border-top-color: transparent;
+ border-radius: 50%;
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg);
+ }
+ }
+}
diff --git a/frappe/sessions.py b/frappe/sessions.py
index 0a0f7e04bd..bbb547f3c1 100644
--- a/frappe/sessions.py
+++ b/frappe/sessions.py
@@ -163,6 +163,7 @@ def get():
# check only when clear cache is done, and don't cache this
if frappe.local.request:
bootinfo["change_log"] = get_change_log()
+ bootinfo["is_first_startup"] = cint(frappe.db.get_single_value('System Settings', 'is_first_startup'))
bootinfo["metadata_version"] = frappe.cache().get_value("metadata_version")
if not bootinfo["metadata_version"]:
diff --git a/frappe/test_runner.py b/frappe/test_runner.py
index 9e2610e5d0..4d0b650c37 100644
--- a/frappe/test_runner.py
+++ b/frappe/test_runner.py
@@ -139,6 +139,11 @@ def run_tests_for_module(module, verbose=False, tests=(), profile=False):
return _run_unittest(module=module, verbose=verbose, tests=tests, profile=profile)
+def run_setup_wizard_ui_test(app=None, verbose=False, profile=False):
+ '''Run setup wizard UI test using test_test_runner'''
+ frappe.flags.run_setup_wizard_ui_test = 1
+ return run_ui_tests(app, None, verbose, profile)
+
def run_ui_tests(app=None, test=None, verbose=False, profile=False):
'''Run a single unit test for UI using test_test_runner'''
module = importlib.import_module('frappe.tests.ui.test_test_runner')
diff --git a/frappe/tests/ui/test_test_runner.py b/frappe/tests/ui/test_test_runner.py
index 3c54731fb1..47a6a568e9 100644
--- a/frappe/tests/ui/test_test_runner.py
+++ b/frappe/tests/ui/test_test_runner.py
@@ -4,9 +4,15 @@ import unittest, os, frappe, time
class TestTestRunner(unittest.TestCase):
def test_test_runner(self):
+ if frappe.flags.run_setup_wizard_ui_test:
+ for setup_wizard_test in frappe.get_hooks("setup_wizard_test"):
+ passed = frappe.get_attr(setup_wizard_test)()
+ self.assertTrue(passed)
+ return
+
driver = TestDriver()
- driver.login()
frappe.db.set_default('in_selenium', '1')
+ driver.login()
for test in get_tests():
if test.startswith('#'):
continue
@@ -26,6 +32,7 @@ class TestTestRunner(unittest.TestCase):
driver.set_route('Form', 'Test Runner')
driver.click_primary_action()
driver.wait_for('#frappe-qunit-done', timeout=timeout)
+
console = driver.get_console()
passed = 'Tests Passed' in console
if frappe.flags.tests_verbose or not passed:
@@ -62,4 +69,3 @@ def get_tests_for(app):
with open(tests_path, 'r') as fileobj:
tests = fileobj.read().strip().splitlines()
return tests
-
diff --git a/frappe/utils/selenium_testdriver.py b/frappe/utils/selenium_testdriver.py
index 0f054077bf..2c6a224be7 100644
--- a/frappe/utils/selenium_testdriver.py
+++ b/frappe/utils/selenium_testdriver.py
@@ -87,6 +87,10 @@ class TestDriver(object):
elem = self.find(xpath='//input[@data-fieldname="{0}"]'.format(fieldname))
elem[0].send_keys(text)
+ def set_select(self, fieldname, text):
+ elem = self.find(xpath='//select[@data-fieldname="{0}"]'.format(fieldname))
+ elem[0].send_keys(text)
+
def set_text_editor(self, fieldname, text):
elem = self.find(xpath='//div[@data-fieldname="{0}"]//div[@contenteditable="true"]'.format(fieldname))
elem[0].send_keys(text)
@@ -99,7 +103,7 @@ class TestDriver(object):
selector = self.cur_route + " " + selector
return self.driver.find_elements_by_css_selector(selector)
- def wait_for(self, selector=None, everywhere=False, timeout=20, xpath=None):
+ def wait_for(self, selector=None, everywhere=False, timeout=20, xpath=None, for_invisible=False):
if self.cur_route and not everywhere:
selector = self.cur_route + " " + selector
@@ -112,8 +116,12 @@ class TestDriver(object):
selector = xpath
try:
- elem = self.get_wait(timeout).until(
- EC.presence_of_element_located((_by, selector)))
+ if not for_invisible:
+ elem = self.get_wait(timeout).until(
+ EC.presence_of_element_located((_by, selector)))
+ else:
+ elem = self.get_wait(timeout).until(
+ EC.invisibility_of_element_located((_by, selector)))
return elem
except Exception as e:
# body = self.driver.find_element_by_id('body_div')
@@ -121,6 +129,9 @@ class TestDriver(object):
self.print_console()
raise e
+ def wait_for_invisible(self, selector=None, everywhere=False, timeout=20, xpath=None):
+ self.wait_for(selector, everywhere, timeout, xpath, True)
+
def get_console(self):
out = []
for entry in self.driver.get_log('browser'):
@@ -193,8 +204,11 @@ class TestDriver(object):
def execute_script(self, js):
self.driver.execute_script(js)
- def wait_for_ajax(self):
+ def wait_for_ajax(self, freeze = False):
self.wait_for('body[data-ajax-state="complete"]', True)
+ if freeze:
+ self.wait_for_invisible(".freeze-message-container")
+
# def go_to_module(module_name, item=None):
# global cur_route