Coder Social home page Coder Social logo

kid1194 / frappe-better-list-view Goto Github PK

View Code? Open in Web Editor NEW
36.0 4.0 34.0 47 KB

Frappe list view plugin that allows modification.

License: MIT License

Python 21.39% JavaScript 78.61%
erpnext erpnext-customization frappe frappe-erpnext frappe-framework javascript listview

frappe-better-list-view's Introduction

Frappe Better List View

A small Frappe list view plugin that allows customization.

v1.4.0


Table of Contents


Requirements

  • Frappe >= v12.0.0

Setup

⚠️ Important ⚠️

Do not forget to replace [sitename] with the name of your site in all commands.

Install

  1. Go to bench directory
cd ~/frappe-bench
  1. Get plugin from Github
bench get-app https://github.com/kid1194/frappe-better-list-view
  1. Build plugin
bench build --app frappe_better_list_view
  1. Install plugin on a specific site
bench --site [sitename] install-app frappe_better_list_view
  1. (Optional) Restart bench to clear cache
bench restart

Update

  1. Go to app directory
cd ~/frappe-bench/apps/frappe_better_list_view
  1. Get updates from Github
git pull
  1. Go to bench directory
cd ~/frappe-bench
  1. Build plugin
bench build --app frappe_better_list_view
  1. Update a specific site
bench --site [sitename] migrate
  1. (Optional) Restart bench to clear cache
bench restart

Uninstall

  1. Go to bench directory
cd ~/frappe-bench
  1. Uninstall plugin from a specific site
bench --site [sitename] uninstall-app frappe_better_list_view
  1. Remove plugin from bench
bench remove-app frappe_better_list_view
  1. (Optional) Restart bench to clear cache
bench restart

Usage

Options

1. status 🔴

Status object to enable or disable ListView.

Keys:

Key Type Description
enable Boolean Enabled or disabled status.

Default: true
message String Disabled message.

Default: ListView is disabled.
color String Message text color.

Colors: green, blue, orange, gray, red

Default: red

Example:

{
    enable: false,
    message: __('ListView is disabled.'),
    color: 'red'
}
2. query_fields

List of additional fields to fetch but not display.

Example:

['is_approved', 'is_paid']
3. query_filters

List of additional filters for the fetch query.

Example:

  • Object:
{is_approved: 1, is_paid: 0}
  • Array:
[
    ['is_approved', '=', 1],
    ['is_paid', '=', 0]
]
4. page_length

Number of rows to display per page.

  • Default: 20
  • Minimum: 20

Example:

50
5. parser

Function to modify the list data before display.

Arguments:

Name Type Description
data Array Data list before display.
render Function ⚠️ Must be called after data parsing is done to render ListView.
error Function ⚠️ Must be called when an error is raised to ignore all data modification.

⚠️ Important ⚠️

If an error isn't caught inside the parser function, all data modification will be ignored and original data will be rendered automatically instead.

Examples:

function(data, render, error) {
    let names = [];
    data.forEach(function(row) {
        names.push(row.name);
    });
    frappe.db.get_list('Doctype', {
        fields: ['name', 'value'],
        filters: {
            name: ['in', names],
        }
    }).then(function(list) {
        list.forEach(function(vals) {
            data.forEach(function(row) {
                if (vals.name === row.name) {
                    row.value = vals.value;
                }
            });
        });
        // Render modified data
        render();
    }).catch(function(e) {
        console.error(e.message, e.stack);
        // Render original data instead
        error();
    });
}
6. set_row_background

Function to set the row background color.

Arguments:

Name Type Description
row Plain Object ListView row data object.

Return:

Type Description
String Row background color.

Color Type: CSS Key, Hex, RGB, RGBA or HSLA.
Null No row background color.

CSS Colors & Keys:

Frappe Better List View

Examples:

function(row) {
    let cost = cint(row.cost);
    if (cost > 1000) return 'danger';
    if (cost > 800) return '#ffeeba';
    if (cost > 600) return 'rgb(190,229,235)';
    if (cost > 400) return 'rgba(190,229,235,1)';
    if (cost < 200) return 'hsla(133.7,41.2%,83.3%,1)';
}

Methods

1. toggle_status

Method to enable or disable ListView on demand. It can be called from within onload event.

Parameters:

Name Type Description
enable Boolean Enabled or disabled status.

Default: true
message String Disabled message.

Default: ListView is disabled.
color String Message text color.

Colors: green, blue, orange, gray, red

Default: red

Example:

frappe.listview_settings['DocType'] = {
    onload: function(listview) {
        if (!frappe.user_roles.includes('Some Role')) {
            listview.toggle_status(false, __('ListView is disabled.'), 'red');
        }
    }
};

Example

