瀏覽代碼

[list-settings] save in redis, db, save filters while switching views and patch

version-14
Rushabh Mehta 9 年之前
父節點
當前提交
a5899a0d0c
共有 14 個文件被更改,包括 222 次插入72 次删除
  1. +9
    -1
      frappe/desk/reportview.py
  2. +7
    -5
      frappe/model/utils/list_settings.py
  3. +12
    -0
      frappe/patches/v7_0/setup_list_settings.py
  4. +3
    -0
      frappe/public/css/common.css
  5. +3
    -0
      frappe/public/css/desk.css
  6. +3
    -0
      frappe/public/css/website.css
  7. +1
    -0
      frappe/public/js/frappe/dom.js
  8. +68
    -55
      frappe/public/js/frappe/list/doclistview.js
  9. +20
    -0
      frappe/public/js/frappe/misc/utils.js
  10. +1
    -0
      frappe/public/js/frappe/model/model.js
  11. +48
    -4
      frappe/public/js/frappe/ui/listing.js
  12. +35
    -6
      frappe/public/js/frappe/views/reports/reportview.js
  13. +7
    -0
      frappe/public/less/common.less
  14. +5
    -1
      frappe/utils/redis_wrapper.py

+ 9
- 1
frappe/desk/reportview.py 查看文件

@@ -14,16 +14,24 @@ from frappe import _
@frappe.whitelist()
def get():
args = get_form_params()
save_list_settings_fields = False

if args.save_list_settings_fields:
save_list_settings_fields = True
del args['save_list_settings_fields']

data = compress(execute(**args))

# update list settings if new search
if not cint(args.limit_start) or cint(args.limit or args.limit_page_length) != 20:
list_settings = {
'columns': args.fields,
'filters': args.filters,
'limit': args.limit or args.limit_page_length,
'order_by': args.order_by
}
if save_list_settings_fields:
list_settings['fields'] = args.fields

update_list_settings(args.doctype, list_settings)

return data


+ 7
- 5
frappe/model/utils/list_settings.py 查看文件

@@ -1,6 +1,6 @@
import frappe, json

def get_list_settings(doctype):
def get_list_settings(doctype, for_update=False):
list_settings = frappe.cache().hget('_list_settings',
'{0}::{1}'.format(doctype, frappe.session.user))

@@ -8,17 +8,19 @@ def get_list_settings(doctype):
list_settings = frappe.db.sql('''select * from __ListSettings
where user=%s and doctype=%s''', (frappe.session.user, doctype), as_dict=True)
list_settings = list_settings and list_settings[0] or '{}'
update_list_settings(doctype, list_settings)

if not for_update:
update_list_settings(doctype, list_settings)

return list_settings

def update_list_settings(doctype, list_settings):
'''update list settings in cache'''
if not isinstance(list_settings, basestring):
list_settings = json.dumps(list_settings)
current = json.loads(get_list_settings(doctype, for_update = True))
current.update(list_settings)

frappe.cache().hset('_list_settings', '{0}::{1}'.format(doctype, frappe.session.user),
list_settings)
json.dumps(current))

def sync_list_settings():
'''Sync from cache to database (called asynchronously via the browser)'''


+ 12
- 0
frappe/patches/v7_0/setup_list_settings.py 查看文件

@@ -1,4 +1,16 @@
from frappe.installer import create_list_settings_table
from frappe.model.utils.list_settings import update_list_settings
import frappe, json

def execute():
create_list_settings_table()

for user in frappe.db.get_all('User', {'user_type': 'System User'}):
defaults = frappe.defaults.get_defaults_for(user.name)
for key, value in defaults.iteritems():
if key.startswith('_list_settings:'):
doctype = key.replace('_list_settings:', '')
columns = ['`tab{1}`.`{0}`'.format(*c) for c in json.loads(value)]

update_list_settings(doctype, {'fields': columns})


+ 3
- 0
frappe/public/css/common.css 查看文件

@@ -1,3 +1,6 @@
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}
a {
cursor: pointer;
}


+ 3
- 0
frappe/public/css/desk.css 查看文件

@@ -1,3 +1,6 @@
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}
a {
cursor: pointer;
}


+ 3
- 0
frappe/public/css/website.css 查看文件

@@ -1,3 +1,6 @@
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}
a {
cursor: pointer;
}


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

