GRID
This commit is contained in:
209
dist/tryton-sao.css
vendored
209
dist/tryton-sao.css
vendored
@@ -11167,6 +11167,78 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
|
||||
box-shadow: 0 2px 8px rgba(53, 81, 84, 0.12);
|
||||
}
|
||||
|
||||
.ag-filter-apply-panel {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 5px;
|
||||
padding: 6px 8px 8px;
|
||||
}
|
||||
|
||||
.ag-filter-apply-panel button,
|
||||
.ag-filter-apply-panel .ag-button,
|
||||
.ag-filter-apply-panel .ag-standard-button,
|
||||
.ag-popup .ag-filter-apply-panel button,
|
||||
.ag-popup .ag-filter-apply-panel .ag-button,
|
||||
.ag-popup .ag-filter-apply-panel .ag-standard-button,
|
||||
.ag-theme-alpine .ag-filter-apply-panel button,
|
||||
.ag-theme-alpine .ag-filter-apply-panel .ag-button,
|
||||
.ag-theme-alpine .ag-filter-apply-panel .ag-standard-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 27px;
|
||||
padding: 3px 8px;
|
||||
border: 1px solid #d8e2df !important;
|
||||
border-radius: 6px !important;
|
||||
background: #ffffff !important;
|
||||
color: #355154 !important;
|
||||
font-size: 11.5px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
line-height: 1.2;
|
||||
text-transform: none !important;
|
||||
box-shadow: none !important;
|
||||
transition: background-color 0.18s ease, border-color 0.18s ease,
|
||||
box-shadow 0.18s ease, transform 0.18s ease;
|
||||
}
|
||||
|
||||
.ag-filter-apply-panel button:hover,
|
||||
.ag-filter-apply-panel .ag-button:hover,
|
||||
.ag-filter-apply-panel .ag-standard-button:hover,
|
||||
.ag-filter-apply-panel button:focus,
|
||||
.ag-filter-apply-panel .ag-button:focus,
|
||||
.ag-filter-apply-panel .ag-standard-button:focus,
|
||||
.ag-popup .ag-filter-apply-panel button:hover,
|
||||
.ag-popup .ag-filter-apply-panel .ag-button:hover,
|
||||
.ag-popup .ag-filter-apply-panel .ag-standard-button:hover,
|
||||
.ag-popup .ag-filter-apply-panel button:focus,
|
||||
.ag-popup .ag-filter-apply-panel .ag-button:focus,
|
||||
.ag-popup .ag-filter-apply-panel .ag-standard-button:focus,
|
||||
.ag-theme-alpine .ag-filter-apply-panel button:hover,
|
||||
.ag-theme-alpine .ag-filter-apply-panel .ag-button:hover,
|
||||
.ag-theme-alpine .ag-filter-apply-panel .ag-standard-button:hover,
|
||||
.ag-theme-alpine .ag-filter-apply-panel button:focus,
|
||||
.ag-theme-alpine .ag-filter-apply-panel .ag-button:focus,
|
||||
.ag-theme-alpine .ag-filter-apply-panel .ag-standard-button:focus {
|
||||
background: linear-gradient(180deg, #f2faf7 0%, #e7f2ed 100%) !important;
|
||||
border-color: #bfd5cd !important;
|
||||
color: #28484b !important;
|
||||
box-shadow: 0 1px 1px rgba(53, 81, 84, 0.05) !important;
|
||||
}
|
||||
|
||||
.ag-filter-apply-panel button:active,
|
||||
.ag-filter-apply-panel .ag-button:active,
|
||||
.ag-filter-apply-panel .ag-standard-button:active,
|
||||
.ag-popup .ag-filter-apply-panel button:active,
|
||||
.ag-popup .ag-filter-apply-panel .ag-button:active,
|
||||
.ag-popup .ag-filter-apply-panel .ag-standard-button:active,
|
||||
.ag-theme-alpine .ag-filter-apply-panel button:active,
|
||||
.ag-theme-alpine .ag-filter-apply-panel .ag-button:active,
|
||||
.ag-theme-alpine .ag-filter-apply-panel .ag-standard-button:active {
|
||||
transform: translateY(1px);
|
||||
box-shadow: 0 2px 8px rgba(53, 81, 84, 0.12) !important;
|
||||
}
|
||||
|
||||
.ag-grid-tree-columns-label,
|
||||
.ag-grid-tree-grouping-label,
|
||||
.ag-grid-tree-layouts-label,
|
||||
@@ -11183,6 +11255,133 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
|
||||
color: #0f6f6d;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chips {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
min-width: 0;
|
||||
max-width: min(520px, 38vw);
|
||||
min-height: 32px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chips.drag-active {
|
||||
min-width: 180px;
|
||||
padding: 2px 6px;
|
||||
border: 1px dashed #8fc3bd;
|
||||
border-radius: 8px;
|
||||
background: #f6fbf9;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chips.drag-over {
|
||||
border-color: #0f817d;
|
||||
background: #eef8f6;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-drop-hint {
|
||||
color: #0f6f6d;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ag-grid-filter-draggable-cell {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.ag-grid-filter-draggable-cell:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 14px;
|
||||
grid-template-rows: auto auto;
|
||||
column-gap: 6px;
|
||||
row-gap: 1px;
|
||||
align-items: center;
|
||||
max-width: 190px;
|
||||
min-height: 32px;
|
||||
padding: 3px 5px 3px 8px;
|
||||
border: 1px solid #c9ded8;
|
||||
border-radius: 7px;
|
||||
background: #f8fbfa;
|
||||
color: #285256;
|
||||
font-size: 10.5px;
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip:hover,
|
||||
.ag-grid-active-filter-chip:focus {
|
||||
border-color: #92bfb8;
|
||||
background: #eff8f5;
|
||||
color: #0f6f6d;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip-name,
|
||||
.ag-grid-active-filter-chip-detail {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip-name {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
color: #637b87;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip-value {
|
||||
display: inline-flex;
|
||||
grid-column: 1;
|
||||
grid-row: 2;
|
||||
min-width: 0;
|
||||
gap: 4px;
|
||||
color: #0f4f60;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip-operator {
|
||||
flex: 0 0 auto;
|
||||
color: #0f817d;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip-detail {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip-remove {
|
||||
display: inline-flex;
|
||||
grid-column: 2;
|
||||
grid-row: 1 / span 2;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
color: #6e8588;
|
||||
font-size: 11px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip-remove:hover {
|
||||
background: #dcebe7;
|
||||
color: #0f6f6d;
|
||||
}
|
||||
|
||||
.ag-grid-active-filter-chip-more {
|
||||
display: inline-flex;
|
||||
max-width: none;
|
||||
min-height: 27px;
|
||||
padding: 2px 7px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.ag-grid-tree-grouping-panel .btn,
|
||||
.ag-grid-tree-layouts-panel .btn,
|
||||
.ag-grid-filter-logic-panel .btn {
|
||||
@@ -12774,7 +12973,10 @@ html[data-theme-mode="dark"] .ag-grid-tree-grouping > .btn,
|
||||
html[data-theme-mode="dark"] .ag-grid-tree-layouts > .btn,
|
||||
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn,
|
||||
html[data-theme-mode="dark"] .ag-grid-tree-layouts-panel .btn,
|
||||
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel .btn {
|
||||
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel .btn,
|
||||
html[data-theme-mode="dark"] .ag-theme-alpine .ag-filter-apply-panel button,
|
||||
html[data-theme-mode="dark"] .ag-theme-alpine .ag-filter-apply-panel .ag-button,
|
||||
html[data-theme-mode="dark"] .ag-theme-alpine .ag-filter-apply-panel .ag-standard-button {
|
||||
background: linear-gradient(180deg, #213130 0%, #1a2726 100%);
|
||||
border-color: #35504d;
|
||||
color: #dce7e2;
|
||||
@@ -12789,7 +12991,10 @@ html[data-theme-mode="dark"] .ag-grid-tree-grouping > .btn:hover,
|
||||
html[data-theme-mode="dark"] .ag-grid-tree-layouts > .btn:hover,
|
||||
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn:hover,
|
||||
html[data-theme-mode="dark"] .ag-grid-tree-layouts-panel .btn:hover,
|
||||
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel .btn:hover {
|
||||
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel .btn:hover,
|
||||
html[data-theme-mode="dark"] .ag-theme-alpine .ag-filter-apply-panel button:hover,
|
||||
html[data-theme-mode="dark"] .ag-theme-alpine .ag-filter-apply-panel .ag-button:hover,
|
||||
html[data-theme-mode="dark"] .ag-theme-alpine .ag-filter-apply-panel .ag-standard-button:hover {
|
||||
background: linear-gradient(180deg, #27403d 0%, #203230 100%);
|
||||
border-color: #4f716c;
|
||||
color: #f0faf6;
|
||||
|
||||
618
dist/tryton-sao.js
vendored
618
dist/tryton-sao.js
vendored
@@ -15008,7 +15008,8 @@ function eval_pyson(value){
|
||||
},
|
||||
_parse_form: function(node, attributes) {
|
||||
var container = new Sao.View.Form.Container(
|
||||
Number(node.getAttribute('col') || 4));
|
||||
Number(node.getAttribute('col') || 4),
|
||||
attributes.col_widths);
|
||||
this.view.containers.push(container);
|
||||
this.parse_child(node, container);
|
||||
if (this._containers.length > 0) {
|
||||
@@ -15205,7 +15206,8 @@ function eval_pyson(value){
|
||||
return;
|
||||
}
|
||||
var container = new Sao.View.Form.Container(
|
||||
Number(node.getAttribute('col') || 4));
|
||||
Number(node.getAttribute('col') || 4),
|
||||
attributes.col_widths);
|
||||
this.view.containers.push(container);
|
||||
this.parse_child(node, container);
|
||||
var page = new Sao.View.Form.Page(
|
||||
@@ -15216,7 +15218,8 @@ function eval_pyson(value){
|
||||
},
|
||||
_parse_group: function(node, attributes) {
|
||||
var group = new Sao.View.Form.Container(
|
||||
Number(node.getAttribute('col') || 4));
|
||||
Number(node.getAttribute('col') || 4),
|
||||
attributes.col_widths);
|
||||
this.view.containers.push(group);
|
||||
this.parse_child(node, group);
|
||||
|
||||
@@ -15259,7 +15262,8 @@ function eval_pyson(value){
|
||||
_parse_child: function(node, attributes) {
|
||||
var paned = this.container;
|
||||
var container = new Sao.View.Form.Container(
|
||||
Number(node.getAttribute('col') || 4));
|
||||
Number(node.getAttribute('col') || 4),
|
||||
attributes.col_widths);
|
||||
this.view.containers.push(container);
|
||||
this.parse_child(node, container);
|
||||
|
||||
@@ -15528,9 +15532,10 @@ function eval_pyson(value){
|
||||
});
|
||||
|
||||
Sao.View.Form.Container = Sao.class_(Object, {
|
||||
init: function(col=4) {
|
||||
init: function(col=4, col_widths=null) {
|
||||
if (col < 0) col = 0;
|
||||
this.col = col;
|
||||
this.col_widths = this._parse_col_widths(col_widths);
|
||||
this.el = jQuery('<div/>', {
|
||||
'class': 'form-container'
|
||||
});
|
||||
@@ -15547,6 +15552,21 @@ function eval_pyson(value){
|
||||
this._grid_cols = [];
|
||||
this._grid_rows = [];
|
||||
},
|
||||
_parse_col_widths: function(col_widths) {
|
||||
if (!col_widths) {
|
||||
return [];
|
||||
}
|
||||
return String(col_widths).split(',').map(width => {
|
||||
width = String(width || '').trim();
|
||||
if (!width) {
|
||||
return null;
|
||||
}
|
||||
if (/^\d+(\.\d+)?$/.test(width)) {
|
||||
return width + 'px';
|
||||
}
|
||||
return width;
|
||||
});
|
||||
},
|
||||
add_row: function() {
|
||||
this._col = 1;
|
||||
this._row += 1;
|
||||
@@ -15659,7 +15679,15 @@ function eval_pyson(value){
|
||||
|
||||
var i;
|
||||
var col = this.col <= 0 ? this._col : this.col;
|
||||
if (this._xexpand.size) {
|
||||
if (this.col_widths.length) {
|
||||
for (i = 1; i <= col; i++) {
|
||||
this._grid_cols.push(
|
||||
this.col_widths[i - 1] ||
|
||||
(this._xexpand.has(i) ?
|
||||
`minmax(min-content, ${col}fr)` :
|
||||
'min-content'));
|
||||
}
|
||||
} else if (this._xexpand.size) {
|
||||
for (i = 1; i <= col; i++) {
|
||||
if (this._xexpand.has(i)) {
|
||||
this._grid_cols.push(`minmax(min-content, ${col}fr)`);
|
||||
@@ -22691,6 +22719,29 @@ function eval_pyson(value){
|
||||
this._toggle_filter_logic_menu();
|
||||
})
|
||||
.appendTo(this.toolbar);
|
||||
this.active_filter_chips = jQuery('<div/>', {
|
||||
'class': 'ag-grid-active-filter-chips',
|
||||
'aria-live': 'polite',
|
||||
}).hide().appendTo(this.toolbar);
|
||||
this.active_filter_chips.on('dragover', evt => {
|
||||
if (!this._filter_drag_payload) {
|
||||
return;
|
||||
}
|
||||
evt.preventDefault();
|
||||
evt.originalEvent.dataTransfer.dropEffect = 'copy';
|
||||
this.active_filter_chips.addClass('drag-over');
|
||||
});
|
||||
this.active_filter_chips.on('dragleave', evt => {
|
||||
if (evt.currentTarget.contains(evt.relatedTarget)) {
|
||||
return;
|
||||
}
|
||||
this.active_filter_chips.removeClass('drag-over');
|
||||
});
|
||||
this.active_filter_chips.on('drop', evt => {
|
||||
evt.preventDefault();
|
||||
this.active_filter_chips.removeClass('drag-over');
|
||||
this._apply_filter_drop(evt.originalEvent);
|
||||
});
|
||||
this.import_layout_input = jQuery('<input/>', {
|
||||
'type': 'file',
|
||||
'accept': 'application/json,.json',
|
||||
@@ -22774,17 +22825,8 @@ function eval_pyson(value){
|
||||
});
|
||||
|
||||
Sao.View.AGGridTree._super.init.call(this, view_id, screen, xml);
|
||||
if (this.is_embedded_one2many) {
|
||||
this._layout_store = this._normalize_layout_store(null);
|
||||
this._persisted_state = null;
|
||||
this._sao_value_filters = {};
|
||||
this._restored_value_filter_state = null;
|
||||
this._sao_value_filter_restore_guard = false;
|
||||
} else {
|
||||
this._persisted_state = this._load_persisted_state();
|
||||
}
|
||||
if (!this.is_embedded_one2many &&
|
||||
this._persisted_state &&
|
||||
this._persisted_state = this._load_persisted_state();
|
||||
if (this._persisted_state &&
|
||||
this._persisted_state.valueFilters) {
|
||||
this._apply_sao_value_filter_state(
|
||||
this._persisted_state.valueFilters);
|
||||
@@ -22792,6 +22834,7 @@ function eval_pyson(value){
|
||||
this._apply_saved_sort_to_screen_order();
|
||||
this._update_layout_button();
|
||||
this._update_sao_value_filter_mode_button();
|
||||
this._render_active_filter_chips();
|
||||
this._update_copy_state();
|
||||
this._init_grid();
|
||||
this._install_resize_observer();
|
||||
@@ -22921,7 +22964,33 @@ function eval_pyson(value){
|
||||
});
|
||||
},
|
||||
_get_layout_store_cache_key: function() {
|
||||
return this._get_storage_key();
|
||||
return this._get_layout_storage_key();
|
||||
},
|
||||
_get_layout_storage_key: function() {
|
||||
var key = this._get_storage_key();
|
||||
if (!this.is_embedded_one2many) {
|
||||
return key;
|
||||
}
|
||||
var attributes = this.screen && this.screen.attributes || {};
|
||||
var context_parts = [
|
||||
'embedded_one2many',
|
||||
attributes.name,
|
||||
attributes.field,
|
||||
attributes.relation_field,
|
||||
attributes.one2many,
|
||||
attributes.parent_name,
|
||||
attributes.child_name,
|
||||
this.screen && this.screen.exclude_field,
|
||||
this.screen && this.screen.group &&
|
||||
this.screen.group.parent_name,
|
||||
this.screen && this.screen.group &&
|
||||
this.screen.group.child_name,
|
||||
].map(function(value) {
|
||||
return String(value || '').replace(/[:\s]+/g, '_');
|
||||
}).filter(function(value) {
|
||||
return Boolean(value);
|
||||
});
|
||||
return [key].concat(context_parts).join(':');
|
||||
},
|
||||
_new_layout_id: function() {
|
||||
return 'layout_' + String(Date.now()) + '_' +
|
||||
@@ -22973,7 +23042,8 @@ function eval_pyson(value){
|
||||
return this._normalize_layout_store(null);
|
||||
}
|
||||
try {
|
||||
var raw_state = localStorage.getItem(this._get_storage_key());
|
||||
var raw_state = localStorage.getItem(
|
||||
this._get_layout_storage_key());
|
||||
if (!raw_state) {
|
||||
return this._normalize_layout_store(null);
|
||||
}
|
||||
@@ -23018,7 +23088,7 @@ function eval_pyson(value){
|
||||
}
|
||||
try {
|
||||
localStorage.setItem(
|
||||
this._get_storage_key(),
|
||||
this._get_layout_storage_key(),
|
||||
JSON.stringify(store));
|
||||
} catch (error) {
|
||||
Sao.Logger.warn(
|
||||
@@ -23142,9 +23212,6 @@ function eval_pyson(value){
|
||||
window.addEventListener('resize', this._window_resize_handler);
|
||||
},
|
||||
_persist_grid_state: function(options) {
|
||||
if (this.is_embedded_one2many) {
|
||||
return;
|
||||
}
|
||||
options = options || {};
|
||||
var state = this._capture_grid_state();
|
||||
state.valueFilters = this._merge_restored_value_filter_state(
|
||||
@@ -23344,6 +23411,7 @@ function eval_pyson(value){
|
||||
this._sao_value_filter_groups = state.groups ?
|
||||
jQuery.extend(true, {}, state.groups) : null;
|
||||
this._update_sao_value_filter_mode_button();
|
||||
this._render_active_filter_chips();
|
||||
},
|
||||
_apply_saved_sort_to_screen_order: function() {
|
||||
if (!this._persisted_state || !this._persisted_state.columns) {
|
||||
@@ -24827,6 +24895,7 @@ function eval_pyson(value){
|
||||
this._schedule_state_save();
|
||||
this._sync_selection_header_checkbox();
|
||||
this._update_summary_bar();
|
||||
this._render_active_filter_chips();
|
||||
},
|
||||
onFirstDataRendered: () => {
|
||||
window.requestAnimationFrame(() => this._update_summary_bar());
|
||||
@@ -25003,6 +25072,10 @@ function eval_pyson(value){
|
||||
}
|
||||
return '';
|
||||
}
|
||||
if (this._is_date_filter_column(column)) {
|
||||
return this._get_column_date_filter_value(
|
||||
column, params.data.__record);
|
||||
}
|
||||
return this._get_column_text_value(
|
||||
column, params.data.__record);
|
||||
},
|
||||
@@ -25023,11 +25096,16 @@ function eval_pyson(value){
|
||||
if (!params.data.__record) {
|
||||
return '';
|
||||
}
|
||||
var rendered;
|
||||
if (badge_column) {
|
||||
return this._render_badge_cell(
|
||||
rendered = this._render_badge_cell(
|
||||
column, params.data.__record);
|
||||
} else {
|
||||
rendered = this._render_cell(
|
||||
column, params.data.__record);
|
||||
}
|
||||
return this._render_cell(column, params.data.__record);
|
||||
return this._make_filter_draggable_cell(
|
||||
rendered, column, params.data.__record);
|
||||
},
|
||||
tooltipValueGetter: params => {
|
||||
if (!params.data || !params.data.__record ||
|
||||
@@ -25230,9 +25308,6 @@ function eval_pyson(value){
|
||||
case 'numeric':
|
||||
return 'agNumberColumnFilter';
|
||||
case 'date':
|
||||
if (this._get_distinct_filter_values(column)) {
|
||||
return Sao.View.AGGridValueSetFilter;
|
||||
}
|
||||
return 'agDateColumnFilter';
|
||||
default:
|
||||
if (this._get_distinct_filter_values(column)) {
|
||||
@@ -25242,6 +25317,9 @@ function eval_pyson(value){
|
||||
}
|
||||
},
|
||||
_get_column_filter_params: function(column) {
|
||||
if (this._is_date_filter_column(column)) {
|
||||
return this._get_date_column_filter_params(column);
|
||||
}
|
||||
var values = this._get_distinct_filter_values(column);
|
||||
if (!values) {
|
||||
return null;
|
||||
@@ -25260,6 +25338,135 @@ function eval_pyson(value){
|
||||
searchPlaceholder: Sao.i18n.gettext('Search'),
|
||||
};
|
||||
},
|
||||
_is_date_filter_column: function(column) {
|
||||
return Boolean(column && column.attributes &&
|
||||
column.attributes.widget == 'date');
|
||||
},
|
||||
_get_date_column_filter_params: function(column) {
|
||||
var relative_options = this._get_relative_date_filter_options();
|
||||
return {
|
||||
browserDatePicker: true,
|
||||
buttons: ['reset', 'apply'],
|
||||
closeOnApply: true,
|
||||
maxNumConditions: 1,
|
||||
defaultOption: 'empty',
|
||||
filterOptions: ['empty'].concat(relative_options).concat([
|
||||
'inRange',
|
||||
'equals',
|
||||
'lessThan',
|
||||
'greaterThan',
|
||||
'blank',
|
||||
'notBlank',
|
||||
]),
|
||||
inRangeInclusive: true,
|
||||
comparator: function(filter_date, cell_value) {
|
||||
if (!cell_value) {
|
||||
return 0;
|
||||
}
|
||||
var cell_date = cell_value instanceof Date ? cell_value :
|
||||
new Date(cell_value);
|
||||
if (isNaN(cell_date.getTime())) {
|
||||
return 0;
|
||||
}
|
||||
var cell_midnight = new Date(
|
||||
cell_date.getFullYear(),
|
||||
cell_date.getMonth(),
|
||||
cell_date.getDate());
|
||||
if (cell_midnight < filter_date) {
|
||||
return -1;
|
||||
}
|
||||
if (cell_midnight > filter_date) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
};
|
||||
},
|
||||
_get_relative_date_filter_options: function() {
|
||||
var make_option = (key, label, range_getter) => {
|
||||
return {
|
||||
displayKey: 'sao' + key,
|
||||
displayName: Sao.i18n.gettext(label),
|
||||
numberOfInputs: 0,
|
||||
predicate: (filter_values, cell_value) => {
|
||||
var cell_date = this._normalize_date_filter_value(cell_value);
|
||||
if (!cell_date) {
|
||||
return false;
|
||||
}
|
||||
var range = range_getter();
|
||||
return cell_date >= range.start && cell_date < range.end;
|
||||
},
|
||||
};
|
||||
};
|
||||
return [
|
||||
make_option('Today', 'Today', () => {
|
||||
var start = this._start_of_today();
|
||||
return {
|
||||
start: start,
|
||||
end: this._add_days(start, 1),
|
||||
};
|
||||
}),
|
||||
make_option('Last7Days', 'Last 7 Days', () => {
|
||||
var today = this._start_of_today();
|
||||
return {
|
||||
start: this._add_days(today, -7),
|
||||
end: this._add_days(today, 1),
|
||||
};
|
||||
}),
|
||||
make_option('Last30Days', 'Last 30 Days', () => {
|
||||
var today = this._start_of_today();
|
||||
return {
|
||||
start: this._add_days(today, -30),
|
||||
end: this._add_days(today, 1),
|
||||
};
|
||||
}),
|
||||
make_option('LastMonth', 'Last Month', () => {
|
||||
var today = this._start_of_today();
|
||||
var start = new Date(
|
||||
today.getFullYear(), today.getMonth() - 1, 1);
|
||||
var end = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
return {
|
||||
start: start,
|
||||
end: end,
|
||||
};
|
||||
}),
|
||||
make_option('ThisMonth', 'This Month', () => {
|
||||
var today = this._start_of_today();
|
||||
var start = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
var end = new Date(
|
||||
today.getFullYear(), today.getMonth() + 1, 1);
|
||||
return {
|
||||
start: start,
|
||||
end: end,
|
||||
};
|
||||
}),
|
||||
make_option('YearToDate', 'Year to Date', () => {
|
||||
var today = this._start_of_today();
|
||||
return {
|
||||
start: new Date(today.getFullYear(), 0, 1),
|
||||
end: this._add_days(today, 1),
|
||||
};
|
||||
}),
|
||||
];
|
||||
},
|
||||
_start_of_today: function() {
|
||||
var now = new Date();
|
||||
return new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||
},
|
||||
_add_days: function(date, days) {
|
||||
return new Date(
|
||||
date.getFullYear(), date.getMonth(), date.getDate() + days);
|
||||
},
|
||||
_normalize_date_filter_value: function(value) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
var date = value instanceof Date ? value : new Date(value);
|
||||
if (isNaN(date.getTime())) {
|
||||
return null;
|
||||
}
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
},
|
||||
_get_sao_value_filter_state: function(col_id) {
|
||||
var filter = this._sao_value_filters &&
|
||||
this._sao_value_filters[col_id];
|
||||
@@ -25285,7 +25492,113 @@ function eval_pyson(value){
|
||||
},
|
||||
_is_sao_value_filter_user_source: function(source) {
|
||||
return ~['checkbox-change', 'all-button', 'none-button',
|
||||
'clear-button'].indexOf(source);
|
||||
'clear-button', 'drag-drop'].indexOf(source);
|
||||
},
|
||||
_make_filter_draggable_cell: function(element, column, record) {
|
||||
if (!element || !column || !column.attributes ||
|
||||
!column.attributes.name || !record) {
|
||||
return element;
|
||||
}
|
||||
var value = this._get_column_text_value(column, record);
|
||||
if (!value) {
|
||||
return element;
|
||||
}
|
||||
var wrapped = jQuery(element);
|
||||
wrapped.attr('draggable', 'true')
|
||||
.addClass('ag-grid-filter-draggable-cell')
|
||||
.on('dragstart', evt => {
|
||||
var payload = {
|
||||
colId: column.attributes.name,
|
||||
label: this._get_column_label(column.attributes.name),
|
||||
value: String(value),
|
||||
};
|
||||
this._filter_drag_payload = payload;
|
||||
evt.originalEvent.dataTransfer.effectAllowed = 'copy';
|
||||
evt.originalEvent.dataTransfer.setData(
|
||||
'application/x-sao-ag-grid-filter',
|
||||
JSON.stringify(payload));
|
||||
evt.originalEvent.dataTransfer.setData(
|
||||
'text/plain',
|
||||
payload.label + ' = ' + payload.value);
|
||||
this._set_filter_dropzone_active(true, payload);
|
||||
})
|
||||
.on('dragend', () => {
|
||||
this._filter_drag_payload = null;
|
||||
this._set_filter_dropzone_active(false);
|
||||
});
|
||||
return wrapped[0];
|
||||
},
|
||||
_set_filter_dropzone_active: function(active, payload) {
|
||||
if (!this.active_filter_chips) {
|
||||
return;
|
||||
}
|
||||
this.active_filter_chips
|
||||
.toggleClass('drag-active', Boolean(active))
|
||||
.removeClass('drag-over');
|
||||
if (active && !this._get_active_filter_chip_entries().length) {
|
||||
this.active_filter_chips.empty();
|
||||
jQuery('<span/>', {
|
||||
'class': 'ag-grid-active-filter-drop-hint',
|
||||
'text': payload ?
|
||||
Sao.i18n.gettext('Drop to filter %1')
|
||||
.replace('%1', payload.label) :
|
||||
Sao.i18n.gettext('Drop to filter'),
|
||||
}).appendTo(this.active_filter_chips);
|
||||
this.active_filter_chips.css('display', 'inline-flex');
|
||||
} else if (!active) {
|
||||
this._render_active_filter_chips();
|
||||
}
|
||||
},
|
||||
_get_filter_drop_payload: function(event) {
|
||||
var payload = this._filter_drag_payload;
|
||||
if (!payload && event && event.dataTransfer) {
|
||||
try {
|
||||
payload = JSON.parse(event.dataTransfer.getData(
|
||||
'application/x-sao-ag-grid-filter') || 'null');
|
||||
} catch (error) {
|
||||
payload = null;
|
||||
}
|
||||
}
|
||||
if (!payload || !payload.colId || !payload.value) {
|
||||
return null;
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
_apply_filter_drop: function(event) {
|
||||
var payload = this._get_filter_drop_payload(event);
|
||||
this._filter_drag_payload = null;
|
||||
if (!payload) {
|
||||
this._set_filter_dropzone_active(false);
|
||||
return;
|
||||
}
|
||||
var column = this._find_column_by_id(payload.colId);
|
||||
if (!column) {
|
||||
this._set_filter_dropzone_active(false);
|
||||
return;
|
||||
}
|
||||
var empty = Sao.i18n.gettext('(Empty)');
|
||||
var value = String(payload.value || '') || empty;
|
||||
var all_values = this._get_live_filter_values(
|
||||
column, payload.colId).map(item => String(item || empty));
|
||||
if (!~all_values.indexOf(value)) {
|
||||
all_values.push(value);
|
||||
}
|
||||
var existing = this._sao_value_filters &&
|
||||
this._sao_value_filters[payload.colId];
|
||||
var selected = existing && existing.selected ?
|
||||
Array.from(existing.selected).map(item => String(item)) : [];
|
||||
if (!selected.length) {
|
||||
selected = [value];
|
||||
} else if (!~selected.indexOf(value)) {
|
||||
selected.push(value);
|
||||
}
|
||||
this._set_sao_value_filter(
|
||||
payload.colId,
|
||||
selected,
|
||||
all_values,
|
||||
'drag-drop',
|
||||
{value: value});
|
||||
this._set_filter_dropzone_active(false);
|
||||
},
|
||||
_forget_sao_value_filter_saved_state: function(col_id) {
|
||||
var remove_filter = value_filters => {
|
||||
@@ -25358,6 +25671,7 @@ function eval_pyson(value){
|
||||
}
|
||||
this._apply_sao_value_filters();
|
||||
this._render_filter_logic_panel();
|
||||
this._render_active_filter_chips();
|
||||
this._schedule_state_save();
|
||||
},
|
||||
_trace_sao_value_filter_change: function(reason, col_id, selected, all,
|
||||
@@ -25599,6 +25913,208 @@ function eval_pyson(value){
|
||||
.find('.ag-grid-value-filter-mode-label')
|
||||
.text(' ' + Sao.i18n.gettext(any ? 'Any filter' : 'All filters'));
|
||||
},
|
||||
_get_column_label: function(col_id) {
|
||||
var column = this._find_column_by_id(col_id);
|
||||
return column && column.attributes ?
|
||||
column.attributes.string || column.attributes.name || col_id :
|
||||
col_id;
|
||||
},
|
||||
_describe_grid_filter_model: function(model) {
|
||||
if (!model) {
|
||||
return {
|
||||
operator: '',
|
||||
value: '',
|
||||
};
|
||||
}
|
||||
var type = model.type || model.operator || '';
|
||||
var value = model.filter;
|
||||
if (value === undefined || value === null || value === '') {
|
||||
value = model.dateFrom || model.filterTo || '';
|
||||
}
|
||||
if (Array.isArray(model.values)) {
|
||||
return {
|
||||
operator: '=',
|
||||
value: model.values.length <= 2 ?
|
||||
model.values.join(', ') :
|
||||
Sao.i18n.gettext('%1 values').replace('%1', model.values.length),
|
||||
};
|
||||
}
|
||||
if (model.condition1 || model.condition2) {
|
||||
return {
|
||||
operator: '',
|
||||
value: Sao.i18n.gettext('complex'),
|
||||
};
|
||||
}
|
||||
var relative_date_labels = {
|
||||
saoToday: 'Today',
|
||||
saoLast7Days: 'Last 7 Days',
|
||||
saoLast30Days: 'Last 30 Days',
|
||||
saoLastMonth: 'Last Month',
|
||||
saoThisMonth: 'This Month',
|
||||
saoYearToDate: 'Year to Date',
|
||||
};
|
||||
if (relative_date_labels[type]) {
|
||||
return {
|
||||
operator: '',
|
||||
value: Sao.i18n.gettext(relative_date_labels[type]),
|
||||
};
|
||||
}
|
||||
var operators = {
|
||||
equals: '=',
|
||||
notEqual: '!=',
|
||||
contains: 'contains',
|
||||
notContains: 'not contains',
|
||||
startsWith: 'starts',
|
||||
endsWith: 'ends',
|
||||
lessThan: '<',
|
||||
lessThanOrEqual: '<=',
|
||||
greaterThan: '>',
|
||||
greaterThanOrEqual: '>=',
|
||||
inRange: 'between',
|
||||
};
|
||||
return {
|
||||
operator: operators[type] || type || '=',
|
||||
value: value,
|
||||
};
|
||||
},
|
||||
_get_active_filter_chip_entries: function() {
|
||||
var entries = [];
|
||||
Object.keys(this._sao_value_filters || {}).forEach(col_id => {
|
||||
var filter = this._sao_value_filters[col_id];
|
||||
if (!this._is_sao_value_filter_active(filter)) {
|
||||
return;
|
||||
}
|
||||
var selected = Array.from(filter.selected || []).sort();
|
||||
var all = Array.from(filter.all || []).sort();
|
||||
var selected_lookup = new Set(selected);
|
||||
var excluded = all.filter(value => !selected_lookup.has(value));
|
||||
var display_values = excluded.length &&
|
||||
excluded.length < selected.length ? excluded : selected;
|
||||
var operator = display_values === excluded ? '<>' : '=';
|
||||
var detail = display_values.length <= 2 ?
|
||||
display_values.join(', ') :
|
||||
Sao.i18n.gettext('%1 values').replace(
|
||||
'%1', display_values.length);
|
||||
entries.push({
|
||||
type: 'sao',
|
||||
colId: col_id,
|
||||
label: this._get_column_label(col_id),
|
||||
operator: operator,
|
||||
detail: detail,
|
||||
});
|
||||
});
|
||||
var filter_model = this.gridApi && this.gridApi.getFilterModel ?
|
||||
this._strip_sao_value_set_filter_model(
|
||||
this.gridApi.getFilterModel()) : {};
|
||||
Object.keys(filter_model || {}).forEach(col_id => {
|
||||
var description =
|
||||
this._describe_grid_filter_model(filter_model[col_id]);
|
||||
entries.push({
|
||||
type: 'grid',
|
||||
colId: col_id,
|
||||
label: this._get_column_label(col_id),
|
||||
operator: description.operator,
|
||||
detail: description.value,
|
||||
});
|
||||
});
|
||||
return entries;
|
||||
},
|
||||
_open_filter_for_chip: function(entry) {
|
||||
if (entry.type == 'sao') {
|
||||
this._show_filter_logic_menu();
|
||||
return;
|
||||
}
|
||||
if (!this.gridApi) {
|
||||
return;
|
||||
}
|
||||
if (this.gridApi.showColumnFilter) {
|
||||
this.gridApi.showColumnFilter(entry.colId);
|
||||
} else if (this.gridApi.showColumnMenu) {
|
||||
this.gridApi.showColumnMenu(entry.colId);
|
||||
}
|
||||
},
|
||||
_remove_filter_chip: function(entry) {
|
||||
if (entry.type == 'sao') {
|
||||
delete this._sao_value_filters[entry.colId];
|
||||
this._forget_sao_value_filter_saved_state(entry.colId);
|
||||
this._apply_sao_value_filters();
|
||||
this._render_filter_logic_panel();
|
||||
this._schedule_state_save();
|
||||
this._render_active_filter_chips();
|
||||
return;
|
||||
}
|
||||
if (!this.gridApi || !this.gridApi.getFilterModel ||
|
||||
!this.gridApi.setFilterModel) {
|
||||
return;
|
||||
}
|
||||
var model = jQuery.extend(true, {}, this.gridApi.getFilterModel() || {});
|
||||
delete model[entry.colId];
|
||||
this.gridApi.setFilterModel(model);
|
||||
if (this.gridApi.onFilterChanged) {
|
||||
this.gridApi.onFilterChanged();
|
||||
}
|
||||
},
|
||||
_render_active_filter_chips: function() {
|
||||
if (!this.active_filter_chips) {
|
||||
return;
|
||||
}
|
||||
var entries = this._get_active_filter_chip_entries();
|
||||
this.active_filter_chips.empty();
|
||||
if (!entries.length) {
|
||||
this.active_filter_chips.hide();
|
||||
return;
|
||||
}
|
||||
var visible = entries.slice(0, 4);
|
||||
visible.forEach(entry => {
|
||||
var text = entry.label + (entry.operator ? ' ' +
|
||||
entry.operator : '') + (entry.detail ? ' ' +
|
||||
entry.detail : '');
|
||||
var chip = jQuery('<button/>', {
|
||||
'class': 'ag-grid-active-filter-chip',
|
||||
'type': 'button',
|
||||
'title': text,
|
||||
}).click(evt => {
|
||||
evt.preventDefault();
|
||||
this._open_filter_for_chip(entry);
|
||||
}).appendTo(this.active_filter_chips);
|
||||
jQuery('<span/>', {
|
||||
'class': 'ag-grid-active-filter-chip-name',
|
||||
'text': entry.label,
|
||||
}).appendTo(chip);
|
||||
var value = jQuery('<span/>', {
|
||||
'class': 'ag-grid-active-filter-chip-value',
|
||||
}).appendTo(chip);
|
||||
jQuery('<span/>', {
|
||||
'class': 'ag-grid-active-filter-chip-operator',
|
||||
'text': entry.operator || '=',
|
||||
}).appendTo(value);
|
||||
jQuery('<span/>', {
|
||||
'class': 'ag-grid-active-filter-chip-detail',
|
||||
'text': entry.detail || '',
|
||||
}).appendTo(value);
|
||||
jQuery('<span/>', {
|
||||
'class': 'ag-grid-active-filter-chip-remove',
|
||||
'text': 'x',
|
||||
'title': Sao.i18n.gettext('Remove filter'),
|
||||
}).click(evt => {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
this._remove_filter_chip(entry);
|
||||
}).appendTo(chip);
|
||||
});
|
||||
if (entries.length > visible.length) {
|
||||
jQuery('<button/>', {
|
||||
'class': 'ag-grid-active-filter-chip ag-grid-active-filter-chip-more',
|
||||
'type': 'button',
|
||||
'text': '+' + String(entries.length - visible.length),
|
||||
'title': Sao.i18n.gettext('Show filter logic'),
|
||||
}).click(evt => {
|
||||
evt.preventDefault();
|
||||
this._show_filter_logic_menu();
|
||||
}).appendTo(this.active_filter_chips);
|
||||
}
|
||||
this.active_filter_chips.css('display', 'inline-flex');
|
||||
},
|
||||
_get_active_sao_value_filter_entries: function() {
|
||||
return Object.keys(this._sao_value_filters || {})
|
||||
.filter(col_id => this._is_sao_value_filter_active(
|
||||
@@ -26229,6 +26745,47 @@ function eval_pyson(value){
|
||||
return '';
|
||||
}
|
||||
},
|
||||
_get_column_date_filter_value: function(column, record) {
|
||||
if (!column || !record || !column.attributes.name) {
|
||||
return null;
|
||||
}
|
||||
var name = column.attributes.name;
|
||||
var value = null;
|
||||
try {
|
||||
var field = record.model && record.model.fields &&
|
||||
record.model.fields[name];
|
||||
if (field && field.get_client) {
|
||||
value = field.get_client(record);
|
||||
}
|
||||
} catch (error) {
|
||||
value = null;
|
||||
}
|
||||
if (!value && record._values &&
|
||||
Object.prototype.hasOwnProperty.call(record._values, name)) {
|
||||
value = record._values[name];
|
||||
}
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
return new Date(
|
||||
value.getFullYear(), value.getMonth(), value.getDate());
|
||||
}
|
||||
if (value.isDate || value.isDateTime) {
|
||||
return new Date(value.year(), value.month(), value.date());
|
||||
}
|
||||
if (typeof value == 'string') {
|
||||
var date = moment(value, [
|
||||
'YYYY-MM-DD',
|
||||
Sao.common.date_format(
|
||||
this.screen && this.screen.context &&
|
||||
this.screen.context.date_format),
|
||||
], true);
|
||||
return date.isValid() ?
|
||||
new Date(date.year(), date.month(), date.date()) : null;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
_is_badge_column: function(column) {
|
||||
if (!column || !column.attributes) {
|
||||
return false;
|
||||
@@ -35527,7 +36084,8 @@ function eval_pyson(value){
|
||||
Sao.View.BoardXMLViewParser = Sao.class_(Sao.View.FormXMLViewParser, {
|
||||
_parse_board: function(node, attributes) {
|
||||
var container = new Sao.View.Form.Container(
|
||||
Number(node.getAttribute('col') || 4));
|
||||
Number(node.getAttribute('col') || 4),
|
||||
attributes.col_widths);
|
||||
this.view.el.append(container.el);
|
||||
this.parse_child(node, container);
|
||||
if (this._containers.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user