From 81133888a8c285a607be4feac06a8b64e0a64d5b Mon Sep 17 00:00:00 2001 From: Manas Solanki Date: Fri, 21 Jul 2017 11:05:54 +0530 Subject: [PATCH 01/17] [fix] add the parsed email id for the email group member (#3741) * add the parsed email id of the email group member * Minor fixe in the patch --- .../email/doctype/email_group/email_group.py | 8 ++++---- frappe/patches.txt | 3 ++- frappe/patches/v8_5/__init__.py | 0 ..._email_group_member_with_invalid_emails.py | 20 +++++++++++++++++++ 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 frappe/patches/v8_5/__init__.py create mode 100644 frappe/patches/v8_5/delete_email_group_member_with_invalid_emails.py diff --git a/frappe/email/doctype/email_group/email_group.py b/frappe/email/doctype/email_group/email_group.py index d74570d0aa..ed4ab32fed 100755 --- a/frappe/email/doctype/email_group/email_group.py +++ b/frappe/email/doctype/email_group/email_group.py @@ -69,15 +69,15 @@ def add_subscribers(name, email_list): count = 0 for email in email_list: email = email.strip() - valid = validate_email_add(email, False) + parsed_email = validate_email_add(email, False) - if valid: + if parsed_email: if not frappe.db.get_value("Email Group Member", - {"email_group": name, "email": email}): + {"email_group": name, "email": parsed_email}): frappe.get_doc({ "doctype": "Email Group Member", "email_group": name, - "email": email + "email": parsed_email }).insert(ignore_permissions = frappe.flags.ignore_permissions) count += 1 diff --git a/frappe/patches.txt b/frappe/patches.txt index 564c73c002..8adf636701 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -187,4 +187,5 @@ frappe.patches.v8_0.update_gender_and_salutation execute:frappe.db.sql('update tabReport set module="Desk" where name="ToDo"') frappe.patches.v8_1.enable_allow_error_traceback_in_system_settings frappe.patches.v8_1.update_format_options_in_auto_email_report -frappe.patches.v8_1.delete_custom_docperm_if_doctype_not_exists \ No newline at end of file +frappe.patches.v8_1.delete_custom_docperm_if_doctype_not_exists +frappe.patches.v8_5.delete_email_group_member_with_invalid_emails diff --git a/frappe/patches/v8_5/__init__.py b/frappe/patches/v8_5/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/patches/v8_5/delete_email_group_member_with_invalid_emails.py b/frappe/patches/v8_5/delete_email_group_member_with_invalid_emails.py new file mode 100644 index 0000000000..e74f1be4ff --- /dev/null +++ b/frappe/patches/v8_5/delete_email_group_member_with_invalid_emails.py @@ -0,0 +1,20 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils import validate_email_add + +def execute(): + ''' update/delete the email group member with the wrong email ''' + + email_group_members = frappe.get_all("Email Group Member", fields=["name", "email"]) + for member in email_group_members: + validated_email = validate_email_add(member.email) + if (validated_email==member.email): + pass + else: + try: + frappe.db.set_value("Email Group Member", member.name, "email", validated_email) + except Exception: + frappe.delete_doc(doctype="Email Group Member", name=member.name, force=1, ignore_permissions=True) \ No newline at end of file From 269c10ff1242df7c14421cfd4fc035a7db58e3b2 Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Mon, 24 Jul 2017 11:23:49 +0530 Subject: [PATCH 02/17] [minor] fix goal label position (#3755) --- frappe/public/js/frappe/ui/graph.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/ui/graph.js b/frappe/public/js/frappe/ui/graph.js index eb7d4c63d4..2347f13b0d 100644 --- a/frappe/public/js/frappe/ui/graph.js +++ b/frappe/public/js/frappe/ui/graph.js @@ -142,10 +142,10 @@ frappe.ui.Graph = class Graph { show_specific_values() { this.specific_values.map(d => { this.specific_y_lines.add(this.snap.g( - this.snap.line(0, 0, this.width - 50, 0).attr({ + this.snap.line(0, 0, this.width - 70, 0).attr({ class: d.line_type === "dashed" ? "dashed": "" }), - this.snap.text(this.width - 100, 0, d.name.toUpperCase()).attr({ + this.snap.text(this.width - 95, 0, d.name.toUpperCase()).attr({ dy: ".32em", class: "specific-value", }) From 0fa951f89390c7abd4cd7d7b5e83add52e4da087 Mon Sep 17 00:00:00 2001 From: Revant Nandgaonkar Date: Mon, 24 Jul 2017 11:25:05 +0530 Subject: [PATCH 03/17] Oauth2 tests (#3756) * Test for oauth2 test_authorize_guest_redirect * fix test oauth2 * [Fix] using py requests instead of werkzeug test client * [Fix] https://www.codacy.com/app/frappe/frappe/pullRequest?prid=788942 * Test OAuth 2 Authorization Code Bearer Token flow * [Fix] https://www.codacy.com/app/frappe/frappe/pullRequest?prid=788942 --- .../doctype/oauth_client/test_records.json | 16 ++++ frappe/tests/ui/test_oauth20.py | 76 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 frappe/integrations/doctype/oauth_client/test_records.json create mode 100644 frappe/tests/ui/test_oauth20.py diff --git a/frappe/integrations/doctype/oauth_client/test_records.json b/frappe/integrations/doctype/oauth_client/test_records.json new file mode 100644 index 0000000000..904d959625 --- /dev/null +++ b/frappe/integrations/doctype/oauth_client/test_records.json @@ -0,0 +1,16 @@ +[ + { + "app_name": "_Test OAuth Client", + "client_id": "test_client_id", + "client_secret": "test_client_secret", + "default_redirect_uri": "http://localhost", + "docstatus": 0, + "doctype": "OAuth Client", + "grant_type": "Authorization Code", + "name": "test_client_id", + "redirect_uris": "http://localhost", + "response_type": "Code", + "scopes": "all openid", + "skip_authorization": 0 + } +] diff --git a/frappe/tests/ui/test_oauth20.py b/frappe/tests/ui/test_oauth20.py new file mode 100644 index 0000000000..54d3223f8c --- /dev/null +++ b/frappe/tests/ui/test_oauth20.py @@ -0,0 +1,76 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt +from __future__ import unicode_literals + +import unittest, frappe, requests, time +from frappe.test_runner import make_test_records +from frappe.utils.selenium_testdriver import TestDriver + +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse + +class TestOAuth20(unittest.TestCase): + def setUp(self): + self.driver = TestDriver() + make_test_records("OAuth Client") + make_test_records("User") + self.client_id = frappe.get_all("OAuth Client", fields=["*"])[0].get("client_id") + + # Set Frappe server URL reqired for id_token generation + frappe.db.set_value("Social Login Keys", None, "frappe_server_url", "http://localhost:8000") + frappe.db.commit() + + def test_login_to_authorize_url(self): + + # Go to Authorize url + self.driver.get( + "api/method/frappe.integrations.oauth2.authorize?client_id=" + + self.client_id + + "&scope=all%20openid&response_type=code&redirect_uri=http%3A%2F%2Flocalhost" + ) + + time.sleep(2) + + # Login + username = self.driver.find("#login_email")[0] + username.send_keys("test@example.com") + + password = self.driver.find("#login_password")[0] + password.send_keys("Eastern_43A1W") + + sign_in = self.driver.find(".btn-login")[0] + sign_in.submit() + + time.sleep(2) + + # Allow access to resource + allow = self.driver.find("#allow")[0] + allow.click() + + time.sleep(2) + + # Get authorization code from redirected URL + auth_code = urlparse(self.driver.driver.current_url).query.split("=")[1] + + payload = "grant_type=authorization_code&code=" + payload += auth_code + payload += "&redirect_uri=http%3A%2F%2Flocalhost&client_id=" + payload += self.client_id + + headers = {'content-type':'application/x-www-form-urlencoded'} + + # Request for bearer token + token_response = requests.post( frappe.get_site_config().host_name + + "/api/method/frappe.integrations.oauth2.get_token", data=payload, headers=headers) + + # Parse bearer token json + bearer_token = token_response.json() + + self.assertTrue(bearer_token.get("access_token")) + self.assertTrue(bearer_token.get("expires_in")) + self.assertTrue(bearer_token.get("id_token")) + self.assertTrue(bearer_token.get("refresh_token")) + self.assertTrue(bearer_token.get("scope")) + self.assertTrue(bearer_token.get("token_type") == "Bearer") From 993692ba32b348359ee88217e14be818b65e4168 Mon Sep 17 00:00:00 2001 From: tundebabzy Date: Mon, 24 Jul 2017 06:57:59 +0100 Subject: [PATCH 04/17] Issue changing 'Unique' field option in v8 (#3760) * fix wrong query * test unique constraint removal --- frappe/core/doctype/doctype/test_doctype.py | 31 +++++++++++++++++++-- frappe/model/db_schema.py | 2 +- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/frappe/core/doctype/doctype/test_doctype.py b/frappe/core/doctype/doctype/test_doctype.py index 678e52451a..6a0794c7a1 100644 --- a/frappe/core/doctype/doctype/test_doctype.py +++ b/frappe/core/doctype/doctype/test_doctype.py @@ -8,13 +8,14 @@ import unittest # test_records = frappe.get_test_records('DocType') + class TestDocType(unittest.TestCase): - def new_doctype(self, name): + def new_doctype(self, name, unique=0): return frappe.get_doc({ "doctype": "DocType", "module": "Core", "custom": 1, - "fields": [{"label": "Some Field", "fieldname": "some_fieldname", "fieldtype": "Data"}], + "fields": [{"label": "Some Field", "fieldname": "some_fieldname", "fieldtype": "Data", "unique": unique}], "permissions": [{"role": "System Manager", "read": 1}], "name": name }) @@ -28,4 +29,28 @@ class TestDocType(unittest.TestCase): frappe.delete_doc("DocType", name) doc = self.new_doctype(name).insert() - doc.delete() \ No newline at end of file + doc.delete() + + def test_doctype_unique_constraint_dropped(self): + if frappe.db.exists("DocType", "With_Unique"): + frappe.delete_doc("DocType", "With_Unique") + + dt = self.new_doctype("With_Unique", unique=1) + dt.insert() + + doc1 = frappe.new_doc("With_Unique") + doc2 = frappe.new_doc("With_Unique") + doc1.some_fieldname = "Something" + doc1.name = "one" + doc2.some_fieldname = "Something" + doc2.name = "two" + + doc1.insert() + self.assertRaises(frappe.UniqueValidationError, doc2.insert) + + dt.fields[0].unique = 0 + dt.save() + + doc2.insert() + doc1.delete() + doc2.delete() diff --git a/frappe/model/db_schema.py b/frappe/model/db_schema.py index a99a783e1f..01725e12a6 100644 --- a/frappe/model/db_schema.py +++ b/frappe/model/db_schema.py @@ -314,7 +314,7 @@ class DbTable: # if index key exists if frappe.db.sql("""show index from `{0}` where key_name=%s - and Non_unique=%s""".format(self.name), (col.fieldname, 0 if col.unique else 1)): + and Non_unique=%s""".format(self.name), (col.fieldname, col.unique)): query.append("drop index `{}`".format(col.fieldname)) for col in self.set_default: From 998e207a34e33575fd1ccaa03f4cac9c3deb94b9 Mon Sep 17 00:00:00 2001 From: Britlog Date: Mon, 24 Jul 2017 08:11:18 +0200 Subject: [PATCH 05/17] Show footer on login page (#3762) --- frappe/templates/includes/login/login.css | 9 ++++++++- frappe/templates/includes/login/login.js | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/frappe/templates/includes/login/login.css b/frappe/templates/includes/login/login.css index 0f5c1ece24..8c656046fb 100644 --- a/frappe/templates/includes/login/login.css +++ b/frappe/templates/includes/login/login.css @@ -26,8 +26,15 @@ background-color: #7575ff; } +.for-login { + display: none; +} + +.for-forgot { + display: none; +} -section { +.for-signup { display: none; } diff --git a/frappe/templates/includes/login/login.js b/frappe/templates/includes/login/login.js index 249487333e..88eb76daf2 100644 --- a/frappe/templates/includes/login/login.js +++ b/frappe/templates/includes/login/login.js @@ -77,7 +77,9 @@ login.route = function() { login.reset_sections = function(hide) { if(hide || hide===undefined) { - $("section").toggle(false); + $("section.for-login").toggle(false); + $("section.for-forgot").toggle(false); + $("section.for-signup").toggle(false); } $('section .indicator').each(function() { $(this).removeClass().addClass('indicator').addClass('blue') From 42e085ca4c613a314788b65370b5d82f16804aaa Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 24 Jul 2017 11:42:34 +0530 Subject: [PATCH 06/17] [refactor] control.js set_disp_area (#3699) --- frappe/public/js/frappe/form/control.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index aacdda239c..83e8022f52 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -318,7 +318,7 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({ } else { $(me.input_area).toggle(false); if (me.disp_area) { - me.set_disp_area(); + me.set_disp_area(me.value); $(me.disp_area).toggle(true); } } @@ -332,8 +332,7 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({ } }, - set_disp_area: function() { - let value = this.get_input_value(); + set_disp_area: function(value) { if(in_list(["Currency", "Int", "Float"], this.df.fieldtype) && (this.value === 0 || value === 0)) { // to set the 0 value in readonly for currency, int, float field @@ -449,7 +448,7 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({ this.last_value = this.value; this.value = value; this.set_formatted_input(value); - this.set_disp_area(); + this.set_disp_area(value); this.set_mandatory && this.set_mandatory(value); }, set_formatted_input: function(value) { @@ -903,11 +902,12 @@ frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({ this.value = value; } if (this.value) { - this.$input && this.$input.val(this.format_for_input(this.value[0], this.value[1])); + let formatted = this.format_for_input(this.value[0], this.value[1]); + this.$input && this.$input.val(formatted); } else { this.$input && this.$input.val(""); } - this.set_disp_area(); + this.set_disp_area(value || ''); this.set_mandatory && this.set_mandatory(value); }, parse: function(value) { @@ -984,7 +984,7 @@ frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({ } this.last_value = value; this.set_mandatory(value); - this.set_disp_area(); + this.set_disp_area(value); } }); From 1549b9aa772e486120e94f7b929ddc4c85383b1f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 25 Jul 2017 10:55:02 +0530 Subject: [PATCH 07/17] Font size 12px (#3771) --- frappe/templates/emails/auto_email_report.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/templates/emails/auto_email_report.html b/frappe/templates/emails/auto_email_report.html index d4bea7c70e..035c3f40ee 100644 --- a/frappe/templates/emails/auto_email_report.html +++ b/frappe/templates/emails/auto_email_report.html @@ -15,7 +15,7 @@ {% endif %} {% if data %} - +
{% for col in columns %} From e540eabdd08920e958489e25c63317a1a6124e85 Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Tue, 25 Jul 2017 10:55:28 +0530 Subject: [PATCH 08/17] [fix] notif translations fixes frappe/erpnext#10054 (#3773) --- frappe/public/js/frappe/ui/toolbar/notifications.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/ui/toolbar/notifications.js b/frappe/public/js/frappe/ui/toolbar/notifications.js index 00149224cd..0a879f8206 100644 --- a/frappe/public/js/frappe/ui/toolbar/notifications.js +++ b/frappe/public/js/frappe/ui/toolbar/notifications.js @@ -67,11 +67,11 @@ frappe.ui.notifications = { add_notification: function(name, value, doc_dt, target = false) { let label = this.config[name] ? this.config[name].label : name; let $list_item = !target - ? $(`
  • ${label} + ? $(`
  • ${__(label)} ${value}
  • `) : $(`
  • ${label} + data-doc="${name}">${__(label)}
    From 3dfdbb4230c01024af3ad11efb1ffc91081a059e Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 25 Jul 2017 10:58:36 +0530 Subject: [PATCH 09/17] Set date according to system timezone (#3770) - Show timezone as description if different from system timezone - cleanup datetime.js --- frappe/public/js/frappe/form/control.js | 102 ++++++++++++++--------- frappe/public/js/frappe/misc/datetime.js | 80 ++++++++++++++---- 2 files changed, 127 insertions(+), 55 deletions(-) diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index 83e8022f52..6a85c24c2f 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -751,29 +751,38 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({ if(!$.fn.datepicker.language[lang]) { lang = 'en'; } + this.today_text = __("Today"); this.datepicker_options = { language: lang, autoClose: true, - todayButton: new Date(), + todayButton: frappe.datetime.now_date(true), dateFormat: (frappe.boot.sysdefaults.date_format || 'yyyy-mm-dd'), - onSelect: function(dateStr) { - me.$input.trigger('change'); + startDate: frappe.datetime.now_date(true), + onSelect: () => { + this.$input.trigger('change'); }, - onShow: function() { - $('.datepicker--button:visible').text(__('Today')); - - if(!me.frm) return; - var window_height = $(window).height(); - var window_scroll_top = $(window).scrollTop(); - var el_offset_top = me.$input.offset().top + 280; - var position = 'top left'; - if(window_height + window_scroll_top >= el_offset_top) { - position = 'bottom left'; - } - me.datepicker.update('position', position); + onShow: () => { + this.datepicker.$datepicker + .find('.datepicker--button:visible') + .text(me.today_text); + + this.update_datepicker_position(); } }; }, + update_datepicker_position: function() { + if(!this.frm) return; + // show datepicker above or below the input + // based on scroll position + var window_height = $(window).height(); + var window_scroll_top = $(window).scrollTop(); + var el_offset_top = this.$input.offset().top + 280; + var position = 'top left'; + if(window_height + window_scroll_top >= el_offset_top) { + position = 'bottom left'; + } + this.datepicker.update('position', position); + }, set_datepicker: function() { this.$input.datepicker(this.datepicker_options); this.datepicker = this.$input.data('datepicker'); @@ -813,6 +822,30 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({ } }); +frappe.ui.form.ControlDatetime = frappe.ui.form.ControlDate.extend({ + set_date_options: function() { + this._super(); + this.today_text = __("Now"); + $.extend(this.datepicker_options, { + timepicker: true, + timeFormat: "hh:ii:ss", + todayButton: frappe.datetime.now_datetime(true) + }); + }, + set_description: function() { + const { description } = this.df; + const { time_zone } = frappe.sys_defaults; + if (!frappe.datetime.is_timezone_same()) { + if (!description) { + this.df.description = time_zone; + } else if (!description.includes(time_zone)) { + this.df.description += '
    ' + time_zone; + } + } + this._super(); + } +}); + frappe.ui.form.ControlTime = frappe.ui.form.ControlData.extend({ make_input: function() { var me = this; @@ -822,13 +855,14 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlData.extend({ timepicker: true, onlyTimepicker: true, timeFormat: "hh:ii:ss", + startDate: frappe.datetime.now_time(true), onSelect: function() { me.$input.trigger('change'); }, onShow: function() { $('.datepicker--button:visible').text(__('Now')); }, - todayButton: new Date() + todayButton: frappe.datetime.now_time(true) }); this.datepicker = this.$input.data('datepicker'); this.refresh(); @@ -839,33 +873,21 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlData.extend({ && ((this.last_value && this.last_value !== this.value) || (!this.datepicker.selectedDates.length))) { - this.datepicker.selectDate(moment(value, 'hh:mm:ss')._d); + var date_obj = frappe.datetime.moment_to_date_obj(moment(value, 'hh:mm:ss')); + this.datepicker.selectDate(date_obj); } }, -}); - -frappe.ui.form.ControlDatetime = frappe.ui.form.ControlDate.extend({ - set_date_options: function() { - this._super(); - this.datepicker_options.timepicker = true; - this.datepicker_options.timeFormat = "hh:ii:ss"; - this.datepicker_options.onShow = function() { - $('.datepicker--button:visible').text(__('Now')); - }; - }, - parse: function(value) { - if(value) { - // parse and convert - value = frappe.datetime.convert_to_system_tz(frappe.datetime.user_to_str(value)); - } - return value; - }, - format_for_input: function(value) { - if(value) { - // convert and format - value = frappe.datetime.str_to_user(frappe.datetime.convert_to_user_tz(value)); + set_description: function() { + const { description } = this.df; + const { time_zone } = frappe.sys_defaults; + if (!frappe.datetime.is_timezone_same()) { + if (!description) { + this.df.description = time_zone; + } else if (!description.includes(time_zone)) { + this.df.description += '
    ' + time_zone; + } } - return value || ""; + this._super(); } }); diff --git a/frappe/public/js/frappe/misc/datetime.js b/frappe/public/js/frappe/misc/datetime.js index 25d409524d..1e49848c38 100644 --- a/frappe/public/js/frappe/misc/datetime.js +++ b/frappe/public/js/frappe/misc/datetime.js @@ -3,8 +3,11 @@ frappe.provide('frappe.datetime'); -moment.defaultFormat = "YYYY-MM-DD"; -moment.defaultDatetimeFormat = "YYYY-MM-DD HH:mm:ss" +moment.defaultDateFormat = "YYYY-MM-DD"; +moment.defaultTimeFormat = "HH:mm:ss"; +moment.defaultDatetimeFormat = moment.defaultDateFormat + " " + moment.defaultTimeFormat; +moment.defaultFormat = moment.defaultDateFormat; + frappe.provide("frappe.datetime"); $.extend(frappe.datetime, { @@ -91,8 +94,14 @@ $.extend(frappe.datetime, { return frappe.sys_defaults.date_format || "yyyy-mm-dd"; }, - str_to_user: function(val, no_time_str) { + str_to_user: function(val, only_time = false) { if(!val) return ""; + + if(only_time) { + return moment(val, moment.defaultTimeFormat) + .format(moment.defaultTimeFormat); + } + var user_fmt = frappe.datetime.get_user_fmt().toUpperCase(); if(typeof val !== "string" || val.indexOf(" ")===-1) { return moment(val).format(user_fmt); @@ -101,15 +110,17 @@ $.extend(frappe.datetime, { } }, - now_datetime: function() { - return moment().format("YYYY-MM-DD HH:mm:ss"); - }, - get_datetime_as_string: function(d) { return moment(d).format("YYYY-MM-DD HH:mm:ss"); }, - user_to_str: function(val, no_time_str) { + user_to_str: function(val, only_time = false) { + + if(only_time) { + return moment(val, moment.defaultTimeFormat) + .format(moment.defaultTimeFormat); + } + var user_fmt = frappe.datetime.get_user_fmt().toUpperCase(); var system_fmt = "YYYY-MM-DD"; @@ -136,21 +147,60 @@ $.extend(frappe.datetime, { } }, - get_today: function() { - return moment().locale("en").format(); + now_date: function(as_obj = false) { + return frappe.datetime._date(moment.defaultDateFormat, as_obj); + }, + + now_time: function(as_obj = false) { + return frappe.datetime._date(moment.defaultTimeFormat, as_obj); + }, + + now_datetime: function(as_obj = false) { + return frappe.datetime._date(moment.defaultDatetimeFormat, as_obj); + }, + + _date: function(format, as_obj = false) { + const { time_zone } = frappe.sys_defaults; + let date; + if (time_zone) { + date = moment.tz(time_zone); + } else { + date = moment(); + } + if (as_obj) { + return frappe.datetime.moment_to_date_obj(date); + } else { + return date.format(format); + } + }, + + moment_to_date_obj: function(moment) { + const date_obj = new Date(); + const date_array = moment.toArray(); + date_obj.setFullYear(date_array[0]); + date_obj.setMonth(date_array[1]); + date_obj.setDate(date_array[2]); + date_obj.setHours(date_array[3]); + date_obj.setMinutes(date_array[4]); + date_obj.setSeconds(date_array[5]); + date_obj.setMilliseconds(date_array[6]); + return date_obj; }, nowdate: function() { - return frappe.datetime.get_today(); + return frappe.datetime.now_date(); }, - now_time: function() { - return frappe.datetime.convert_to_system_tz(moment(), false) - .locale("en").format("HH:mm:ss"); + get_today: function() { + return frappe.datetime.now_date(); }, validate: function(d) { - return moment(d).isValid(); + return moment(d, [ + moment.defaultDateFormat, + moment.defaultDatetimeFormat, + moment.defaultTimeFormat + ], true).isValid(); }, }); From 05a542d7cc707d414aeca60a321e4f5ef0251f0f Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Tue, 25 Jul 2017 10:59:39 +0530 Subject: [PATCH 10/17] Set image control alignment via df (#3754) * image control alignment via df * [wiz] remove application brand name --- .../desk/page/setup_wizard/setup_wizard.css | 30 +------------------ frappe/desk/page/setup_wizard/setup_wizard.js | 11 +------ frappe/public/css/form.css | 8 +++++ frappe/public/js/frappe/form/control.js | 9 ++++++ frappe/public/less/form.less | 10 +++++++ 5 files changed, 29 insertions(+), 39 deletions(-) diff --git a/frappe/desk/page/setup_wizard/setup_wizard.css b/frappe/desk/page/setup_wizard/setup_wizard.css index b17b3676bc..5313a6b4bc 100644 --- a/frappe/desk/page/setup_wizard/setup_wizard.css +++ b/frappe/desk/page/setup_wizard/setup_wizard.css @@ -2,25 +2,6 @@ margin-top: 30px; } -.setup-wizard-brand { - margin: 30px; - 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; @@ -59,14 +40,6 @@ 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; } @@ -113,8 +86,7 @@ .setup-wizard-slide .frappe-control[data-fieldtype="Attach Image"] { width: 140px; height: 180px; /*depends on presence of heading*/ - text-align: center; - margin-left: calc((100% - 140px)/2); + margin-top: 20px; } .setup-wizard-slide .frappe-control[data-fieldtype="Attach Image"] .form-group, diff --git a/frappe/desk/page/setup_wizard/setup_wizard.js b/frappe/desk/page/setup_wizard/setup_wizard.js index c5aab1c178..f76787e0e3 100644 --- a/frappe/desk/page/setup_wizard/setup_wizard.js +++ b/frappe/desk/page/setup_wizard/setup_wizard.js @@ -78,7 +78,6 @@ frappe.setup.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)}; @@ -506,7 +505,7 @@ var frappe_slides = [ icon: "fa fa-user", fields: [ { "fieldtype":"Attach Image", "fieldname":"attach_user_image", - label: __("Attach Your Picture"), is_private: 0}, + label: __("Attach Your Picture"), is_private: 0, align: 'center'}, { "fieldname": "full_name", "label": __("Full Name"), "fieldtype": "Data", reqd:1}, { "fieldname": "email", "label": __("Email Address") + ' (' + __("Will be your login ID") + ')', @@ -721,12 +720,4 @@ var utils = { frappe.setup.on("before_load", function() { // load slides frappe_slides.map(frappe.setup.add_slide); - - // set header image - let $icon = $('header .setup-wizard-brand'); - if($icon.length === 0) { - $('header').append(`
    -
    `); - } }); diff --git a/frappe/public/css/form.css b/frappe/public/css/form.css index 844c2dc761..62c27756af 100644 --- a/frappe/public/css/form.css +++ b/frappe/public/css/form.css @@ -515,6 +515,14 @@ h6.uppercase, padding: 0px; margin: 0px; } +.flex-justify-center { + display: flex; + justify-content: center; +} +.flex-justify-end { + display: flex; + justify-content: flex-end; +} .hide-control { display: none !important; } diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index 6a85c24c2f..80fbafce4a 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -1241,6 +1241,15 @@ frappe.ui.form.ControlAttachImage = frappe.ui.form.ControlAttach.extend({ make: function() { var me = this; this._super(); + + this.container = $('
    ').appendTo($(this.parent).empty()); + this.container.attr('data-fieldtype', this.df.fieldtype).append(this.wrapper); + if(this.df.align === 'center') { + this.container.addClass("flex-justify-center"); + } else if (this.df.align === 'right') { + this.container.addClass("flex-justify-end"); + } + this.img_wrapper = $('
    \
    ') .appendTo(this.wrapper); diff --git a/frappe/public/less/form.less b/frappe/public/less/form.less index 5bcf903c3b..d54ce51f89 100644 --- a/frappe/public/less/form.less +++ b/frappe/public/less/form.less @@ -650,6 +650,16 @@ h6.uppercase, .h6.uppercase { } } +.flex-justify-center { + display: flex; + justify-content: center; +} + +.flex-justify-end { + display: flex; + justify-content: flex-end; +} + .hide-control { display: none !important; } From 23d073adb797970442695c668e35d51265548b00 Mon Sep 17 00:00:00 2001 From: bcornwellmott Date: Mon, 24 Jul 2017 22:49:22 -0700 Subject: [PATCH 11/17] Added tag search (#3759) * Added tag search * Added permissions check for document --- frappe/desk/tags.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frappe/desk/tags.py b/frappe/desk/tags.py index b02e814280..5b8103a54e 100644 --- a/frappe/desk/tags.py +++ b/frappe/desk/tags.py @@ -47,6 +47,13 @@ def remove_tag(tag, dt, dn): "removes tag from the record" DocTags(dt).remove(dn, tag) +@frappe.whitelist() +def get_tagged_docs(doctype, tag): + frappe.has_permission(doctype, throw=True) + + return frappe.db.sql("""SELECT name + FROM `tab{0}` + WHERE _user_tags LIKE '%{1}%'""".format(doctype, tag)) @frappe.whitelist() def get_tags(doctype, txt, cat_tags): From 6d35855a7b174d1840606c8c67202f8ae644b8d6 Mon Sep 17 00:00:00 2001 From: Manas Solanki Date: Tue, 25 Jul 2017 11:25:28 +0530 Subject: [PATCH 12/17] Fix for dropbox settings (#3749) --- .../integrations/doctype/dropbox_settings/dropbox_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py index ed81d663d8..8d37745073 100644 --- a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py +++ b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py @@ -86,7 +86,7 @@ def backup_to_dropbox(): access_token = generate_oauth2_access_token_from_oauth1_token(dropbox_settings) if not access_token.get('oauth2_token'): - return + return 'Failed backup upload', 'No Access Token exists! Please generate the access token for Dropbox.' dropbox_settings['access_token'] = access_token['oauth2_token'] set_dropbox_access_token(access_token['oauth2_token']) From 1fde84627249fee15e3025af9572b0e18a50cdeb Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 25 Jul 2017 11:55:29 +0530 Subject: [PATCH 13/17] Form Timeline styling (#3778) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Left align Indicator and corrected “Add to Knowledge Base” button misalignment. * Left align Indicator and corrected “Add to Knowledge Base” button misalignment. * Pushing title changes only, reverted timeline changes. * Pushing title changes only, reverted timeline changes. * Timelime tilte design update for small resolution. * Review changes and added minified date * Review changes for Timeline for smaller screen. * Changes for tilte, delete icon change and removed duplicate date. * Review changes * Fixed Alignment for action buttons. * Small resolution alignment changes. * Class name changes. * Timelime tilte design update for small resolution. * Changes for tilte, delete icon change and removed duplicate date. --- frappe/public/css/form.css | 22 ++- frappe/public/css/mobile.css | 63 +++++++ .../public/js/frappe/form/footer/timeline.js | 12 +- .../js/frappe/form/footer/timeline_item.html | 158 ++++++++++-------- frappe/public/less/form.less | 24 ++- frappe/public/less/mobile.less | 66 ++++++++ 6 files changed, 265 insertions(+), 80 deletions(-) diff --git a/frappe/public/css/form.css b/frappe/public/css/form.css index 62c27756af..0d21271862 100644 --- a/frappe/public/css/form.css +++ b/frappe/public/css/form.css @@ -287,6 +287,8 @@ h6.uppercase, border-radius: 3px; margin-left: -7px; position: relative; + max-width: calc(100% - 50px); + padding-right: 0px; overflow: visible; } .timeline-item.user-content .avatar-medium { @@ -294,6 +296,11 @@ h6.uppercase, height: 45px; width: 45px; } +.timeline-item.user-content .action-btns { + position: absolute; + right: 0; + padding: 5px 15px 2px 5px; +} .timeline-item.user-content .comment-header { background-color: #fafbfc; padding: 10px 15px 10px 13px; @@ -301,12 +308,19 @@ h6.uppercase, color: #8D99A6; border-bottom: 1px solid #EBEFF2; } +.timeline-item.user-content .comment-header.links-active { + padding-right: 60px; +} +.timeline-item.user-content .comment-header .commented-on-small { + display: none; +} .timeline-item.user-content .comment-header .octicon-heart { color: #ff5858; cursor: pointer; } .timeline-item.user-content .reply { padding: 15px; + overflow: auto; } .timeline-item.user-content .reply > div > p:first-child { margin-top: 0px; @@ -317,11 +331,13 @@ h6.uppercase, .timeline-item.user-content .reply hr { margin: 10px 0px; } -.timeline-item.user-content .close-btn-container { - padding: 4px 10px 2px 5px; +.timeline-item.user-content .close-btn-container .close { + color: inherit; + opacity: 1; + padding: 0 0 0 10px; } .timeline-item.user-content .edit-btn-container { - padding: 4px 5px; + padding: 0; } .timeline-item.user-content .edit-btn-container .edit { color: inherit; diff --git a/frappe/public/css/mobile.css b/frappe/public/css/mobile.css index 9e0bbe3597..ebcc52084f 100644 --- a/frappe/public/css/mobile.css +++ b/frappe/public/css/mobile.css @@ -192,6 +192,9 @@ body { } } @media (max-width: 767px) { + .toggle-sidebar { + margin-right: 0; + } body[data-route^="Form"] .page-title .title-text { font-size: 16px; width: calc(100% - 30px); @@ -331,4 +334,64 @@ body { body[data-route^="Form"] .page-head .sub-heading { right: 90px; } + .timeline::before { + content: none; + } + .timeline .timeline-new-email { + margin: 20px 0; + padding-left: 15px; + } + .timeline .timeline-new-email::before { + content: none; + } + .timeline .timeline-item.user-content { + margin: 20px 15px; + } + .timeline .timeline-item.user-content .media-body { + margin-left: 0; + max-width: 100%; + overflow: hidden; + } + .timeline .timeline-item.user-content .media-body:before { + content: none; + } + .timeline .timeline-item.user-content .action-btns { + padding: 5px 10px 2px 5px; + } + .timeline .timeline-item.user-content .comment-header { + padding: 7px 10px; + } + .timeline .timeline-item.user-content .comment-header .links-active { + padding-right: 10px; + } + .timeline .timeline-item.user-content .avatar-medium { + margin-right: 10px; + } + .timeline .timeline-item.user-content .reply { + padding: 10px; + } + .timeline .timeline-item.user-content .commented-on-small { + display: inline-block; + } + .timeline .timeline-item.user-content .commented-on-small { + display: inline-block; + } + .timeline .timeline-item.notification-content { + padding-left: 15px; + margin: 20px 0; + } + .timeline .timeline-item.notification-content::before { + content: none; + } + .timeline .timeline-item.notification-content .small { + padding-left: 0; + } + .timeline .timeline-item .delivery-status-indicator { + float: left; + margin: 0 5px 0 0; + } + .timeline .asset-details { + line-height: 24px; + /*Height of avtar image -36px to align text center vertically*/ + } } diff --git a/frappe/public/js/frappe/form/footer/timeline.js b/frappe/public/js/frappe/form/footer/timeline.js index d80ebf85dd..d2c3b69d0f 100644 --- a/frappe/public/js/frappe/form/footer/timeline.js +++ b/frappe/public/js/frappe/form/footer/timeline.js @@ -248,14 +248,14 @@ frappe.ui.form.Timeline = Class.extend({ c["edit"] = ""; if(c.communication_type=="Comment" && (c.comment_type || "Comment") === "Comment") { if(frappe.model.can_delete("Communication")) { - c["delete"] = '
    '; + c["delete"] = ''; } if(frappe.user.name == c.sender || (frappe.user.name == 'Administrator')) { - c["edit"] = ''; + c["edit"] = ''; } } - + c.comment_on_small = comment_when(c.creation, true); c.comment_on = comment_when(c.creation); if(!c.fullname) { c.fullname = c.sender_full_name || frappe.user.full_name(c.sender); @@ -358,7 +358,8 @@ frappe.ui.form.Timeline = Class.extend({ "Unshared": "octicon octicon-circle-slash", "Like": "octicon octicon-heart", "Edit": "octicon octicon-pencil", - "Relinked": "octicon octicon-check" + "Relinked": "octicon octicon-check", + "Reply": "octicon octicon-mail-reply" }[c.comment_type || c.communication_medium] c.color = { @@ -376,7 +377,8 @@ frappe.ui.form.Timeline = Class.extend({ "Label": "#2c3e50", "Attachment": "#7f8c8d", "Attachment Removed": "#eee", - "Relinked": "#16a085" + "Relinked": "#16a085", + "Reply": "#8d99a6" }[c.comment_type || c.communication_medium]; c.icon_fg = { diff --git a/frappe/public/js/frappe/form/footer/timeline_item.html b/frappe/public/js/frappe/form/footer/timeline_item.html index c35ffa26d6..215dd06fc2 100755 --- a/frappe/public/js/frappe/form/footer/timeline_item.html +++ b/frappe/public/js/frappe/form/footer/timeline_item.html @@ -1,6 +1,6 @@
    {% if (data.user_content) { %} - + {% } %} -
    +
    -
    - - {%= data.delete %} - -
    -
    - - {%= data.edit %} - +
    + {% if(data.delete) { %} + + {% } %} + {% if(data.edit) { %} +
    + + {%= data.edit %} + +
    + {% } %}
    {% if(data.communication_type==="Communication" || data.communication_type==="Feedback" || (data.communication_type==="Comment" && data.comment_type==="Comment")) { %} -
    - - {%= data.fullname %} - - {% if (data.timeline_doctype===data.frm.doc.doctype - && data.timeline_name===data.frm.doc.name) { %} - – - - {{ __(data.reference_doctype) }} - {{ data.reference_name }} - + -
    +
    {% if data.show_subject %}

    @@ -143,7 +163,7 @@ {% if(data.link_doctype && data.link_name) { %} {% } %} - + – {%= data.comment_on %}

    {% } else { %} @@ -172,7 +192,7 @@ {% } %} {% } %} - + – {%= data.comment_on %}
    {% } %} diff --git a/frappe/public/less/form.less b/frappe/public/less/form.less index d54ce51f89..69767fddf4 100644 --- a/frappe/public/less/form.less +++ b/frappe/public/less/form.less @@ -376,7 +376,8 @@ h6.uppercase, .h6.uppercase { border-radius: 3px; margin-left: -7px; position: relative; - + max-width: calc(~"100% - 50px"); + padding-right: 0px; // to display the triangle beside the box overflow: visible; } @@ -387,12 +388,24 @@ h6.uppercase, .h6.uppercase { width: 45px; } + .action-btns { + position: absolute; + right: 0; + padding: 5px 15px 2px 5px; + } + .comment-header { background-color: @light-bg; padding: 10px 15px 10px 13px; margin: 0px; color: @text-muted; border-bottom: 1px solid @light-border-color; + &.links-active { + padding-right: 60px; + } + .commented-on-small { + display: none; + } .octicon-heart { color: @heart-color; @@ -402,6 +415,7 @@ h6.uppercase, .h6.uppercase { .reply { padding: 15px; + overflow: auto; & > div > p:first-child { margin-top: 0px; @@ -417,11 +431,15 @@ h6.uppercase, .h6.uppercase { } .close-btn-container { - padding: 4px 10px 2px 5px; + .close { + color: inherit; + opacity: 1; + padding: 0 0 0 10px; + } } .edit-btn-container { - padding: 4px 5px; + padding: 0; .edit { color: inherit; diff --git a/frappe/public/less/mobile.less b/frappe/public/less/mobile.less index 06a3a26a15..40d673c169 100644 --- a/frappe/public/less/mobile.less +++ b/frappe/public/less/mobile.less @@ -223,6 +223,9 @@ body { } @media(max-width: 767px) { + .toggle-sidebar { + margin-right: 0; + } body[data-route^="Form"]{ .page-title { .title-text { @@ -406,4 +409,67 @@ body { right: 90px; } } + .timeline { + &::before { + content: none; + } + .timeline-new-email { + margin: 20px 0; + padding-left: 15px; + &::before { + content: none; + } + } + .timeline-item { + &.user-content { + margin: 20px 15px; + .media-body { + margin-left: 0; + max-width: 100%; + overflow: hidden; + &:before { + content: none; + } + } + .action-btns { + padding: 5px 10px 2px 5px; + } + .comment-header{ + padding: 7px 10px; + .links-active { + padding-right: 10px; + } + } + .avatar-medium { + margin-right: 10px; + } + .reply { + padding: 10px; + } + .commented-on-small{ + display: inline-block; + } + .commented-on-small{ + display: inline-block; + } + } + &.notification-content { + padding-left: 15px; + margin: 20px 0; + &::before { + content: none; + } + .small { + padding-left: 0; + } + } + .delivery-status-indicator { + float: left; + margin: 0 5px 0 0; + } + } + .asset-details { + line-height: 24px; /*Height of avtar image -36px to align text center vertically*/ + } + } } From 877f8e2a23b568beb79a988bcca5db889abe4c70 Mon Sep 17 00:00:00 2001 From: Utkarsh Yadav Date: Tue, 25 Jul 2017 12:05:18 +0530 Subject: [PATCH 14/17] [UI Test] Kanban view (#3777) * added changes and one test for column * changes in tests for new test runner * codacy fixes --- .../ui/test_kanban/test_kanban_column.js | 31 ++++++++++++++++ .../ui/test_kanban/test_kanban_creation.js | 30 ++++++++++++++++ .../ui/test_kanban/test_kanban_filters.js | 27 ++++++++++++++ .../tests/ui/test_kanban/test_kanban_view.js | 26 ++++++++++++++ .../ui/test_module/test_module_option.js | 35 ------------------- frappe/tests/ui/tests.txt | 6 +++- 6 files changed, 119 insertions(+), 36 deletions(-) create mode 100644 frappe/tests/ui/test_kanban/test_kanban_column.js create mode 100644 frappe/tests/ui/test_kanban/test_kanban_creation.js create mode 100644 frappe/tests/ui/test_kanban/test_kanban_filters.js create mode 100644 frappe/tests/ui/test_kanban/test_kanban_view.js delete mode 100644 frappe/tests/ui/test_module/test_module_option.js diff --git a/frappe/tests/ui/test_kanban/test_kanban_column.js b/frappe/tests/ui/test_kanban/test_kanban_column.js new file mode 100644 index 0000000000..0c4593a8dd --- /dev/null +++ b/frappe/tests/ui/test_kanban/test_kanban_column.js @@ -0,0 +1,31 @@ +QUnit.module('views'); + +QUnit.test("Test: Setting column colour [Kanban view]", function(assert) { + assert.expect(3); + let done = assert.async(); + function get_column(name, colour) { + return ('.kanban-column:contains('+name+')>div>div>ul>li>div.'+colour); + } + + frappe.run_serially([ + () => frappe.set_route("List", "ToDo", "Kanban", "Kanban test"), + () => frappe.timeout(1), + () => assert.deepEqual(["List", "ToDo", "Kanban", "Kanban test"], frappe.get_route(), + "Kanban view opened successfully."), + () => { + // set colour for columns + $(get_column('High', "red")).click(); + $(get_column('Medium', "green")).click(); + $(get_column('Low', "yellow")).click(); + }, + () => frappe.timeout(1), + () => { + //check if different colours are set + assert.equal($('.red > span')[0].innerText, 'High', + "Colour is set for kanban column."); + assert.equal($('.green > span')[0].innerText, 'Medium', + "Different colour is set for other column."); + }, + () => done() + ]); +}); \ No newline at end of file diff --git a/frappe/tests/ui/test_kanban/test_kanban_creation.js b/frappe/tests/ui/test_kanban/test_kanban_creation.js new file mode 100644 index 0000000000..2ef7127f1f --- /dev/null +++ b/frappe/tests/ui/test_kanban/test_kanban_creation.js @@ -0,0 +1,30 @@ +QUnit.module('views'); + +QUnit.test("Test: Creation [Kanban view]", function(assert) { + assert.expect(2); + let done = assert.async(); + + frappe.run_serially([ + () => frappe.set_route("List", "ToDo", "List"), + // click kanban in side bar + () => frappe.click_link('Kanban'), + () => frappe.click_link('New Kanban Board'), + () => frappe.timeout(0.5), + // create new kanban + () => { + assert.equal(cur_dialog.title, 'New Kanban Board', + "Dialog for new kanban opened."); + cur_dialog.set_value('board_name', 'Kanban test'); + cur_dialog.set_value('field_name', 'Priority'); + }, + () => frappe.timeout(0.5), + () => cur_dialog.get_primary_btn().click(), + () => frappe.timeout(1), + () => frappe.set_route("List", "Kanban Board", "List"), + () => frappe.timeout(0.5), + // check in kanban list if new kanban is created + () => assert.equal(cur_list.data[0].name, 'Kanban test', + "Added kanban is visible in kanban list."), + () => done() + ]); +}); \ No newline at end of file diff --git a/frappe/tests/ui/test_kanban/test_kanban_filters.js b/frappe/tests/ui/test_kanban/test_kanban_filters.js new file mode 100644 index 0000000000..b4d4ca1222 --- /dev/null +++ b/frappe/tests/ui/test_kanban/test_kanban_filters.js @@ -0,0 +1,27 @@ +QUnit.module('views'); + +QUnit.test("Test: Filters [Kanban view]", function(assert) { + assert.expect(3); + let done = assert.async(); + + frappe.run_serially([ + () => frappe.set_route("List", "ToDo", "Kanban", "Kanban test"), + () => frappe.timeout(1), + () => { + assert.deepEqual(["List", "ToDo", "Kanban", "Kanban test"], frappe.get_route(), + "Kanban view opened successfully."); + // set filter values + return frappe.set_control('priority', 'Low'); + }, + () => frappe.timeout(1), + () => cur_list.page.btn_secondary.click(), + () => frappe.timeout(1), + () => { + assert.equal(cur_list.data[0].priority, 'Low', + 'visible element has low priority'); + let non_low_items = cur_list.data.filter(d => d.priority != 'Low'); + assert.equal(non_low_items.length, 0, 'No item without low priority'); + }, + () => done() + ]); +}); \ No newline at end of file diff --git a/frappe/tests/ui/test_kanban/test_kanban_view.js b/frappe/tests/ui/test_kanban/test_kanban_view.js new file mode 100644 index 0000000000..9cf7787d2b --- /dev/null +++ b/frappe/tests/ui/test_kanban/test_kanban_view.js @@ -0,0 +1,26 @@ +QUnit.module('views'); + +QUnit.test("Test: Kanban view", function(assert) { + assert.expect(3); + let done = assert.async(); + let total_elements; + + frappe.run_serially([ + () => frappe.set_route("List", "ToDo", "List"), + // calculate number of element in list + () => frappe.timeout(1), + () => total_elements = cur_list.data.length, + () => frappe.set_route("List", "ToDo", "Kanban", "Kanban test"), + () => frappe.timeout(1), + () => { + assert.equal('Kanban', cur_list.current_view, + "Current view is kanban."); + assert.equal("Kanban test", cur_list.list_renderer.page_title, + "Kanban view opened successfully."); + // check if all elements are visible in kanban view + assert.equal(total_elements, cur_list.data.length, + "All elements are visible in kanban view."); + }, + () => done() + ]); +}); \ No newline at end of file diff --git a/frappe/tests/ui/test_module/test_module_option.js b/frappe/tests/ui/test_module/test_module_option.js deleted file mode 100644 index 4f6910309a..0000000000 --- a/frappe/tests/ui/test_module/test_module_option.js +++ /dev/null @@ -1,35 +0,0 @@ -QUnit.module('views'); - -QUnit.test("Test option click [Module view]", function(assert) { - assert.expect(4); - let done = assert.async(); - - frappe.run_serially([ - - //click Document Share Report in Permissions section [Report] - () => frappe.set_route("modules", "Setup"), - () => frappe.timeout(0.5), - () => frappe.tests.click_and_wait('a.small:contains("Document Share Report")', 0), - () => assert.deepEqual(frappe.get_route(), ["Report", "DocShare", "Document Share Report"], "First click test."), - - //click Print Setting in Printing section [Form] - () => frappe.set_route("modules", "Setup"), - () => frappe.timeout(0.5), - () => frappe.tests.click_and_wait('a.small:contains("Print Setting")', 0), - () => assert.deepEqual(frappe.get_route(), ["Form", "Print Settings"], "Second click test."), - - //click Workflow Action in Workflow section [List] - () => frappe.set_route("modules", "Setup"), - () => frappe.timeout(0.5), - () => frappe.tests.click_and_wait('a.small:contains(" Workflow Action ")', 0), - () => assert.deepEqual(frappe.get_route(), ["List", "Workflow Action", "List"], "Third click test."), - - //click Application Installer in Applications section - () => frappe.set_route("modules", "Setup"), - () => frappe.timeout(0.5), - () => frappe.tests.click_and_wait('a.small:contains("Application Installer")', 0), - () => assert.deepEqual(frappe.get_route(), ["applications"], "Fourth click test."), - - () => done() - ]); -}); \ No newline at end of file diff --git a/frappe/tests/ui/tests.txt b/frappe/tests/ui/tests.txt index de7d34fddb..ce0c91c77e 100644 --- a/frappe/tests/ui/tests.txt +++ b/frappe/tests/ui/tests.txt @@ -2,4 +2,8 @@ frappe/tests/ui/test_number_format.js frappe/tests/ui/test_list/test_list_filter.js frappe/tests/ui/test_list/test_list_paging.js frappe/tests/ui/test_module_view.js -frappe/tests/ui/test_calendar_view.js \ No newline at end of file +frappe/tests/ui/test_calendar_view.js +frappe/tests/ui/test_kanban/test_kanban_creation.js +frappe/tests/ui/test_kanban/test_kanban_view.js +frappe/tests/ui/test_kanban/test_kanban_filters.js +frappe/tests/ui/test_kanban/test_kanban_column.js \ No newline at end of file From c2f18dd9e40bcc9eab812212ed5b817efd874d24 Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Wed, 26 Jul 2017 11:50:22 +0530 Subject: [PATCH 15/17] [fix] detach instead of emptying parent (#3783) --- frappe/public/js/frappe/form/control.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index 80fbafce4a..a9ada5e180 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -1242,7 +1242,8 @@ frappe.ui.form.ControlAttachImage = frappe.ui.form.ControlAttach.extend({ var me = this; this._super(); - this.container = $('
    ').appendTo($(this.parent).empty()); + $(this.wrapper).detach(); + this.container = $('
    ').appendTo($(this.parent)); this.container.attr('data-fieldtype', this.df.fieldtype).append(this.wrapper); if(this.df.align === 'center') { this.container.addClass("flex-justify-center"); From fad9c91cfe619d53c8140a1d1ff1ea6e0bc6a06c Mon Sep 17 00:00:00 2001 From: omkarghaisas Date: Wed, 26 Jul 2017 11:52:21 +0530 Subject: [PATCH 16/17] Added mobile number in edit user profile web form (#3766) updated mobile number is required to login using mobile number --- .../web_form/edit_profile/edit_profile.json | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/frappe/core/web_form/edit_profile/edit_profile.json b/frappe/core/web_form/edit_profile/edit_profile.json index ecf1e5ba70..30e8437986 100644 --- a/frappe/core/web_form/edit_profile/edit_profile.json +++ b/frappe/core/web_form/edit_profile/edit_profile.json @@ -1,17 +1,24 @@ { + "accept_payment": 0, "allow_comments": 0, "allow_delete": 0, "allow_edit": 1, + "allow_incomplete": 0, "allow_multiple": 0, + "allow_print": 0, + "amount": 0.0, + "amount_based_on_field": 0, "breadcrumbs": "[{\"title\": _(\"My Account\"), \"route\": \"me\"}]", "creation": "2016-09-19 05:16:59.242754", "doc_type": "User", "docstatus": 0, "doctype": "Web Form", "idx": 0, + "introduction_text": "", "is_standard": 1, "login_required": 1, - "modified": "2016-09-24 04:31:41.920694", + "max_attachment_size": 0, + "modified": "2017-07-24 12:14:04.039284", "modified_by": "Administrator", "module": "Core", "name": "edit-profile", @@ -29,6 +36,8 @@ "fieldtype": "Data", "hidden": 0, "label": "First Name", + "max_length": 0, + "max_value": 0, "read_only": 0, "reqd": 1 }, @@ -37,6 +46,8 @@ "fieldtype": "Data", "hidden": 0, "label": "Middle Name (Optional)", + "max_length": 0, + "max_value": 0, "read_only": 0, "reqd": 0 }, @@ -45,6 +56,8 @@ "fieldtype": "Data", "hidden": 0, "label": "Last Name", + "max_length": 0, + "max_value": 0, "read_only": 0, "reqd": 0 }, @@ -54,6 +67,8 @@ "fieldtype": "Attach", "hidden": 0, "label": "User Image", + "max_length": 0, + "max_value": 0, "read_only": 0, "reqd": 0 }, @@ -61,6 +76,8 @@ "fieldtype": "Section Break", "hidden": 0, "label": "More Information", + "max_length": 0, + "max_value": 0, "read_only": 0, "reqd": 0 }, @@ -69,6 +86,18 @@ "fieldtype": "Data", "hidden": 0, "label": "Phone", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0 + }, + { + "fieldname": "mobile_no", + "fieldtype": "Data", + "hidden": 0, + "label": "Mobile Number", + "max_length": 0, + "max_value": 0, "read_only": 0, "reqd": 0 }, @@ -78,6 +107,8 @@ "fieldtype": "Link", "hidden": 0, "label": "Language", + "max_length": 0, + "max_value": 0, "options": "Language", "read_only": 0, "reqd": 0 From d94d992337b04fea15c8b7ef745817c9bf6b1bde Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Wed, 26 Jul 2017 17:50:49 +0530 Subject: [PATCH 17/17] [fix][img-control] detach wrapper after inserting (#3794) --- frappe/public/js/frappe/form/control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js index a9ada5e180..54bb4e0595 100755 --- a/frappe/public/js/frappe/form/control.js +++ b/frappe/public/js/frappe/form/control.js @@ -1242,8 +1242,8 @@ frappe.ui.form.ControlAttachImage = frappe.ui.form.ControlAttach.extend({ var me = this; this._super(); + this.container = $('
    ').insertAfter($(this.wrapper)); $(this.wrapper).detach(); - this.container = $('
    ').appendTo($(this.parent)); this.container.attr('data-fieldtype', this.df.fieldtype).append(this.wrapper); if(this.df.align === 'center') { this.container.addClass("flex-justify-center");