@@ -289,3 +289,4 @@ frappe.dom.set_box_shadow = function(ele, spread) {
return this;
}
})(jQuery);


+ 68
- 55
frappe/public/js/frappe/list/doclistview.js 查看文件

@@ -132,14 +132,6 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
this.init_select_all();
},

init_list_settings: function() {
if(frappe.model.list_settings[this.doctype]) {
this.list_settings = frappe.model.list_settings[this.doctype];
} else {
this.list_settings = {};
}
},

init_headers: function() {
var main = frappe.render_template("list_item_main_head", {
columns: this.listview.columns,
@@ -227,10 +219,18 @@ frappe.views.DocListView = frappe.ui.Listing.extend({

if(this.list_settings.order_by) {
// last saved settings
parts = this.list_settings.order_by.split(' ');
var order_by = this.list_settings.order_by

if(order_by.indexOf('`.`')!==-1) {
// scrub table name (separted by dot), like `tabTime Log`.`modified` desc`
order_by = order_by.split('.')[1];
}

parts = order_by.split(' ');
if(parts.length===2) {
var fieldname = strip(parts[0], '`');
args = {
sort_by: parts[0],
sort_by: fieldname,
sort_order: parts[1]
}
}
@@ -267,6 +267,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
// init list
this.make({
method: 'frappe.desk.reportview.get',
save_list_settings: true,
get_args: this.get_args,
parent: this.wrapper,
freeze: true,
@@ -303,10 +304,8 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
this.listview.settings.refresh(this);
}

if(frappe.route_options) {
this.set_route_options();
this.run();
} else if(this.dirty) {
this.set_filters_before_run();
if(this.dirty) {
this.run();
} else {
if(new Date() - (this.last_updated_on || 0) > 30000) {
@@ -316,57 +315,69 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
}
},

set_route_options: function() {
set_filters_before_run: function() {
// set filters from frappe.route_options
// before switching pages, frappe.route_options can have pre-set filters
// for the list view
var me = this;
me.filter_list.clear_filters();
$.each(frappe.route_options, function(key, value) {
var doctype = null;

// if `Child DocType.fieldname`
if (key.indexOf(".")!==-1) {
doctype = key.split(".")[0];
key = key.split(".")[1];
}

// find the table in which the key exists
// for example the filter could be {"item_code": "X"}
// where item_code is in the child table.

// we can search all tables for mapping the doctype
if(!doctype) {
if(in_list(frappe.model.std_fields_list, key)) {
// standard
doctype = me.doctype;
} else if(frappe.meta.has_field(me.doctype, key)) {
// found in parent
doctype = me.doctype;
} else {
frappe.meta.get_table_fields(me.doctype).every(function(d) {
if(frappe.meta.has_field(d.options, key)) {
doctype = d.options;
return false;
}
});
if(frappe.route_options) {
this.filter_list.clear_filters();
$.each(frappe.route_options, function(key, value) {
var doctype = null;

// if `Child DocType.fieldname`
if (key.indexOf(".")!==-1) {
doctype = key.split(".")[0];
key = key.split(".")[1];
}

if(!doctype) {
frappe.msgprint(__('Warning: Unable to find {0} in any table related to {1}', [
key, __(me.doctype)]));
// find the table in which the key exists
// for example the filter could be {"item_code": "X"}
// where item_code is in the child table.

// we can search all tables for mapping the doctype
if(!doctype) {
if(in_list(frappe.model.std_fields_list, key)) {
// standard
doctype = me.doctype;
} else if(frappe.meta.has_field(me.doctype, key)) {
// found in parent
doctype = me.doctype;
} else {
frappe.meta.get_table_fields(me.doctype).every(function(d) {
if(frappe.meta.has_field(d.options, key)) {
doctype = d.options;
return false;
}
});

if(!doctype) {
frappe.msgprint(__('Warning: Unable to find {0} in any table related to {1}', [
key, __(me.doctype)]));
}
}
}
}

if(doctype) {
if($.isArray(value)) {
me.filter_list.add_filter(doctype, key, value[0], value[1]);
} else {
me.filter_list.add_filter(doctype, key, "=", value);
if(doctype) {
if($.isArray(value)) {
me.filter_list.add_filter(doctype, key, value[0], value[1]);
} else {
me.filter_list.add_filter(doctype, key, "=", value);
}
}
}
});
frappe.route_options = null;
});
frappe.route_options = null;
this.dirty = true;
} else if(this.list_settings && this.list_settings.filters
&& this.list_settings.updated_on != this.list_settings_updated_on) {
// update remembered list settings
this.filter_list.clear_filters();
this.list_settings.filters.forEach(function(f) {
me.filter_list.add_filter(f[0], f[1], f[2], f[3]);
});
this.dirty = true;
}
},

run: function(more) {
@@ -415,6 +426,8 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
if(this.listview.settings.post_render) {
this.listview.settings.post_render(this);
}

this.list_settings_updated_on = this.list_settings.updated_on;
},

make_no_result: function() {


+ 20
- 0
frappe/public/js/frappe/misc/utils.js 查看文件

@@ -325,6 +325,26 @@ frappe.utils = {
return list.reduce(function(previous_value, current_value) { return flt(previous_value) + flt(current_value); }, 0.0);
},

arrays_equal: function(arr1, arr2) {
if (!arr1 || !arr2) {
return false;
}
if (arr1.length != arr2.length) {
return false;
}
for (var i = 0; i < arr1.length; i++) {
if ($.isArray(arr1[i])) {
if (!frappe.utils.arrays_equal(arr1[i], arr2[i])) {
return false;
}
}
else if (arr1[i] !== arr2[i]) {
return false;
}
}
return true;
},

intersection: function(a, b) {
// from stackoverflow: http://stackoverflow.com/questions/1885557/simplest-code-for-array-intersection-in-javascript
/* finds the intersection of


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

@@ -118,6 +118,7 @@ $.extend(frappe.model, {
if(r.list_settings) {
// remember filters and other settings from last view
frappe.model.list_settings[doctype] = JSON.parse(r.list_settings);
frappe.model.list_settings[doctype].updated_on = moment().toString();
}
callback && callback(r);
}


+ 48
- 4
frappe/public/js/frappe/ui/listing.js 查看文件

@@ -52,7 +52,7 @@ frappe.ui.Listing = Class.extend({
this.opts.no_result_message = __('Nothing to show');
}
if(!this.opts.page_length) {
this.opts.page_length = 20;
this.opts.page_length = this.list_settings ? (this.list_settings.limit || 20) : 20;
}
this.opts._more = __("More");
},
@@ -174,14 +174,18 @@ frappe.ui.Listing = Class.extend({
if(this.onreset) this.onreset();
}

if(!me.opts.no_loading)
if(!me.opts.no_loading) {
me.set_working(true);
}

var args = this.get_call_args();
this.save_list_settings_locally(args);

return frappe.call({
method: this.opts.method || 'frappe.desk.query_builder.runquery',
type: "GET",
freeze: (this.opts.freeze != undefined ? this.opts.freeze : true),
args: this.get_call_args(),
args: args,
callback: function(r) {
if(!me.opts.no_loading)
me.set_working(false);
@@ -191,6 +195,39 @@ frappe.ui.Listing = Class.extend({
no_spinner: this.opts.no_loading
});
},
save_list_settings_locally: function(args) {
if(this.opts.save_list_settings && this.doctype && !this.docname) {
// save list settings locally
list_settings = frappe.model.list_settings[this.doctype];

var different = false;

if(!frappe.utils.arrays_equal(args.filters, list_settings.filters)) {
// settings are dirty if filters change
list_settings.filters = args.filters || [];
different = true;
}

if(list_settings.order_by !== args.order_by) {
list_settings.order_by = args.order_by;
different = true;
}

if(list_settings.limit != args.limit_page_length) {
list_settings.limit = args.limit_page_length || 20
different = true;
}

// save fields in list settings
if(args.save_list_settings_fields) {
list_settings.fields = args.fields;
};

if(different) {
list_settings.updated_on = moment().toString();
}
}
},
set_working: function(flag) {
this.$w.find('.img-load').toggle(flag);
},
@@ -325,5 +362,12 @@ frappe.ui.Listing = Class.extend({
}
}
return this;
}
},
init_list_settings: function() {
if(frappe.model.list_settings[this.doctype]) {
this.list_settings = frappe.model.list_settings[this.doctype];
} else {
this.list_settings = {};
}
},
});

+ 35
- 6
frappe/public/js/frappe/views/reports/reportview.js 查看文件

@@ -30,7 +30,7 @@ frappe.views.ReportViewPage = Class.extend({
me.parent.reportview.run();
});
} else {
me.parent.reportview.set_route_filters();
me.parent.reportview.set_route_filters(true);
me.parent.reportview.run();
}
});
@@ -89,10 +89,12 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
var me = this;
this.page = this.parent.page;
this.page_title = __('Report')+ ': ' + __(this.docname ? (this.doctype + ' - ' + this.docname) : this.doctype);
this.page.set_title(this.page_title)
this.page.set_title(this.page_title);
this.init_list_settings();
this.make({
page: this.parent.page,
method: 'frappe.desk.reportview.get',
save_list_settings: true,
get_args: this.get_args,
parent: this.page.main,
start: 0,
@@ -130,8 +132,17 @@ frappe.views.ReportView = frappe.ui.Listing.extend({

set_init_columns: function() {
// pre-select mandatory columns
var columns = frappe.defaults.get_default("_list_settings:" + this.doctype);
if(!columns) {
var me = this;
var columns = [];
if(this.list_settings.fields) {
this.list_settings.fields.forEach(function(field) {
var coldef = me.get_column_info_from_field(field);
if(!in_list(['_seen', '_comments', '_user_tags', '_assign', '_liked_by', 'docstatus'], coldef[0])) {
columns.push(coldef);
}
});
};
if(!columns.length) {
var columns = [['name', this.doctype],];
$.each(frappe.meta.docfield_list[this.doctype], function(i, df) {
if((df.in_filter || df.in_list_view) && df.fieldname!='naming_series'
@@ -168,7 +179,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
if(opts.sort_order_next) this.sort_order_next_select.val(opts.sort_order_next);
},

set_route_filters: function() {
set_route_filters: function(first_load) {
var me = this;
if(frappe.route_options) {
me.filter_list.clear_filters();
@@ -177,7 +188,16 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
});
frappe.route_options = null;
return true;
} else if(this.list_settings && this.list_settings.filters &&
(this.list_settings.updated_on != this.list_settings_updated_on)) {
// list settings (previous settings)
this.filter_list.clear_filters();
$.each(this.list_settings.filters, function(i, f) {
me.filter_list.add_filter(f[0], f[1], f[2], f[3]);
});
return true;
}
this.list_settings_updated_on = this.list_settings.updated_on;
},

setup_print: function() {
@@ -196,6 +216,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
fields: $.map(this.columns, function(v) { return me.get_full_column_name(v) }),
order_by: this.get_order_by(),
filters: this.filter_list.get_filters(),
save_list_settings_fields: 1,
with_childnames: 1
}
},
@@ -229,6 +250,15 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
return (v[1] ? ('`tab' + v[1] + '`') : this.tab_name) + '.`' + v[0] + '`';
},

get_column_info_from_field: function(t) {
if(t.indexOf('.')===-1) {
return [strip(t, '`'), this.doctype];
} else {
var parts = t.split('.');
return [strip(parts[1], '`'), strip(parts[0], '`').substr(3)];
}
},

// build columns for slickgrid
build_columns: function() {
var me = this;
@@ -706,7 +736,6 @@ frappe.ui.ColumnPicker = Class.extend({
: null;
});

frappe.defaults.set_default("_list_settings:" + this.doctype, columns);
this.list.columns = columns;
this.list.run();
}


+ 7
- 0
frappe/public/less/common.less 查看文件

@@ -7,6 +7,13 @@
// font-family: "Open Sans", "Helvetica", Arial, "sans-serif";
// }

body {
font-family: -apple-system, BlinkMacSystemFont,
"Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell",
"Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
}

a {
cursor: pointer;
}


+ 5
- 1
frappe/utils/redis_wrapper.py 查看文件

@@ -2,7 +2,7 @@
# MIT License. See license.txt
from __future__ import unicode_literals

import redis, frappe, re, copy
import redis, frappe, re
import cPickle as pickle
from frappe.utils import cstr

@@ -126,6 +126,10 @@ class RedisWrapper(redis.Redis):
except redis.exceptions.ConnectionError:
pass

def hgetall(self, name):
return {key: pickle.loads(value) for key, value in
super(redis.Redis, self).hgetall(self.make_key(name)).iteritems()}

def hget(self, name, key, generator=None):
if not name in frappe.local.cache:
frappe.local.cache[name] = {}


Loading…
取消
儲存