Skip to content

Commit a6942a5

Browse files
committed
[REF] runbot: tracking_value revamp
Globally, a cleanup of the tracking value diff implementation: - avoid multiple (many?) diff recompute using memoization - uses CopyButton component - modernize a bit, the JavaScript syntax - "Boostrapify" and refine diff rendering - diff's line highlight on hover is back
1 parent 373ba88 commit a6942a5

File tree

3 files changed

+114
-97
lines changed

3 files changed

+114
-97
lines changed
Lines changed: 56 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,68 @@
11
/** @odoo-module **/
22
import { patch } from "@web/core/utils/patch";
33
import { Message } from "@mail/core/common/message";
4+
import { CopyButton } from "@web/core/copy_button/copy_button";
5+
import { memoize } from "@web/core/utils/functions";
6+
7+
const diffMatchPatch = new diff_match_patch();
8+
9+
function makeDiff(text1, text2) {
10+
const { chars1, chars2, lineArray } = diffMatchPatch.diff_linesToChars_(text1, text2);
11+
const diffs = diffMatchPatch.diff_main(chars1, chars2, false);
12+
diffMatchPatch.diff_charsToLines_(diffs, lineArray);
13+
diffMatchPatch.diff_cleanupSemantic(diffs);
14+
return diffs;
15+
}
16+
17+
function prepareForRendering(diffs) {
18+
let lines = [];
19+
let preLineCounter = 0
20+
let postLineCounter = 0
21+
for (const { 0: diffType, 1: data } of diffs) {
22+
for (const line of data.split("\n")) {
23+
let type;
24+
if (diffType === -1) {
25+
type = "removed";
26+
preLineCounter += 1;
27+
} else if (diffType === 0) {
28+
type = "kept";
29+
preLineCounter += 1;
30+
postLineCounter += 1;
31+
} else if (diffType === 1) {
32+
type = "added";
33+
postLineCounter += 1;
34+
}
35+
lines.push({ type, preLineCounter, postLineCounter, line});
36+
}
37+
}
38+
return lines;
39+
}
40+
41+
function computeDiff({ oldValue, newValue }) {
42+
const diff = makeDiff(oldValue, newValue);
43+
return prepareForRendering(diff);
44+
}
45+
46+
patch(Message, {
47+
components: {
48+
...Message.components,
49+
CopyButton,
50+
},
51+
});
452

