Skip to content

Commit

Permalink
[MIG] web_widget_x2_many_2d_matrix: Migration to 16.0
Browse files Browse the repository at this point in the history
[MIG] web_widget_x2_many_2d_matrix: Migration to 16.0 (WIP, columns)

[MIG] web_widget_x2_many_2d_matrix: Migration to 16.0 (WIP, rows)

[MIG] web_widget_x2_many_2d_matrix: Migration to 16.0 (WIP, add value component)

Aggregated values

[MIG] web_widget_x2many_2d_matrix: Fix commitChanges of matrix.

[FIX] Fix commitChanges

[FIX] setDirty

[FIX] Aggregated values

[IMP] readonly working

[FIX] Update matrix on changing props

[FIX] Remove old files

[IMP] Run precommit stuff

[FIX] Remove deprecated readme sections

[MIG] Migrate show_row_totals and show_column_totals attributes

[MIG] sticky headers

Fixup

Fixup

Fixup

fixup

remove console.log
  • Loading branch information
tarteo committed May 11, 2023
1 parent 8292aec commit b9d3f0e
Show file tree
Hide file tree
Showing 11 changed files with 329 additions and 929 deletions.
18 changes: 12 additions & 6 deletions web_widget_x2many_2d_matrix/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "2D matrix for x2many fields",
"version": "15.0.1.0.2",
"version": "16.0.1.0.0",
"maintainers": ["ChrisOForgeFlow"],
"development_status": "Production/Stable",
"author": (
"Therp BV, "
"Tecnativa, "
"Camptocamp, "
"CorporateHub, "
"Onestein, "
"Odoo Community Association (OCA)"
),
"website": "https://github.com/OCA/web",
Expand All @@ -24,11 +25,16 @@
"installable": True,
"assets": {
"web.assets_backend": [
"web_widget_x2many_2d_matrix/static/src/scss/web_widget_x2many_2d_matrix.scss",
"web_widget_x2many_2d_matrix/static/src/js/2d_matrix_renderer.js",
"web_widget_x2many_2d_matrix/static/src/js/2d_matrix_view.js",
"web_widget_x2many_2d_matrix/static/src/js/abstract_view_matrix_limit_extend.js",
"web_widget_x2many_2d_matrix/static/src/js/widget_x2many_2d_matrix.js",
"web_widget_x2many_2d_matrix/static/src/components/x2many_2d_matrix_renderer/"
"x2many_2d_matrix_renderer.esm.js",
"web_widget_x2many_2d_matrix/static/src/components/x2many_2d_matrix_renderer/"
"x2many_2d_matrix_renderer.xml",
"web_widget_x2many_2d_matrix/static/src/components/x2many_2d_matrix_field/"
"x2many_2d_matrix_field.esm.js",
"web_widget_x2many_2d_matrix/static/src/components/x2many_2d_matrix_field/"
"x2many_2d_matrix_field.xml",
"web_widget_x2many_2d_matrix/static/src/components/x2many_2d_matrix_field/"
"x2many_2d_matrix_field.scss",
],
},
}
4 changes: 0 additions & 4 deletions web_widget_x2many_2d_matrix/readme/USAGE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ field_x_axis
The field that indicates the x value of a point
field_y_axis
The field that indicates the y value of a point
field_label_x_axis
Use another field to display in the table header
field_label_y_axis
Use another field to display in the table header
field_value
Show this field as value
show_row_totals
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/** @odoo-module **/

import {Component} from "@odoo/owl";
import {standardFieldProps} from "@web/views/fields/standard_field_props";
import {registry} from "@web/core/registry";
import {archParseBoolean} from "@web/views/utils";
import {X2Many2DMatrixRenderer} from "@web_widget_x2many_2d_matrix/components/x2many_2d_matrix_renderer/x2many_2d_matrix_renderer.esm";

export class X2Many2DMatrixField extends Component {
setup() {
this.activeField = this.props.record.activeFields[this.props.name];
}

getList() {
return this.props.value;
}

get list() {
return this.getList();
}

_getDefaultRecordValues() {
return {};
}

async commitChange(x, y, value) {
const fields = this.props.matrixFields;

const values = this._getDefaultRecordValues();
values[fields.x] = x;
values[fields.y] = y;

const matchingRecords = this.list.records.filter(
(record) => record.data[fields.x] === x && record.data[fields.y] === y
);
if (matchingRecords.length === 1) {
values[fields.value] = value;
await matchingRecords[0].update(values);
} else {
let total = 0;
if (matchingRecords.length) {
total = matchingRecords
.map((r) => r.data[fields.value])
.reduce((aggr, v) => aggr + v);
}
const diff = value - total;
values[fields.value] = diff;
const record = await this.list.addNew({
mode: "edit",
});
await record.update(values);
}
this.props.setDirty(false);
}
}