frappe.listview_settings['DocType'] = {
    /*
     *---------------------------------------------------
     *---------- 🔴 Plugin Custom Options 🔴 ------------
     *---------------------------------------------------
     */
    
    /*
     * 1. ListView status
     */
    status: {
        enable: false,
        message: __('ListView is disabled.'),
        color: 'red'
    },
    /*
     * 2. Fields to fetch but not display
     */
    query_fields: ['is_approved', 'is_paid'],
    /*
     * 3. Additional filters (array or object) for fetch query
     */
    query_filters: {
        is_approved: 1,
        is_paid: 1,
    },
    /*
     * 4. Only 50 rows will be displayed per page
     */
    page_length: 50,
    /*
     * 5. List data modify function
     */
    parser: function(data, render, error) {
        let names = [];
        data.forEach(function(row) {
            names.push(row.name);
        });
        if (!names.length) {
            return render();
        }
        frappe.db.get_list('Doctype', {
            fields: ['name', 'price'],
            filters: {
                name: ['in', names],
                is_approved: 1,
            }
        }).then(function(list) {
            list.forEach(function(vals) {
                data.forEach(function(row) {
                    if (vals.name === row.name) {
                        row.price = vals.price;
                    }
                });
            });
            // Render modified data
            render();
        }).catch(function(e) {
            console.error(e.message, e.stack);
            // Render original data instead
            error();
        });
    },
    /*
     * 6. Custom row background color
     */
    set_row_background: function(row) {
        if (!cint(row.is_approved)) return 'info';
    },
    
    
    /*
     *---------------------------------------------------
     *-------- 🔵 ListView Options & Events 🔵 ----------
     *---------------------------------------------------
     */
    
    /*
     * 1. Onload event
     *
     * ListView status can be toggled and changed using
     * the method "toggle_status" added by the plugin.
     */
    onload: function(listview) {
        if (!frappe.user_roles.includes('Some Role')) {
            listview.toggle_status(false, __('ListView is disabled.'), 'red');
        }
    },
    /*
     * 2. Custom indicator method
     *
     * Additional fields listed in the "query_fields" option above
     * are added to the "doc" object and can be accessed directly.
     */
    get_indicator: function(doc) {
        if (doc.is_paid) {
            return [__('Paid'), 'blue', 'is_paid,=,Yes|is_approved,=,Yes'];
        }
        if (doc.is_approved) {
            return [__('Approved'), 'green', 'is_paid,=,No|is_approved,=,Yes'];
        }
        return [__('Pending'), 'gray', 'is_paid,=,No|is_approved,=,No'];
    },
    /*
     * 2. Column data formatters
     *
     * Additional fields listed in the "query_fields" option above
     * are added to the "doc" object and can be accessed directly.
     */
    formatters: {
        name: function(value, field, doc) {
            let html = value;
            if (doc.is_approved) {
                html += ' <span class="fa fa-check"></span>';
            }
            return html;
        },
    },
};

Issues

If you find a bug, please create a bug report and let us know about it.


License

This plugin has been released under the MIT License.

frappe-better-list-view's People

Contributors

kid1194 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

frappe-better-list-view's Issues

[BUG] parser not applied on listview refresh or backwards navigation

parser function is working as expected ON INITIAL LOAD of a listview BUT NOT after the following scenarios:

  1. listview refresh icon is clicked
  2. list item is clicked on and followed to another page, then browser back button is used to return to the listview
  3. list item is clicked on and followed ... then listview breadcrumb is clicked to return to the listview
    basically under the above failure scenarios, the parser function IS NOT EXECUTED, so some mechanism is needed to execute the parser under the above conditions.

NOTE: listview before_render() function IS CALLED under each of the above scenario's, but I haven't been able to find a way to retrigger the parser function from the before_render() function.

[BUG]

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Additional context
Add any other context about the problem here.

