Skip to content

Commit

Permalink
fix: recordset table
Browse files Browse the repository at this point in the history
  • Loading branch information
Tardo committed Mar 7, 2025
1 parent 5c7b0f8 commit 874a7f0
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 57 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# Changelog

**11.7.3**
**11.8.0**

```
ADD: options: Theming (part 1)
FIX: exportfile xml: Include ids for records without reference
FIX: hex2rgb: Correctly handle hex values
FIX: Command Assistant: Colors (issue #142)
FIX: Recordset Table: Display the contents of fields of type Object (issue #143)
FIX: Recordset Table: Correct processing of binary type fields
```

**11.7.2**
Expand Down
26 changes: 14 additions & 12 deletions src/js/page/odoo/commands/common/read.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,24 @@ import type Terminal from '@odoo/terminal';
async function cmdSearchModelRecordId(this: Terminal, kwargs: CMDCallbackArgs, ctx: CMDCallbackContext) {
const search_all_fields = kwargs.field[0] === '*';
let fields = kwargs.field;
const bin_fields = [];
let fieldDefs = {};

// Due to possible problems with binary fields it is necessary to filter them out
if (search_all_fields) {
if (!kwargs.read_binary) {
// $FlowFixMe
const fieldDefs = await callModel<{[string]: Object}>(
fieldDefs = await callModel<{[string]: Object}>(
kwargs.model,
'fields_get',
[fields],
[],
null,
await this.getContext(),
kwargs.options,
);

fields = [];
Object.entries(fieldDefs).forEach(item => {
if (item[1].type === 'binary') {
bin_fields.push(item[0]);
} else {
if (item[1].type !== 'binary') {
fields.push(item[0]);
}
});
Expand All @@ -44,16 +42,20 @@ async function cmdSearchModelRecordId(this: Terminal, kwargs: CMDCallbackArgs, c
}

const result = await searchRead(kwargs.model, [['id', 'in', kwargs.id]], fields, await this.getContext());

if (bin_fields.length !== 0) {
for (const item of result) {
for (const bin_field of bin_fields) {
item[bin_field] = {oterm: true, binary: true};
if (search_all_fields) {
if (!kwargs.read_binary) {
const def_fields = Object.keys(fieldDefs);
for (const field of def_fields) {
if (fieldDefs[field].type === 'binary') {
for (const record of result) {
record[field] = null;
}
}
}
}
}

const recordset = Recordset.make(kwargs.model, result);
const recordset = Recordset.make(kwargs.model, result, fieldDefs);
ctx.screen.print(recordset);
return recordset;
}
Expand Down
26 changes: 15 additions & 11 deletions src/js/page/odoo/commands/common/search.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ async function cmdSearchModelRecord(this: Terminal, kwargs: CMDCallbackArgs, ctx
}
const sresult = buff.data.slice(0, lines_total);
buff.data = buff.data.slice(lines_total);
const recordset = Recordset.make(kwargs.model, sresult);
const recordset = Recordset.make(kwargs.model, sresult, buff.fieldDefs);
ctx.screen.print(recordset);
if (buff.data.length) {
ctx.screen.printError(
Expand All @@ -52,16 +52,14 @@ async function cmdSearchModelRecord(this: Terminal, kwargs: CMDCallbackArgs, ctx
}

// Due to possible problems with binary fields it is necessary to filter them out
const bin_fields = [];
let fieldDefs = {};
if (search_all_fields) {
if (!kwargs.read_binary) {
const fieldDefs = await getFieldsInfo(kwargs.model, false, await this.getContext(), kwargs.options);
fieldDefs = await getFieldsInfo(kwargs.model, false, await this.getContext(), kwargs.options);

fields = [];
Object.entries(fieldDefs).forEach(item => {
if (item[1].type === 'binary') {
bin_fields.push(item[0]);
} else {
if (item[1].type !== 'binary') {
fields.push(item[0]);
}
});
Expand All @@ -76,10 +74,15 @@ async function cmdSearchModelRecord(this: Terminal, kwargs: CMDCallbackArgs, ctx
orderBy: kwargs.order,
}));

if (bin_fields.length !== 0) {
for (const item of result) {
for (const bin_field of bin_fields) {
item[bin_field] = {oterm: true, binary: true};
if (search_all_fields) {
if (!kwargs.read_binary) {
const def_fields = Object.keys(fieldDefs);
for (const field of def_fields) {
if (fieldDefs[field].type === 'binary') {
for (const record of result) {
record[field] = null;
}
}
}
}
}
Expand All @@ -90,10 +93,11 @@ async function cmdSearchModelRecord(this: Terminal, kwargs: CMDCallbackArgs, ctx
search_buffer[ctx.meta.info.cmdName] = {
model: kwargs.model,
data: sresult.slice(lines_total),
fieldDefs: fieldDefs,
};
sresult = sresult.slice(0, lines_total);
}
const recordset = Recordset.make(kwargs.model, sresult);
const recordset = Recordset.make(kwargs.model, sresult, fieldDefs);
ctx.screen.print(recordset);
ctx.screen.print(i18n.t("cmdSearch.result.count", "Records count: {{count}}", {count: sresult.length}));
if (need_truncate) {
Expand Down
60 changes: 32 additions & 28 deletions src/js/page/terminal/core/recordset.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import isEmpty from '@trash/utils/is_empty';
import isNumber from '@trash/utils/is_number';

export type FieldDef = {...};

const RecordHandler = {
// $FlowFixMe
get(target: Object, prop: mixed) {
Expand All @@ -13,33 +15,31 @@ const RecordHandler = {
prop === 'toWrite' ||
prop === 'rollback' ||
prop === 'persist' ||
prop === '__info' ||
typeof prop === 'symbol'
) {
const ref = target[prop];
if (typeof ref === 'function') {
return ref.bind(target);
}
return target[prop];
return (typeof ref === 'function') ? ref.bind(target) : ref;
}
return target.values[prop];
return target.__values[prop];
},
// $FlowFixMe
set(target: Object, prop: mixed, value: mixed) {
target.modified_fields.push(prop);
if (target.values.length === 1) {
return Reflect.set(target.values[0], prop, value);
target.__modified_fields.push(prop);
if (target.__values.length === 1) {
return Reflect.set(target.__values[0], prop, value);
}
return Reflect.set(target.values, prop, value);
return Reflect.set(target.__values, prop, value);
},

// $FlowFixMe
ownKeys(target: Object) {
return Reflect.ownKeys(target.values);
return Reflect.ownKeys(target.__values);
},
// $FlowFixMe
has(target: Object, prop: mixed) {
if (typeof prop === 'string' || typeof prop === 'number') {
return prop in target.values;
return prop in target.__values;
}
return false;
},
Expand All @@ -50,36 +50,38 @@ const RecordHandler = {

export class Record {
#origin: {[string]: mixed} = {};
values: {[string]: mixed};
modified_fields: Array<string> = [];
__info: FieldDef;
__values: {[string]: mixed};
__modified_fields: Array<string> = [];

constructor(values: {...}) {
constructor(values: {...}, field_info: FieldDef) {
this.#origin = {...values};
this.values = values;
this.__values = values;
this.__info = field_info;
}

persist() {
this.#origin = {...this.values};
this.modified_fields = [];
this.#origin = {...this.__values};
this.__modified_fields = [];
}

toJSON(): {...} {
return this.values;
return this.__values;
}

toWrite(): {[string]: mixed} {
const write_vals: {[string]: mixed} = {};
for (const field_name of this.modified_fields) {
write_vals[field_name] = this.values[field_name];
for (const field_name of this.__modified_fields) {
write_vals[field_name] = this.__values[field_name];
}
return write_vals;
}

rollback() {
for (const field_name of this.modified_fields) {
this.values[field_name] = this.#origin[field_name];
for (const field_name of this.__modified_fields) {
this.__values[field_name] = this.#origin[field_name];
}
this.modified_fields = [];
this.__modified_fields = [];
}

// $FlowFixMe
Expand All @@ -90,7 +92,7 @@ export class Record {
// $FlowFixMe
[Symbol.toPrimitive](hint) {
if (hint === 'string') {
return JSON.stringify(this.values);
return JSON.stringify(this.__values);
}
}
}
Expand Down Expand Up @@ -136,21 +138,23 @@ const RecordsetHandler = {
export default class Recordset {
#model: string;
#records: Array<Record> = [];
#fields: {[string]: FieldDef} = {};

// $FlowFixMe
static isValid(obj: Object) {
return obj instanceof Recordset;
}

static make(model: string, values: Array<{[string]: mixed}>): Recordset {
const rs = new Recordset(model, values);
static make(model: string, values: Array<{[string]: mixed}>, fields?: {[string]: FieldDef}): Recordset {
const rs = new Recordset(model, values, fields);
return new Proxy(rs, RecordsetHandler);
}

constructor(model: string, values: Array<{[string]: mixed}>) {
constructor(model: string, values: Array<{[string]: mixed}>, fields?: {[string]: FieldDef}) {
this.#model = model;
this.#fields = fields || {};
for (const rec_vals of values) {
const record = new Record(rec_vals);
const record = new Record(rec_vals, this.#fields);
this.#records.push(new Proxy(record, RecordHandler));
}
}
Expand Down
12 changes: 7 additions & 5 deletions src/js/page/terminal/templates/screen_table_cell_record.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
// Copyright Alexandre Díaz <[email protected]>
// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import {Record} from '@terminal/core/recordset';
import encodeHTML from '@terminal/utils/encode_html';
import prettyObjectString from '@terminal/utils/pretty_object_string';

export default function (model: string, field: string, item: {[string]: string | number}): string {
const item_val = item[field];
if (
if (item instanceof Record && item.__info[field]?.type === 'binary') {
return `<span class='btn terminal-btn-secondary o_terminal_click o_terminal_read_bin_field' data-model='${model}' data-id='${item.id}' data-field='${field}'>Try Read Field</span>`;
} else if (
item_val !== null &&
typeof item_val !== 'undefined' &&
typeof item_val === 'object' &&
item_val.oterm &&
item_val.binary
!(item_val instanceof Array)
) {
return `<span class='btn terminal-btn-secondary o_terminal_click o_terminal_read_bin_field' data-model='${model}' data-id='${item.id}' data-field='${field}'>Try Read Field</span>`;
return prettyObjectString(item_val);
}
return encodeHTML(String(item_val));
}

0 comments on commit 874a7f0

Please sign in to comment.