X2Many2DMatrixField.template = "web_widget_x2many_2d_matrix.X2Many2DMatrixField";
X2Many2DMatrixField.props = {
...standardFieldProps,
matrixFields: Object,
isXClickable: Boolean,
isYClickable: Boolean,
showRowTotals: Boolean,
showColumnTotals: Boolean,
};
X2Many2DMatrixField.components = {X2Many2DMatrixRenderer};
X2Many2DMatrixField.extractProps = ({attrs}) => {
return {
matrixFields: {
value: attrs.field_value,
x: attrs.field_x_axis,
y: attrs.field_y_axis,
},
isXClickable: archParseBoolean(attrs.x_axis_clickable),
isYClickable: archParseBoolean(attrs.y_axis_clickable),
showRowTotals:
"show_row_totals" in attrs ? archParseBoolean(attrs.show_row_totals) : true,
showColumnTotals:
"show_column_totals" in attrs
? archParseBoolean(attrs.show_column_totals)
: true,
};
};

registry.category("fields").add("x2many_2d_matrix", X2Many2DMatrixField);
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ $x2many_2d_matrix_max_height: 450px;
overflow-y: auto;
}

.o_x2many_2d_matrix.o_list_view {
.table {
> thead > tr > th {
white-space: pre-line;
position: sticky;
Expand Down Expand Up @@ -42,6 +42,7 @@ $x2many_2d_matrix_max_height: 450px;
box-shadow: -1px 5px 10px $gray-300;
}
&.row-total {
padding: 0.75rem;
font-weight: bold;
position: sticky;
right: 0;
Expand All @@ -54,7 +55,7 @@ $x2many_2d_matrix_max_height: 450px;
}
}

> tfoot > tr > td {
> tfoot > tr > th {
padding: 0.75rem;
text-align: left;
background-color: $o-list-footer-bg-color;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates>
<t t-name="web_widget_x2many_2d_matrix.X2Many2DMatrixField" owl="1">
<div class="table-responsive">
<X2Many2DMatrixRenderer
list="list"
matrixFields="props.matrixFields"
showRowTotals="props.showRowTotals"
showColumnTotals="props.showColumnTotals"
setDirty="(isDirty) => this.setDirty(isDirty)"
onUpdate="(x, y, value) => this.commitChange(x, y, value)"
readonly="props.readonly"
/>
</div>
</t>
</templates>
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/** @odoo-module **/

import {Component, onWillUpdateProps} from "@odoo/owl";
import {registry} from "@web/core/registry";

export class X2Many2DMatrixRenderer extends Component {
setup() {
this.ValueFieldComponent = this._getValueFieldComponent();
this.columns = this._getColumns();
this.rows = this._getRows();
this.matrix = this._getMatrix();

onWillUpdateProps((newProps) => {
this.columns = this._getColumns(newProps.list.records);
this.rows = this._getRows(newProps.list.records);
this.matrix = this._getMatrix(newProps.list.records);
});
}

_getColumns(records = this.list.records) {
const columns = [];
records.forEach((record) => {
const column = {
value: record.data[this.matrixFields.x],
text: record.data[this.matrixFields.x],
};
if (record.fields[this.matrixFields.x].type === "many2one") {
column.text = column.value[1];
column.value = column.value[0];
}
if (columns.findIndex((c) => c.value === column.value) !== -1) return;
columns.push(column);
});
return columns;
}

_getRows(records = this.list.records) {
const rows = [];
records.forEach((record) => {
const row = {
value: record.data[this.matrixFields.y],
text: record.data[this.matrixFields.y],
};
if (record.fields[this.matrixFields.y].type === "many2one") {
row.text = row.value[1];
row.value = row.value[0];
}
if (rows.findIndex((r) => r.value === row.value) !== -1) return;
rows.push(row);
});
return rows;
}

_getPointOfRecord(record) {
let xValue = record.data[this.matrixFields.x];
if (record.fields[this.matrixFields.x].type === "many2one") {
xValue = xValue[0];
}
let yValue = record.data[this.matrixFields.y];
if (record.fields[this.matrixFields.y].type === "many2one") {
yValue = yValue[0];
}

const x = this.columns.findIndex((c) => c.value === xValue);
const y = this.rows.findIndex((r) => r.value === yValue);
return {x, y};
}

_getMatrix(records = this.list.records) {
const matrix = this.rows.map(() =>
new Array(this.columns.length).fill(null).map(() => {
return {value: 0, records: []};
})
);
records.forEach((record) => {
const value = record.data[this.matrixFields.value];
const {x, y} = this._getPointOfRecord(record);
matrix[y][x].value += value;
matrix[y][x].records.push(record);
});
return matrix;
}

get list() {
return this.props.list;
}

get matrixFields() {
return this.props.matrixFields;
}

_getValueFieldComponent() {
const field = this.list.activeFields[this.matrixFields.value];
if (!field.widget) {
return this.list.activeFields[this.matrixFields.value].FieldComponent;
}
return registry.category("fields").get(field.widget);
}

_aggregateRow(row) {
const y = this.rows.findIndex((r) => r.value === row);
return this.matrix[y].map((r) => r.value).reduce((aggr, x) => aggr + x);
}

_aggregateColumn(column) {
const x = this.columns.findIndex((c) => c.value === column);
return this.matrix
.map((r) => r[x])
.map((r) => r.value)
.reduce((aggr, y) => aggr + y);
}

_aggregateAll() {
return this.matrix
.map((r) => r.map((x) => x.value).reduce((aggr, x) => aggr + x))
.reduce((aggr, y) => aggr + y);
}

update(x, y, value) {
this.matrix[y][x].value = value;
const xFieldValue = this.columns[x].value;
const yFieldValue = this.rows[y].value;

this.props.onUpdate(xFieldValue, yFieldValue, value);
}

getValueFieldProps(column, row) {
const x = this.columns.findIndex((c) => c.value === column);
const y = this.rows.findIndex((r) => r.value === row);
return {
value: this.matrix[y][x].value,
update: (value) => this.update(x, y, value),
readonly: this.props.readonly,
};
}
}

X2Many2DMatrixRenderer.template = "web_widget_x2many_2d_matrix.X2Many2DMatrixRenderer";
X2Many2DMatrixRenderer.props = {
list: Object,
matrixFields: Object,
setDirty: Function,
onUpdate: Function,
readonly: Boolean,
showRowTotals: Boolean,
showColumnTotals: Boolean,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates>
<t t-name="web_widget_x2many_2d_matrix.X2Many2DMatrixRenderer" owl="1">
<table
class="o_list_table table table-responsive table-sm table-hover position-relative mb-0 o_list_table_ungrouped table-striped"
t-if="rows.length > 0"
>
<thead>
<tr>
<th />
<th
t-foreach="columns"
t-as="column"
t-key="column.value"
class="text-center"
>
<t t-esc="column.text" />
</th>
<th t-if="props.showRowTotals" />
</tr>
</thead>
<tbody>
<tr t-foreach="rows" t-as="row" t-key="row.value">
<td>
<t t-esc="row.text" />
</td>
<td t-foreach="columns" t-as="column" t-key="column.value">
<t
t-component="ValueFieldComponent"
t-props="getValueFieldProps(column.value, row.value)"
/>
</td>
<td t-if="props.showRowTotals" class="row-total">
<t
t-component="ValueFieldComponent"
readonly="true"
value="_aggregateRow(row.value)"
/>
</td>
</tr>
</tbody>
<tfoot>
<tr t-if="props.showColumnTotals">
<th />
<th t-foreach="columns" t-as="column" t-key="column.value">
<t
t-component="ValueFieldComponent"
readonly="true"
value="_aggregateColumn(column.value)"
/>
</th>
<th t-if="props.showRowTotals" class="col-total">
<t
t-component="ValueFieldComponent"
readonly="true"
value="_aggregateAll()"
/>
</th>
</tr>
</tfoot>
</table>
<div t-else="" class="alert alert-info">
Nothing to display.
</div>
</t>
</templates>
Loading

0 comments on commit b9d3f0e

Please sign in to comment.