From 218749e4011a236887426465aa58cdbf43b85139 Mon Sep 17 00:00:00 2001 From: Emil Date: Wed, 5 Aug 2020 16:20:17 +0300 Subject: [PATCH 01/34] :sparkles: Add Map View --- frappe/geo/utils.py | 39 ++++++++ frappe/public/build.json | 1 + frappe/public/css/list.css | 4 + frappe/public/js/frappe/list/base_list.js | 2 +- .../public/js/frappe/list/list_sidebar.html | 2 + frappe/public/js/frappe/list/list_sidebar.js | 8 ++ frappe/public/js/frappe/views/map/map_view.js | 97 +++++++++++++++++++ frappe/public/less/list.less | 6 ++ 8 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 frappe/geo/utils.py create mode 100644 frappe/public/js/frappe/views/map/map_view.js diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py new file mode 100644 index 0000000000..4bc07249fe --- /dev/null +++ b/frappe/geo/utils.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals + +import frappe + +from pymysql import InternalError + + +@frappe.whitelist() +def get_coords(doctype, filters): + '''Get list of coordinates in form + returns {names: ['latitude', 'longitude']}''' + filters_sql = get_coords_conditions(doctype, filters)[4:] + if filters_sql: + try: + coords = frappe.db.sql("""SELECT * FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) + except InternalError: + frappe.msgprint(frappe._('This Doctype did not contains latitude and longitude fields')) + return + else: + coords = frappe.get_all(doctype, fields=['name', 'latitude', 'longitude']) + out = frappe._dict() + for i in coords: + out[i.name] = out.get(i.docname, []) + out[i.name].append(i.latitude) + out[i.name].append(i.longitude) + return out + + +def get_coords_conditions(doctype, filters=None): + """Returns SQL conditions with user permissions and filters for event queries""" + from frappe.desk.reportview import get_filters_cond + if not frappe.has_permission(doctype): + frappe.throw(frappe._("Not Permitted"), frappe.PermissionError) + + return get_filters_cond(doctype, filters, [], with_match_conditions=True) \ No newline at end of file diff --git a/frappe/public/build.json b/frappe/public/build.json index 997a3092ad..096bb09c6e 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -304,6 +304,7 @@ "public/js/frappe/views/calendar/calendar.js", "public/js/frappe/views/dashboard/dashboard_view.js", "public/js/frappe/views/image/image_view.js", + "public/js/frappe/views/map/map_view.js", "public/js/frappe/views/kanban/kanban_view.js", "public/js/frappe/views/inbox/inbox_view.js", "public/js/frappe/views/file/file_view.js", diff --git a/frappe/public/css/list.css b/frappe/public/css/list.css index 5ae77c73ca..49ffbcd9e9 100644 --- a/frappe/public/css/list.css +++ b/frappe/public/css/list.css @@ -401,6 +401,10 @@ input.list-row-checkbox { .pswp__more-item img { max-height: 100%; } +.map-view-container { + display: flex; + flex-wrap: wrap; +} .list-paging-area .gantt-view-mode { margin-left: 15px; margin-right: 15px; diff --git a/frappe/public/js/frappe/list/base_list.js b/frappe/public/js/frappe/list/base_list.js index bbe2fa2f95..af220a97d3 100644 --- a/frappe/public/js/frappe/list/base_list.js +++ b/frappe/public/js/frappe/list/base_list.js @@ -695,5 +695,5 @@ class FilterArea { } // utility function to validate view modes -frappe.views.view_modes = ['List', 'Gantt', 'Kanban', 'Calendar', 'Image', 'Inbox', 'Report', 'Dashboard']; +frappe.views.view_modes = ['List', 'Gantt', 'Kanban', 'Calendar', 'Image', 'Map', 'Inbox', 'Report']; frappe.views.is_valid = view_mode => frappe.views.view_modes.includes(view_mode); diff --git a/frappe/public/js/frappe/list/list_sidebar.html b/frappe/public/js/frappe/list/list_sidebar.html index dcbbe7ac5e..c5b75782b5 100644 --- a/frappe/public/js/frappe/list/list_sidebar.html +++ b/frappe/public/js/frappe/list/list_sidebar.html @@ -30,6 +30,8 @@ {%= __("Dashboard") %} +
  • ${display_name}
  • `).appendTo($dropdown); + $(`
  • ${account.email_id}
  • `).appendTo($dropdown); if (account.email_id === "Sent Mail") divider = false; }); @@ -233,21 +225,40 @@ frappe.views.ListSidebar = class ListSidebar { }); } - setup_keyboard_shortcuts() { - this.sidebar.find('.list-link > a, .list-link > .btn-group > a').each((i, el) => { - frappe.ui.keys - .get_shortcut_group(this.page) - .add($(el)); + setup_assigned_to_me() { + this.page.sidebar.find(".assigned-to-me a").on("click", () => { + this.list_view.filter_area.add(this.list_view.doctype, "_assign", "like", `%${frappe.session.user}%`); }); } - setup_list_group_by() { - this.list_group_by = new frappe.views.ListGroupBy({ - doctype: this.doctype, - sidebar: this, - list_view: this.list_view, - page: this.page - }); + setup_upgrade_box() { + let upgrade_list = $(``).appendTo(this.sidebar); + + // Show Renew/Upgrade button, + // if account is holding one user free plan or + // if account's expiry date within range of 30 days from today's date + + let upgrade_date = frappe.datetime.add_days(frappe.datetime.get_today(), 30); + if (frappe.boot.limits.users === 1 || upgrade_date >= frappe.boot.limits.expiry) { + let upgrade_box = $(`
    + +
    Go Premium
    +

    Upgrade to a premium plan with more users, storage and priority support.

    + +
    `).appendTo(upgrade_list); + + upgrade_box.find('.btn-upgrade').on('click', () => { + frappe.set_route('usage-info'); + }); + + upgrade_box.find('.close').on('click', () => { + upgrade_list.remove(); + frappe.flags.upgrade_dismissed = 1; + }); + } } get_cat_tags() { @@ -258,7 +269,6 @@ frappe.views.ListSidebar = class ListSidebar { var me = this; frappe.call({ method: 'frappe.desk.reportview.get_sidebar_stats', - type: 'GET', args: { stats: me.stats, doctype: me.doctype, @@ -266,9 +276,29 @@ frappe.views.ListSidebar = class ListSidebar { filters: (me.list_view.filter_area ? me.list_filter.get_current_filters() : me.default_filters) || [] }, callback: function(r) { - me.render_stat("_user_tags", (r.message.stats || {})["_user_tags"]); - let stats_dropdown = me.sidebar.find('.list-stats-dropdown'); - frappe.utils.setup_search(stats_dropdown, '.stat-link', '.stat-label'); + me.defined_category = r.message; + if (r.message.defined_cat) { + me.defined_category = r.message.defined_cat; + me.cats = {}; + //structure the tag categories + for (var i in me.defined_category) { + if (me.cats[me.defined_category[i].category] === undefined) { + me.cats[me.defined_category[i].category] = [me.defined_category[i].tag]; + } else { + me.cats[me.defined_category[i].category].push(me.defined_category[i].tag); + } + me.cat_tags[i] = me.defined_category[i].tag; + } + me.tempstats = r.message.stats; + + $.each(me.cats, function(i, v) { + me.render_stat(i, (me.tempstats || {})["_user_tags"], v); + }); + me.render_stat("_user_tags", (me.tempstats || {})["_user_tags"]); + } else { + //render normal stats + me.render_stat("_user_tags", (r.message.stats || {})["_user_tags"]); + } } }); } @@ -331,7 +361,7 @@ frappe.views.ListSidebar = class ListSidebar { me.list_view.refresh(); }); }) - .appendTo(this.sidebar.find(".list-stats-dropdown")); + .insertBefore(this.sidebar.find(".close-sidebar-button")); } set_fieldtype(df) { @@ -362,8 +392,8 @@ frappe.views.ListSidebar = class ListSidebar { } reload_stats() { - this.sidebar.find(".stat-link").remove(); - this.sidebar.find(".stat-no-records").remove(); + this.sidebar.find(".sidebar-stat").remove(); + this.sidebar.find(".list-tag-preview").remove(); this.get_stats(); } From 526f470bed8aa581c16eed321aecc225971d5bd8 Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Mon, 10 Aug 2020 17:16:05 +0300 Subject: [PATCH 06/34] :art: Beauty code --- frappe/public/js/frappe/views/map/map_view.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 66a219162c..d511460798 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -63,13 +63,12 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { lastCoords = [value[0], value[1]]; } } - if (this.type === 'location_field'){ - for (let i = 0; i < this.coords.length; i++){ + if (this.type === 'location_field') { + for (let i = 0; i < this.coords.length; i++) { let features = JSON.parse(this.coords[i].location).features; features.forEach( coords => L.geoJSON(coords).bindPopup(this.coords[i].name).addTo(this.map) ); - console.log(features[0].geometry.coordinates); lastCoords = features[0].geometry.coordinates.reverse(); } } @@ -84,11 +83,11 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { get_coords_method = frappe.listview_settings[this.doctype].get_coords_method; } if (cur_list.meta.fields.find(i => i.fieldname === 'location') && - cur_list.meta.fields.find(i => i.fieldtype === 'Geolocation')){ + cur_list.meta.fields.find(i => i.fieldtype === 'Geolocation')) { this.type = 'location_field'; } if (cur_list.meta.fields.find(i => i.fieldname === "latitude") && - cur_list.meta.fields.find(i => i.fieldname === "longitude")){ + cur_list.meta.fields.find(i => i.fieldname === "longitude")) { this.type = 'coordinates'; } return frappe.call({ From d4dd7e097a0a5da1358598271b3201d1aab331b8 Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Tue, 11 Aug 2020 14:13:08 +0300 Subject: [PATCH 07/34] :art: Apply suggestions from code review Co-authored-by: Mathieu Brunot --- frappe/geo/utils.py | 6 +++--- frappe/public/build.json | 2 +- frappe/public/js/frappe/list/base_list.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index 249f3ffcca..b99ca56ce8 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -14,7 +14,7 @@ from pymysql import InternalError @frappe.whitelist() def get_coords(doctype, filters, type): '''Get list of coordinates in form - returns {names: ['latitude', 'longitude']} or location type''' + returns {name, location} with location being a geojson string''' filters_sql = get_coords_conditions(doctype, filters)[4:] out = None if type == 'coordinates': @@ -28,10 +28,10 @@ def return_location(doctype, filters_sql): try: coords = frappe.db.sql("""SELECT * FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) except InternalError: - frappe.msgprint(frappe._('This Doctype did not contains latitude and longitude fields')) + frappe.msgprint(frappe._('This Doctype did not contain location field')) return else: - coords = frappe.get_all(doctype, fields = ['location', 'name']) + coords = frappe.get_all(doctype, fields = ['name', 'location']) return coords def return_coordinates(doctype, filters_sql): diff --git a/frappe/public/build.json b/frappe/public/build.json index c5678e485e..874b9d2419 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -304,7 +304,7 @@ "public/js/frappe/views/calendar/calendar.js", "public/js/frappe/views/dashboard/dashboard_view.js", "public/js/frappe/views/image/image_view.js", - "public/js/frappe/views/map/map_view.js", + "public/js/frappe/views/map/map_view.js", "public/js/frappe/views/kanban/kanban_view.js", "public/js/frappe/views/inbox/inbox_view.js", "public/js/frappe/views/file/file_view.js", diff --git a/frappe/public/js/frappe/list/base_list.js b/frappe/public/js/frappe/list/base_list.js index af220a97d3..0f8508b4c1 100644 --- a/frappe/public/js/frappe/list/base_list.js +++ b/frappe/public/js/frappe/list/base_list.js @@ -695,5 +695,5 @@ class FilterArea { } // utility function to validate view modes -frappe.views.view_modes = ['List', 'Gantt', 'Kanban', 'Calendar', 'Image', 'Map', 'Inbox', 'Report']; +frappe.views.view_modes = ['List', 'Gantt', 'Kanban', 'Calendar', 'Image', 'Map', 'Inbox', 'Report', 'Dashboard']; frappe.views.is_valid = view_mode => frappe.views.view_modes.includes(view_mode); From 632b41bab7521c97fb3eab060e31cd769133005f Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Tue, 11 Aug 2020 14:23:33 +0300 Subject: [PATCH 08/34] :bug: Fix list sidebar --- frappe/public/js/frappe/list/list_sidebar.js | 103 +++++++------------ 1 file changed, 37 insertions(+), 66 deletions(-) diff --git a/frappe/public/js/frappe/list/list_sidebar.js b/frappe/public/js/frappe/list/list_sidebar.js index e0c3c721de..b3f65253c7 100644 --- a/frappe/public/js/frappe/list/list_sidebar.js +++ b/frappe/public/js/frappe/list/list_sidebar.js @@ -13,7 +13,6 @@ frappe.views.ListSidebar = class ListSidebar { constructor(opts) { $.extend(this, opts); this.make(); - this.get_stats(); this.cat_tags = []; } @@ -26,17 +25,25 @@ frappe.views.ListSidebar = class ListSidebar { this.setup_reports(); this.setup_list_filter(); - this.setup_assigned_to_me(); this.setup_views(); this.setup_kanban_boards(); this.setup_calendar_view(); this.setup_email_inbox(); + this.setup_keyboard_shortcuts(); + this.setup_list_group_by(); - let limits = frappe.boot.limits; + // do not remove + // used to trigger custom scripts + $(document).trigger('list_sidebar_setup'); - if (limits.upgrade_url && limits.expiry && !frappe.flags.upgrade_dismissed) { - this.setup_upgrade_box(); + if (this.list_view.list_view_settings && this.list_view.list_view_settings.disable_sidebar_stats) { + this.sidebar.find('.sidebar-stat').remove(); + } else { + this.sidebar.find('.list-stats').on('click', (e) => { + this.reload_stats(); + }); } + } setup_views() { @@ -54,7 +61,7 @@ frappe.views.ListSidebar = class ListSidebar { show_list_link = true; } - if (frappe.treeview_settings[this.doctype]) { + if (frappe.treeview_settings[this.doctype] || frappe.get_meta(this.doctype).is_tree) { this.sidebar.find(".tree-link").removeClass("hide"); } @@ -83,7 +90,7 @@ frappe.views.ListSidebar = class ListSidebar { this.sidebar.find('.list-link[data-view="Image"]').removeClass('hide'); show_list_link = true; } - // show map link if map_view doctype has get_coords or latitude and longitude + if ((JSON.stringify(frappe.listview_settings) !== '{}' && frappe.listview_settings[this.list_view.doctype].get_coords_method) || (this.list_view.meta.fields.find(i => i.fieldname === "latitude") && @@ -162,7 +169,7 @@ frappe.views.ListSidebar = class ListSidebar { reference_doctype: doctype } }).then(result => { - if (!result) return; + if (!(result && Array.isArray(result) && result.length)) return; const calendar_views = result; const $link_calendar = this.sidebar.find('.list-link[data-view="Calendar"]'); @@ -211,11 +218,13 @@ frappe.views.ListSidebar = class ListSidebar { accounts.forEach((account) => { let email_account = (account.email_id == "All Accounts") ? "All Accounts" : account.email_account; let route = ["List", "Communication", "Inbox", email_account].join('/'); + let display_name = ["All Accounts", "Sent Mail", "Spam", "Trash"].includes(account.email_id) ? __(account.email_id) : account.email_id; + if (!divider) { this.get_divider().appendTo($dropdown); divider = true; } - $(`
  • ${account.email_id}
  • `).appendTo($dropdown); + $(`
  • ${display_name}
  • `).appendTo($dropdown); if (account.email_id === "Sent Mail") divider = false; }); @@ -225,40 +234,21 @@ frappe.views.ListSidebar = class ListSidebar { }); } - setup_assigned_to_me() { - this.page.sidebar.find(".assigned-to-me a").on("click", () => { - this.list_view.filter_area.add(this.list_view.doctype, "_assign", "like", `%${frappe.session.user}%`); + setup_keyboard_shortcuts() { + this.sidebar.find('.list-link > a, .list-link > .btn-group > a').each((i, el) => { + frappe.ui.keys + .get_shortcut_group(this.page) + .add($(el)); }); } - setup_upgrade_box() { - let upgrade_list = $(``).appendTo(this.sidebar); - - // Show Renew/Upgrade button, - // if account is holding one user free plan or - // if account's expiry date within range of 30 days from today's date - - let upgrade_date = frappe.datetime.add_days(frappe.datetime.get_today(), 30); - if (frappe.boot.limits.users === 1 || upgrade_date >= frappe.boot.limits.expiry) { - let upgrade_box = $(`
    - -
    Go Premium
    -

    Upgrade to a premium plan with more users, storage and priority support.

    - -
    `).appendTo(upgrade_list); - - upgrade_box.find('.btn-upgrade').on('click', () => { - frappe.set_route('usage-info'); - }); - - upgrade_box.find('.close').on('click', () => { - upgrade_list.remove(); - frappe.flags.upgrade_dismissed = 1; - }); - } + setup_list_group_by() { + this.list_group_by = new frappe.views.ListGroupBy({ + doctype: this.doctype, + sidebar: this, + list_view: this.list_view, + page: this.page + }); } get_cat_tags() { @@ -269,6 +259,7 @@ frappe.views.ListSidebar = class ListSidebar { var me = this; frappe.call({ method: 'frappe.desk.reportview.get_sidebar_stats', + type: 'GET', args: { stats: me.stats, doctype: me.doctype, @@ -276,29 +267,9 @@ frappe.views.ListSidebar = class ListSidebar { filters: (me.list_view.filter_area ? me.list_filter.get_current_filters() : me.default_filters) || [] }, callback: function(r) { - me.defined_category = r.message; - if (r.message.defined_cat) { - me.defined_category = r.message.defined_cat; - me.cats = {}; - //structure the tag categories - for (var i in me.defined_category) { - if (me.cats[me.defined_category[i].category] === undefined) { - me.cats[me.defined_category[i].category] = [me.defined_category[i].tag]; - } else { - me.cats[me.defined_category[i].category].push(me.defined_category[i].tag); - } - me.cat_tags[i] = me.defined_category[i].tag; - } - me.tempstats = r.message.stats; - - $.each(me.cats, function(i, v) { - me.render_stat(i, (me.tempstats || {})["_user_tags"], v); - }); - me.render_stat("_user_tags", (me.tempstats || {})["_user_tags"]); - } else { - //render normal stats - me.render_stat("_user_tags", (r.message.stats || {})["_user_tags"]); - } + me.render_stat("_user_tags", (r.message.stats || {})["_user_tags"]); + let stats_dropdown = me.sidebar.find('.list-stats-dropdown'); + frappe.utils.setup_search(stats_dropdown, '.stat-link', '.stat-label'); } }); } @@ -361,7 +332,7 @@ frappe.views.ListSidebar = class ListSidebar { me.list_view.refresh(); }); }) - .insertBefore(this.sidebar.find(".close-sidebar-button")); + .appendTo(this.sidebar.find(".list-stats-dropdown")); } set_fieldtype(df) { @@ -392,8 +363,8 @@ frappe.views.ListSidebar = class ListSidebar { } reload_stats() { - this.sidebar.find(".sidebar-stat").remove(); - this.sidebar.find(".list-tag-preview").remove(); + this.sidebar.find(".stat-link").remove(); + this.sidebar.find(".stat-no-records").remove(); this.get_stats(); } From 8373520296751b76a4617b1869acb6e30714f78f Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Tue, 11 Aug 2020 14:24:51 +0300 Subject: [PATCH 09/34] :bug: Remove blank line --- frappe/public/js/frappe/list/list_sidebar.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_sidebar.js b/frappe/public/js/frappe/list/list_sidebar.js index b3f65253c7..4dbd1076db 100644 --- a/frappe/public/js/frappe/list/list_sidebar.js +++ b/frappe/public/js/frappe/list/list_sidebar.js @@ -219,7 +219,6 @@ frappe.views.ListSidebar = class ListSidebar { let email_account = (account.email_id == "All Accounts") ? "All Accounts" : account.email_account; let route = ["List", "Communication", "Inbox", email_account].join('/'); let display_name = ["All Accounts", "Sent Mail", "Spam", "Trash"].includes(account.email_id) ? __(account.email_id) : account.email_id; - if (!divider) { this.get_divider().appendTo($dropdown); divider = true; From 325d0e32c11f4dc31cd8fe6b8541132d56a118bf Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Tue, 11 Aug 2020 17:20:03 +0300 Subject: [PATCH 10/34] :art: Changes from new requirements (python) --- frappe/geo/utils.py | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index b99ca56ce8..1f9dd2d335 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -4,17 +4,17 @@ from __future__ import unicode_literals +import json + import frappe from pymysql import InternalError - - @frappe.whitelist() def get_coords(doctype, filters, type): '''Get list of coordinates in form - returns {name, location} with location being a geojson string''' + returns {names: ['latitude', 'longitude']} or location type''' filters_sql = get_coords_conditions(doctype, filters)[4:] out = None if type == 'coordinates': @@ -23,18 +23,34 @@ def get_coords(doctype, filters, type): out = return_location(doctype, filters_sql) return out + +def convert_to_geo_json(coords_list): + handled_geo_json_dict = [] + for element in coords_list: + handled_geo_json = json.loads(element['location']) + for coord in handled_geo_json['features']: + coord['properties']['name'] = element['name'] + handled_geo_json_dict.append(coord.copy()) + print(handled_geo_json['features']) + handled_geo_json = {"type": "FeatureCollection", "features": handled_geo_json_dict} + return handled_geo_json + + def return_location(doctype, filters_sql): if filters_sql: try: - coords = frappe.db.sql("""SELECT * FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) + coords = frappe.db.sql("""SELECT name,location FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) except InternalError: - frappe.msgprint(frappe._('This Doctype did not contain location field')) + frappe.msgprint(frappe._('This Doctype did not contains latitude and longitude fields')) return else: - coords = frappe.get_all(doctype, fields = ['name', 'location']) - return coords + coords = frappe.get_all(doctype, fields=['location', 'name']) + handled_geo_json = convert_to_geo_json(coords) + return handled_geo_json + def return_coordinates(doctype, filters_sql): + handled_geo_json = {"type": "FeatureCollection", "features": None} if filters_sql: try: coords = frappe.db.sql("""SELECT * FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) @@ -43,12 +59,15 @@ def return_coordinates(doctype, filters_sql): return else: coords = frappe.get_all(doctype, fields=['name', 'latitude', 'longitude']) - out = frappe._dict() + out_list = [] for i in coords: - out[i.name] = out.get(i.docname, []) - out[i.name].append(i.latitude) - out[i.name].append(i.longitude) - return out + node = {"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": None}} + node['properties']['name'] = i.name + node['geometry']['coordinates'] = [i.latitude, i.longitude] + out_list.append(node.copy()) + handled_geo_json['features'] = out_list + print(handled_geo_json) + return handled_geo_json def get_coords_conditions(doctype, filters=None): From da46ca2f1234e788a39f353fb677349041356b84 Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Tue, 11 Aug 2020 17:21:57 +0300 Subject: [PATCH 11/34] :art: Changes from new requirements --- frappe/public/js/frappe/views/map/map_view.js | 26 +++++-------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index d511460798..7e75dd0640 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -53,25 +53,11 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { }).addTo(this.map); L.control.scale().addTo(this.map); - - let lastCoords = []; - if (this.type === 'coordinates') { - for (const [key, value] of Object.entries(this.coords)) { - new L.marker([value[0], value[1]]) - .bindPopup(key) - .addTo(this.map); - lastCoords = [value[0], value[1]]; - } - } - if (this.type === 'location_field') { - for (let i = 0; i < this.coords.length; i++) { - let features = JSON.parse(this.coords[i].location).features; - features.forEach( - coords => L.geoJSON(coords).bindPopup(this.coords[i].name).addTo(this.map) - ); - lastCoords = features[0].geometry.coordinates.reverse(); - } - } + console.log(this.coords); + this.coords.features.forEach( + coords => L.geoJSON(coords).bindPopup(coords.properties.name).addTo(this.map) + ); + let lastCoords = this.coords.features[0].geometry.coordinates.reverse(); this.map.panTo(lastCoords, 8); } @@ -98,7 +84,7 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { type: this.type } }).then(r => { - this.coords = Object.assign(r.message); + this.coords = r.message; }); } From f27eee1ce67ac95b5f4538a6994074f8d93d51e9 Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Tue, 11 Aug 2020 17:30:36 +0300 Subject: [PATCH 12/34] :bug: Only location or latitude and longitude --- frappe/geo/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index 1f9dd2d335..c1fc5bbb52 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -37,11 +37,11 @@ def convert_to_geo_json(coords_list): def return_location(doctype, filters_sql): - if filters_sql: + if filters_sql: try: - coords = frappe.db.sql("""SELECT name,location FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) + coords = frappe.db.sql("""SELECT name, location FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) except InternalError: - frappe.msgprint(frappe._('This Doctype did not contains latitude and longitude fields')) + frappe.msgprint(frappe._('This Doctype did not contains location fields')) return else: coords = frappe.get_all(doctype, fields=['location', 'name']) @@ -53,7 +53,7 @@ def return_coordinates(doctype, filters_sql): handled_geo_json = {"type": "FeatureCollection", "features": None} if filters_sql: try: - coords = frappe.db.sql("""SELECT * FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) + coords = frappe.db.sql("""SELECT name, latitude, longitude FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) except InternalError: frappe.msgprint(frappe._('This Doctype did not contains latitude and longitude fields')) return From 32546694b796060c1812ba311f7a4fe54d56e826 Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Tue, 11 Aug 2020 17:50:55 +0300 Subject: [PATCH 13/34] :pencil: Update description Co-authored-by: Mathieu Brunot --- frappe/geo/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index c1fc5bbb52..ab7b856c3c 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -14,7 +14,7 @@ from pymysql import InternalError @frappe.whitelist() def get_coords(doctype, filters, type): '''Get list of coordinates in form - returns {names: ['latitude', 'longitude']} or location type''' + returns {name, location} with location being a geojson string''' filters_sql = get_coords_conditions(doctype, filters)[4:] out = None if type == 'coordinates': From 8061b37748b1058bc04b643fa9c7ba1a7c7cff5d Mon Sep 17 00:00:00 2001 From: Mathieu Brunot Date: Tue, 11 Aug 2020 17:10:02 +0200 Subject: [PATCH 14/34] :art: Restore empty line --- frappe/public/js/frappe/list/list_sidebar.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/public/js/frappe/list/list_sidebar.js b/frappe/public/js/frappe/list/list_sidebar.js index 4dbd1076db..b3f65253c7 100644 --- a/frappe/public/js/frappe/list/list_sidebar.js +++ b/frappe/public/js/frappe/list/list_sidebar.js @@ -219,6 +219,7 @@ frappe.views.ListSidebar = class ListSidebar { let email_account = (account.email_id == "All Accounts") ? "All Accounts" : account.email_account; let route = ["List", "Communication", "Inbox", email_account].join('/'); let display_name = ["All Accounts", "Sent Mail", "Spam", "Trash"].includes(account.email_id) ? __(account.email_id) : account.email_id; + if (!divider) { this.get_divider().appendTo($dropdown); divider = true; From be76942394b01778767c11880b34630b58d47956 Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Wed, 12 Aug 2020 12:57:08 +0300 Subject: [PATCH 15/34] :fire: Remove debug print --- frappe/geo/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index ab7b856c3c..836b52f4b2 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -31,7 +31,6 @@ def convert_to_geo_json(coords_list): for coord in handled_geo_json['features']: coord['properties']['name'] = element['name'] handled_geo_json_dict.append(coord.copy()) - print(handled_geo_json['features']) handled_geo_json = {"type": "FeatureCollection", "features": handled_geo_json_dict} return handled_geo_json @@ -44,7 +43,7 @@ def return_location(doctype, filters_sql): frappe.msgprint(frappe._('This Doctype did not contains location fields')) return else: - coords = frappe.get_all(doctype, fields=['location', 'name']) + coords = frappe.get_all(doctype, fields=['name', 'location']) handled_geo_json = convert_to_geo_json(coords) return handled_geo_json From 60153cb857bd16139f72a8cf2f364bbffb251864 Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Wed, 12 Aug 2020 16:29:07 +0300 Subject: [PATCH 16/34] :truck: Rename function --- frappe/geo/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index 836b52f4b2..949efb6d5e 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -24,7 +24,7 @@ def get_coords(doctype, filters, type): return out -def convert_to_geo_json(coords_list): +def merge_all_feature_collection_in_one(coords_list): handled_geo_json_dict = [] for element in coords_list: handled_geo_json = json.loads(element['location']) @@ -44,7 +44,7 @@ def return_location(doctype, filters_sql): return else: coords = frappe.get_all(doctype, fields=['name', 'location']) - handled_geo_json = convert_to_geo_json(coords) + handled_geo_json = merge_all_feature_collection_in_one(coords) return handled_geo_json From d0728df83b99be00a20094dadb392fd81b06ebae Mon Sep 17 00:00:00 2001 From: AminovE99 <32329685+AminovE99@users.noreply.github.com> Date: Wed, 12 Aug 2020 16:30:01 +0300 Subject: [PATCH 17/34] :fire: Remove console log --- frappe/public/js/frappe/views/map/map_view.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 7e75dd0640..8b46ef1a95 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -53,7 +53,6 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { }).addTo(this.map); L.control.scale().addTo(this.map); - console.log(this.coords); this.coords.features.forEach( coords => L.geoJSON(coords).bindPopup(coords.properties.name).addTo(this.map) ); From e9b3085c6a1ab1376000bac74c8582a22841f4fe Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Wed, 12 Aug 2020 17:19:35 +0200 Subject: [PATCH 18/34] :art: Split Geo Utils into specific functions Signed-off-by: mathieu.brunot --- frappe/geo/utils.py | 78 ++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index 949efb6d5e..919dcfd961 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -13,64 +13,82 @@ from pymysql import InternalError @frappe.whitelist() def get_coords(doctype, filters, type): - '''Get list of coordinates in form - returns {name, location} with location being a geojson string''' + '''Get a geojson dict representing a doctype.''' filters_sql = get_coords_conditions(doctype, filters)[4:] - out = None - if type == 'coordinates': - out = return_coordinates(doctype, filters_sql) + + coords = None if type == 'location_field': - out = return_location(doctype, filters_sql) + coords = return_location(doctype, filters_sql) + elif type == 'coordinates': + coords = return_coordinates(doctype, filters_sql) + + out = convert_to_geojson(type, coords) return out +def convert_to_geojson(type, coords): + '''Converts GPS coordinates to geoJSON string.''' + geojson = {"type": "FeatureCollection", "features": None} -def merge_all_feature_collection_in_one(coords_list): - handled_geo_json_dict = [] - for element in coords_list: - handled_geo_json = json.loads(element['location']) - for coord in handled_geo_json['features']: + if type == 'location_field': + geojson['features'] = merge_location_features_in_one(coords) + elif type == 'coordinates': + geojson['features'] = create_gps_markers(coords) + + return geojson + + +def merge_location_features_in_one(coords): + '''Merging all features from location field.''' + geojson_dict = [] + for element in coords: + geojson_loc = json.loads(element['location']) + for coord in geojson_loc['features']: coord['properties']['name'] = element['name'] - handled_geo_json_dict.append(coord.copy()) - handled_geo_json = {"type": "FeatureCollection", "features": handled_geo_json_dict} - return handled_geo_json + geojson_dict.append(coord.copy()) + + return geojson_dict + + +def create_gps_markers(coords): + '''Build Marker based on latitude and longitude.''' + geojson_dict = [] + for i in coords: + node = {"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": None}} + node['properties']['name'] = i.name + node['geometry']['coordinates'] = [i.latitude, i.longitude] + geojson_dict.append(node.copy()) + + return geojson_dict def return_location(doctype, filters_sql): - if filters_sql: + '''Get name and location fields for Doctype.''' + if filters_sql: try: - coords = frappe.db.sql("""SELECT name, location FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) + coords = frappe.db.sql('''SELECT name, location FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) except InternalError: frappe.msgprint(frappe._('This Doctype did not contains location fields')) return else: coords = frappe.get_all(doctype, fields=['name', 'location']) - handled_geo_json = merge_all_feature_collection_in_one(coords) - return handled_geo_json + return coords def return_coordinates(doctype, filters_sql): - handled_geo_json = {"type": "FeatureCollection", "features": None} + '''Get name, latitude and longitude fields for Doctype.''' if filters_sql: try: - coords = frappe.db.sql("""SELECT name, latitude, longitude FROM `tab{}` WHERE {}""".format(doctype, filters_sql), as_dict=True) + coords = frappe.db.sql('''SELECT name, latitude, longitude FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) except InternalError: frappe.msgprint(frappe._('This Doctype did not contains latitude and longitude fields')) return else: coords = frappe.get_all(doctype, fields=['name', 'latitude', 'longitude']) - out_list = [] - for i in coords: - node = {"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": None}} - node['properties']['name'] = i.name - node['geometry']['coordinates'] = [i.latitude, i.longitude] - out_list.append(node.copy()) - handled_geo_json['features'] = out_list - print(handled_geo_json) - return handled_geo_json + return coords def get_coords_conditions(doctype, filters=None): - """Returns SQL conditions with user permissions and filters for event queries""" + '''Returns SQL conditions with user permissions and filters for event queries.''' from frappe.desk.reportview import get_filters_cond if not frappe.has_permission(doctype): frappe.throw(frappe._("Not Permitted"), frappe.PermissionError) From 80857f6c90c94094c391f61fe9438b6cd69d9ced Mon Sep 17 00:00:00 2001 From: Emil Date: Fri, 14 Aug 2020 14:52:57 +0300 Subject: [PATCH 19/34] :white_check_mark: Add tests Signed-off-by: Emil --- frappe/geo/utils.py | 4 ++-- frappe/tests/tests_geo_utils.py | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 frappe/tests/tests_geo_utils.py diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index 919dcfd961..d7011a7eb0 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -67,7 +67,7 @@ def return_location(doctype, filters_sql): try: coords = frappe.db.sql('''SELECT name, location FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) except InternalError: - frappe.msgprint(frappe._('This Doctype did not contains location fields')) + frappe.msgprint(frappe._('This Doctype did not contains location fields'), raise_exception=True) return else: coords = frappe.get_all(doctype, fields=['name', 'location']) @@ -80,7 +80,7 @@ def return_coordinates(doctype, filters_sql): try: coords = frappe.db.sql('''SELECT name, latitude, longitude FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) except InternalError: - frappe.msgprint(frappe._('This Doctype did not contains latitude and longitude fields')) + frappe.msgprint(frappe._('This Doctype did not contains latitude and longitude fields'), raise_exception=True) return else: coords = frappe.get_all(doctype, fields=['name', 'latitude', 'longitude']) diff --git a/frappe/tests/tests_geo_utils.py b/frappe/tests/tests_geo_utils.py new file mode 100644 index 0000000000..3c5757423e --- /dev/null +++ b/frappe/tests/tests_geo_utils.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals + +import unittest + +import frappe +from frappe.geo.utils import get_coords + + +class TestGeoUtils(unittest.TestCase): + def setUp(self): + self.todo = frappe.get_doc( + dict(doctype='ToDo', description='Test description', assigned_by='Administrator')).insert() + + self.test_location_dict = {'type': 'FeatureCollection', 'features': [ + {'type': 'Feature', 'properties': {}, "geometry": {'type': 'Point', 'coordinates': [49.20433, 55.753395]}}]} + self.test_location = frappe.get_doc({'name': 'Test Location', 'doctype': 'Location', + 'location': str(self.test_location_dict)}) + + self.test_filter_exists = [['Location', 'name', 'like', '%Test Location%']] + self.test_filter_not_exists = [['Location', 'name', 'like', '%Test Location Not exists%']] + self.test_filter_todo = [['ToDo', 'description', 'like', '%Test description%']] + + def test_get_coords_location_with_filter_exists(self): + coords = get_coords('Location', self.test_filter_exists, 'location_field') + self.assertEqual(self.test_location_dict['features'][0]['geometry'], coords['features'][0]['geometry']) + + def test_get_coords_location_with_filter_not_exists(self): + coords = get_coords('Location', self.test_filter_not_exists, 'location_field') + self.assertEqual(coords, {'type': 'FeatureCollection', 'features': []}) + + def test_get_coords_from_not_existable_location(self): + self.assertRaises(frappe.ValidationError, get_coords, 'ToDo', self.test_filter_todo, 'location_field') + + def test_get_coords_from_not_existable_coords(self): + self.assertRaises(frappe.ValidationError, get_coords, 'ToDo', self.test_filter_todo, 'coordinates') + + def tearDown(self): + self.todo.delete() From a22347d806f98da3c54b2cab8a4c9f2d59a26022 Mon Sep 17 00:00:00 2001 From: Mathieu Brunot Date: Wed, 7 Oct 2020 18:10:18 +0200 Subject: [PATCH 20/34] chore: Apply suggestions from code review Co-authored-by: Prssanna Desai --- frappe/geo/utils.py | 4 ++-- frappe/public/js/frappe/views/map/map_view.js | 13 ++++--------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index d7011a7eb0..f1102f2289 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -67,7 +67,7 @@ def return_location(doctype, filters_sql): try: coords = frappe.db.sql('''SELECT name, location FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) except InternalError: - frappe.msgprint(frappe._('This Doctype did not contains location fields'), raise_exception=True) + frappe.msgprint(frappe._('This Doctype does not contain location fields'), raise_exception=True) return else: coords = frappe.get_all(doctype, fields=['name', 'location']) @@ -80,7 +80,7 @@ def return_coordinates(doctype, filters_sql): try: coords = frappe.db.sql('''SELECT name, latitude, longitude FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) except InternalError: - frappe.msgprint(frappe._('This Doctype did not contains latitude and longitude fields'), raise_exception=True) + frappe.msgprint(frappe._('This Doctype does not contain latitude and longitude fields'), raise_exception=True) return else: coords = frappe.get_all(doctype, fields=['name', 'latitude', 'longitude']) diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 8b46ef1a95..c70199f041 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -61,17 +61,12 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { } get_coords() { - let get_coords_method; - if (JSON.stringify(frappe.listview_settings) === '{}') { - get_coords_method = 'frappe.geo.utils.get_coords'; - } else { - get_coords_method = frappe.listview_settings[this.doctype].get_coords_method; - } - if (cur_list.meta.fields.find(i => i.fieldname === 'location') && - cur_list.meta.fields.find(i => i.fieldtype === 'Geolocation')) { + let get_coords_method = this.settings && this.settings.get_coords_method || 'frappe.geo.utils.get_coords'; + + if (cur_list.meta.fields.find(i => i.fieldname === 'location' && i.fieldtype === 'Geolocation')) { this.type = 'location_field'; } - if (cur_list.meta.fields.find(i => i.fieldname === "latitude") && + else if (cur_list.meta.fields.find(i => i.fieldname === "latitude") && cur_list.meta.fields.find(i => i.fieldname === "longitude")) { this.type = 'coordinates'; } From ad313cf549e3be84fc9c3deaa42b8a59f7fbc61d Mon Sep 17 00:00:00 2001 From: Mathieu Brunot Date: Wed, 7 Oct 2020 18:12:03 +0200 Subject: [PATCH 21/34] chore: Apply suggestions from code review Co-authored-by: Prssanna Desai --- frappe/geo/utils.py | 2 +- frappe/public/js/frappe/list/list_sidebar.js | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index f1102f2289..f4b0284226 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -41,7 +41,7 @@ def merge_location_features_in_one(coords): '''Merging all features from location field.''' geojson_dict = [] for element in coords: - geojson_loc = json.loads(element['location']) + geojson_loc = frappe.parse_json(element['location']) for coord in geojson_loc['features']: coord['properties']['name'] = element['name'] geojson_dict.append(coord.copy()) diff --git a/frappe/public/js/frappe/list/list_sidebar.js b/frappe/public/js/frappe/list/list_sidebar.js index b3f65253c7..4d637602a3 100644 --- a/frappe/public/js/frappe/list/list_sidebar.js +++ b/frappe/public/js/frappe/list/list_sidebar.js @@ -91,11 +91,10 @@ frappe.views.ListSidebar = class ListSidebar { show_list_link = true; } - if ((JSON.stringify(frappe.listview_settings) !== '{}' && - frappe.listview_settings[this.list_view.doctype].get_coords_method) || - (this.list_view.meta.fields.find(i => i.fieldname === "latitude") && - this.list_view.meta.fields.find(i => i.fieldname === "longitude")) || - (this.list_view.meta.fields.find(i => i.fieldname === 'location') && this.list_view.meta.fields.find(i => i.fieldtype === 'Geolocation'))) { + if (this.list_view.settings.get_coords_method || + (this.list_view.meta.fields.find(i => i.fieldname === "latitude") && + this.list_view.meta.fields.find(i => i.fieldname === "longitude")) || + (this.list_view.meta.fields.find(i => i.fieldname === 'location' && i.fieldtype == 'Geolocation'))) this.sidebar.find('.list-link[data-view="Map"]').removeClass('hide'); show_list_link = true; } From 3c181bf2a203a8c82060e70b0e502e90090fca7e Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Wed, 7 Oct 2020 18:57:01 +0200 Subject: [PATCH 22/34] Replace spaces by tabs Signed-off-by: mathieu.brunot --- frappe/geo/utils.py | 114 ++++++++++++++++---------------- frappe/tests/tests_geo_utils.py | 44 ++++++------ 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index f4b0284226..ffb27e62dc 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -13,84 +13,84 @@ from pymysql import InternalError @frappe.whitelist() def get_coords(doctype, filters, type): - '''Get a geojson dict representing a doctype.''' - filters_sql = get_coords_conditions(doctype, filters)[4:] + '''Get a geojson dict representing a doctype.''' + filters_sql = get_coords_conditions(doctype, filters)[4:] - coords = None - if type == 'location_field': - coords = return_location(doctype, filters_sql) - elif type == 'coordinates': - coords = return_coordinates(doctype, filters_sql) + coords = None + if type == 'location_field': + coords = return_location(doctype, filters_sql) + elif type == 'coordinates': + coords = return_coordinates(doctype, filters_sql) - out = convert_to_geojson(type, coords) - return out + out = convert_to_geojson(type, coords) + return out def convert_to_geojson(type, coords): - '''Converts GPS coordinates to geoJSON string.''' - geojson = {"type": "FeatureCollection", "features": None} + '''Converts GPS coordinates to geoJSON string.''' + geojson = {"type": "FeatureCollection", "features": None} - if type == 'location_field': - geojson['features'] = merge_location_features_in_one(coords) - elif type == 'coordinates': - geojson['features'] = create_gps_markers(coords) + if type == 'location_field': + geojson['features'] = merge_location_features_in_one(coords) + elif type == 'coordinates': + geojson['features'] = create_gps_markers(coords) - return geojson + return geojson def merge_location_features_in_one(coords): - '''Merging all features from location field.''' - geojson_dict = [] - for element in coords: - geojson_loc = frappe.parse_json(element['location']) - for coord in geojson_loc['features']: - coord['properties']['name'] = element['name'] - geojson_dict.append(coord.copy()) + '''Merging all features from location field.''' + geojson_dict = [] + for element in coords: + geojson_loc = frappe.parse_json(element['location']) + for coord in geojson_loc['features']: + coord['properties']['name'] = element['name'] + geojson_dict.append(coord.copy()) - return geojson_dict + return geojson_dict def create_gps_markers(coords): - '''Build Marker based on latitude and longitude.''' - geojson_dict = [] - for i in coords: - node = {"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": None}} - node['properties']['name'] = i.name - node['geometry']['coordinates'] = [i.latitude, i.longitude] - geojson_dict.append(node.copy()) + '''Build Marker based on latitude and longitude.''' + geojson_dict = [] + for i in coords: + node = {"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": None}} + node['properties']['name'] = i.name + node['geometry']['coordinates'] = [i.latitude, i.longitude] + geojson_dict.append(node.copy()) - return geojson_dict + return geojson_dict def return_location(doctype, filters_sql): - '''Get name and location fields for Doctype.''' - if filters_sql: - try: - coords = frappe.db.sql('''SELECT name, location FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) - except InternalError: - frappe.msgprint(frappe._('This Doctype does not contain location fields'), raise_exception=True) - return - else: - coords = frappe.get_all(doctype, fields=['name', 'location']) - return coords + '''Get name and location fields for Doctype.''' + if filters_sql: + try: + coords = frappe.db.sql('''SELECT name, location FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) + except InternalError: + frappe.msgprint(frappe._('This Doctype does not contain location fields'), raise_exception=True) + return + else: + coords = frappe.get_all(doctype, fields=['name', 'location']) + return coords def return_coordinates(doctype, filters_sql): - '''Get name, latitude and longitude fields for Doctype.''' - if filters_sql: - try: - coords = frappe.db.sql('''SELECT name, latitude, longitude FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) - except InternalError: - frappe.msgprint(frappe._('This Doctype does not contain latitude and longitude fields'), raise_exception=True) - return - else: - coords = frappe.get_all(doctype, fields=['name', 'latitude', 'longitude']) - return coords + '''Get name, latitude and longitude fields for Doctype.''' + if filters_sql: + try: + coords = frappe.db.sql('''SELECT name, latitude, longitude FROM `tab{}` WHERE {}'''.format(doctype, filters_sql), as_dict=True) + except InternalError: + frappe.msgprint(frappe._('This Doctype does not contain latitude and longitude fields'), raise_exception=True) + return + else: + coords = frappe.get_all(doctype, fields=['name', 'latitude', 'longitude']) + return coords def get_coords_conditions(doctype, filters=None): - '''Returns SQL conditions with user permissions and filters for event queries.''' - from frappe.desk.reportview import get_filters_cond - if not frappe.has_permission(doctype): - frappe.throw(frappe._("Not Permitted"), frappe.PermissionError) + '''Returns SQL conditions with user permissions and filters for event queries.''' + from frappe.desk.reportview import get_filters_cond + if not frappe.has_permission(doctype): + frappe.throw(frappe._("Not Permitted"), frappe.PermissionError) - return get_filters_cond(doctype, filters, [], with_match_conditions=True) + return get_filters_cond(doctype, filters, [], with_match_conditions=True) diff --git a/frappe/tests/tests_geo_utils.py b/frappe/tests/tests_geo_utils.py index 3c5757423e..2067a6aa97 100644 --- a/frappe/tests/tests_geo_utils.py +++ b/frappe/tests/tests_geo_utils.py @@ -11,32 +11,32 @@ from frappe.geo.utils import get_coords class TestGeoUtils(unittest.TestCase): - def setUp(self): - self.todo = frappe.get_doc( - dict(doctype='ToDo', description='Test description', assigned_by='Administrator')).insert() + def setUp(self): + self.todo = frappe.get_doc( + dict(doctype='ToDo', description='Test description', assigned_by='Administrator')).insert() - self.test_location_dict = {'type': 'FeatureCollection', 'features': [ - {'type': 'Feature', 'properties': {}, "geometry": {'type': 'Point', 'coordinates': [49.20433, 55.753395]}}]} - self.test_location = frappe.get_doc({'name': 'Test Location', 'doctype': 'Location', - 'location': str(self.test_location_dict)}) + self.test_location_dict = {'type': 'FeatureCollection', 'features': [ + {'type': 'Feature', 'properties': {}, "geometry": {'type': 'Point', 'coordinates': [49.20433, 55.753395]}}]} + self.test_location = frappe.get_doc({'name': 'Test Location', 'doctype': 'Location', + 'location': str(self.test_location_dict)}) - self.test_filter_exists = [['Location', 'name', 'like', '%Test Location%']] - self.test_filter_not_exists = [['Location', 'name', 'like', '%Test Location Not exists%']] - self.test_filter_todo = [['ToDo', 'description', 'like', '%Test description%']] + self.test_filter_exists = [['Location', 'name', 'like', '%Test Location%']] + self.test_filter_not_exists = [['Location', 'name', 'like', '%Test Location Not exists%']] + self.test_filter_todo = [['ToDo', 'description', 'like', '%Test description%']] - def test_get_coords_location_with_filter_exists(self): - coords = get_coords('Location', self.test_filter_exists, 'location_field') - self.assertEqual(self.test_location_dict['features'][0]['geometry'], coords['features'][0]['geometry']) + def test_get_coords_location_with_filter_exists(self): + coords = get_coords('Location', self.test_filter_exists, 'location_field') + self.assertEqual(self.test_location_dict['features'][0]['geometry'], coords['features'][0]['geometry']) - def test_get_coords_location_with_filter_not_exists(self): - coords = get_coords('Location', self.test_filter_not_exists, 'location_field') - self.assertEqual(coords, {'type': 'FeatureCollection', 'features': []}) + def test_get_coords_location_with_filter_not_exists(self): + coords = get_coords('Location', self.test_filter_not_exists, 'location_field') + self.assertEqual(coords, {'type': 'FeatureCollection', 'features': []}) - def test_get_coords_from_not_existable_location(self): - self.assertRaises(frappe.ValidationError, get_coords, 'ToDo', self.test_filter_todo, 'location_field') + def test_get_coords_from_not_existable_location(self): + self.assertRaises(frappe.ValidationError, get_coords, 'ToDo', self.test_filter_todo, 'location_field') - def test_get_coords_from_not_existable_coords(self): - self.assertRaises(frappe.ValidationError, get_coords, 'ToDo', self.test_filter_todo, 'coordinates') + def test_get_coords_from_not_existable_coords(self): + self.assertRaises(frappe.ValidationError, get_coords, 'ToDo', self.test_filter_todo, 'coordinates') - def tearDown(self): - self.todo.delete() + def tearDown(self): + self.todo.delete() From 007e59184da031beeee99f6f5333dda6676bde1d Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Sat, 24 Oct 2020 03:03:16 +0200 Subject: [PATCH 23/34] chore: Fix sider issues Signed-off-by: mathieu.brunot --- frappe/geo/utils.py | 2 -- frappe/public/js/frappe/views/map/map_view.js | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index ffb27e62dc..77e48acb76 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -4,8 +4,6 @@ from __future__ import unicode_literals -import json - import frappe from pymysql import InternalError diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index c70199f041..48e4ac8b3e 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -65,8 +65,7 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { if (cur_list.meta.fields.find(i => i.fieldname === 'location' && i.fieldtype === 'Geolocation')) { this.type = 'location_field'; - } - else if (cur_list.meta.fields.find(i => i.fieldname === "latitude") && + } else if (cur_list.meta.fields.find(i => i.fieldname === "latitude") && cur_list.meta.fields.find(i => i.fieldname === "longitude")) { this.type = 'coordinates'; } From df72f80d25deefbb27dbaee58e123bca0c29bf43 Mon Sep 17 00:00:00 2001 From: Mathieu Brunot Date: Fri, 20 Nov 2020 00:25:43 +0100 Subject: [PATCH 24/34] Update frappe/public/js/frappe/list/list_sidebar.js Co-authored-by: Prssanna Desai --- frappe/public/js/frappe/list/list_sidebar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_sidebar.js b/frappe/public/js/frappe/list/list_sidebar.js index 4d637602a3..0622e26dbd 100644 --- a/frappe/public/js/frappe/list/list_sidebar.js +++ b/frappe/public/js/frappe/list/list_sidebar.js @@ -94,7 +94,7 @@ frappe.views.ListSidebar = class ListSidebar { if (this.list_view.settings.get_coords_method || (this.list_view.meta.fields.find(i => i.fieldname === "latitude") && this.list_view.meta.fields.find(i => i.fieldname === "longitude")) || - (this.list_view.meta.fields.find(i => i.fieldname === 'location' && i.fieldtype == 'Geolocation'))) + (this.list_view.meta.fields.find(i => i.fieldname === 'location' && i.fieldtype == 'Geolocation'))) { this.sidebar.find('.list-link[data-view="Map"]').removeClass('hide'); show_list_link = true; } From a08692346994a0928550479b5dbf447cffe76d41 Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Fri, 20 Nov 2020 00:37:19 +0100 Subject: [PATCH 25/34] chore: Remove useless prepare_data Signed-off-by: mathieu.brunot --- frappe/public/js/frappe/views/map/map_view.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 48e4ac8b3e..84e5b70ab6 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -20,13 +20,6 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { this.get_coords(); } - prepare_data(data) { - super.prepare_data(data); - this.items = this.data.map(d => { - return d; - }); - } - render() { this.get_coords() .then(() => { From 90875ef21c3c3e4b32667970ff6bf1816ca938de Mon Sep 17 00:00:00 2001 From: Mathieu Brunot Date: Thu, 26 Nov 2020 02:26:57 +0100 Subject: [PATCH 26/34] Update frappe/geo/utils.py Co-authored-by: Prssanna Desai --- frappe/geo/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/geo/utils.py b/frappe/geo/utils.py index 77e48acb76..d94a13ea41 100644 --- a/frappe/geo/utils.py +++ b/frappe/geo/utils.py @@ -40,6 +40,8 @@ def merge_location_features_in_one(coords): geojson_dict = [] for element in coords: geojson_loc = frappe.parse_json(element['location']) + if not geojson_loc: + continue for coord in geojson_loc['features']: coord['properties']['name'] = element['name'] geojson_dict.append(coord.copy()) From 56b775a3deafd8d15b341c14abcf9d7c79c2bbfa Mon Sep 17 00:00:00 2001 From: Mathieu Brunot Date: Thu, 26 Nov 2020 02:54:41 +0100 Subject: [PATCH 27/34] Update frappe/public/js/frappe/views/map/map_view.js Co-authored-by: Prssanna Desai --- frappe/public/js/frappe/views/map/map_view.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 84e5b70ab6..2c068277ad 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -46,11 +46,13 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { }).addTo(this.map); L.control.scale().addTo(this.map); +if (this.coords.features && this.coords.features.length) { this.coords.features.forEach( coords => L.geoJSON(coords).bindPopup(coords.properties.name).addTo(this.map) ); let lastCoords = this.coords.features[0].geometry.coordinates.reverse(); this.map.panTo(lastCoords, 8); +} } get_coords() { From 24e021474f094fc3e7bd9fd46af5b900860cee70 Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Mon, 14 Dec 2020 02:01:24 +0100 Subject: [PATCH 28/34] chore: Move inline styles to CSS class Signed-off-by: mathieu.brunot --- frappe/public/css/list.css | 3 +++ frappe/public/js/frappe/views/map/map_view.js | 19 ++++++++++--------- frappe/public/less/list.less | 3 +++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/frappe/public/css/list.css b/frappe/public/css/list.css index 49ffbcd9e9..88ad147d33 100644 --- a/frappe/public/css/list.css +++ b/frappe/public/css/list.css @@ -404,6 +404,9 @@ input.list-row-checkbox { .map-view-container { display: flex; flex-wrap: wrap; + width: 100%; + height: calc(100vh - 284px); + z-index: 0; } .list-paging-area .gantt-view-mode { margin-left: 15px; diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 2c068277ad..8a75ecc457 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -32,13 +32,14 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { this.map_id = frappe.dom.get_unique_id(); this.$result.html(` -
    +
    `); - this.map = L.map(this.map_id).setView([12.3112899, -85.7384542], 8); //coords of India if markers does not exists + //coords of India if markers does not exists + this.map = L.map(this.map_id).setView([12.3112899, -85.7384542], 8); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors', @@ -46,13 +47,13 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { }).addTo(this.map); L.control.scale().addTo(this.map); -if (this.coords.features && this.coords.features.length) { - this.coords.features.forEach( - coords => L.geoJSON(coords).bindPopup(coords.properties.name).addTo(this.map) - ); - let lastCoords = this.coords.features[0].geometry.coordinates.reverse(); - this.map.panTo(lastCoords, 8); -} + if (this.coords.features && this.coords.features.length) { + this.coords.features.forEach( + coords => L.geoJSON(coords).bindPopup(coords.properties.name).addTo(this.map) + ); + let lastCoords = this.coords.features[0].geometry.coordinates.reverse(); + this.map.panTo(lastCoords, 8); + } } get_coords() { diff --git a/frappe/public/less/list.less b/frappe/public/less/list.less index 662e753b38..fba99ee50d 100644 --- a/frappe/public/less/list.less +++ b/frappe/public/less/list.less @@ -487,6 +487,9 @@ input.list-check-all, input.list-row-checkbox { .map-view-container { display: flex; flex-wrap: wrap; + width: 100%; + height: calc(100vh - 284px); + z-index: 0; } // list view From f2747a0de4258649782644e5a350bb5ebae25029 Mon Sep 17 00:00:00 2001 From: Mathieu Brunot Date: Mon, 14 Dec 2020 02:02:01 +0100 Subject: [PATCH 29/34] Update frappe/public/js/frappe/views/map/map_view.js Co-authored-by: Prssanna Desai --- frappe/public/js/frappe/views/map/map_view.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 2c068277ad..0ec8353ccb 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -31,11 +31,7 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { render_map_view() { this.map_id = frappe.dom.get_unique_id(); - this.$result.html(` -
    - -
    - `); + this.$result.html(`
    `); this.map = L.map(this.map_id).setView([12.3112899, -85.7384542], 8); //coords of India if markers does not exists From 4961774facbe7bb70d87d396d61f61c736b3ef4f Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Wed, 23 Dec 2020 01:20:39 +0100 Subject: [PATCH 30/34] chore: Define constants for map and geolocation Signed-off-by: mathieu.brunot --- frappe/public/js/frappe/form/controls/geolocation.js | 8 ++++---- frappe/public/js/frappe/views/map/map_view.js | 12 +++++------- frappe/public/js/frappe/widgets/utils.js | 11 ++++++++++- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/geolocation.js b/frappe/public/js/frappe/form/controls/geolocation.js index 9dfad09299..b6a04e5218 100644 --- a/frappe/public/js/frappe/form/controls/geolocation.js +++ b/frappe/public/js/frappe/form/controls/geolocation.js @@ -1,3 +1,5 @@ +import { map_defaults } from "../../widgets/utils"; + frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({ horizontal: false, @@ -90,11 +92,9 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({ }); L.Icon.Default.imagePath = '/assets/frappe/images/leaflet/'; - this.map = L.map(this.map_id).setView([19.0800, 72.8961], 13); + this.map = L.map(this.map_id).setView(map_defaults.center, map_defaults.zoom); - L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { - attribution: '© OpenStreetMap contributors' - }).addTo(this.map); + L.tileLayer(map_defaults.tiles, map_defaults.options).addTo(this.map); }, bind_leaflet_locate_control() { diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 12b4cef921..b6119eef1a 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -1,6 +1,8 @@ /** * frappe.views.MapView */ +import { map_defaults } from "../../widgets/utils"; + frappe.provide("frappe.views"); frappe.views.MapView = class MapView extends frappe.views.ListView { @@ -33,14 +35,10 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { this.$result.html(`
    `); + L.Icon.Default.imagePath = '/assets/frappe/images/leaflet/'; + this.map = L.map(this.map_id).setView(map_defaults.center, map_defaults.zoom); - //coords of India if markers does not exists - this.map = L.map(this.map_id).setView([12.3112899, -85.7384542], 8); - - L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution: '© OpenStreetMap contributors', - maxZoom: 18 - }).addTo(this.map); + L.tileLayer(map_defaults.tiles, map_defaults.options).addTo(this.map); L.control.scale().addTo(this.map); if (this.coords.features && this.coords.features.length) { diff --git a/frappe/public/js/frappe/widgets/utils.js b/frappe/public/js/frappe/widgets/utils.js index 4599b4adc8..03fb6995e0 100644 --- a/frappe/public/js/frappe/widgets/utils.js +++ b/frappe/public/js/frappe/widgets/utils.js @@ -163,4 +163,13 @@ function get_number_system(country) { return number_system_map[country]; } -export { generate_route, generate_grid, build_summary_item, shorten_number }; +const map_defaults = { + center: [19.0800, 72.8961], + zoom: 13, + tiles: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + options: { + attribution: '© OpenStreetMap contributors' + } +}; + +export { generate_route, generate_grid, build_summary_item, shorten_number, map_defaults }; From 5131697f3cebde4a258fc44f5aa61529a9b94c41 Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Wed, 23 Dec 2020 01:34:59 +0100 Subject: [PATCH 31/34] chore: Improve format of map defaults Signed-off-by: mathieu.brunot --- .../js/frappe/form/controls/geolocation.js | 8 +++++--- frappe/public/js/frappe/views/map/map_view.js | 9 +++++---- frappe/public/js/frappe/widgets/utils.js | 19 ++++++++----------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/geolocation.js b/frappe/public/js/frappe/form/controls/geolocation.js index b6a04e5218..31a5854f9a 100644 --- a/frappe/public/js/frappe/form/controls/geolocation.js +++ b/frappe/public/js/frappe/form/controls/geolocation.js @@ -1,4 +1,4 @@ -import { map_defaults } from "../../widgets/utils"; +frappe.provide('frappe.widget.utils'); frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({ horizontal: false, @@ -92,9 +92,11 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({ }); L.Icon.Default.imagePath = '/assets/frappe/images/leaflet/'; - this.map = L.map(this.map_id).setView(map_defaults.center, map_defaults.zoom); + this.map = L.map(this.map_id).setView(frappe.widget.utils.map_defaults.center, + frappe.widget.utils.map_defaults.zoom); - L.tileLayer(map_defaults.tiles, map_defaults.options).addTo(this.map); + L.tileLayer(frappe.widget.utils.map_defaults.tiles, + frappe.widget.utils.map_defaults.options).addTo(this.map); }, bind_leaflet_locate_control() { diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index b6119eef1a..539ac86e99 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -1,8 +1,7 @@ /** * frappe.views.MapView */ -import { map_defaults } from "../../widgets/utils"; - +frappe.provide('frappe.widget.utils'); frappe.provide("frappe.views"); frappe.views.MapView = class MapView extends frappe.views.ListView { @@ -36,9 +35,11 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { this.$result.html(`
    `); L.Icon.Default.imagePath = '/assets/frappe/images/leaflet/'; - this.map = L.map(this.map_id).setView(map_defaults.center, map_defaults.zoom); + this.map = L.map(this.map_id).setView(frappe.widget.utils.map_defaults.center, + frappe.widget.utils.map_defaults.zoom); - L.tileLayer(map_defaults.tiles, map_defaults.options).addTo(this.map); + L.tileLayer(frappe.widget.utils.map_defaults.tiles, + frappe.widget.utils.map_defaults.options).addTo(this.map); L.control.scale().addTo(this.map); if (this.coords.features && this.coords.features.length) { diff --git a/frappe/public/js/frappe/widgets/utils.js b/frappe/public/js/frappe/widgets/utils.js index 5121ee398e..e3632856bb 100644 --- a/frappe/public/js/frappe/widgets/utils.js +++ b/frappe/public/js/frappe/widgets/utils.js @@ -21,15 +21,12 @@ frappe.widget.utils = { }

    ${value}

    ` ); }, + map_defaults: { + center: [19.0800, 72.8961], + zoom: 13, + tiles: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + options: { + attribution: '© OpenStreetMap contributors' + } + }, }; - -const map_defaults = { - center: [19.0800, 72.8961], - zoom: 13, - tiles: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - options: { - attribution: '© OpenStreetMap contributors' - } -}; - -export { map_defaults }; From d6488a043ee0be982db5e54199fb242dab8dda0e Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Thu, 24 Dec 2020 13:59:02 +0100 Subject: [PATCH 32/34] refactor: Move map default to utils Signed-off-by: mathieu.brunot --- frappe/public/js/frappe/form/controls/geolocation.js | 2 +- frappe/public/js/frappe/utils/utils.js | 8 ++++++++ frappe/public/js/frappe/views/map/map_view.js | 2 +- frappe/public/js/frappe/widgets/utils.js | 8 -------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/geolocation.js b/frappe/public/js/frappe/form/controls/geolocation.js index 31a5854f9a..96a80fb1d1 100644 --- a/frappe/public/js/frappe/form/controls/geolocation.js +++ b/frappe/public/js/frappe/form/controls/geolocation.js @@ -1,4 +1,4 @@ -frappe.provide('frappe.widget.utils'); +frappe.provide('frappe.utils.utils'); frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({ horizontal: false, diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index f8f25293b3..32be29df92 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1051,6 +1051,14 @@ Object.assign(frappe.utils, { return number_system_map[country]; }, + map_defaults: { + center: [19.0800, 72.8961], + zoom: 13, + tiles: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + options: { + attribution: '© OpenStreetMap contributors' + } + }, }); // Array de duplicate diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 539ac86e99..205df5f4d3 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -1,7 +1,7 @@ /** * frappe.views.MapView */ -frappe.provide('frappe.widget.utils'); +frappe.provide('frappe.utils.utils'); frappe.provide("frappe.views"); frappe.views.MapView = class MapView extends frappe.views.ListView { diff --git a/frappe/public/js/frappe/widgets/utils.js b/frappe/public/js/frappe/widgets/utils.js index e3632856bb..ade35dae35 100644 --- a/frappe/public/js/frappe/widgets/utils.js +++ b/frappe/public/js/frappe/widgets/utils.js @@ -21,12 +21,4 @@ frappe.widget.utils = { }

    ${value}

    ` ); }, - map_defaults: { - center: [19.0800, 72.8961], - zoom: 13, - tiles: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - options: { - attribution: '© OpenStreetMap contributors' - } - }, }; From 9dde944f102a165ca2668b7c1e93207950a456fc Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Thu, 24 Dec 2020 15:32:23 +0100 Subject: [PATCH 33/34] fix: Fix call to utils map defaults Signed-off-by: mathieu.brunot --- frappe/public/js/frappe/form/controls/geolocation.js | 8 ++++---- frappe/public/js/frappe/views/map/map_view.js | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/geolocation.js b/frappe/public/js/frappe/form/controls/geolocation.js index 96a80fb1d1..9e4d1d82ec 100644 --- a/frappe/public/js/frappe/form/controls/geolocation.js +++ b/frappe/public/js/frappe/form/controls/geolocation.js @@ -92,11 +92,11 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({ }); L.Icon.Default.imagePath = '/assets/frappe/images/leaflet/'; - this.map = L.map(this.map_id).setView(frappe.widget.utils.map_defaults.center, - frappe.widget.utils.map_defaults.zoom); + this.map = L.map(this.map_id).setView(frappe.utils.map_defaults.center, + frappe.utils.map_defaults.zoom); - L.tileLayer(frappe.widget.utils.map_defaults.tiles, - frappe.widget.utils.map_defaults.options).addTo(this.map); + L.tileLayer(frappe.utils.map_defaults.tiles, + frappe.utils.map_defaults.options).addTo(this.map); }, bind_leaflet_locate_control() { diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index 205df5f4d3..a6936d58e1 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -35,11 +35,11 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { this.$result.html(`
    `); L.Icon.Default.imagePath = '/assets/frappe/images/leaflet/'; - this.map = L.map(this.map_id).setView(frappe.widget.utils.map_defaults.center, - frappe.widget.utils.map_defaults.zoom); + this.map = L.map(this.map_id).setView(frappe.utils.map_defaults.center, + frappe.utils.map_defaults.zoom); - L.tileLayer(frappe.widget.utils.map_defaults.tiles, - frappe.widget.utils.map_defaults.options).addTo(this.map); + L.tileLayer(frappe.utils.map_defaults.tiles, + frappe.utils.map_defaults.options).addTo(this.map); L.control.scale().addTo(this.map); if (this.coords.features && this.coords.features.length) { From 6a02f5ad52cda9ae9fe534a70a04f8b5bc310756 Mon Sep 17 00:00:00 2001 From: "mathieu.brunot" Date: Tue, 29 Dec 2020 01:27:13 +0100 Subject: [PATCH 34/34] style: Fix Sider issues Signed-off-by: mathieu.brunot --- frappe/public/js/frappe/views/map/map_view.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/views/map/map_view.js b/frappe/public/js/frappe/views/map/map_view.js index a6936d58e1..878311b9bd 100644 --- a/frappe/public/js/frappe/views/map/map_view.js +++ b/frappe/public/js/frappe/views/map/map_view.js @@ -43,11 +43,11 @@ frappe.views.MapView = class MapView extends frappe.views.ListView { L.control.scale().addTo(this.map); if (this.coords.features && this.coords.features.length) { - this.coords.features.forEach( - coords => L.geoJSON(coords).bindPopup(coords.properties.name).addTo(this.map) - ); - let lastCoords = this.coords.features[0].geometry.coordinates.reverse(); - this.map.panTo(lastCoords, 8); + this.coords.features.forEach( + coords => L.geoJSON(coords).bindPopup(coords.properties.name).addTo(this.map) + ); + let lastCoords = this.coords.features[0].geometry.coordinates.reverse(); + this.map.panTo(lastCoords, 8); } }