553
patch(Message.prototype, {
654
setup() {
755
super.setup(...arguments);
8-
this.kept = false;
56+
this.state.showKept = false;
957
},
10-
isMultiline(trackingValue) {
11-
const oldValue = trackingValue.oldValue;
12-
const newValue = trackingValue.newValue;
13-
return ((oldValue && typeof oldValue=== 'string' && oldValue.includes('\n')) && (newValue && typeof oldValue=== 'string' && newValue.includes('\n')))
14-
},
15-
formatTracking(trackingFieldInfo, trackingValue) {
16-
return super.formatTracking(trackingFieldInfo, trackingValue)
58+
59+
lines: memoize(computeDiff),
60+
61+
isMultiline({ oldValue, newValue }) {
62+
return typeof oldValue === "string" && oldValue.includes("\n") && typeof oldValue === "string" && newValue.includes("\n");
1763
},
64+
1865
toggleKept() {
19-
this.kept = !this.kept;
20-
},
21-
copyToClipboard(trackingValue) {
22-
return function () {
23-
navigator.clipboard.writeText(trackingValue);
24-
};
66+
this.state.showKept = !this.state.showKept;
2567
},
26-
lines(trackingValue) {
27-
const oldValue = trackingValue.oldValue;
28-
const newValue = trackingValue.newValue;
29-
const diff = this.makeDiff(oldValue, newValue);
30-
const lines = this.prepareForRendering(diff);
31-
return lines;
32-
},
33-
makeDiff(text1, text2) {
34-
var dmp = new diff_match_patch();
35-
var a = dmp.diff_linesToChars_(text1, text2);
36-
var lineText1 = a.chars1;
37-
var lineText2 = a.chars2;
38-
var lineArray = a.lineArray;
39-
var diffs = dmp.diff_main(lineText1, lineText2, false);
40-
dmp.diff_charsToLines_(diffs, lineArray);
41-
dmp.diff_cleanupSemantic(diffs);
42-
return diffs;
43-
},
44-
prepareForRendering(diffs) {
45-
var lines = [];
46-
var pre_line_counter = 0
47-
var post_line_counter = 0
48-
for (var x = 0; x < diffs.length; x++) {
49-
var diff_type = diffs[x][0];
50-
var data = diffs[x][1];
51-
var data_lines = data.split('\n');
52-
for (var line_index in data_lines) {
53-
var line = data_lines[line_index];
54-
line = line.replace(/&/g, '&amp;');
55-
line = line.replace(/</g, '&lt;');
56-
line = line.replace(/>/g, '&gt;');
57-
//text = text.replace(/\n/g, '<br>');
58-
//text = text.replace(/ /g, '&nbsp&nbsp');
59-
if (diff_type == -1) {
60-
lines.push({type:'removed', pre_line_counter: pre_line_counter, post_line_counter: '-', line: line})
61-
pre_line_counter += 1
62-
} else if (diff_type == 0) {
63-
lines.push({type:'kept', pre_line_counter: '', post_line_counter: post_line_counter, line: line})
64-
pre_line_counter += 1
65-
post_line_counter +=1
66-
} else if (diff_type == 1) {
67-
lines.push({type:'added', pre_line_counter: '+', post_line_counter: post_line_counter, line: line})
68-
post_line_counter +=1
69-
}
70-
}
71-
}
72-
return lines;
73-
},
7468
});
Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,43 @@
1-
.code_diff {
2-
white-space: nowrap;
3-
overflow-x: auto;
4-
font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
1+
.code-diff {
2+
.table {
3+
> tbody {
4+
font-family: var(--font-monospace);
5+
font-size: 0.75rem;
6+
line-height: 1;
7+
white-space: nowrap;
8+
}
59

6-
.col_number {
7-
background-color: #EEE;
8-
}
10+
> :not(caption) > * {
11+
border-width: 0 var(--border-width);
912

10-
.added {
11-
background:#a1f1a1;
12-
}
13-
14-
.removed {
15-
background:#f3a3a3;
13+
&:first-child {
14+
border-top-width: var(--border-width);
15+
}
16+
17+
&:last-child {
18+
border-bottom-width: var(--border-width);
19+
}
20+
21+
> * {
22+
border-width: 0;
23+
padding: 0.3rem;
24+
25+
&.diff-line-sign {
26+
border-left-width: var(--border-width);
27+
}
28+
}
29+
}
1630
}
17-
18-
.code {
19-
white-space: pre-wrap;
31+
32+
.diff-line-number {
33+
width: 4ch;
2034
}
21-
.diff_line {
22-
background-color: #FFF;
35+
36+
.diff-line-sign {
37+
width: 2ch;
2338
}
2439

25-
.diff_line:hover {
26-
filter: brightness(92%);
40+
.diff-line-code {
41+
white-space: pre-wrap;
2742
}
28-
2943
}

runbot/static/src/js/fields/tracking_value.xml

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,30 @@
44
<xpath expr="//li[hasclass('o-mail-Message-tracking')]" position="replace">
55
<li class="o-mail-Message-tracking mb-1" role="group">
66
<t t-if="isMultiline(trackingValue)">
7-
<div class="btn-group btn-group-toggle mb-1">
8-
<button class="btn btn-sm btn-outline-primary" t-on-click="copyToClipboard(trackingValue.oldValue)">Copy old value to clipboard</button>
9-
<button class="btn btn-sm btn-outline-primary" t-on-click="toggleKept">Toggle context</button>
10-
<button class="btn btn-sm btn-outline-primary" t-on-click="copyToClipboard(trackingValue.newValue)">Copy new value to clipboard</button>
7+
<div class="btn-group btn-group-sm">
8+
<CopyButton copyText="'Copy old value'" content="trackingValue.oldValue" successText="'Old value copied'" className="'btn-outline-primary'"/>
9+
<button class="btn btn-outline-primary" t-on-click="toggleKept">
10+
<i class="fa fa-arrows-v mx-1"/>
11+
Toggle context
12+
</button>
13+
<CopyButton copyText="'Copy new value'" content="trackingValue.newValue" successText="'New value copied'" className="'btn-outline-primary'"/>
1114
</div>
12-
<div class="o-mail-Message-trackingField ms-1 fst-italic text-muted">(<t t-out="trackingValue.fieldInfo.changedField"/>)</div>
13-
<div class="code_diff">
14-
<table>
15-
<t t-foreach="lines(trackingValue)" t-as="line" t-key="line_index">
16-
<tr t-if="kept or line.type!=='kept'">
17-
<td class="col_number" t-out="line.pre_line_counter"/>
18-
<td class="col_number" t-out="line.post_line_counter"/>
19-
<td class="code" t-att-class="line.type" t-out="line.line"/>
20-
</tr>
21-
</t>
15+
<div class="code-diff table-responsive">
16+
<table class="table table-sm table-hover caption-top">
17+
<caption class="o-mail-Message-trackingField fst-italic">(<t t-out="trackingValue.fieldInfo.changedField"/>)</caption>
18+
<tbody>
19+
<t t-foreach="lines(trackingValue)" t-as="line" t-key="line_index" t-if="state.showKept or line.type !== 'kept'">
20+
<tr t-att-class="{'table-success': line.type === 'added', 'table-danger': line.type === 'removed'}">
21+
<td class="diff-line-number text-muted"><t t-if="['removed','kept'].includes(line.type)" t-out="line.preLineCounter"/></td>
22+
<td class="diff-line-number text-muted"><t t-if="['added','kept'].includes(line.type)" t-out="line.postLineCounter"/></td>
23+
<td class="diff-line-sign text-muted">
24+
<t t-if="line.type === 'removed'">-</t>
25+
<t t-elif="line.type === 'added'">+</t>
26+
</td>
27+
<td class="diff-line-code" t-att-class="line.type" t-out="line.line"/>
28+
</tr>
29+
</t>
30+
</tbody>
2231
</table>
2332
</div>
2433
</t>

0 commit comments

Comments
 (0)