LIST VIEW NOT WORKING [BUG]

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.
Traceback with variables (most recent call last):
File "apps/frappe/frappe/website/serve.py", line 18, in get_response
response = renderer_instance.render()
path = '/list'
http_status_code = 200
response = None
endpoint = 'list'
path_resolver = <frappe.website.path_resolver.PathResolver object at 0x7fb22d03b760>
renderer_instance = <frappe.website.page_renderers.template_page.TemplatePage object at 0x7fb22d063820>
e = DoesNotExistError('DocType None not found')
File "apps/frappe/frappe/website/page_renderers/template_page.py", line 78, in render
html = self.get_html()
self = <frappe.website.page_renderers.template_page.TemplatePage object at 0x7fb22d063820>
File "apps/frappe/frappe/website/utils.py", line 510, in cache_html_decorator
html = func(*args, **kwargs)
args = (<frappe.website.page_renderers.template_page.TemplatePage object at 0x7fb22d063820>,)
kwargs = {}
html = None
page_cache = None
func = <function TemplatePage.get_html at 0x7fb23171f880>
File "apps/frappe/frappe/website/page_renderers/template_page.py", line 89, in get_html
self.update_context()
self = <frappe.website.page_renderers.template_page.TemplatePage object at 0x7fb22d063820>
File "apps/frappe/frappe/website/page_renderers/template_page.py", line 157, in update_context
data = self.run_pymodule_method("get_context")
self = <frappe.website.page_renderers.template_page.TemplatePage object at 0x7fb22d063820>
File "apps/frappe/frappe/website/page_renderers/template_page.py", line 219, in run_pymodule_method
return method(self.context)
self = <frappe.website.page_renderers.template_page.TemplatePage object at 0x7fb22d063820>
method_name = 'get_context'
inspect = <module 'inspect' from '/usr/lib/python3.10/inspect.py'>
method = <function get_context at 0x7fb22d179120>
File "apps/frappe/frappe/www/list.py", line 21, in get_context
context.meta = frappe.get_meta(doctype)
context = {'top_bar_items': [<TopBarItem: 7640ad8412 parent=Website Settings>, <TopBarItem: 5d35593e2f parent=Website Settings>, <TopBarItem: 23e2f47521 parent=Website Settings>, <TopBarItem: 32af5b00d3 parent=Website Settings>, <TopBarItem: 201660d38f parent=Website Settings>, <TopBarItem: 33e817700b parent=Website Settings>], 'footer_items': [<TopBarItem: c2cef792f0 parent=Website Settings>, <TopBarItem: 046fb0ef7b parent=Website Settings>, <TopBarItem: 2e0aed9725 parent=Website Settings>, <TopBarItem: d713ae5fad parent=Website Settings>, <TopBarItem: 399981147a parent=Website Settings>, <TopBarItem: 8e3b89a8ee parent=Website Settings>, <TopBarItem: 8fe12c75b3 parent=Website Settings>, <TopBarItem: 950daae9eb parent=Website Settings>], 'post_login': [{'label': 'My Account', 'url': '/me'}, {'label': 'Log out', 'url': '/?cmd=web_logout'}], 'banner_image': '/files/CK COLOR CRP.png', 'brand_html': "", 'copyright': 'Desifoods Processing ...
dict_params = {}
doctype = None
File "apps/frappe/frappe/init.py", line 1203, in get_meta
return frappe.model.meta.get_meta(doctype, cached=cached)
doctype = None
cached = True
frappe = <module 'frappe' from 'apps/frappe/frappe/init.py'>
File "apps/frappe/frappe/model/meta.py", line 65, in get_meta
meta = Meta(doctype)
doctype = None
cached = True
meta = None
File "apps/frappe/frappe/model/meta.py", line 123, in init
super().init("DocType", doctype)
self = <Meta: unsaved>
doctype = None
class = <class 'frappe.model.meta.Meta'>
File "apps/frappe/frappe/model/document.py", line 106, in init
self.load_from_db()
self = <Meta: unsaved>
args = ('DocType', None)
kwargs = {}
class = <class 'frappe.model.document.Document'>
File "apps/frappe/frappe/model/meta.py", line 129, in load_from_db
super().load_from_db()
self = <Meta: unsaved>
class = <class 'frappe.model.meta.Meta'>
File "apps/frappe/frappe/model/document.py", line 149, in load_from_db
frappe.throw(
self = <Meta: unsaved>
d = None
class = <class 'frappe.model.document.Document'>
File "apps/frappe/frappe/init.py", line 522, in throw
msgprint(
msg = 'DocType None not found'
exc = <class 'frappe.exceptions.DoesNotExistError'>
title = None
is_minimizable = False
wide = False
as_list = False
File "apps/frappe/frappe/init.py", line 490, in msgprint
_raise_exception()
title = None
as_table = False
as_list = False
indicator = 'red'
alert = False
primary_action = None
is_minimizable = False
wide = False
sys = <module 'sys' (built-in)>
out = {'message': 'DocType None not found', 'title': 'Message', 'indicator': 'red', 'raise_exception': 1}
_strip_html_tags = <functools._lru_cache_wrapper object at 0x7fb22d0ba140>
_raise_exception = <function msgprint.._raise_exception at 0x7fb22d09a050>
inspect = <module 'inspect' from '/usr/lib/python3.10/inspect.py'>
msg = 'DocType None not found'
raise_exception = <class 'frappe.exceptions.DoesNotExistError'>
strip_html_tags = <function strip_html_tags at 0x7fb234883f40>
File "apps/frappe/frappe/init.py", line 442, in _raise_exception
raise raise_exception(msg)
inspect = <module 'inspect' from '/usr/lib/python3.10/inspect.py'>
msg = 'DocType None not found'
raise_exception = <class 'frappe.exceptions.DoesNotExistError'>
frappe.exceptions.DoesNotExistError: DocType None not found
Additional context
Add any other context about the problem here.

[BUG]

Describe the bug
A clear and concise description of what the bug is.

[REQ] Detailed Docs

We want to use Status based coluroing based on select field, can we achive different rows colur functiolity. What portion of exmpale code should be used in such a scanario

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.