瀏覽代碼

[realtime] clear doc locally if updated

version-14
Rushabh Mehta 9 年之前
父節點
當前提交
a15af7882b
共有 16 個檔案被更改,包括 1295 行新增538 行删除
  1. +5
    -2
      frappe/__init__.py
  2. +11
    -6
      frappe/async.py
  3. +1191
    -506
      frappe/core/doctype/user/user.json
  4. +3
    -1
      frappe/desk/page/messages/messages.js
  5. +6
    -2
      frappe/desk/page/messages/messages_main.html
  6. +6
    -3
      frappe/desk/page/messages/messages_row.html
  7. +3
    -0
      frappe/model/document.py
  8. +1
    -1
      frappe/public/css/form.css
  9. +1
    -0
      frappe/public/js/frappe/desk.js
  10. +1
    -0
      frappe/public/js/frappe/form/dashboard.js
  11. +6
    -2
      frappe/public/js/frappe/list/doclistview.js
  12. +26
    -0
      frappe/public/js/frappe/model/model.js
  13. +20
    -10
      frappe/public/js/frappe/socket.js
  14. +10
    -0
      frappe/public/js/legacy/form.js
  15. +1
    -2
      frappe/public/less/form.less
  16. +4
    -3
      socketio.js

+ 5
- 2
frappe/__init__.py 查看文件

@@ -1000,7 +1000,10 @@ def publish_realtime(*args, **kwargs):

:param event: Event name, like `task_progress` etc.
:param message: JSON message object. For async must contain `task_id`
:param room: Room in which to publish update (default entire site)"""
:param room: Room in which to publish update (default entire site)
:param user: Transmit to user
:param doctype: Transmit to doctype, docname
:param docname: Transmit to doctype, docname"""
import frappe.async

frappe.async.publish_realtime(*args, **kwargs)
return frappe.async.publish_realtime(*args, **kwargs)

+ 11
- 6
frappe/async.py 查看文件

@@ -120,7 +120,7 @@ def is_file_old(file_path):
return ((time.time() - os.stat(file_path).st_mtime) > TASK_LOG_MAX_AGE)


def publish_realtime(event, message, room=None, user=None, doctype=None, docname=None):
def publish_realtime(event, message=None, room=None, user=None, doctype=None, docname=None):
"""Publish real-time updates

:param event: Event name, like `task_progress` etc.
@@ -128,18 +128,23 @@ def publish_realtime(event, message, room=None, user=None, doctype=None, docname
:param room: Room in which to publish update (default entire site)
:param user: Transmit to user
:param doctype: Transmit to doctype, docname
:param doctype: Transmit to doctype, docname"""
:param docname: Transmit to doctype, docname"""
if message is None:
message = {}

if not room:
if user:
get_user_room(user)
if doctype and docname:
get_doc_room(doctype, docname)
room = get_user_room(user)
elif doctype and docname:
room = get_doc_room(doctype, docname)
message["doctype"] = doctype
message["name"] = docname
else:
room = get_site_room()

emit_via_redis(event, message, room)

def emit_via_redis(event, message, room=None):
def emit_via_redis(event, message, room):
"""Publish real-time updates via redis

:param event: Event name, like `task_progress` etc.


+ 1191
- 506
frappe/core/doctype/user/user.json
文件差異過大導致無法顯示
查看文件


+ 3
- 1
frappe/desk/page/messages/messages.js 查看文件

