summaryrefslogtreecommitdiff
path: root/addons/web
diff options
context:
space:
mode:
authorAaron Bohy <aab@odoo.com>2020-04-29 07:21:34 +0000
committerAaron Bohy <aab@odoo.com>2020-05-05 08:48:34 +0000
commit1d6e4948d2e8534379b6815e931a6eaa58955e18 (patch)
tree587a061ffa02f6797383b26b020139d61bb3fde5 /addons/web
parent56787d587858760355e6703f1afce54a66f7800f (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/web')
-rw-r--r--addons/web/static/src/js/fields/basic_fields_owl.js23
-rw-r--r--addons/web/static/src/js/fields/field_registry_owl.js1
-rw-r--r--addons/web/static/src/scss/fields.scss8
-rw-r--r--addons/web/static/src/scss/list_view.scss3
-rw-r--r--addons/web/static/src/scss/webclient.scss5
-rw-r--r--addons/web/static/src/xml/fields.xml4
-rw-r--r--addons/web/static/tests/fields/basic_fields_tests.js73
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();
+ });
});
});
});