├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── frappe_better_list_view
├── __init__.py
├── config
│ ├── __init__.py
│ ├── desktop.py
│ └── docs.py
├── frappe_better_list_view
│ └── __init__.py
├── hooks.py
├── modules.txt
├── patches.txt
├── public
│ ├── build.json
│ └── js
│ │ ├── better_list_view.bundle.js
│ │ └── better_list_view_v12.bundle.js
└── version.py
├── images
└── row_bg.png
├── pyproject.toml
├── requirements.txt
└── setup.py
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[BUG]"
5 | labels: bug
6 | assignees: kid1194
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Additional context**
27 | Add any other context about the problem here.
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[REQ]"
5 | labels: enhancement
6 | assignees: kid1194
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright 2022 Level Up Marketing & Development Services
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 | software and associated documentation files (the "Software"), to deal in the Software
7 | without restriction, including without limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
9 | to whom the Software is furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all copies
12 | or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
16 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
17 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19 | USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include MANIFEST.in
2 | include requirements.txt
3 | include *.json
4 | include *.md
5 | include *.py
6 | include *.txt
7 | recursive-include frappe_better_list_view *.css
8 | recursive-include frappe_better_list_view *.csv
9 | recursive-include frappe_better_list_view *.html
10 | recursive-include frappe_better_list_view *.ico
11 | recursive-include frappe_better_list_view *.js
12 | recursive-include frappe_better_list_view *.json
13 | recursive-include frappe_better_list_view *.md
14 | recursive-include frappe_better_list_view *.png
15 | recursive-include frappe_better_list_view *.py
16 | recursive-include frappe_better_list_view *.svg
17 | recursive-include frappe_better_list_view *.txt
18 | recursive-exclude frappe_better_list_view *.pyc
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Frappe Better List View
2 |
3 | A small **Frappe** list view plugin that allows customization.
4 |
5 | 
6 |
7 | ---
8 |
9 | ### Table of Contents
10 | - [Requirements](#requirements)
11 | - [Setup](#setup)
12 | - [Install](#install)
13 | - [Update](#update)
14 | - [Uninstall](#uninstall)
15 | - [Usage](#usage)
16 | - [Options](#options)
17 | - [Methods](#methods)
18 | - [Example](#example)
19 | - [Issues](#issues)
20 | - [License](#license)
21 |
22 | ---
23 |
24 | ### Requirements
25 | - Frappe >= v12.0.0
26 |
27 | ---
28 |
29 | ### Setup
30 |
31 | ⚠️ *Important* ⚠️
32 |
33 | *Do not forget to replace [sitename] with the name of your site in all commands.*
34 |
35 | #### Install
36 | 1. Go to bench directory
37 |
38 | ```
39 | cd ~/frappe-bench
40 | ```
41 |
42 | 2. Get plugin from Github
43 |
44 | ```
45 | bench get-app https://github.com/kid1194/frappe-better-list-view
46 | ```
47 |
48 | 3. Build plugin
49 |
50 | ```
51 | bench build --app frappe_better_list_view
52 | ```
53 |
54 | 4. Install plugin on a specific site
55 |
56 | ```
57 | bench --site [sitename] install-app frappe_better_list_view
58 | ```
59 |
60 | 5. (Optional) Restart bench to clear cache
61 |
62 | ```
63 | bench restart
64 | ```
65 |
66 | #### Update
67 | 1. Go to app directory
68 |
69 | ```
70 | cd ~/frappe-bench/apps/frappe_better_list_view
71 | ```
72 |
73 | 2. Get updates from Github
74 |
75 | ```
76 | git pull
77 | ```
78 |
79 | 3. Go to bench directory
80 |
81 | ```
82 | cd ~/frappe-bench
83 | ```
84 |
85 | 4. Build plugin
86 |
87 | ```
88 | bench build --app frappe_better_list_view
89 | ```
90 |
91 | 5. Update a specific site
92 |
93 | ```
94 | bench --site [sitename] migrate
95 | ```
96 |
97 | 6. (Optional) Restart bench to clear cache
98 |
99 | ```
100 | bench restart
101 | ```
102 |
103 | #### Uninstall
104 | 1. Go to bench directory
105 |
106 | ```
107 | cd ~/frappe-bench
108 | ```
109 |
110 | 2. Uninstall plugin from a specific site
111 |
112 | ```
113 | bench --site [sitename] uninstall-app frappe_better_list_view
114 | ```
115 |
116 | 3. Remove plugin from bench
117 |
118 | ```
119 | bench remove-app frappe_better_list_view
120 | ```
121 |
122 | 4. (Optional) Restart bench to clear cache
123 |
124 | ```
125 | bench restart
126 | ```
127 |
128 | ---
129 |
130 | ### Usage
131 |
132 | #### Options
133 | ##### 1. `status` 🔴
134 |
135 | Status object to enable or disable ListView.
136 |
137 | **Keys:**
138 | | Key | Type | Description |
139 | | :--- | :--- | :--- |
140 | | `enable` | Boolean | Enabled or disabled status.
Default: `true` |
141 | | `message` | String | Disabled message.
Default: `ListView is disabled.` |
142 | | `color` | String | Message text color.
Colors: `green`, `blue`, `orange`, `gray`, `red`
Default: `red` |
143 |
144 | **Example:**
145 | ```
146 | {
147 | enable: false,
148 | message: __('ListView is disabled.'),
149 | color: 'red'
150 | }
151 | ```
152 |
153 | ##### 2. `query_fields`
154 |
155 | List of additional fields to fetch but not display.
156 |
157 | **Example:**
158 | ```
159 | ['is_approved', 'is_paid']
160 | ```
161 |
162 | ##### 3. `query_filters`
163 |
164 | List of additional filters for the fetch query.
165 |
166 | **Example:**
167 | - Object:
168 | ```
169 | {is_approved: 1, is_paid: 0}
170 | ```
171 | - Array:
172 | ```
173 | [
174 | ['is_approved', '=', 1],
175 | ['is_paid', '=', 0]
176 | ]
177 | ```
178 |
179 | ##### 4. `page_length`
180 |
181 | Number of rows to display per page.
182 | - Default: `20`
183 | - Minimum: `20`
184 |
185 | **Example:**
186 | ```
187 | 50
188 | ```
189 |
190 | ##### 5. `parser`
191 |
192 | Function to modify the list data before display.
193 |
194 | **Arguments:**
195 | | Name | Type | Description |
196 | | :--- | :--- | :--- |
197 | | `data` | Array | Data list before display. |
198 | | `render` | Function | ⚠️ Must be called after data parsing is done to render ListView. |
199 | | `error` | Function | ⚠️ Must be called when an error is raised to ignore all data modification. |
200 |
201 | ⚠️ *Important* ⚠️
202 |
203 | If an error isn't caught inside the parser function, all data modification will be ignored and original data will be rendered automatically instead.
204 |
205 | **Examples:**
206 | ```
207 | function(data, render, error) {
208 | let names = [];
209 | data.forEach(function(row) {
210 | names.push(row.name);
211 | });
212 | frappe.db.get_list('Doctype', {
213 | fields: ['name', 'value'],
214 | filters: {
215 | name: ['in', names],
216 | }
217 | }).then(function(list) {
218 | list.forEach(function(vals) {
219 | data.forEach(function(row) {
220 | if (vals.name === row.name) {
221 | row.value = vals.value;
222 | }
223 | });
224 | });
225 | // Render modified data
226 | render();
227 | }).catch(function(e) {
228 | console.error(e.message, e.stack);
229 | // Render original data instead
230 | error();
231 | });
232 | }
233 | ```
234 |
235 | ##### 6. `set_row_background`
236 |
237 | Function to set the row background color.
238 |
239 | **Arguments:**
240 | | Name | Type | Description |
241 | | :--- | :--- | :--- |
242 | | `row` | Plain Object | ListView row data object. |
243 |
244 |
245 | **Return:**
246 | | Type | Description |
247 | | :--- | :--- |
248 | | `String` | Row background color.
Color Type: `CSS Key`, `Hex`, `RGB`, `RGBA` or `HSLA`. |
249 | | `Null` | No row background color. |
250 |
251 |
252 | **CSS Colors & Keys:**
253 |
254 |
255 |
256 |
257 | **Examples:**
258 | ```
259 | function(row) {
260 | let cost = cint(row.cost);
261 | if (cost > 1000) return 'danger';
262 | if (cost > 800) return '#ffeeba';
263 | if (cost > 600) return 'rgb(190,229,235)';
264 | if (cost > 400) return 'rgba(190,229,235,1)';
265 | if (cost < 200) return 'hsla(133.7,41.2%,83.3%,1)';
266 | }
267 | ```
268 |
269 | #### Methods
270 | ##### 1. `toggle_status`
271 |
272 | Method to enable or disable ListView on demand. It can be called from within `onload` event.
273 |
274 | **Parameters:**
275 | | Name | Type | Description |
276 | | :--- | :--- | :--- |
277 | | `enable` | Boolean | Enabled or disabled status.
Default: `true` |
278 | | `message` | String | Disabled message.
Default: `ListView is disabled.` |
279 | | `color` | String | Message text color.
Colors: `green`, `blue`, `orange`, `gray`, `red`
Default: `red` |
280 |
281 |
282 | **Example:**
283 | ```
284 | frappe.listview_settings['DocType'] = {
285 | onload: function(listview) {
286 | if (!frappe.user_roles.includes('Some Role')) {
287 | listview.toggle_status(false, __('ListView is disabled.'), 'red');
288 | }
289 | }
290 | };
291 | ```
292 |
293 | #### Example
294 |
295 | ```
296 | frappe.listview_settings['DocType'] = {
297 | /*
298 | *---------------------------------------------------
299 | *---------- 🔴 Plugin Custom Options 🔴 ------------
300 | *---------------------------------------------------
301 | */
302 |
303 | /*
304 | * 1. ListView status
305 | */
306 | status: {
307 | enable: false,
308 | message: __('ListView is disabled.'),
309 | color: 'red'
310 | },
311 | /*
312 | * 2. Fields to fetch but not display
313 | */
314 | query_fields: ['is_approved', 'is_paid'],
315 | /*
316 | * 3. Additional filters (array or object) for fetch query
317 | */
318 | query_filters: {
319 | is_approved: 1,
320 | is_paid: 1,
321 | },
322 | /*
323 | * 4. Only 50 rows will be displayed per page
324 | */
325 | page_length: 50,
326 | /*
327 | * 5. List data modify function
328 | */
329 | parser: function(data, render, error) {
330 | let names = [];
331 | data.forEach(function(row) {
332 | names.push(row.name);
333 | });
334 | if (!names.length) {
335 | return render();
336 | }
337 | frappe.db.get_list('Doctype', {
338 | fields: ['name', 'price'],
339 | filters: {
340 | name: ['in', names],
341 | is_approved: 1,
342 | }
343 | }).then(function(list) {
344 | list.forEach(function(vals) {
345 | data.forEach(function(row) {
346 | if (vals.name === row.name) {
347 | row.price = vals.price;
348 | }
349 | });
350 | });
351 | // Render modified data
352 | render();
353 | }).catch(function(e) {
354 | console.error(e.message, e.stack);
355 | // Render original data instead
356 | error();
357 | });
358 | },
359 | /*
360 | * 6. Custom row background color
361 | */
362 | set_row_background: function(row) {
363 | if (!cint(row.is_approved)) return 'info';
364 | },
365 |
366 |
367 | /*
368 | *---------------------------------------------------
369 | *-------- 🔵 ListView Options & Events 🔵 ----------
370 | *---------------------------------------------------
371 | */
372 |
373 | /*
374 | * 1. Onload event
375 | *
376 | * ListView status can be toggled and changed using
377 | * the method "toggle_status" added by the plugin.
378 | */
379 | onload: function(listview) {
380 | if (!frappe.user_roles.includes('Some Role')) {
381 | listview.toggle_status(false, __('ListView is disabled.'), 'red');
382 | }
383 | },
384 | /*
385 | * 2. Custom indicator method
386 | *
387 | * Additional fields listed in the "query_fields" option above
388 | * are added to the "doc" object and can be accessed directly.
389 | */
390 | get_indicator: function(doc) {
391 | if (doc.is_paid) {
392 | return [__('Paid'), 'blue', 'is_paid,=,Yes|is_approved,=,Yes'];
393 | }
394 | if (doc.is_approved) {
395 | return [__('Approved'), 'green', 'is_paid,=,No|is_approved,=,Yes'];
396 | }
397 | return [__('Pending'), 'gray', 'is_paid,=,No|is_approved,=,No'];
398 | },
399 | /*
400 | * 2. Column data formatters
401 | *
402 | * Additional fields listed in the "query_fields" option above
403 | * are added to the "doc" object and can be accessed directly.
404 | */
405 | formatters: {
406 | name: function(value, field, doc) {
407 | let html = value;
408 | if (doc.is_approved) {
409 | html += ' ';
410 | }
411 | return html;
412 | },
413 | },
414 | };
415 | ```
416 |
417 | ---
418 |
419 | ### Issues
420 | If you find a bug, please create a [bug report](https://github.com/kid1194/frappe-better-list-view/issues/new?assignees=kid1194&labels=bug&template=bug_report.md&title=%5BBUG%5D) and let us know about it.
421 |
422 | ---
423 |
424 | ### License
425 | This plugin has been released under the [MIT License](https://github.com/kid1194/frappe-better-list-view/blob/main/LICENSE).
426 |
--------------------------------------------------------------------------------
/frappe_better_list_view/__init__.py:
--------------------------------------------------------------------------------
1 | # Frappe Better List View © 2024
2 | # Author: Ameen Ahmed
3 | # Company: Level Up Marketing & Software Development Services
4 | # Licence: Please refer to LICENSE file
5 |
6 |
7 | __version__ = "1.4.0"
--------------------------------------------------------------------------------
/frappe_better_list_view/config/__init__.py:
--------------------------------------------------------------------------------
1 | # Frappe Better List View © 2024
2 | # Author: Ameen Ahmed
3 | # Company: Level Up Marketing & Software Development Services
4 | # Licence: Please refer to LICENSE file
--------------------------------------------------------------------------------
/frappe_better_list_view/config/desktop.py:
--------------------------------------------------------------------------------
1 | # Frappe Better List View © 2024
2 | # Author: Ameen Ahmed
3 | # Company: Level Up Marketing & Software Development Services
4 | # Licence: Please refer to LICENSE file
5 |
6 |
7 | from frappe import _
8 |
9 |
10 | def get_data():
11 | return [
12 | {
13 | "module_name": "Frappe Better List View",
14 | "color": "blue",
15 | "icon": "octicon octicon-list-unordered",
16 | "type": "module",
17 | "label": _("Frappe Better List View")
18 | }
19 | ]
--------------------------------------------------------------------------------
/frappe_better_list_view/config/docs.py:
--------------------------------------------------------------------------------
1 | # Frappe Better List View © 2024
2 | # Author: Ameen Ahmed
3 | # Company: Level Up Marketing & Software Development Services
4 | # Licence: Please refer to LICENSE file
5 |
6 |
7 | """
8 | Configuration for docs
9 | """
10 |
11 |
12 | def get_context(context):
13 | context.brand_html = "Frappe Better List View"
14 |
--------------------------------------------------------------------------------
/frappe_better_list_view/frappe_better_list_view/__init__.py:
--------------------------------------------------------------------------------
1 | # Frappe Better List View © 2024
2 | # Author: Ameen Ahmed
3 | # Company: Level Up Marketing & Software Development Services
4 | # Licence: Please refer to LICENSE file
--------------------------------------------------------------------------------
/frappe_better_list_view/hooks.py:
--------------------------------------------------------------------------------
1 | # Frappe Better List View © 2024
2 | # Author: Ameen Ahmed
3 | # Company: Level Up Marketing & Software Development Services
4 | # Licence: Please refer to LICENSE file
5 |
6 |
7 | from .version import is_version_gt
8 |
9 |
10 | app_name = "frappe_better_list_view"
11 | app_title = "Frappe Better List View"
12 | app_publisher = "Ameen Ahmed (Level Up)"
13 | app_description = "Frappe list view plugin that allows modification."
14 | app_icon = "octicon octicon-list-unordered"
15 | app_color = "blue"
16 | app_email = "kid1194@gmail.com"
17 | app_license = "MIT"
18 |
19 |
20 | app_include_js = [
21 | 'better_list_view.bundle.js'
22 | ] if is_version_gt(13) else ([
23 | '/assets/frappe_better_list_view/js/better_list_view.js'
24 | ] if is_version_gt(12) else [
25 | '/assets/frappe_better_list_view/js/better_list_view_v12.js'
26 | ])
--------------------------------------------------------------------------------
/frappe_better_list_view/modules.txt:
--------------------------------------------------------------------------------
1 | Frappe Better List View
--------------------------------------------------------------------------------
/frappe_better_list_view/patches.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kid1194/frappe-better-list-view/c8bb8d3c9338f4dc6a4d6f17a3d1bae326c841ff/frappe_better_list_view/patches.txt
--------------------------------------------------------------------------------
/frappe_better_list_view/public/build.json:
--------------------------------------------------------------------------------
1 | {
2 | "frappe_better_list_view/js/better_list_view.js": [
3 | "public/js/better_list_view.bundle.js"
4 | ],
5 | "frappe_better_list_view/js/better_list_view_v12.js": [
6 | "public/js/better_list_view_v12.bundle.js"
7 | ]
8 | }
--------------------------------------------------------------------------------
/frappe_better_list_view/public/js/better_list_view.bundle.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Frappe Better List View © 2024
3 | * Author: Ameen Ahmed
4 | * Company: Level Up Marketing & Software Development Services
5 | * Licence: Please refer to LICENSE file
6 | */
7 |
8 |
9 | frappe.views.ListView = class ListView extends frappe.views.ListView {
10 | constructor(opts) {
11 | super(opts);
12 | this._is_enabled = true;
13 | this._row_class = 'level list-row';
14 | this._row_backgrounds = [
15 | 'active', 'primary', 'secondary',
16 | 'success', 'danger', 'warning', 'info',
17 | ];
18 | }
19 | toggle_status(enable, message, color) {
20 | if (enable) {
21 | this._is_enabled = true;
22 | this.page.clear_inner_toolbar();
23 | this.set_primary_action();
24 | } else {
25 | this._is_enabled = false;
26 | this.page.hide_actions_menu();
27 | this.page.clear_primary_action();
28 | this.page.clear_inner_toolbar();
29 | message = message || __('ListView is disabled.');
30 | color = color || 'red';
31 | let colors = {
32 | green: 'success',
33 | blue: 'info',
34 | orange: 'warning',
35 | gray: 'muted',
36 | red: 'danger'
37 | };
38 | this.page.add_inner_message(message)
39 | .removeClass('text-muted')
40 | .addClass('text-' + (colors[color] || colors.red));
41 | }
42 | }
43 | set_primary_action() {
44 | if (this._is_enabled) super.set_primary_action();
45 | else this.page.clear_primary_action();
46 | }
47 | toggle_actions_menu_button() {
48 | if (this._is_enabled) super.toggle_actions_menu_button();
49 | }
50 | setup_events() {
51 | super.setup_events();
52 | if (
53 | $.isPlainObject(this.settings.status)
54 | && this.settings.status.enabled != null
55 | ) {
56 | this.toggle_status(
57 | this.settings.status.enabled,
58 | this.settings.status.message,
59 | this.settings.status.color
60 | );
61 | }
62 | }
63 | get_args() {
64 | let args = super.get_args();
65 | if (args.doctype !== this.doctype) {
66 | console.error(__('ListView invalid super args.'));
67 | return args;
68 | }
69 | if (
70 | $.isArray(this.settings.query_fields)
71 | && this.settings.query_fields.length
72 | ) {
73 | for (let i = 0, l = this.settings.query_fields.length, f; i < l; i++) {
74 | f = frappe.model.get_full_column_name(
75 | this.settings.query_fields[i],
76 | this.doctype
77 | );
78 | if (args.fields.indexOf(f) < 0) args.fields.push(f);
79 | }
80 | }
81 | if (
82 | $.isPlainObject(this.settings.query_filters)
83 | && !$.isEmptyObject(this.settings.query_filters)
84 | ) {
85 | for (let key in this.settings.query_filters) {
86 | this._add_query_filter(args, key);
87 | }
88 | } else if (
89 | $.isArray(this.settings.query_filters)
90 | && this.settings.query_filters.length
91 | ) {
92 | for (let i = 0, l = this.settings.query_filters.length; i < l; i++) {
93 | this._add_query_filter(args, i);
94 | }
95 | }
96 | if (cint(this.settings.page_length) >= 20)
97 | args.page_length = cint(this.settings.page_length);
98 | return args;
99 | }
100 | render_list() {
101 | if (
102 | this._data_rendered
103 | || !$.isFunction(this.settings.parser)
104 | ) {
105 | delete this._data_rendered;
106 | return super.render_list();
107 | }
108 | var me = this,
109 | clone = [];
110 | for (let i = 0, l = this.data.length; i < l; i++) {
111 | clone[i] = $.extend(true, {}, this.data[i]);
112 | }
113 | let promise = new Promise(function(res, rej) {
114 | try {
115 | me.settings.parser(me.data, res, rej);
116 | } catch(_) { rej(); }
117 | });
118 | promise.then(
119 | function() { clone = null; },
120 | function() { me.data = clone; }
121 | );
122 | promise.catch(function() { me.data = clone; });
123 | promise.finally(function() {
124 | me._data_rendered = 1;
125 | me.render_list();
126 | });
127 | }
128 | get_list_row_html(doc) {
129 | let html = super.get_list_row_html(doc);
130 | if (!$.isFunction(this.settings.set_row_background)) return html;
131 | let color = this.settings.set_row_background(doc);
132 | if (
133 | !color
134 | || Object.prototype.toString.call(color) !== '[object String]'
135 | || !color.length
136 | ) return html;
137 | if (this._row_backgrounds.indexOf(color) >= 0) {
138 | html = html.replace(this._row_class, this._row_class + ' table-' + color);
139 | } else if (/^(\#([a-z0-9]{3,})|(rgb(a|)|hsla)\(([0-9\,\%\.]+)\))$/i.test(color)) {
140 | html = html.replace(this._row_class, this._row_class + '" style="background-color:' + color + '"');
141 | }
142 | return html;
143 | }
144 | _add_query_filter(args, field) {
145 | let qry = this._get_query_filter(field);
146 | if (qry && args.filters.indexOf(qry) < 0)
147 | args.filters.push(qry);
148 | }
149 | _get_query_filter(field) {
150 | let ret = [
151 | this.doctype, field, '=',
152 | this.settings.query_filters[field]
153 | ];
154 | if ($.isArray(ret[3])) {
155 | let cond = ret[3];
156 | if (cond.length < 2) return;
157 | if (cond.length > 2) ret[1] = cond.shift();
158 | ret[2] = cond[0];
159 | ret[3] = cond[1];
160 | }
161 | return ret;
162 | }
163 | };
--------------------------------------------------------------------------------
/frappe_better_list_view/public/js/better_list_view_v12.bundle.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Frappe Better List View © 2024
3 | * Author: Ameen Ahmed
4 | * Company: Level Up Marketing & Software Development Services
5 | * Licence: Please refer to LICENSE file
6 | */
7 |
8 |
9 | frappe.views.ListView = class ListView extends frappe.views.ListView {
10 | constructor(opts) {
11 | super(opts);
12 | this._is_enabled = true;
13 | this._row_class = 'level list-row';
14 | this._row_backgrounds = [
15 | 'active', 'primary', 'secondary',
16 | 'success', 'danger', 'warning', 'info',
17 | ];
18 | }
19 | toggle_status(enable, message, color) {
20 | if (enable) {
21 | this._is_enabled = true;
22 | this.page.clear_inner_toolbar();
23 | this.set_primary_action();
24 | } else {
25 | this._is_enabled = false;
26 | this.page.hide_actions_menu();
27 | this.page.clear_primary_action();
28 | this.page.clear_inner_toolbar();
29 | message = message || __('ListView is disabled.');
30 | color = color || 'red';
31 | var colors = {
32 | green: 'success',
33 | blue: 'info',
34 | orange: 'warning',
35 | gray: 'muted',
36 | red: 'danger'
37 | };
38 | this.page.add_inner_message(message)
39 | .removeClass('text-muted')
40 | .addClass('text-' + (colors[color] || colors.red));
41 | }
42 | }
43 | set_primary_action() {
44 | if (this._is_enabled) super.set_primary_action();
45 | else this.page.clear_primary_action();
46 | }
47 | toggle_actions_menu_button() {
48 | if (this._is_enabled) super.toggle_actions_menu_button();
49 | }
50 | setup_events() {
51 | super.setup_events();
52 | if (
53 | $.isPlainObject(this.settings.status)
54 | && this.settings.status.enabled != null
55 | ) {
56 | this.toggle_status(
57 | this.settings.status.enabled,
58 | this.settings.status.message,
59 | this.settings.status.color
60 | );
61 | }
62 | }
63 | get_args() {
64 | var args = super.get_args();
65 | if (args.doctype !== this.doctype) {
66 | console.error(__('Invalid list args.'));
67 | return args;
68 | }
69 | if (
70 | $.isArray(this.settings.query_fields)
71 | && this.settings.query_fields.length
72 | ) {
73 | for (var i = 0, l = this.settings.query_fields.length, f; i < l; i++) {
74 | f = frappe.model.get_full_column_name(
75 | this.settings.query_fields[i],
76 | this.doctype
77 | );
78 | if (args.fields.indexOf(f) < 0) args.fields.push(f);
79 | }
80 | }
81 | if (
82 | $.isPlainObject(this.settings.query_filters)
83 | && !$.isEmptyObject(this.settings.query_filters)
84 | ) {
85 | for (var key in this.settings.query_filters) {
86 | this._add_query_filter(args, key);
87 | }
88 | } else if (
89 | $.isArray(this.settings.query_filters)
90 | && this.settings.query_filters.length
91 | ) {
92 | for (var i = 0, l = this.settings.query_filters.length; i < l; i++) {
93 | this._add_query_filter(args, i);
94 | }
95 | }
96 | if (cint(this.settings.page_length) >= 20)
97 | args.page_length = cint(this.settings.page_length);
98 | return args;
99 | }
100 | render() {
101 | if (
102 | this._data_rendered
103 | || !$.isFunction(this.settings.parser)
104 | ) {
105 | delete this._data_rendered;
106 | return super.render_list();
107 | }
108 | var me = this,
109 | clone = [];
110 | for (var i = 0, l = this.data.length; i < l; i++) {
111 | clone[i] = $.extend(true, {}, this.data[i]);
112 | }
113 | var promise = new Promise(function(res, rej) {
114 | try {
115 | me.settings.parser(me.data, res, rej);
116 | } catch(_) { rej(); }
117 | });
118 | promise.then(
119 | function() { clone = null; },
120 | function() { me.data = clone; }
121 | );
122 | promise.catch(function() { me.data = clone; });
123 | promise.finally(function() {
124 | me._data_rendered = 1;
125 | me.render_list();
126 | });
127 | }
128 | get_list_row_html(doc) {
129 | var html = super.get_list_row_html(doc);
130 | if (!$.isFunction(this.settings.set_row_background)) return html;
131 | var color = this.settings.set_row_background(doc);
132 | if (
133 | !color
134 | || Object.prototype.toString.call(color) !== '[object String]'
135 | || !color.length
136 | ) return html;
137 | if (this._row_backgrounds.indexOf(color) >= 0) {
138 | html = html.replace(this._row_class, this._row_class + ' table-' + color);
139 | } else if (/^(\#([a-z0-9]{3,})|(rgb(a|)|hsla)\(([0-9\,\%\.]+)\))$/i.test(color)) {
140 | html = html.replace(this._row_class, this._row_class + '" style="background-color:' + color + '"');
141 | }
142 | return html;
143 | }
144 | _add_query_filter(args, field) {
145 | var qry = this._get_query_filter(field);
146 | if (qry && args.filters.indexOf(qry) < 0)
147 | args.filters.push(qry);
148 | }
149 | _get_query_filter(field) {
150 | var ret = [
151 | this.doctype, field, '=',
152 | this.settings.query_filters[field]
153 | ];
154 | if ($.isArray(ret[3])) {
155 | var cond = ret[3];
156 | if (cond.length < 2) return;
157 | if (cond.length > 2) ret[1] = cond.shift();
158 | ret[2] = cond[0];
159 | ret[3] = cond[1];
160 | }
161 | return ret;
162 | }
163 | };
--------------------------------------------------------------------------------
/frappe_better_list_view/version.py:
--------------------------------------------------------------------------------
1 | # Frappe Better List View © 2024
2 | # Author: Ameen Ahmed
3 | # Company: Level Up Marketing & Software Development Services
4 | # Licence: Please refer to LICENSE file
5 |
6 |
7 | from frappe import __version__
8 |
9 |
10 | # [Internal]
11 | __frappe_version__ = int(__version__.split(".")[0])
12 |
13 |
14 | # [Hooks]
15 | def is_version_gt(num: int):
16 | return __frappe_version__ > num
--------------------------------------------------------------------------------
/images/row_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kid1194/frappe-better-list-view/c8bb8d3c9338f4dc6a4d6f17a3d1bae326c841ff/images/row_bg.png
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "frappe_better_list_view"
3 | authors = [
4 | {name = "Ameen Ahmed (Level Up)", email = "kid1194@gmail.com"}
5 | ]
6 | description = "Frappe list view plugin that allows modification."
7 | keywords = ["frappe", "list view", "better list view"]
8 | classifiers = [
9 | "Development Status :: 5 - Production/Stable",
10 | "License :: OSI Approved :: MIT License",
11 | "Programming Language :: JavaScript"
12 | ]
13 | requires-python = ">=3.6"
14 | readme = "README.md"
15 | dynamic = ["version"]
16 | dependencies = [
17 | "frappe>=12.0.0"
18 | ]
19 |
20 | [project.urls]
21 | Documentation = "https://github.com/kid1194/frappe-better-list-view"
22 | Source = "https://github.com/kid1194/frappe-better-list-view"
23 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | frappe>=12.0.0
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # Frappe Better List View © 2024
2 | # Author: Ameen Ahmed
3 | # Company: Level Up Marketing & Software Development Services
4 | # Licence: Please refer to LICENSE file
5 |
6 |
7 | from setuptools import setup, find_packages
8 |
9 | from frappe_better_list_view import __version__
10 |
11 |
12 | with open('requirements.txt') as f:
13 | install_requires = f.read().strip().split('\n')
14 |
15 |
16 | setup(
17 | name='frappe_better_list_view',
18 | version=__version__,
19 | description='Frappe list view plugin that allows modification.',
20 | author='Ameen Ahmed (Level Up)',
21 | author_email='kid1194@gmail.com',
22 | packages=find_packages(),
23 | zip_safe=False,
24 | include_package_data=True,
25 | install_requires=install_requires
26 | )
27 |
--------------------------------------------------------------------------------