@@ -42,7 +42,9 @@ frappe.desk.pages.Messages = Class.extend({

setup_realtime: function() {
frappe.realtime.on('new_message', function(comment) {
frappe.utils.notify(__("Message from {0}", [comment.comment_by_fullname]), comment.comment);
if(comment.modified_by !== user) {
frappe.utils.notify(__("Message from {0}", [comment.comment_by_fullname]), comment.comment);
}
if (frappe.get_route()[0] === 'messages') {
var current_contact = $(cur_page.page).find('[data-contact]').data('contact');
var on_broadcast_page = current_contact === user;


+ 6
- 2
frappe/desk/page/messages/messages_main.html 查看文件

@@ -8,11 +8,15 @@
class="form-control messages-textarea"></textarea>
</div>
<div style="padding-top: 15px;">
<button class="pull-right btn btn-default btn-sm btn-post" data-contact="{%= contact %}">
<button class="pull-right btn btn-primary btn-sm btn-post" data-contact="{%= contact %}">
{%= __("Post") %}
</button>
{% if (contact === user) { %}
<span class="pull-right indicator orange">{%= __("Public") %}</span>
<span class="pull-right"
style="margin-top: 4px; margin-right: 10px;">
<i class="octicon octicon-rss"></i>
<span class="text-muted small">{%= __("Public") %}</span>
</span>
{% } %}
<div class="pull-right checkbox text-muted small"
style="margin-right: 15px; margin-top: 7px;">


+ 6
- 3
frappe/desk/page/messages/messages_row.html 查看文件

@@ -1,9 +1,12 @@
<div class="row message-row small">
{% if (data.owner==data.comment_docname && data.parenttype!="Assignment") { %}
<span class="pull-left indicator orange" title="{%= __("Public") %}"></span>
{% } %}
<div class="col-sm-9">
<div class="media">
{% if (data.owner==data.comment_docname
&& data.parenttype!="Assignment") { %}
<span class="pull-left" title="{{ __("Public") }}"><i class="octicon octicon-rss text-muted" style="margin-top: 3px;"></i></span>
{% } else { %}
<span class="pull-left" title="{{ __("Public") }}" style="width: 20px; height: 16px; display: inline-block;"></span>
{% } %}
<div class="pull-left hidden-xs">
<span class="avatar avatar-small" title="{%= frappe.user.full_name(data.owner) %} ">
<img class="media-object {{ data.is_system_message ? "grayscale" : "" }}"


+ 3
- 0
frappe/model/document.py 查看文件

@@ -574,6 +574,9 @@ class Document(BaseDocument):

frappe.cache().hdel("last_modified", self.doctype)

frappe.publish_realtime("doc_update", {"modified_by": frappe.session.user},
doctype=self.doctype, docname=self.name)

self.latest = None

def check_no_back_links_exist(self):


+ 1
- 1
frappe/public/css/form.css 查看文件

@@ -163,7 +163,7 @@ select.form-control {
}
.form-headline .alert {
font-size: 12px;
border-color: #d1d8dd;
background-color: #fffce7;
margin-bottom: 0px;
}
.delivery-status-indicator {


+ 1
- 0
frappe/public/js/frappe/desk.js 查看文件

@@ -22,6 +22,7 @@ frappe.Application = Class.extend({
this.startup();
},
startup: function() {
frappe.model.init();
this.load_bootinfo();
this.make_nav_bar();
this.set_favicon();


+ 1
- 0
frappe/public/js/frappe/form/dashboard.js 查看文件

@@ -23,6 +23,7 @@ frappe.ui.form.Dashboard = Class.extend({
this.wrapper.toggle(true);
},
set_headline_alert: function(text, alert_class, icon) {
if(!alert_class) alert_class = "alert-warning";
this.set_headline(repl('<div class="alert %(alert_class)s">%(icon)s%(text)s</div>', {
"alert_class": alert_class || "",
"icon": icon ? '<i class="'+icon+'" /> ' : "",


+ 6
- 2
frappe/public/js/frappe/list/doclistview.js 查看文件

@@ -38,12 +38,16 @@ frappe.views.ListFactory = frappe.views.Factory.extend({
});

$(document).on("save", function(event, doc) {
var list_page = "List/" + doc.doctype;
frappe.views.set_list_as_dirty(doc.doctype);
});

frappe.views.set_list_as_dirty = function(doctype) {
var list_page = "List/" + doctype;
if(frappe.pages[list_page]) {
if(frappe.pages[list_page].doclistview)
frappe.pages[list_page].doclistview.dirty = true;
}
})
}

frappe.views.DocListView = frappe.ui.Listing.extend({
init: function(opts) {


+ 26
- 0
frappe/public/js/frappe/model/model.js 查看文件

@@ -34,6 +34,32 @@ $.extend(frappe.model, {
new_names: {},
events: {},

init: function() {
// setup refresh if the document is updated somewhere else
frappe.realtime.on("doc_update", function(data) {
// set list dirty
frappe.views.set_list_as_dirty(data.doctype);
var doc = locals[data.doctype] && locals[data.doctype][data.name];
if(doc) {
// current document is dirty, show message if its not me
if(cur_frm.doc.doctype===doc.doctype && cur_frm.doc.name===doc.name) {
if(data.modified_by!==user) {
doc.__needs_refresh = true;
cur_frm.show_if_needs_refresh();
}
} else {
if(!doc.__unsaved) {
// no local changes, remove from locals
frappe.model.remove_from_locals(doc.doctype, doc.name);
} else {
// show message when user navigates back
doc.__needs_refresh = true;
}
}
}
});
},

is_value_type: function(fieldtype) {
// not in no-value type
return frappe.model.no_value_type.indexOf(fieldtype)===-1;


+ 20
- 10
frappe/public/js/frappe/socket.js 查看文件

@@ -1,5 +1,6 @@
frappe.socket = {
open_tasks: {},
open_docs: [],
init: function() {
if (frappe.boot.disable_async) {
return;
@@ -16,9 +17,9 @@ frappe.socket = {
frappe.socket.doc_subscribe(frm.doctype, frm.docname);
});

$(document).on('form-unload', function(e, frm) {
frappe.socket.doc_unsubscribe(frm.doctype, frm.docname);
});
// $(document).on('form-unload', function(e, frm) {
// frappe.socket.doc_unsubscribe(frm.doctype, frm.docname);
// });
},
subscribe: function(task_id, opts) {
frappe.socket.socket.emit('task_subscribe', task_id);
@@ -28,11 +29,17 @@ frappe.socket = {
},
doc_subscribe: function(doctype, docname) {
frappe.socket.socket.emit('doc_subscribe', doctype, docname);
frappe.socket.open_doc = {doctype: doctype, docname: docname};
frappe.socket.open_docs.push({doctype: doctype, docname: docname});
},
doc_unsubscribe: function(doctype, docname) {
frappe.socket.socket.emit('doc_unsubscribe', doctype, docname);
frappe.socket.open_doc = null;
frappe.socket.open_docs = $.filter(frappe.socket.open_docs, function(d) {
if(d.doctype===doctype && d.name===docname) {
return null;
} else {
return d;
}
})
},
setup_listeners: function() {
frappe.socket.socket.on('task_status_change', function(data) {
@@ -47,7 +54,6 @@ frappe.socket = {
frappe.socket.socket.on('task_progress', function(data) {
frappe.socket.process_response(data, "progress");
});

},
setup_reconnect: function() {
// subscribe again to open_tasks
@@ -55,11 +61,15 @@ frappe.socket = {
$.each(frappe.socket.open_tasks, function(task_id, opts) {
frappe.socket.subscribe(task_id, opts);
});

// re-connect open docs
$.each(frappe.socket.open_docs, function(d) {
if(locals[d.doctype] && locals[d.doctype][d.name]) {
frappe.socket.doc_subscribe(d.doctype, d.name);
}
})
});

if(frappe.socket.open_doc) {
frappe.socket.doc_subscribe(frappe.socket.open_doc.doctype, frappe.socket.open_doc.docname);
}
},
process_response: function(data, method) {
if(!data) {
@@ -87,7 +97,7 @@ frappe.socket = {

$(frappe.socket.init);

frappe.require("frappe.realtime");
frappe.provide("frappe.realtime");
frappe.realtime.on = function(event, callback) {
frappe.socket.socket.on(event, callback);
}

+ 10
- 0
frappe/public/js/legacy/form.js 查看文件

@@ -406,6 +406,16 @@ _f.Frm.prototype.refresh = function(docname) {
if(this.print_preview.wrapper.is(":visible")) {
this.print_preview.preview();
}

this.show_if_needs_refresh();
}
}

_f.Frm.prototype.show_if_needs_refresh = function() {
if(this.doc.__needs_refresh) {
this.dashboard.set_headline_alert(__("This form has been modified after you have loaded it")
+ '<a class="btn btn-xs btn-primary pull-right" onclick="cur_frm.reload_doc()">'
+ __("Refresh") + '</a>', "alert-warning");
}
}



+ 1
- 2
frappe/public/less/form.less 查看文件

@@ -212,8 +212,7 @@ select.form-control {

.form-headline .alert {
font-size: @text-medium;
border-color: @border-color;
// background-color: @light-bg;
background-color: @light-yellow;
margin-bottom: 0px;
}



+ 4
- 3
socketio.js 查看文件

@@ -43,6 +43,7 @@ io.on('connection', function(socket){
var room = get_user_room(socket, res.body.message.user);
// console.log('joining', room);
socket.join(room);
socket.join(get_site_room(socket));
}
})
socket.on('task_subscribe', function(task_id) {
@@ -64,7 +65,7 @@ io.on('connection', function(socket){
docname: docname
})
.end(function(err, res) {
console.log(err)
if(err) console.log(err);
if(res.status == 200) {
var room = get_doc_room(socket, doctype, docname);
// console.log('joining', room)
@@ -89,7 +90,7 @@ function send_existing_lines(task_id, socket) {
})
}

subscriber.on("message", function(channel, message) {
message = JSON.parse(message);
io.to(message.room).emit(message.event, message.message);
@@ -97,7 +98,7 @@ subscriber.on("message", function(channel, message) {
});

subscriber.subscribe("events");
http.listen(3000, function(){
console.log('listening on *:3000');
});


Loading…
取消
儲存