@@ -11,7 +11,7 @@ context('Web Form', () => { | |||
cy.get('.modal.show > .modal-dialog').should('be.visible'); | |||
}); | |||
it('Timeline should have submit and cancel activity information', () => { | |||
it('Navigate and Submit a MultiStep WebForm', () => { | |||
cy.call('frappe.tests.ui_test_helpers.update_webform_to_multistep').then(() => { | |||
cy.visit('/update-profile'); | |||
cy.get_field('last_name', 'Data').type('_Test User', {force: true}).wait(200); | |||
@@ -46,14 +46,6 @@ frappe.pages['setup-wizard'].on_page_load = function (wrapper) { | |||
slide_class: frappe.setup.SetupWizardSlide, | |||
unidirectional: 1, | |||
done_state: 1, | |||
before_load: ($footer) => { | |||
$footer.find('.next-btn').removeClass('btn-default') | |||
.addClass('btn-primary'); | |||
$footer.find('.text-right').prepend( | |||
$(`<button class="complete-btn btn btn-sm primary"> | |||
${__("Complete Setup")}</button>`)); | |||
} | |||
} | |||
frappe.wizard = new frappe.setup.SetupWizard(wizard_settings); | |||
frappe.setup.run_event("after_load"); | |||
@@ -97,7 +89,7 @@ frappe.setup.SetupWizard = class SetupWizard extends frappe.ui.Slides { | |||
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'); | |||
this.$complete_btn.addClass('action'); | |||
this.setup_keyboard_nav(); | |||
} | |||
@@ -145,7 +137,6 @@ frappe.setup.SetupWizard = class SetupWizard extends frappe.ui.Slides { | |||
this.$next_btn.removeClass("btn-primary").hide(); | |||
this.$complete_btn.addClass("btn-primary").show() | |||
.on('click', () => this.action_on_complete()); | |||
} else { | |||
this.$next_btn.addClass("btn-primary").show(); | |||
this.$complete_btn.removeClass("btn-primary").hide(); | |||
@@ -178,6 +169,7 @@ frappe.setup.SetupWizard = class SetupWizard extends frappe.ui.Slides { | |||
this.setup(); | |||
this.show_slide(this.current_id); | |||
this.refresh(this.current_id); | |||
setTimeout(() => { | |||
this.container.find('.form-control').first().focus(); | |||
}, 200); | |||
@@ -347,7 +339,6 @@ frappe.setup.SetupWizardSlide = class SetupWizardSlide extends frappe.ui.Slide { | |||
// Frappe slides settings | |||
// ====================================================== | |||
frappe.setup.slides_settings = [ | |||
{ | |||
// Welcome (language) slide | |||
@@ -365,10 +356,10 @@ frappe.setup.slides_settings = [ | |||
onload: function (slide) { | |||
this.setup_fields(slide); | |||
let browser_language = frappe.setup.utils.get_language_name_from_code(navigator.language); | |||
let language_field = slide.get_field("language"); | |||
var language_field = slide.get_field("language"); | |||
language_field.set_input(frappe.setup.data.default_language || "English"); | |||
language_field.set_input(browser_language || "English"); | |||
if (!frappe.setup._from_load_messages) { | |||
language_field.$input.trigger("change"); | |||
@@ -532,12 +523,18 @@ frappe.setup.utils = { | |||
/* | |||
Set a slide's country, timezone and currency fields | |||
*/ | |||
var data = frappe.setup.data.regional_data; | |||
var country_field = slide.get_field('country'); | |||
let data = frappe.setup.data.regional_data; | |||
let country_field = slide.get_field('country'); | |||
let translated_countries = []; | |||
Object.keys(data.country_info).sort().forEach(country => { | |||
translated_countries.push({ | |||
label: __(country), | |||
value: country | |||
}); | |||
}); | |||
country_field.set_data(Object.keys(data.country_info).sort()); | |||
country_field.set_data(translated_countries); | |||
slide.get_input("currency") | |||
.empty() | |||
@@ -584,6 +581,10 @@ frappe.setup.utils = { | |||
}); | |||
}, | |||
get_language_name_from_code: function (language_code) { | |||
return frappe.setup.data.lang.codes_to_names[language_code] || "English"; | |||
}, | |||
bind_region_events: function (slide) { | |||
/* | |||
Bind a slide's country, timezone and currency fields | |||
@@ -190,7 +190,7 @@ class Document(BaseDocument): | |||
:param permtype: one of `read`, `write`, `submit`, `cancel`, `delete`""" | |||
if self.flags.ignore_permissions: | |||
return True | |||
return frappe.has_permission(self.doctype, permtype, self, verbose=verbose) | |||
return frappe.permissions.has_permission(self.doctype, permtype, self, verbose=verbose) | |||
def raise_no_permission_to(self, perm_type): | |||
"""Raise `frappe.PermissionError`.""" | |||
@@ -456,6 +456,8 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat | |||
this.docname, value); | |||
} | |||
validate_link_and_fetch(df, options, docname, value) { | |||
if (!options) return; | |||
let field_value = ""; | |||
const fetch_map = this.fetch_map; | |||
const columns_to_fetch = Object.values(fetch_map); | |||
@@ -21,7 +21,7 @@ frappe.ui.Slide = class Slide { | |||
this.$body = $(`<div class="slide-body"> | |||
<div class="content text-center"> | |||
<h1 class="title slide-title">${this.title}</h1> | |||
<h1 class="title slide-title">${__(this.title)}</h1> | |||
</div> | |||
<div class="form-wrapper"> | |||
<div class="form"></div> | |||
@@ -40,7 +40,7 @@ frappe.ui.Slide = class Slide { | |||
if (this.image_src) this.$content.append( | |||
$(`<img src="${this.image_src}" style="margin: 20px;">`)); | |||
if (this.help) this.$content.append($(`<p class="slide-help">${this.help}</p>`)); | |||
if (this.help) this.$content.append($(`<p class="slide-help">${__(this.help)}</p>`)); | |||
this.reqd_fields = []; | |||
@@ -263,7 +263,7 @@ frappe.ui.Slides = class Slides { | |||
.appendTo(this.container); | |||
this.render_progress_dots(); | |||
this.make_prev_next_buttons(); | |||
this.make_prev_next_complete_buttons(); | |||
if (this.before_load) this.before_load(this.$footer); | |||
// can be on demand | |||
@@ -289,6 +289,7 @@ frappe.ui.Slides = class Slides { | |||
} | |||
} else { | |||
if (this.made_slide_ids.includes(id + "")) { | |||
this.slide_dict[id].done = false; | |||
this.slide_dict[id].destroy(); | |||
this.slide_dict[id].make(); | |||
} | |||
@@ -298,6 +299,7 @@ frappe.ui.Slides = class Slides { | |||
refresh(id) { | |||
this.render_progress_dots(); | |||
this.make_prev_next_complete_buttons(); | |||
this.show_hide_prev_next(id); | |||
this.$body.find('.form-control').first().focus(); | |||
} | |||
@@ -338,13 +340,16 @@ frappe.ui.Slides = class Slides { | |||
if (!this.unidirectional) this.bind_progress_dots(); | |||
} | |||
make_prev_next_buttons() { | |||
make_prev_next_complete_buttons() { | |||
this.$footer.empty(); | |||
$(`<div class="row"> | |||
<div class="col-sm-4 text-left prev-div"> | |||
<button class="prev-btn btn btn-secondary btn-sm" tabindex="0">${__("Previous")}</button> | |||
<button class="prev-btn btn btn-secondary btn-sm" tabindex="0">${__("Previous", null, "Go to previous slide")}</button> | |||
</div> | |||
<div class="col-sm-8 text-right next-div"> | |||
<button class="next-btn btn btn-default btn-sm" tabindex="0">${__("Next")}</button> | |||
<button class="complete-btn btn btn-sm primary">${__("Complete Setup", null, "Finish the setup wizard")}</button> | |||
<button class="next-btn btn btn-default btn-sm" tabindex="0">${__("Next", null, "Go to next slide")}</button> | |||
</div> | |||
</div>`).appendTo(this.$footer); | |||
@@ -361,6 +366,8 @@ frappe.ui.Slides = class Slides { | |||
this.show_slide(this.current_id + 1); | |||
} | |||
}); | |||
this.$complete_btn = this.$footer.find('.complete-btn').attr('tabIndex', 0); | |||
} | |||
bind_progress_dots() { | |||
@@ -90,8 +90,8 @@ export default class WebForm extends frappe.ui.FieldGroup { | |||
if (!is_validated) return; | |||
/* | |||
eslint cannot figure out if this is an infinite loop in backwards and | |||
/** | |||
The eslint utility cannot figure out if this is an infinite loop in backwards and | |||
throws an error. Disabling for-direction just for this section. | |||
for-direction doesnt throw an error if the values are hardcoded in the | |||
reverse for-loop, but in this case its a dynamic loop. | |||
@@ -474,6 +474,24 @@ class TestCommands(BaseTestCommands): | |||
# cleanup | |||
shutil.rmtree(test_app_path) | |||
def disable_test_bench_drop_site_should_archive_site(self): | |||
site = 'test_site.localhost' | |||
self.execute( | |||
f"bench new-site {site} --force --verbose --admin-password {frappe.conf.admin_password} " | |||
f"--mariadb-root-password {frappe.conf.root_password}" | |||
) | |||
self.assertEqual(self.returncode, 0) | |||
self.execute(f"bench drop-site {site} --force --root-password {frappe.conf.root_password}") | |||
self.assertEqual(self.returncode, 0) | |||
bench_path = frappe.utils.get_bench_path() | |||
site_directory = os.path.join(bench_path, f'sites/{site}') | |||
self.assertFalse(os.path.exists(site_directory)) | |||
archive_directory = os.path.join(bench_path, f'archived/sites/{site}') | |||
self.assertTrue(os.path.exists(archive_directory)) | |||
class RemoveAppUnitTests(unittest.TestCase): | |||
def test_delete_modules(self): | |||