Badge notes
This commit is contained in:
307
tryton-sao.js
307
tryton-sao.js
@@ -22624,6 +22624,9 @@ function eval_pyson(value){
|
||||
this.status = jQuery('<div/>', {
|
||||
'class': 'ag-grid-tree-status text-muted',
|
||||
}).appendTo(this.toolbar);
|
||||
this.summary_bar = jQuery('<div/>', {
|
||||
'class': 'ag-grid-tree-summary',
|
||||
}).appendTo(this.el);
|
||||
this.grid_host = jQuery('<div/>', {
|
||||
'class': 'ag-grid-theme-alpine ag-grid-tree-host',
|
||||
}).appendTo(this.el);
|
||||
@@ -22946,6 +22949,7 @@ function eval_pyson(value){
|
||||
if (!options.skipLayoutRefresh) {
|
||||
this._schedule_grid_layout_refresh();
|
||||
}
|
||||
this._update_summary_bar();
|
||||
},
|
||||
_on_grid_column_resized: function(params) {
|
||||
this._trace_aggrid_column_resize('event', params);
|
||||
@@ -24629,6 +24633,7 @@ function eval_pyson(value){
|
||||
onFilterChanged: () => {
|
||||
this._schedule_state_save();
|
||||
this._sync_selection_header_checkbox();
|
||||
this._update_summary_bar();
|
||||
},
|
||||
onColumnMoved: this._on_grid_column_layout_changed.bind(this),
|
||||
onColumnPinned: this._on_grid_column_layout_changed.bind(this),
|
||||
@@ -25220,6 +25225,7 @@ function eval_pyson(value){
|
||||
this._log_sao_value_filter_empty_result(this.group.slice());
|
||||
}
|
||||
this._resize_grid_host();
|
||||
this._update_summary_bar();
|
||||
this._schedule_grid_layout_refresh([0, 80]);
|
||||
});
|
||||
},
|
||||
@@ -25258,6 +25264,7 @@ function eval_pyson(value){
|
||||
this._refresh_grid_layout_after_row_data(row_data);
|
||||
this._sync_selection(selected);
|
||||
this._update_copy_state();
|
||||
this._update_summary_bar();
|
||||
},
|
||||
_toggle_sao_value_filter_mode: function() {
|
||||
this._set_sao_value_filter_mode(
|
||||
@@ -26061,6 +26068,17 @@ function eval_pyson(value){
|
||||
});
|
||||
return parsed;
|
||||
},
|
||||
_normalize_badge_text_key: function(text) {
|
||||
text = text === null || text === undefined ? '' : String(text);
|
||||
return text.replace(/^[^A-Za-z0-9]+/, '').trim();
|
||||
},
|
||||
_get_badge_color_order: function(colors) {
|
||||
return (colors || '').split(',').map(item => {
|
||||
var pair = item.split(':');
|
||||
return pair.length < 2 ? '' :
|
||||
this._normalize_badge_text_key(pair.shift());
|
||||
}).filter(Boolean);
|
||||
},
|
||||
_get_record_field_value: function(record, name) {
|
||||
if (!record || !name) {
|
||||
return '';
|
||||
@@ -26084,34 +26102,73 @@ function eval_pyson(value){
|
||||
color = color === null || color === undefined ? '' :
|
||||
String(color).trim();
|
||||
var palette = {
|
||||
red: '#e06a6a',
|
||||
danger: '#e06a6a',
|
||||
coral: '#e06a6a',
|
||||
orange: '#d99a2b',
|
||||
warning: '#d99a2b',
|
||||
amber: '#d99a2b',
|
||||
yellow: '#f1c40f',
|
||||
green: '#2b8c87',
|
||||
success: '#2b8c87',
|
||||
teal: '#2b8c87',
|
||||
blue: '#57c1b9',
|
||||
info: '#57c1b9',
|
||||
red: '#ef4444',
|
||||
danger: '#ef4444',
|
||||
coral: '#ef4444',
|
||||
orange: '#f59e0b',
|
||||
warning: '#f59e0b',
|
||||
amber: '#f59e0b',
|
||||
yellow: '#eab308',
|
||||
green: '#16a34a',
|
||||
success: '#16a34a',
|
||||
teal: '#0f766e',
|
||||
blue: '#2563eb',
|
||||
info: '#2563eb',
|
||||
purple: '#8b5cf6',
|
||||
violet: '#8b5cf6',
|
||||
gray: '#6c757d',
|
||||
grey: '#6c757d',
|
||||
muted: '#6c757d',
|
||||
};
|
||||
return palette[color.toLowerCase()] || color;
|
||||
},
|
||||
_hex_to_rgb_badge_color: function(color) {
|
||||
color = this._normalize_badge_color(color);
|
||||
var match = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color || '');
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
var hex = match[1];
|
||||
if (hex.length == 3) {
|
||||
hex = hex.split('').map(part => part + part).join('');
|
||||
}
|
||||
return {
|
||||
r: parseInt(hex.slice(0, 2), 16),
|
||||
g: parseInt(hex.slice(2, 4), 16),
|
||||
b: parseInt(hex.slice(4, 6), 16),
|
||||
};
|
||||
},
|
||||
_rgb_to_badge_color: function(rgb) {
|
||||
var part = value => Math.max(0, Math.min(255, Math.round(value)))
|
||||
.toString(16).padStart(2, '0');
|
||||
return '#' + part(rgb.r) + part(rgb.g) + part(rgb.b);
|
||||
},
|
||||
_mix_badge_color: function(color, mix_with, weight) {
|
||||
var source = this._hex_to_rgb_badge_color(color);
|
||||
var target = this._hex_to_rgb_badge_color(mix_with);
|
||||
if (!source || !target) {
|
||||
return '';
|
||||
}
|
||||
return this._rgb_to_badge_color({
|
||||
r: source.r * (1 - weight) + target.r * weight,
|
||||
g: source.g * (1 - weight) + target.g * weight,
|
||||
b: source.b * (1 - weight) + target.b * weight,
|
||||
});
|
||||
},
|
||||
_get_badge_colors: function(column, record, text) {
|
||||
var attributes = column.attributes || {};
|
||||
var color = '';
|
||||
var text_color = '';
|
||||
var mapped = this._parse_badge_colors(attributes.badge_colors);
|
||||
var normalized_text = this._normalize_badge_text_key(text);
|
||||
if (Object.prototype.hasOwnProperty.call(mapped, text)) {
|
||||
color = mapped[text];
|
||||
} else if (Object.prototype.hasOwnProperty.call(
|
||||
mapped, String(text).toLowerCase())) {
|
||||
color = mapped[String(text).toLowerCase()];
|
||||
mapped, normalized_text)) {
|
||||
color = mapped[normalized_text];
|
||||
} else if (Object.prototype.hasOwnProperty.call(
|
||||
mapped, String(normalized_text).toLowerCase())) {
|
||||
color = mapped[String(normalized_text).toLowerCase()];
|
||||
}
|
||||
if (!color && attributes.badge_color_field) {
|
||||
color = this._get_record_field_value(
|
||||
@@ -26138,6 +26195,19 @@ function eval_pyson(value){
|
||||
color: this._normalize_badge_color(text_color),
|
||||
};
|
||||
},
|
||||
_get_badge_display_colors: function(column, record, text) {
|
||||
var colors = this._get_badge_colors(column, record, text);
|
||||
var accent = colors.color || colors.background;
|
||||
if (!accent) {
|
||||
return colors;
|
||||
}
|
||||
return {
|
||||
background: this._mix_badge_color(accent, '#ffffff', 0.86) ||
|
||||
colors.background,
|
||||
color: colors.color || accent,
|
||||
accent: accent,
|
||||
};
|
||||
},
|
||||
_render_badge_cell: function(column, record) {
|
||||
var text = this._get_column_text_value(column, record);
|
||||
var cell = jQuery('<div/>', {
|
||||
@@ -26153,7 +26223,7 @@ function eval_pyson(value){
|
||||
if (parseInt(column.attributes.badge_bold || '0', 10)) {
|
||||
badge.addClass('ag-grid-badge-bold');
|
||||
}
|
||||
var colors = this._get_badge_colors(column, record, text);
|
||||
var colors = this._get_badge_display_colors(column, record, text);
|
||||
if (colors.background) {
|
||||
badge.css('background-color', colors.background);
|
||||
}
|
||||
@@ -26621,6 +26691,205 @@ function eval_pyson(value){
|
||||
this.copy_button.prop('disabled', !this.selected_records.length);
|
||||
this.status.text(String(this.group.length) + ' records');
|
||||
},
|
||||
_get_visible_record_rows: function() {
|
||||
var rows = [];
|
||||
if (!this.gridApi) {
|
||||
return rows;
|
||||
}
|
||||
var collect = node => {
|
||||
if (node && node.data && node.data.__kind == 'record') {
|
||||
rows.push(node.data);
|
||||
}
|
||||
};
|
||||
if (this.gridApi.forEachNodeAfterFilterAndSort) {
|
||||
this.gridApi.forEachNodeAfterFilterAndSort(collect);
|
||||
} else if (this.gridApi.forEachNodeAfterFilter) {
|
||||
this.gridApi.forEachNodeAfterFilter(collect);
|
||||
} else {
|
||||
(this._last_row_data || []).forEach(row => {
|
||||
if (row && row.__kind == 'record') {
|
||||
rows.push(row);
|
||||
}
|
||||
});
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
_get_summary_badge_columns: function() {
|
||||
var visible_columns = {};
|
||||
var column_api = this.gridColumnApi || this.gridApi;
|
||||
if (column_api && column_api.getAllDisplayedColumns) {
|
||||
column_api.getAllDisplayedColumns().forEach(column => {
|
||||
if (column && column.getColId) {
|
||||
visible_columns[column.getColId()] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
return this.columns.filter(column => {
|
||||
var name = column.attributes && column.attributes.name;
|
||||
var label = column.attributes &&
|
||||
(column.attributes.string || column.attributes.name) || '';
|
||||
var is_status_column = /(^|[_\s-])(status|state|type)([_\s-]|$)/i
|
||||
.test(String(name || '') + ' ' + String(label || ''));
|
||||
if (!name || (!this._is_badge_column(column) &&
|
||||
!is_status_column)) {
|
||||
return false;
|
||||
}
|
||||
return !Object.keys(visible_columns).length ||
|
||||
visible_columns[name];
|
||||
});
|
||||
},
|
||||
_render_summary_item: function(label, value, color) {
|
||||
var item = jQuery('<div/>', {
|
||||
'class': 'ag-grid-summary-item',
|
||||
});
|
||||
jQuery('<span/>', {
|
||||
'class': 'ag-grid-summary-label',
|
||||
'text': label,
|
||||
}).appendTo(item);
|
||||
var value_el = jQuery('<span/>', {
|
||||
'class': 'ag-grid-summary-value',
|
||||
'text': value,
|
||||
}).appendTo(item);
|
||||
if (color) {
|
||||
value_el.css('color', color);
|
||||
}
|
||||
return item;
|
||||
},
|
||||
_get_default_badge_summary_color: function(value) {
|
||||
var key = String(value || '').toLowerCase();
|
||||
var palette = {
|
||||
open: '#2563eb',
|
||||
physic: '#8b5cf6',
|
||||
physical: '#8b5cf6',
|
||||
scheduled: '#f59e0b',
|
||||
shipped: '#16a34a',
|
||||
unshipped: '#ef4444',
|
||||
done: '#16a34a',
|
||||
cancelled: '#ef4444',
|
||||
canceled: '#ef4444',
|
||||
draft: '#64748b',
|
||||
quote: '#2563eb',
|
||||
confirmed: '#16a34a',
|
||||
processing: '#f59e0b',
|
||||
};
|
||||
return palette[key] || '#0f766e';
|
||||
},
|
||||
_append_badge_summary_items: function(summary_items, rows, column, source) {
|
||||
var name = source && source.name ||
|
||||
column && column.attributes && column.attributes.name;
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
var counts = {};
|
||||
var samples = {};
|
||||
var order = [];
|
||||
var empty = Sao.i18n.gettext('(Empty)');
|
||||
rows.forEach(row => {
|
||||
var value = row[name] ?
|
||||
this._normalize_badge_text_key(row[name]) : empty;
|
||||
if (value == empty) {
|
||||
return;
|
||||
}
|
||||
if (!Object.prototype.hasOwnProperty.call(counts, value)) {
|
||||
counts[value] = 0;
|
||||
samples[value] = row;
|
||||
order.push(value);
|
||||
}
|
||||
counts[value] += 1;
|
||||
});
|
||||
var color_order = this._get_badge_color_order(
|
||||
column && column.attributes && column.attributes.badge_colors);
|
||||
var color_order_lower = color_order.map(value =>
|
||||
String(value).toLowerCase());
|
||||
order.sort((a, b) => {
|
||||
var a_index = color_order.indexOf(a);
|
||||
var b_index = color_order.indexOf(b);
|
||||
if (a_index < 0) {
|
||||
a_index = color_order_lower.indexOf(
|
||||
String(a).toLowerCase());
|
||||
}
|
||||
if (b_index < 0) {
|
||||
b_index = color_order_lower.indexOf(
|
||||
String(b).toLowerCase());
|
||||
}
|
||||
if (a_index >= 0 || b_index >= 0) {
|
||||
return (a_index < 0 ? 999 : a_index) -
|
||||
(b_index < 0 ? 999 : b_index);
|
||||
}
|
||||
return counts[b] - counts[a] ||
|
||||
String(a).localeCompare(String(b), undefined, {
|
||||
numeric: true,
|
||||
sensitivity: 'base',
|
||||
});
|
||||
});
|
||||
order.forEach(value => {
|
||||
var colors = column ? this._get_badge_display_colors(
|
||||
column,
|
||||
samples[value] && samples[value].__record,
|
||||
value) : {};
|
||||
summary_items.push({
|
||||
label: value,
|
||||
count: counts[value],
|
||||
color: colors.color || colors.accent ||
|
||||
this._get_default_badge_summary_color(value),
|
||||
});
|
||||
});
|
||||
return Boolean(order.length);
|
||||
},
|
||||
_get_summary_status_sources_from_grid: function() {
|
||||
var sources = [];
|
||||
var seen = {};
|
||||
(this._grid_columns || []).forEach(col_def => {
|
||||
var name = col_def && col_def.field || col_def && col_def.colId;
|
||||
if (!name || name == '__selection__' || seen[name]) {
|
||||
return;
|
||||
}
|
||||
var label = col_def.headerName || name;
|
||||
if (!/(status|state|type|shipping|shipment|open\/physic)/i
|
||||
.test(String(name) + ' ' + String(label))) {
|
||||
return;
|
||||
}
|
||||
seen[name] = true;
|
||||
sources.push({
|
||||
name: name,
|
||||
label: label,
|
||||
});
|
||||
});
|
||||
return sources;
|
||||
},
|
||||
_update_summary_bar: function() {
|
||||
if (!this.summary_bar || !this.summary_bar.length) {
|
||||
return;
|
||||
}
|
||||
var rows = this._get_visible_record_rows();
|
||||
var locale = Sao.i18n.BC47(Sao.i18n.getlang());
|
||||
this.summary_bar.empty();
|
||||
this.summary_bar.append(this._render_summary_item(
|
||||
Sao.i18n.gettext('Rows'),
|
||||
rows.length.toLocaleString(locale),
|
||||
'#145369'));
|
||||
var summary_items = [];
|
||||
var summarized_names = {};
|
||||
this._get_summary_badge_columns().forEach(column => {
|
||||
if (this._append_badge_summary_items(
|
||||
summary_items, rows, column)) {
|
||||
summarized_names[column.attributes.name] = true;
|
||||
}
|
||||
});
|
||||
this._get_summary_status_sources_from_grid().forEach(source => {
|
||||
if (summarized_names[source.name]) {
|
||||
return;
|
||||
}
|
||||
this._append_badge_summary_items(
|
||||
summary_items, rows, null, source);
|
||||
});
|
||||
summary_items.forEach(item => {
|
||||
this.summary_bar.append(this._render_summary_item(
|
||||
item.label,
|
||||
item.count.toLocaleString(locale),
|
||||
item.color));
|
||||
});
|
||||
},
|
||||
on_copy: function() {
|
||||
var data = [];
|
||||
this.selected_records.forEach(record => {
|
||||
@@ -26739,6 +27008,7 @@ function eval_pyson(value){
|
||||
this._update_layout_button();
|
||||
this._render_filter_logic_panel();
|
||||
this._update_copy_state();
|
||||
this._update_summary_bar();
|
||||
if (this._has_active_sao_value_filters()) {
|
||||
this._apply_sao_value_filters({refreshRowData: false});
|
||||
}
|
||||
@@ -26765,6 +27035,8 @@ function eval_pyson(value){
|
||||
var screen_container = this.grid_host.closest('.screen-container');
|
||||
var toolbar_height = this.toolbar && this.toolbar.length ?
|
||||
Math.ceil(this.toolbar.outerHeight(true)) : 0;
|
||||
var summary_height = this.summary_bar && this.summary_bar.length ?
|
||||
Math.ceil(this.summary_bar.outerHeight(true)) : 0;
|
||||
var external_scroll_height = 20;
|
||||
var bottom_margin = 96;
|
||||
var available = window.innerHeight - rect.top -
|
||||
@@ -26774,7 +27046,7 @@ function eval_pyson(value){
|
||||
available = Math.min(
|
||||
available,
|
||||
window.innerHeight - content_rect.top - toolbar_height -
|
||||
external_scroll_height - bottom_margin);
|
||||
summary_height - external_scroll_height - bottom_margin);
|
||||
}
|
||||
var compact_min_height = 260;
|
||||
var readable_min_height = 420;
|
||||
@@ -26805,7 +27077,8 @@ function eval_pyson(value){
|
||||
width: available_width + 'px',
|
||||
maxWidth: available_width + 'px',
|
||||
});
|
||||
var container_height = height + toolbar_height + external_scroll_height;
|
||||
var container_height = height + toolbar_height + summary_height +
|
||||
external_scroll_height;
|
||||
this.el.css({
|
||||
height: container_height + 'px',
|
||||
minHeight: container_height + 'px',
|
||||
|
||||
Reference in New Issue
Block a user