[FIX] web: image field resets when using manual save

**Steps to reproduce:**

- go to a product page
- replace image (=> image is shown)
- click on "Save manually" (the cloud upload icon)
- BUG: previous image is displayed.

But it was saved: if you move to another record and return then it
shows the correct one.

**Solution:**

Basically, in an image_field: If its props.value is a "binary size",
then the image source is a url pointing to a server endpoint and
this url is based on the rawCacheKey, otherwise, we use the "base64"
of the uploaded image.

The proposed solution for the said issue is to invalidate the
rawCacheKey during upload. Then, during the calculation of image url
(at `getUrl`), we reassign the rawCacheKey with the newest
"__last_update" value of the record when needed (if the props.value
is a "binary size").

closes odoo/odoo#106236

X-original-commit: 93911daab238e96c8aa9b0a951b9a268d83a9847
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
Joseph Caburnay
2022-11-22 13:46:04 +01:00
parent 57fa76c01f
commit 7ec41bb9e1
2 changed files with 69 additions and 5 deletions
@@ -76,6 +76,9 @@ export class ImageField extends Component {
getUrl(previewFieldName) {
if (this.state.isValid && this.props.value) {
if (isBinarySize(this.props.value)) {
if (!this.rawCacheKey) {
this.rawCacheKey = this.props.record.data.__last_update;
}
return url("/web/image", {
model: this.props.record.resModel,
id: this.props.record.resId,
@@ -96,6 +99,8 @@ export class ImageField extends Component {
}
onFileUploaded(info) {
this.state.isValid = true;
// Invalidate the `rawCacheKey`.
this.rawCacheKey = null;
this.props.update(info.data);
}
onLoadFailed() {
@@ -19,6 +19,11 @@ const PRODUCT_IMAGE =
let serverData;
let target;
function getUnique(target) {
const src = target.dataset.src;
return new URL(src).searchParams.get("unique");
}
QUnit.module("Fields", (hooks) => {
hooks.beforeEach(() => {
target = getFixture();
@@ -263,6 +268,65 @@ QUnit.module("Fields", (hooks) => {
);
});
QUnit.test(
"clicking save manually after uploading new image should change the unique of the image src",
async function (assert) {
serverData.models.partner.onchanges = { foo: () => {} };
const rec = serverData.models.partner.records.find((rec) => rec.id === 1);
rec.document = "3 kb";
rec.__last_update = "2022-08-05 08:37:00"; // 1659688620000
await makeView({
type: "form",
resModel: "partner",
resId: 1,
serverData,
arch: /* xml */ `
<form>
<field name="foo"/>
<field name="document" widget="image" />
</form>`,
mockRPC(_route, { method, args }) {
if (method === "write") {
args[1].__last_update = "2022-08-05 09:37:00"; // 1659692220000
args[1].document = "4 kb";
}
},
});
assert.strictEqual(
getUnique(target.querySelector(".o_field_image img")),
"1659688620000"
);
await editInput(
target,
"input[type=file]",
new File(
[Uint8Array.from([...atob(MY_IMAGE)].map((c) => c.charCodeAt(0)))],
"fake_file.png",
{ type: "png" }
)
);
assert.strictEqual(
target.querySelector("div[name=document] img").dataset.src,
`data:image/png;base64,${MY_IMAGE}`
);
await editInput(target, ".o_field_widget[name='foo'] input", "grrr");
assert.strictEqual(
target.querySelector("div[name=document] img").dataset.src,
`data:image/png;base64,${MY_IMAGE}`
);
await clickSave(target);
assert.strictEqual(
getUnique(target.querySelector(".o_field_image img")),
"1659692220000"
);
}
);
QUnit.test("ImageField: option accepted_file_extensions", async function (assert) {
await makeView({
type: "form",
@@ -534,11 +598,6 @@ QUnit.module("Fields", (hooks) => {
},
});
function getUnique(target) {
const src = target.dataset.src;
return new URL(src).searchParams.get("unique");
}
assert.verifySteps(["get_views", "read"]);
assert.strictEqual(getUnique(target.querySelector(".o_field_image img")), "1659688620000");