[IMP] web: hide in kanban tag's color (#20815)
New feature:
- New Transparent tag visual (grey border & text, white bg),
- By default, newly created kanban tags are transparent,
- Tag's colorpicker has now a 'Hide in Kanban' checkbox,
to select the transparent color.
Toggling off 'Hide in Kanban' sets the color of the tag as follow:
- Previous color, if 'Hide in Kanban' was toggled on on the
same formview session.
- Color 1 (dark orange), otherwise.
This commit is contained in:
@@ -34,7 +34,7 @@ class AccountAccountTag(models.Model):
|
||||
|
||||
name = fields.Char(required=True)
|
||||
applicability = fields.Selection([('accounts', 'Accounts'), ('taxes', 'Taxes')], required=True, default='accounts')
|
||||
color = fields.Integer('Color Index', default=10)
|
||||
color = fields.Integer('Color Index')
|
||||
active = fields.Boolean(default=True, help="Set active to false to hide the Account Tag without removing it.")
|
||||
|
||||
#----------------------------------------------------------
|
||||
|
||||
@@ -8,7 +8,7 @@ class AccountAnalyticTag(models.Model):
|
||||
_name = 'account.analytic.tag'
|
||||
_description = 'Analytic Tags'
|
||||
name = fields.Char(string='Analytic Tag', index=True, required=True)
|
||||
color = fields.Integer('Color Index', default=10)
|
||||
color = fields.Integer('Color Index')
|
||||
active = fields.Boolean(default=True, help="Set active to false to hide the Analytic Tag without removing it.")
|
||||
|
||||
|
||||
|
||||
@@ -1220,7 +1220,7 @@ class Tag(models.Model):
|
||||
_description = "Category of lead"
|
||||
|
||||
name = fields.Char('Name', required=True, translate=True)
|
||||
color = fields.Integer('Color Index', default=10)
|
||||
color = fields.Integer('Color Index')
|
||||
|
||||
_sql_constraints = [
|
||||
('name_uniq', 'unique (name)', "Tag name already exists !"),
|
||||
|
||||
@@ -297,7 +297,7 @@ class FleetVehicleTag(models.Model):
|
||||
_name = 'fleet.vehicle.tag'
|
||||
|
||||
name = fields.Char(required=True, translate=True)
|
||||
color = fields.Integer('Color Index', default=10)
|
||||
color = fields.Integer('Color Index')
|
||||
|
||||
_sql_constraints = [('name_uniq', 'unique (name)', "Tag name already exists !")]
|
||||
|
||||
|
||||
@@ -873,7 +873,7 @@ class ProjectTags(models.Model):
|
||||
_description = "Tasks Tags"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
color = fields.Integer(string='Color Index', default=10)
|
||||
color = fields.Integer(string='Color Index')
|
||||
|
||||
_sql_constraints = [
|
||||
('name_uniq', 'unique (name)', "Tag name already exists!"),
|
||||
|
||||
@@ -1703,6 +1703,7 @@ var FormFieldMany2ManyTags = FieldMany2ManyTags.extend({
|
||||
events: _.extend({}, FieldMany2ManyTags.prototype.events, {
|
||||
'click .badge': '_onOpenColorPicker',
|
||||
'mousedown .o_colorpicker a': '_onUpdateColor',
|
||||
'mousedown .o_colorpicker .o_hide_in_kanban': '_onUpdateColor',
|
||||
'focusout .o_colorpicker': '_onCloseColorPicker',
|
||||
}),
|
||||
|
||||
@@ -1713,43 +1714,63 @@ var FormFieldMany2ManyTags = FieldMany2ManyTags.extend({
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onCloseColorPicker: function (){
|
||||
_onCloseColorPicker: function () {
|
||||
this.$color_picker.remove();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onOpenColorPicker: function (event) {
|
||||
var tag_id = $(event.currentTarget).data('id');
|
||||
var tag = _.findWhere(this.value.data, { res_id: tag_id });
|
||||
_onOpenColorPicker: function (ev) {
|
||||
var tagID = $(ev.currentTarget).data('id');
|
||||
var tagColor = $(ev.currentTarget).data('color');
|
||||
var tag = _.findWhere(this.value.data, { res_id: tagID });
|
||||
if (tag && this.colorField in tag.data) { // if there is a color field on the related model
|
||||
this.$color_picker = $(qweb.render('FieldMany2ManyTag.colorpicker', {
|
||||
'widget': this,
|
||||
'tag_id': tag_id,
|
||||
'tag_id': tagID,
|
||||
}));
|
||||
|
||||
$(event.currentTarget).append(this.$color_picker);
|
||||
$(ev.currentTarget).append(this.$color_picker);
|
||||
this.$color_picker.dropdown('toggle');
|
||||
this.$color_picker.attr("tabindex", 1).focus();
|
||||
if (!tagColor) {
|
||||
this.$('.o_checkbox input').prop('checked', true);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Update color based on target of ev
|
||||
* either by clicking on a color item or
|
||||
* by toggling the 'Hide in Kanban' checkbox.
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onUpdateColor: function (event) {
|
||||
event.preventDefault();
|
||||
var self = this;
|
||||
var color = $(event.currentTarget).data('color');
|
||||
var id = $(event.currentTarget).data('id');
|
||||
var tag = self.$("span.badge[data-id='" + id + "']");
|
||||
var current_color = tag.data('color');
|
||||
|
||||
if (color === current_color) { return; }
|
||||
|
||||
_onUpdateColor: function (ev) {
|
||||
ev.preventDefault();
|
||||
var $target = $(ev.currentTarget);
|
||||
var color = $target.data('color');
|
||||
var id = $target.data('id');
|
||||
var tag = this.$("span.badge[data-id='" + id + "']");
|
||||
var currentColor = tag.data('color');
|
||||
var changes = {};
|
||||
|
||||
if ($target.is('.o_hide_in_kanban')) {
|
||||
var $checkbox = $('.o_hide_in_kanban .o_checkbox input');
|
||||
$checkbox.prop('checked', !$checkbox.prop('checked')); // toggle checkbox
|
||||
this.prevColors = this.prevColors ? this.prevColors : {};
|
||||
if ($checkbox.is(':checked')) {
|
||||
this.prevColors[id] = currentColor
|
||||
} else {
|
||||
color = this.prevColors[id] ? this.prevColors[id] : 1;
|
||||
}
|
||||
} else if ($target.is('[class^="o_tag_color"]')) { // $target.is('o_tag_color_')
|
||||
if (color === currentColor) { return; }
|
||||
}
|
||||
|
||||
changes[this.colorField] = color;
|
||||
|
||||
this.trigger_up('field_changed', {
|
||||
dataPointID: _.findWhere(this.value.data, {res_id: id}).id,
|
||||
changes: changes,
|
||||
|
||||
@@ -91,16 +91,6 @@
|
||||
.o-flex-flow(row, wrap);
|
||||
.o-align-items(baseline);
|
||||
|
||||
.o-tag-color(@size: 0) when (@size < @odoo-nb-ui-color) {
|
||||
.o_tag_color_@{size} {
|
||||
&, &::after {
|
||||
background-color: ~"@{odoo-color-@{size}}";
|
||||
}
|
||||
}
|
||||
.o-tag-color(@size + 1);
|
||||
}
|
||||
.o-tag-color();
|
||||
|
||||
> .o_field_widget {
|
||||
.o-flex(1, 0, 100px);
|
||||
position: initial;
|
||||
@@ -119,8 +109,45 @@
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
// o-kanban-colorpicker without customizing
|
||||
// '&:first-child > a::before' (transparent red-crossed colorpick)
|
||||
.o-tag-colorpicker() {
|
||||
@o-tag-colorpicker-padding-right: @odoo-dropdown-hpadding - 2 * @o-kanban-inner-hmargin;
|
||||
|
||||
max-width: 100%;
|
||||
padding: 3px @o-tag-colorpicker-padding-right 3px @odoo-dropdown-hpadding;
|
||||
|
||||
> li {
|
||||
display: inline-block;
|
||||
margin: @o-kanban-inner-hmargin @o-kanban-inner-hmargin 0 0;
|
||||
border: 1px solid white;
|
||||
box-shadow: 0 0 0 1px @gray-lighter-dark;
|
||||
|
||||
> a {
|
||||
display: block;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
box-shadow: 0 0 0 0px white; // remove grey border on hide in kanban
|
||||
color: @odoo-main-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .tagcolor_dropdown_menu {
|
||||
min-width: 150px; // down from 160px of .dropdown-menu
|
||||
margin-right: 0px; // cancel right margin of .dropdown-menu
|
||||
}
|
||||
|
||||
> .o_colorpicker > ul {
|
||||
.o-kanban-colorpicker();
|
||||
.o-tag-colorpicker();
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
@@ -128,6 +155,27 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.o-tag-color(@size: 0) when (@size < @odoo-nb-ui-color) {
|
||||
.o_tag_color_@{size} when (@size = 0) {
|
||||
& {
|
||||
background-color: white;
|
||||
color: ~"@{odoo-color-@{size}}";
|
||||
box-shadow: inset 0 0 0 2px ~"@{odoo-color-@{size}}";
|
||||
}
|
||||
&::after {
|
||||
background-color: ~"@{odoo-color-@{size}}";
|
||||
}
|
||||
}
|
||||
.o_tag_color_@{size} when (@size > 0) {
|
||||
&, &::after {
|
||||
background-color: ~"@{odoo-color-@{size}}";
|
||||
}
|
||||
}
|
||||
.o-tag-color(@size + 1);
|
||||
}
|
||||
.o-tag-color();
|
||||
|
||||
}
|
||||
|
||||
// Stars
|
||||
|
||||
@@ -792,14 +792,23 @@
|
||||
</t>
|
||||
</t>
|
||||
<t t-name="FieldMany2ManyTag.colorpicker">
|
||||
<div class="o_colorpicker dropdown-menu" role="menu">
|
||||
<div class="o_colorpicker dropdown-menu tagcolor_dropdown_menu" role="menu">
|
||||
<ul>
|
||||
<li t-foreach="12" t-as="color">
|
||||
<li t-foreach="11" t-as="color">
|
||||
<a href="#"
|
||||
t-att-data-id="tag_id"
|
||||
t-att-data-color="color"
|
||||
t-attf-class="o_tag_color_#{color}"
|
||||
t-att-title="color === 0 ? 'Not shown in kanban' : ''"/>
|
||||
t-att-data-color="color+1"
|
||||
t-attf-class="o_tag_color_#{color+1}"/>
|
||||
</li>
|
||||
<li> <!-- checkbox for tag color 0 -->
|
||||
<div class="o_hide_in_kanban"
|
||||
t-att-data-id="tag_id"
|
||||
t-att-data-color="0">
|
||||
<div class="o_checkbox">
|
||||
<input type="checkbox"/>
|
||||
<span/>
|
||||
</div> Hide in Kanban
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -8322,7 +8322,7 @@ QUnit.module('relational_fields', {
|
||||
});
|
||||
|
||||
QUnit.test('fieldmany2many tags with color: rendering and edition', function (assert) {
|
||||
assert.expect(20);
|
||||
assert.expect(28);
|
||||
|
||||
this.data.partner.records[0].timmy = [12, 14];
|
||||
this.data.partner_type.records.push({id: 13, display_name: "red", color: 8});
|
||||
@@ -8391,6 +8391,31 @@ QUnit.module('relational_fields', {
|
||||
// save the record (should do the write RPC with the correct commands)
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
|
||||
// checkbox 'Hide in Kanban'
|
||||
$input = form.$('.o_field_many2manytags span[data-id=13]'); // selects 'red' tag
|
||||
$input.click(); // opens the colorpicker dropdown
|
||||
assert.ok(form.$('.o_field_many2manytags span[data-id=13] .o_colorpicker .o_checkbox'), "should have a checkbox in the colorpicker dropdown menu");
|
||||
|
||||
$input.click();
|
||||
var $checkBox = form.$('.o_field_many2manytags span[data-id=13] .o_colorpicker .o_checkbox input');
|
||||
assert.notOk($checkBox.is(':checked'), "should have unticked checkbox in colorpicker dropdown menu");
|
||||
|
||||
$checkBox.mousedown();
|
||||
$input = form.$('.o_field_many2manytags span[data-id=13]'); // refresh
|
||||
assert.equal($input.data('color'), "0", "should become transparent when toggling on checkbox");
|
||||
|
||||
$input.click();
|
||||
$checkBox = form.$('.o_field_many2manytags span[data-id=13] .o_colorpicker .o_checkbox input'); // refresh
|
||||
assert.ok($checkBox.is(':checked'), "should have a ticked checkbox in colorpicker dropdown menu after mousedown");
|
||||
|
||||
$checkBox.mousedown();
|
||||
$input = form.$('.o_field_many2manytags span[data-id=13]'); // refresh
|
||||
assert.equal($input.data('color'), "8", "should revert to old color when toggling off checkbox");
|
||||
|
||||
$input.click();
|
||||
$checkBox = form.$('.o_field_many2manytags span[data-id=13] .o_colorpicker .o_checkbox input'); // refresh
|
||||
assert.notOk($checkBox.is(':checked'), "should have an unticked checkbox in colorpicker dropdown menu after 2nd click");
|
||||
|
||||
// TODO: it would be nice to test the behaviors of the autocomplete dropdown
|
||||
// (like refining the research, creating new tags...), but ui-autocomplete
|
||||
// makes it difficult to test
|
||||
|
||||
@@ -13,7 +13,7 @@ class TrackTag(models.Model):
|
||||
|
||||
name = fields.Char('Tag')
|
||||
track_ids = fields.Many2many('event.track', string='Tracks')
|
||||
color = fields.Integer(string='Color Index', default=10)
|
||||
color = fields.Integer(string='Color Index')
|
||||
|
||||
_sql_constraints = [
|
||||
('name_uniq', 'unique (name)', "Tag name already exists !"),
|
||||
|
||||
Reference in New Issue
Block a user