[realtime] clear doc locally if updated
This commit is contained in:
parent
6d08f862b0
commit
a15af7882b
16 changed files with 1239 additions and 482 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;">
|
||||
|
|
|
|||
|
|
@ -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" : "" }}"
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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+'" /> ' : "",
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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…
Add table
Reference in a new issue