diff options
| author | Aaron Bohy <aab@odoo.com> | 2020-04-29 07:21:34 +0000 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2020-05-05 08:48:34 +0000 |
| commit | 1d6e4948d2e8534379b6815e931a6eaa58955e18 (patch) | |
| tree | 587a061ffa02f6797383b26b020139d61bb3fde5 /addons | |
| parent | 56787d587858760355e6703f1afce54a66f7800f (diff) | |
[IMP] web: add BadgeField component
This new field component displays the field's value inside a
bootstrap pill badge. Supported field types are 'char', 'selection'
and 'many2one'. The background color of the badge can be customized
by using the decoration-xxx mechanism, e.g.
<field name="state" decoration-danger="state == 'cancel'" widget="badge"/>
Part of task 2195254
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/web/static/src/js/fields/basic_fields_owl.js | 23 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/field_registry_owl.js | 1 | ||||
| -rw-r--r-- | addons/web/static/src/scss/fields.scss | 8 | ||||
| -rw-r--r-- | addons/web/static/src/scss/list_view.scss | 3 | ||||
| -rw-r--r-- | addons/web/static/src/scss/webclient.scss | 5 | ||||
| -rw-r--r-- | addons/web/static/src/xml/fields.xml | 4 | ||||
| -rw-r--r-- | addons/web/static/tests/fields/basic_fields_tests.js | 73 |
7 files changed, 117 insertions, 0 deletions
diff --git a/addons/web/static/src/js/fields/basic_fields_owl.js b/addons/web/static/src/js/fields/basic_fields_owl.js index a00b14fb9ee..8a5915410ee 100644 --- a/addons/web/static/src/js/fields/basic_fields_owl.js +++ b/addons/web/static/src/js/fields/basic_fields_owl.js @@ -7,6 +7,27 @@ odoo.define('web.basic_fields_owl', function (require) { const _lt = core._lt; + + /** + * FieldBadge displays the field's value inside a bootstrap pill badge. + * The supported field's types are 'char', 'selection' and 'many2one'. + * + * By default, the background color of the badge is a light gray, but it can + * be customized by setting a 'decoration-xxx' attribute on the field. + * For instance, + * <field name="some_field" widget="badge" decoration-danger="state == 'cancel'"/> + * renders a badge with a red background on records matching the condition. + */ + class FieldBadge extends AbstractField { + _getClassFromDecoration(decoration) { + return `bg-${decoration.split('-')[1]}-light`; + } + } + FieldBadge.description = _lt("Badge"); + FieldBadge.supportedFieldTypes = ['selection', 'many2one', 'char']; + FieldBadge.template = 'web.FieldBadge'; + + class FieldBoolean extends AbstractField { patched() { super.patched(); @@ -105,7 +126,9 @@ odoo.define('web.basic_fields_owl', function (require) { FieldBoolean.supportedFieldTypes = ['boolean']; FieldBoolean.template = 'web.FieldBoolean'; + return { + FieldBadge, FieldBoolean, }; }); diff --git a/addons/web/static/src/js/fields/field_registry_owl.js b/addons/web/static/src/js/fields/field_registry_owl.js index f5f7d900ef8..907ea38a9d7 100644 --- a/addons/web/static/src/js/fields/field_registry_owl.js +++ b/addons/web/static/src/js/fields/field_registry_owl.js @@ -27,5 +27,6 @@ odoo.define('web._field_registry_owl', function (require) { // Basic fields registry + .add('badge', basicFields.FieldBadge) .add('boolean', basicFields.FieldBoolean); }); diff --git a/addons/web/static/src/scss/fields.scss b/addons/web/static/src/scss/fields.scss index 6bae4914db1..f0d15adbd52 100644 --- a/addons/web/static/src/scss/fields.scss +++ b/addons/web/static/src/scss/fields.scss @@ -476,6 +476,14 @@ margin: 0 5px 0 0; display: inline-block; } + + &.o_field_badge { + border: 0; + font-size: 12px; + user-select: none; + background-color: rgba(lightgray, 0.5);; + font-weight: 500; + } } span.o_field_copy:empty { diff --git a/addons/web/static/src/scss/list_view.scss b/addons/web/static/src/scss/list_view.scss index 4c0633cf0f3..176e31262b5 100644 --- a/addons/web/static/src/scss/list_view.scss +++ b/addons/web/static/src/scss/list_view.scss @@ -290,6 +290,9 @@ > .o_row_handle { visibility: hidden; // hide sequence when editing } + > .o_field_badge { + width: auto; // override width: 100% to keep the optimal badge width + } } .o_field_x2many_list_row_add, .o_group_field_row_add { diff --git a/addons/web/static/src/scss/webclient.scss b/addons/web/static/src/scss/webclient.scss index 9bc77f1b29d..19f107b4064 100644 --- a/addons/web/static/src/scss/webclient.scss +++ b/addons/web/static/src/scss/webclient.scss @@ -82,6 +82,11 @@ div.o_boolean_toggle.custom-control.custom-checkbox { background-color: #dee2e6; } +// Light version of contextual bg colors (e.g. bg-danger-light) +@each $name in ('primary', 'secondary', 'success', 'danger', 'warning', 'info') { + @include bg-variant('.bg-#{$name}-light', rgba(theme-color($name), .5), #333); +} + .o_web_accesskey_overlay { font-family: $font-family-sans-serif; } diff --git a/addons/web/static/src/xml/fields.xml b/addons/web/static/src/xml/fields.xml index ff7939f36a3..ce271ba2123 100644 --- a/addons/web/static/src/xml/fields.xml +++ b/addons/web/static/src/xml/fields.xml @@ -6,4 +6,8 @@ class="o_field_boolean" t-on-change="_onChange"/> </t> + <t t-name="web.FieldBadge" owl="1"> + <span class="badge badge-pill o_field_badge" t-esc="_formatValue(value)"/> + </t> + </templates> diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index b04fdda089f..1f78efeb7f2 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -7053,6 +7053,79 @@ QUnit.module('basic_fields', { form.destroy(); }); + + QUnit.module('FieldBadge'); + + QUnit.test('FieldBadge component on a char field in list view', async function (assert) { + assert.expect(3); + + const list = await createView({ + View: ListView, + model: 'partner', + data: this.data, + arch: `<list><field name="display_name" widget="badge"/></list>`, + }); + + assert.containsOnce(list, '.o_field_badge[name="display_name"]:contains(first record)'); + assert.containsOnce(list, '.o_field_badge[name="display_name"]:contains(second record)'); + assert.containsOnce(list, '.o_field_badge[name="display_name"]:contains(aaa)'); + + list.destroy(); + }); + + QUnit.test('FieldBadge component on a selection field in list view', async function (assert) { + assert.expect(3); + + const list = await createView({ + View: ListView, + model: 'partner', + data: this.data, + arch: `<list><field name="selection" widget="badge"/></list>`, + }); + + assert.containsOnce(list, '.o_field_badge[name="selection"]:contains(Blocked)'); + assert.containsOnce(list, '.o_field_badge[name="selection"]:contains(Normal)'); + assert.containsOnce(list, '.o_field_badge[name="selection"]:contains(Done)'); + + list.destroy(); + }); + + QUnit.test('FieldBadge component on a many2one field in list view', async function (assert) { + assert.expect(2); + + const list = await createView({ + View: ListView, + model: 'partner', + data: this.data, + arch: `<list><field name="trululu" widget="badge"/></list>`, + }); + + assert.containsOnce(list, '.o_field_badge[name="trululu"]:contains(first record)'); + assert.containsOnce(list, '.o_field_badge[name="trululu"]:contains(aaa)'); + + list.destroy(); + }); + + QUnit.test('FieldBadge component with decoration-xxx attributes', async function (assert) { + assert.expect(3); + + const list = await createView({ + View: ListView, + model: 'partner', + data: this.data, + arch: ` + <list> + <field name="selection"/> + <field name="foo" widget="badge" decoration-danger="selection == 'done'" decoration-warning="selection == 'blocked'"/> + </list>`, + }); + + assert.containsN(list, '.o_field_badge[name="foo"]', 5); + assert.containsOnce(list, '.o_field_badge[name="foo"].bg-danger-light'); + assert.containsOnce(list, '.o_field_badge[name="foo"].bg-warning-light'); + + list.destroy(); + }); }); }); }); |
