diff --git a/.eslintrc b/.eslintrc
index 05a5930db6..ec8d486c1e 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -56,6 +56,7 @@
"root": true,
"globals": {
"frappe": true,
+ "Vue": true,
"__": true,
"_p": true,
"_f": true,
@@ -112,11 +113,9 @@
"getCookie": true,
"getCookies": true,
"get_url_arg": true,
-
"md5": true,
"$": true,
"jQuery": true,
- "Vue": true,
"moment": true,
"hljs": true,
"Awesomplete": true,
diff --git a/frappe/api.py b/frappe/api.py
index 13123c742e..e5dfae186f 100644
--- a/frappe/api.py
+++ b/frappe/api.py
@@ -53,6 +53,7 @@ def handle():
if call=="method":
frappe.local.form_dict.cmd = doctype
+ frappe.local.form_dict.pop("data", None)
return frappe.handler.handle()
elif call=="resource":
diff --git a/frappe/boot.py b/frappe/boot.py
index 043c1b0361..05117acb7a 100644
--- a/frappe/boot.py
+++ b/frappe/boot.py
@@ -98,6 +98,7 @@ def load_conf_settings(bootinfo):
def load_desktop_icons(bootinfo):
from frappe.config import get_modules_from_all_apps_for_user
bootinfo.allowed_modules = get_modules_from_all_apps_for_user()
+ bootinfo.home_settings = frappe.db.get_value("User", frappe.session.user, 'home_settings','')
def get_allowed_pages():
return get_user_pages_or_reports('Page')
diff --git a/frappe/client.py b/frappe/client.py
index 39f0fd8516..fb2d47925b 100644
--- a/frappe/client.py
+++ b/frappe/client.py
@@ -7,6 +7,7 @@ from frappe import _
import frappe.model
import frappe.utils
import json, os
+from frappe.utils import get_safe_filters
from six import iteritems, string_types, integer_types
@@ -370,17 +371,4 @@ def check_parent_permission(parent, child_doctype):
if frappe.permissions.has_permission(parent):
return
# Either parent not passed or the user doesn't have permission on parent doctype of child table!
- raise frappe.PermissionError
-
-def get_safe_filters(filters):
- try:
- filters = json.loads(filters)
-
- if isinstance(filters, (integer_types, float)):
- filters = frappe.as_unicode(filters)
-
- except (TypeError, ValueError):
- # filters are not passesd, not json
- pass
-
- return filters
+ raise frappe.PermissionError
\ No newline at end of file
diff --git a/frappe/config/__init__.py b/frappe/config/__init__.py
index 506c59eb58..eaacf26442 100644
--- a/frappe/config/__init__.py
+++ b/frappe/config/__init__.py
@@ -11,28 +11,22 @@ def get_modules_from_all_apps_for_user(user=None):
all_modules = get_modules_from_all_apps()
user_blocked_modules = frappe.get_doc('User', user).get_blocked_modules()
-
allowed_modules_list = [m for m in all_modules if m.get("module_name") not in user_blocked_modules]
empty_tables_by_module = get_all_empty_tables_by_module()
- home_settings = frappe.db.get_value("User", frappe.session.user, 'home_settings')
- if home_settings:
- home_settings = json.loads(home_settings)
-
for module in allowed_modules_list:
- module_name = module["module_name"]
+ module_name = module.get("module_name")
+
+ # Apply onboarding status
if module_name in empty_tables_by_module:
module["onboard_present"] = 1
- if home_settings:
- category_settings = home_settings.get(module.get("category"), {}) if module.get("category") else {}
- if module_name not in category_settings:
- module["hidden"] = 1
- else:
- links = category_settings[module_name]["links"]
- if links:
- module["links"] = get_module_link_items_from_list(module["app"], module_name, links.split(","))
+
+
+
+ # Set defaults links
+ module["links"] = get_onboard_items(module["app"], frappe.scrub(module_name))[:5]
else:
module["links"] = get_onboard_items(module["app"], frappe.scrub(module_name))[:6]
diff --git a/frappe/core/doctype/view_log/view_log.json b/frappe/core/doctype/view_log/view_log.json
index cf9d2eb746..af192cf32b 100644
--- a/frappe/core/doctype/view_log/view_log.json
+++ b/frappe/core/doctype/view_log/view_log.json
@@ -20,6 +20,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "viewed_by",
"fieldtype": "Data",
"hidden": 0,
@@ -40,7 +41,7 @@
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
- "search_index": 0,
+ "search_index": 1,
"set_only_once": 1,
"translatable": 0,
"unique": 0
@@ -52,6 +53,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "reference_doctype",
"fieldtype": "Link",
"hidden": 0,
@@ -73,7 +75,7 @@
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
- "search_index": 0,
+ "search_index": 1,
"set_only_once": 1,
"translatable": 0,
"unique": 0
@@ -85,6 +87,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fetch_if_empty": 0,
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
"hidden": 0,
@@ -106,7 +109,7 @@
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
- "search_index": 0,
+ "search_index": 1,
"set_only_once": 1,
"translatable": 0,
"unique": 0
@@ -122,7 +125,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2019-01-03 13:04:31.389182",
+ "modified": "2019-03-11 18:28:33.277683",
"modified_by": "Administrator",
"module": "Core",
"name": "View Log",
diff --git a/frappe/core/notifications.py b/frappe/core/notifications.py
index 0f932d9f67..26e2049273 100644
--- a/frappe/core/notifications.py
+++ b/frappe/core/notifications.py
@@ -17,6 +17,9 @@ def get_notification_config():
"for_other": {
"Likes": "frappe.core.notifications.get_unseen_likes",
"Email": "frappe.core.notifications.get_unread_emails",
+ },
+ "for_module": {
+ "Social": "frappe.social.doctype.post.post.get_unseen_post_count"
}
}
diff --git a/frappe/desk/doctype/todo/todo_list.js b/frappe/desk/doctype/todo/todo_list.js
index 47cb7bd1f6..6200e85dca 100644
--- a/frappe/desk/doctype/todo/todo_list.js
+++ b/frappe/desk/doctype/todo/todo_list.js
@@ -10,21 +10,14 @@ frappe.listview_settings['ToDo'] = {
},
hide_name_column: true,
refresh: function(me) {
- // override assigned to me by owner
if (me.todo_sidebar_setup) return;
- me.page.sidebar.find(".assigned-to-me a").off("click").on("click", function() {
- me.filter_area.remove("assigned_by");
- me.filter_area.add([[me.doctype, "owner", '=', frappe.session.user]]);
- });
-
// add assigned by me
me.page.add_sidebar_item(__("Assigned By Me"), function() {
- me.filter_area.remove("owner");
me.filter_area.add([[me.doctype, "assigned_by", '=', frappe.session.user]]);
- }, ".assigned-to-me");
+ }, ('.list-link[data-view="Kanban"]'));
me.todo_sidebar_setup = true;
},
add_fields: ["reference_type", "reference_name"],
-}
+}
\ No newline at end of file
diff --git a/frappe/desk/listview.py b/frappe/desk/listview.py
index 8d439f228a..a05a3e7f04 100644
--- a/frappe/desk/listview.py
+++ b/frappe/desk/listview.py
@@ -24,3 +24,10 @@ def set_list_settings(doctype, values):
frappe.clear_messages()
doc.update(json.loads(values))
doc.save()
+
+@frappe.whitelist()
+def get_user_assignments_and_count():
+ user_list = frappe.get_list("User", filters={"user_type": "System User"})
+ assignment_data = sorted([{"count":frappe.db.count('ToDo', filters = {'reference_type': 'Issue', 'owner': user['name'], 'status': 'Open'}),
+ "name": user['name']} for user in user_list], key=lambda k: k['count'], reverse = True)
+ return assignment_data
\ No newline at end of file
diff --git a/frappe/desk/moduleview.py b/frappe/desk/moduleview.py
index d5b62d1406..5978bc7ef0 100644
--- a/frappe/desk/moduleview.py
+++ b/frappe/desk/moduleview.py
@@ -300,18 +300,32 @@ def get_links(app, module):
for section in sections:
for item in section["items"]:
link_names.append(item.get("label"))
- print(link_names)
return link_names
@frappe.whitelist()
-def get_module_link_items_from_dict(module_link_list_map):
- module_link_list_map = json.loads(module_link_list_map)
- module_links = {}
- for module, data in module_link_list_map.items():
- print(data)
- module_links[module] = get_module_link_items_from_list(data["app"], module, data["links"])
- return module_links
+def update_desk_section_settings(desk_section, new_settings):
+ home_settings = frappe.db.get_value("User", frappe.session.user, 'home_settings')
+ if home_settings:
+ home_settings = json.loads(home_settings)
+ else:
+ return {}
+
+ new_settings = json.loads(new_settings)
+
+ for module, data in new_settings.items():
+ if data.get("links"):
+ data["links"] = get_module_link_items_from_list(data["app"], module, data.get("links"))
+ data.pop("app", None)
+
+ home_settings[desk_section] = new_settings
+ settings_json_str = json.dumps(home_settings)
+ # # This didn't work
+ # frappe.db.set_value("User", frappe.session.user, 'home_settings', json.dumps(home_settings))
+ frappe.db.sql("""update tabUser set home_settings = %s""", (settings_json_str), debug=True)
+ frappe.db.commit()
+
+ return new_settings
def get_module_link_items_from_list(app, module, list_of_link_names):
diff --git a/frappe/model/document.py b/frappe/model/document.py
index 4542cb03cb..697278f4bd 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -1154,7 +1154,7 @@ class Document(BaseDocument):
frappe.local.flags.commit = True
def add_viewed(self, user=None):
- '''add log to communication when a user viewes a document'''
+ '''add log to communication when a user views a document'''
if not user:
user = frappe.session.user
diff --git a/frappe/patches.txt b/frappe/patches.txt
index 487aabc21f..467efe6a62 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -14,6 +14,7 @@ execute:frappe.reload_doc('core', 'doctype', 'comment')
frappe.patches.v8_0.drop_is_custom_from_docperm
execute:frappe.reload_doc('core', 'doctype', 'module_def') #2017-09-22
execute:frappe.reload_doc('core', 'doctype', 'version') #2017-04-01
+execute:frappe.reload_doc('email', 'doctype', 'document_follow')
frappe.patches.v11_0.replicate_old_user_permissions
frappe.patches.v11_0.reload_and_rename_view_log #2019-01-03
frappe.patches.v7_1.rename_scheduler_log_to_error_log
@@ -200,7 +201,6 @@ frappe.patches.v9_1.move_feed_to_activity_log
execute:frappe.delete_doc('Page', 'data-import-tool', ignore_missing=True)
frappe.patches.v10_0.reload_countries_and_currencies
frappe.patches.v10_0.refactor_social_login_keys
-execute:frappe.reload_doc('email', 'doctype', 'document_follow')
frappe.patches.v10_0.enable_chat_by_default_within_system_settings
frappe.patches.v10_0.remove_custom_field_for_disabled_domain
execute:frappe.delete_doc("Page", "chat")
@@ -232,8 +232,7 @@ frappe.patches.v11_0.set_missing_creation_and_modified_value_for_user_permission
frappe.patches.v11_0.remove_doctype_user_permissions_for_page_and_report
frappe.patches.v11_0.set_default_letter_head_source
frappe.patches.v12_0.set_primary_key_in_series
-execute:frappe.reload_doc('email', 'doctype', 'document_follow')
execute:frappe.delete_doc("Page", "modules", ignore_missing=True)
frappe.patches.v11_0.set_default_letter_head_source
frappe.patches.v12_0.setup_comments_from_communications
-frappe.patches.v12_0.init_desk_settings
+frappe.patches.v12_0.init_desk_settings #11-03-2019
diff --git a/frappe/patches/v12_0/init_desk_settings.py b/frappe/patches/v12_0/init_desk_settings.py
index aa1060b906..782ced8a26 100644
--- a/frappe/patches/v12_0/init_desk_settings.py
+++ b/frappe/patches/v12_0/init_desk_settings.py
@@ -6,29 +6,6 @@ from frappe.config import get_modules_from_all_apps_for_user
from frappe.desk.moduleview import get_onboard_items
def execute():
- """Set the initial customizations for desk, with modules, indices and links."""
+ """Reset the initial customizations for desk, with modules, indices and links."""
frappe.reload_doc("core", "doctype", "user")
- all_modules = get_modules_from_all_apps_for_user()
-
- settings = {}
-
- for module in all_modules:
- if not module.get("app"): continue
-
- links = get_onboard_items(module["app"], frappe.scrub(module["module_name"]))[:5]
- module_settings = {
- "links": ",".join([d["label"] for d in links])
- }
- category_dict = settings.get(module.get("category", ""), None)
- if category_dict:
- module_settings["index"] = len(category_dict)
- category_dict[module.get("module_name")] = module_settings
- else:
- module_settings["index"] = 0
- settings[module.get("category", "")] = {
- module.get("module_name"): module_settings
- }
-
- settings_json_str = json.dumps(settings)
-
- frappe.db.sql("""update tabUser set home_settings = %s""", (settings_json_str), debug=True)
+ frappe.db.sql("""update tabUser set home_settings = %s""", (''), debug=True)
diff --git a/frappe/public/build.json b/frappe/public/build.json
index 682cc6f3f1..73a9fae189 100755
--- a/frappe/public/build.json
+++ b/frappe/public/build.json
@@ -22,9 +22,6 @@
"js/chat.js": [
"public/js/frappe/chat.js"
],
- "js/frappe-vue.min.js": [
- "public/js/frappe_vue.js"
- ],
"js/frappe-recorder.min.js": [
"public/js/frappe/recorder/recorder.js"
],
diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js
index d0464d46cd..87538b287a 100644
--- a/frappe/public/js/frappe/desk.js
+++ b/frappe/public/js/frappe/desk.js
@@ -39,6 +39,7 @@ frappe.Application = Class.extend({
throw 'boot failed';
}
+ this.setup_frappe_vue();
this.load_bootinfo();
this.load_user_permissions();
this.make_nav_bar();
@@ -106,6 +107,8 @@ frappe.Application = Class.extend({
dialog.get_close_btn().toggle(false);
});
+ this.setup_social_listeners();
+
// listen to build errors
this.setup_build_error_listener();
@@ -119,6 +122,12 @@ frappe.Application = Class.extend({
}
},
+
+ setup_frappe_vue() {
+ Vue.prototype.__ = window.__;
+ Vue.prototype.frappe = window.frappe;
+ },
+
set_password: function(user) {
var me=this;
frappe.call({
@@ -530,6 +539,14 @@ frappe.Application = Class.extend({
console.log(data);
});
}
+ },
+
+ setup_social_listeners() {
+ frappe.realtime.on('mention', (message) => {
+ if (frappe.get_route()[0] !== 'social') {
+ frappe.show_alert(message);
+ }
+ });
}
});
diff --git a/frappe/public/js/frappe/dom.js b/frappe/public/js/frappe/dom.js
index 39e576ebf8..830ed0a5ce 100644
--- a/frappe/public/js/frappe/dom.js
+++ b/frappe/public/js/frappe/dom.js
@@ -68,7 +68,7 @@ frappe.dom = {
return txt;
}
},
- is_element_in_viewport: function (el) {
+ is_element_in_viewport: function (el, tolerance=0) {
//special bonus for those using jQuery
if (typeof jQuery === "function" && el instanceof jQuery) {
@@ -78,10 +78,10 @@ frappe.dom = {
var rect = el.getBoundingClientRect();
return (
- rect.top >= 0
- && rect.left >= 0
- // && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
- // && rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
+ rect.top + tolerance >= 0
+ && rect.left + tolerance >= 0
+ && rect.bottom - tolerance <= $(window).height()
+ && rect.right - tolerance <= $(window).width()
);
},
diff --git a/frappe/public/js/frappe/form/footer/timeline.js b/frappe/public/js/frappe/form/footer/timeline.js
index 4508760631..b2926b31d8 100644
--- a/frappe/public/js/frappe/form/footer/timeline.js
+++ b/frappe/public/js/frappe/form/footer/timeline.js
@@ -368,7 +368,6 @@ frappe.ui.form.Timeline = class Timeline {
} else {
c.content_html = c.content;
c.content_html = frappe.utils.strip_whitespace(c.content_html);
- c.content_html = c.content_html.replace(/</g,"<").replace(/>/g,">");
}
// bold @mentions
diff --git a/frappe/public/js/frappe/list/list_sidebar.html b/frappe/public/js/frappe/list/list_sidebar.html
index 48ed21765b..619fa66277 100644
--- a/frappe/public/js/frappe/list/list_sidebar.html
+++ b/frappe/public/js/frappe/list/list_sidebar.html
@@ -45,8 +45,12 @@
-
- {%= __("Assigned To Me") %}
+
+
+ {%= __("Assigned To") %}
+
+
{% if(frappe.help.has_help(doctype)) { %}
{{ __("Help") }}
diff --git a/frappe/public/js/frappe/list/list_sidebar.js b/frappe/public/js/frappe/list/list_sidebar.js
index 20f1f030d4..9f5ebfb2a7 100644
--- a/frappe/public/js/frappe/list/list_sidebar.js
+++ b/frappe/public/js/frappe/list/list_sidebar.js
@@ -26,7 +26,7 @@ frappe.views.ListSidebar = class ListSidebar {
this.setup_reports();
this.setup_list_filter();
- this.setup_assigned_to_me();
+ this.setup_assigned_to();
this.setup_views();
this.setup_kanban_boards();
this.setup_calendar_view();
@@ -216,12 +216,35 @@ 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_assigned_to() {
+ let dropdown = this.page.sidebar.find('.assigned-dropdown');
+ if(this.doctype === 'ToDo') {
+ $('.assigned-to').remove();
+ }
+ frappe.call('frappe.desk.listview.get_user_assignments_and_count').then((data) => {
+ let current_user_count = data.message.find(user => user.name === frappe.session.user).count;
+ this.get_html_for_assigned(frappe.session.user, current_user_count).appendTo(dropdown);
+ let user_list = data.message.filter(user => !['Guest', frappe.session.user, 'Administrator'].includes(user.name));
+ user_list.forEach((user) => {
+ this.get_html_for_assigned(user.name, user.count).appendTo(dropdown);
+ });
+ $(".assigned-dropdown li a").on("click", (e) => {
+ let assigned_user = $(e.currentTarget).find($('.assigned-user')).text();
+ if(assigned_user === 'Me') assigned_user = frappe.session.user;
+ this.list_view.filter_area.remove('_assign');
+ this.list_view.filter_area.add(this.list_view.doctype, "_assign", "like", `%${assigned_user}%`);
+ });
});
}
+ get_html_for_assigned(name, count) {
+ if (name === frappe.session.user) name='Me';
+ if (count > 99) count='99+';
+ let html = $(''
+ + name + '' + count + '');
+ return html;
+ }
+
setup_upgrade_box() {
let upgrade_list = $(``).appendTo(this.sidebar);
diff --git a/frappe/public/js/frappe/social/Home.vue b/frappe/public/js/frappe/social/Home.vue
index 5b0297b725..55397de76b 100644
--- a/frappe/public/js/frappe/social/Home.vue
+++ b/frappe/public/js/frappe/social/Home.vue
@@ -11,6 +11,7 @@
import Wall from './pages/Wall.vue';
import Profile from './pages/Profile.vue';
+import UserList from './pages/UserList.vue';
import NotFound from './components/NotFound.vue';
import ImageViewer from './components/ImageViewer.vue';
@@ -27,6 +28,10 @@ function get_route_map() {
'key': frappe.get_route()[2]
}
},
+ 'social/users': {
+ 'component': UserList,
+ 'props': {}
+ },
'not_found': {
'component': NotFound,
}
@@ -58,11 +63,14 @@ export default {
frappe.app_updates.on('user_image_updated', () => {
this.$root.$emit('user_image_updated')
})
+
+ this.update_primary_action(frappe.get_route()[1])
},
mounted() {
frappe.route.on('change', () => {
if (frappe.get_route()[0] === 'social') {
this.set_current_page();
+ this.update_primary_action(frappe.get_route()[1])
frappe.utils.scroll_to(0);
$("body").attr("data-route", frappe.get_route_str());
}
@@ -73,6 +81,15 @@ export default {
set_current_page() {
this.current_page = this.get_current_page();
},
+ update_primary_action(current_route) {
+ if (current_route === 'home') {
+ this.$root.page.set_primary_action(__('Post'), () => {
+ frappe.social.post_dialog.show();
+ });
+ } else {
+ this.$root.page.clear_primary_action()
+ }
+ },
get_current_page() {
const route_map = get_route_map();
const route = frappe.get_route_str();
diff --git a/frappe/public/js/frappe/social/components/Post.vue b/frappe/public/js/frappe/social/components/Post.vue
index 71afccfa1f..297ffa702f 100644
--- a/frappe/public/js/frappe/social/components/Post.vue
+++ b/frappe/public/js/frappe/social/components/Post.vue
@@ -12,6 +12,12 @@
v-if="options.length"
:options="options"
/>
+
+
+
+
{{ user_name }}
@@ -170,6 +176,11 @@ export default {
}).then(frappe.dom.unfreeze)
})
},
+ update_seen() {
+ frappe.xcall('frappe.social.doctype.post.post.set_seen', {
+ post_name: this.post.name
+ }).then(() => this.post.seen = true)
+ },
generate_preview(link_element) {
// TODO: move the code to separate component
frappe.xcall('frappe.social.doctype.post.post.get_link_info', {
@@ -203,5 +214,14 @@ export default {
padding-top: 0px;
background: #F6F6F6;
}
+.indicator {
+ margin-left: 15px;
+}
+.fade-enter-active, .fade-leave-active {
+ transition: opacity .8s;
+}
+.fade-enter, .fade-leave-to {
+ opacity: 0;
+}
diff --git a/frappe/public/js/frappe/social/components/PostAction.vue b/frappe/public/js/frappe/social/components/PostAction.vue
index 491238210d..3c506dc198 100644
--- a/frappe/public/js/frappe/social/components/PostAction.vue
+++ b/frappe/public/js/frappe/social/components/PostAction.vue
@@ -44,7 +44,7 @@ export default {
cursor: pointer;
color: #8d99a6;
span {
- padding-left: 5px;
+ padding: 5px;
}
&:hover {
color: darken(#8d99a6, 10%);
diff --git a/frappe/public/js/frappe/social/components/PostComment.vue b/frappe/public/js/frappe/social/components/PostComment.vue
index 2d41a0a839..b102fba5b5 100644
--- a/frappe/public/js/frappe/social/components/PostComment.vue
+++ b/frappe/public/js/frappe/social/components/PostComment.vue
@@ -2,26 +2,30 @@
-
@@ -29,10 +33,9 @@
+
+
+
+
diff --git a/frappe/public/js/frappe/social/social_home.js b/frappe/public/js/frappe/social/social_home.js
index ccddbb580a..26e4542d88 100644
--- a/frappe/public/js/frappe/social/social_home.js
+++ b/frappe/public/js/frappe/social/social_home.js
@@ -8,25 +8,20 @@ frappe.social.Home = class SocialHome {
this.page = parent.page;
this.setup_header();
this.make_body();
- this.set_primary_action();
}
make_body() {
this.$social_container = this.$parent.find('.layout-main');
- frappe.require('/assets/js/frappe-vue.min.js', () => {
- new Vue({
- el: this.$social_container[0],
- render: h => h(Home)
- });
+ new Vue({
+ el: this.$social_container[0],
+ render: h => h(Home),
+ data: {
+ 'page': this.page
+ }
});
}
setup_header() {
this.page.set_title(__('Social'));
}
- set_primary_action() {
- this.page.set_primary_action(__('Post'), () => {
- frappe.social.post_dialog.show();
- });
- }
};
frappe.social.post_dialog = new frappe.ui.Dialog({
diff --git a/frappe/public/js/frappe/ui/like.js b/frappe/public/js/frappe/ui/like.js
index c99f62dee6..8bed02119f 100644
--- a/frappe/public/js/frappe/ui/like.js
+++ b/frappe/public/js/frappe/ui/like.js
@@ -85,26 +85,30 @@ frappe.ui.click_toggle_like = function() {
return false;
}
-frappe.ui.setup_like_popover = function($parent, selector, check_not_liked=true) {
+frappe.ui.setup_like_popover = ($parent, selector, check_not_liked=true) => {
if (frappe.dom.is_touchscreen()) {
return;
}
- $parent.on("mouseover", selector, function() {
- var $wrapper = $(this);
-
- $wrapper.popover({
+ $parent.on('mouseover', selector, function() {
+ const target_element = $(this);
+ target_element.popover({
animation: true,
- placement: "right",
- content: function() {
- var liked_by = $wrapper.attr('data-liked-by');
+ placement: 'right',
+ trigger: 'manual',
+ template:`
`,
+ content: () => {
+ let liked_by = target_element.attr('data-liked-by');
liked_by = liked_by ? decodeURI(liked_by) : '[]';
liked_by = JSON.parse(liked_by);
- var user = frappe.session.user;
+ const user = frappe.session.user;
// hack
if (check_not_liked) {
- if ($wrapper.find(".not-liked").length) {
+ if (target_element.find(".not-liked").length) {
if (liked_by.indexOf(user)!==-1) {
liked_by.splice(liked_by.indexOf(user), 1);
}
@@ -118,16 +122,46 @@ frappe.ui.setup_like_popover = function($parent, selector, check_not_liked=true)
if (!liked_by.length) {
return "";
}
- return frappe.render_template("liked_by", {"liked_by": liked_by});
+
+ let liked_by_list = $(`
`);
+
+ // to show social profile of the user
+ let link_base = '#social/profile/';
+
+ liked_by.forEach(user => {
+ // append user list item
+ liked_by_list.append(`
+
${frappe.avatar(user)}
+ ${frappe.user.full_name(user)}
+
+ `);
+ });
+
+ liked_by_list.children('li').click(ev => {
+ let user = ev.currentTarget.dataset.user;
+ target_element.popover('hide');
+ frappe.set_route(link_base + user);
+ });
+
+ return liked_by_list;
},
html: true,
container: 'body'
});
- $wrapper.popover('show');
+ target_element.popover('show');
+
+ $(".popover").on("mouseleave", () => {
+ target_element.popover('hide');
+ });
+
+ target_element.on('mouseout', () => {
+ setTimeout(() => {
+ if (!$('.popover:hover').length) {
+ target_element.popover('hide');
+ }
+ }, 100);
+ });
});
- $parent.on("mouseout", selector, function() {
- $(this).popover('destroy');
- });
-}
+};
diff --git a/frappe/public/js/frappe/ui/liked_by.html b/frappe/public/js/frappe/ui/liked_by.html
deleted file mode 100644
index 0b836c5561..0000000000
--- a/frappe/public/js/frappe/ui/liked_by.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
- {% for (var i in liked_by) { var liked_by_user = liked_by[i]; %}
- -
- {%= frappe.avatar(liked_by_user) %}
- {%= frappe.user.full_name(liked_by_user) %}
-
- {% } %}
-
diff --git a/frappe/public/js/frappe/views/components/DeskSection.vue b/frappe/public/js/frappe/views/components/DeskSection.vue
index 0718f05d02..3a9ec45e9c 100644
--- a/frappe/public/js/frappe/views/components/DeskSection.vue
+++ b/frappe/public/js/frappe/views/components/DeskSection.vue
@@ -28,192 +28,216 @@ import DeskModuleBox from "./DeskModuleBox.vue";
import { generate_route } from "./utils.js";
export default {
- props: ["category", "all_modules"],
- components: {
- DeskModuleBox
- },
- data() {
- let template_modules = this.all_modules;
- template_modules.forEach(module => {
- if (module.links) {
- module.links.forEach(link => {
- link.route = generate_route(link);
- });
- }
- });
+ props: ['category', 'all_modules', 'customization_settings'],
+ components: {
+ DeskModuleBox
+ },
+ data() {
+ let default_modules = this.all_modules;
+ let modules = this.get_customized_modules(default_modules, this.customization_settings);
- return {
- template_modules: template_modules,
- modules: template_modules.slice(),
- settings: {},
- all_settings: {},
- dragged_index: -1,
- hovered_index: -1
- };
- },
- methods: {
- show_customize_dialog() {
- if (!this.dialog) {
- this.get_settings().then(() => {
- const fields = this.make_fields();
- this.make_and_show_dialog(fields);
- });
- } else {
- this.dialog.show();
- }
- },
- get_settings() {
- return frappe.db.get_value("User", user, "home_settings").then(resp => {
- this.all_settings = JSON.parse(resp.message["home_settings"]);
- this.settings = this.all_settings[this.category];
- });
- },
- make_fields() {
- let fields = [];
- let template_modules = this.template_modules;
- let selected_modules = Object.keys(this.settings);
+ return {
+ default_modules: default_modules,
+ modules: modules,
+ new_settings: {},
+ dragged_index: -1,
+ hovered_index: -1,
+ }
+ },
+ methods: {
+ show_customize_dialog() {
+ if(!this.dialog) {
+ const fields = this.make_fields();
+ this.make_and_show_dialog(fields);
+ } else {
+ this.dialog.show();
+ }
+ },
+ make_fields() {
+ let fields = [];
+ this.modules.forEach(module => {
+ fields.push(this.get_module_select_field(module));
- template_modules.forEach(module => {
- fields.push(this.get_module_select_field(module, selected_modules));
+ if(module.links) {
+ fields.push(this.get_links_multiselect_field(module));
+ }
+ });
+ return fields;
+ },
+ make_and_show_dialog(fields) {
+ this.dialog = new frappe.ui.Dialog({
+ title: __("Customize " + this.category),
+ fields: fields,
+ primary_action_label: __("Update"),
+ primary_action: (values) => {
+ this.update_settings(values);
+ }
+ });
- if (module.links) {
- fields.push(this.get_links_multiselect_field(module));
- }
- });
+ this.dialog.modal_body.find('.clearfix').css({'display': 'none'});
+ this.dialog.modal_body.find('.frappe-control*[data-fieldtype="MultiSelect"]').css({'margin-bottom': '30px'});
- return fields;
- },
- make_and_show_dialog(fields) {
- this.dialog = new frappe.ui.Dialog({
- title: __("Customize " + this.category),
- fields: fields,
- primary_action_label: __("Update"),
- primary_action: values => {
- let module_link_list_map = {};
+ this.dialog.show();
+ },
- Object.keys(values).forEach(module_name => {
- if (!module_name.includes("links") && values[module_name]) {
- const links_str = values[module_name + "_links"] || "";
- this.settings[module_name]["links"] = links_str;
- if (values[module_name]) {
- module_link_list_map[module_name] = {
- links: links_str.split(","),
- app: this.template_modules.filter(
- m => m.module_name === module_name
- )[0].app
- };
- }
- }
- });
+ update_settings(values) {
+ // Figure out the diff from the default settings known from modules
+ let new_settings = {};
+ const checkbox_fields = Object.keys(values).filter(f => !f.includes('links'));
- frappe.db
- .set_value("User", user, "home_settings", this.all_settings)
- .then(resp => {
- this.update_modules(module_link_list_map);
- this.dialog.hide();
- })
- .fail(err => {
- frappe.msgprint(err);
- });
- }
- });
+ checkbox_fields.forEach(module_name => {
+ const default_module = this.default_modules.filter(f => f.module_name === module_name)[0];
- this.dialog.modal_body.find(".clearfix").css({ display: "none" });
- this.dialog.modal_body
- .find('.frappe-control*[data-fieldtype="MultiSelect"]')
- .css({ "margin-bottom": "30px" });
+ // Check if hidden changed
+ const default_hidden = default_module.hidden ? 1 : 0;
+ const new_hidden = !values[module_name] ? 1 : 0;
+ const hidden_changed = new_hidden != default_hidden;
- this.dialog.show();
- },
+ // Check if links changed
+ let links_changed = 0;
+ let new_links = [];
- update_modules(module_link_list_map) {
- frappe.call({
- type: "GET",
- method: "frappe.desk.moduleview.get_module_link_items_from_dict",
- freeze: true,
- args: {
- module_link_list_map: module_link_list_map
- },
- callback: r => {
- const module_links_dict = r.message;
- this.template_modules.map((m, i) => {
- let raw_links = module_links_dict[m.module_name];
- raw_links.forEach(link => {
- link.route = generate_route(link);
- });
- if (Object.keys(module_link_list_map).includes(m.module_name)) {
- m.hidden = 0;
- m.links = raw_links;
- } else {
- m.hidden = 1;
- }
- });
+ if(!new_hidden) {
+ const default_links = default_module.links.map(l => (l.name || l.label));
+ const new_links_str = values[module_name + '_links'] || '';
+ new_links = new_links_str ? new_links_str.split(",") : [];
+ links_changed = !this.are_arrays_equal(new_links, default_links);
+ }
- this.modules = this.template_modules.filter(m => !m.hidden);
- }
- });
- },
+ // Make new settings
+ let new_module_settings;
- get_module_select_field(module, selected_modules) {
- return {
- label: __(module.module_name),
- fieldname: module.module_name,
- fieldtype: "Check",
- default: selected_modules.includes(module.module_name) ? 1 : 0
- };
- },
+ if(hidden_changed || links_changed) {
+ new_module_settings = {};
+ if(hidden_changed) {
+ new_module_settings.hidden = new_hidden;
+ }
+ if(links_changed) {
+ new_module_settings.links = new_links;
+ }
+ }
- get_links_multiselect_field(module) {
- return {
- label: __(""),
- fieldname: module.module_name + "_links",
- fieldtype: "MultiSelect",
- get_data: function() {
- let data = [];
+ if(new_module_settings) {
+ new_module_settings.app = this.default_modules.filter(m => m.module_name === module_name)[0].app;
+ new_settings[module_name] = new_module_settings;
+ }
+ });
- frappe.call({
- type: "GET",
- method: "frappe.desk.moduleview.get_links",
- async: false,
- no_spinner: true,
- args: {
- app: module.app,
- module: module.module_name
- },
- callback: function(r) {
- data = r.message;
- }
- });
- return data;
- },
- default: module.links.map(m => m.name || m.label),
- depends_on: module.module_name
- };
- },
+ if(Object.keys(new_settings)) {
+ frappe.call({
+ type: "GET",
+ method:'frappe.desk.moduleview.update_desk_section_settings',
+ freeze: true,
+ args: {
+ desk_section: this.category,
+ new_settings: new_settings
+ },
+ callback: (r) => {
+ let new_settings_with_link_objects = r.message;
+ let home_settings = JSON.parse(frappe.boot.home_settings);
+ home_settings[this.category] = new_settings_with_link_objects;
+ frappe.boot.home_settings = JSON.stringify(home_settings);
- box_dragstart(index) {
- this.dragged_index = index;
- },
+ this.modules = this.get_customized_modules(this.default_modules, new_settings_with_link_objects);
+ this.dialog.hide();
+ }
+ });
+ } else {
+ this.dialog.hide();
+ };
+ },
- box_dragend(index) {
- this.dragged_index = -1;
- this.hovered_index = -1;
- },
+ get_customized_modules(default_modules, customization_settings={}) {
+ return default_modules.map(module => {
+ let customized_module = JSON.parse(JSON.stringify(module));
- box_enter(index) {
- this.hovered_index = index;
- },
+ const module_settings = customization_settings[module.module_name];
+ if(module_settings) {
+ if(module_settings.links) {
+ customized_module.links = module_settings.links;
+ }
+ customized_module.hidden = module_settings ? module_settings.hidden : 0;
+ }
- box_drop(index) {
- let d = this.dragged_index;
- let h = this.hovered_index;
- if (d < h) {
- this.modules.splice(h, 0, this.modules[d]);
- this.modules.splice(d, 1);
- }
- }
- }
-};
+ if(customized_module.links) {
+ customized_module.links.forEach(link => {
+ link.route = generate_route(link);
+ });
+ }
+
+ return customized_module;
+ });
+ },
+
+ get_module_select_field(module) {
+ return {
+ label: __(module.module_name),
+ fieldname: module.module_name,
+ fieldtype: "Check",
+ default: module.hidden ? 0 : 1
+ }
+ },
+
+ get_links_multiselect_field(module) {
+ return {
+ label: __(""),
+ fieldname: module.module_name + "_links",
+ fieldtype: "MultiSelect",
+ get_data: function() {
+ let data = [];
+
+ frappe.call({
+ type: "GET",
+ method:'frappe.desk.moduleview.get_links',
+ async: false,
+ no_spinner: true,
+ args: {
+ app: module.app,
+ module: module.module_name,
+ },
+ callback: function(r) {
+ data = r.message;
+ }
+ });
+ return data;
+ },
+ default: module.links.map(l => (l.name || l.label)),
+ depends_on: module.module_name
+ };
+ },
+
+ are_arrays_equal(arr1, arr2) {
+ if(arr1.length !== arr2.length) return false;
+ let areEqual = true;
+ arr1.map((d, i) => {
+ if(arr2[i] !== d) areEqual = false;
+ });
+ return areEqual;
+ },
+
+ box_dragstart(index) {
+ this.dragged_index = index;
+ },
+
+ box_dragend(index) {
+ this.dragged_index = -1;
+ this.hovered_index = -1;
+ },
+
+ box_enter(index) {
+ this.hovered_index = index;
+ },
+
+ box_drop(index) {
+ let d = this.dragged_index;
+ let h = this.hovered_index;
+ if (d < h) {
+ this.modules.splice(h, 0, this.modules[d]);
+ this.modules.splice(d, 1);
+ }
+ },
+ }
+}