From 2f231625ca7f53f9de898181c0b6658a13717604 Mon Sep 17 00:00:00 2001 From: Merve Ceynek Date: Wed, 17 Dec 2025 13:33:29 +0100 Subject: [PATCH 1/4] fix(nanoflow-commons-native): synchronization issue with Base64 images --- packages/jsActions/nanoflow-actions-native/CHANGELOG.md | 5 ++++- .../src/other/Base64DecodeToImage.ts | 8 +++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/jsActions/nanoflow-actions-native/CHANGELOG.md b/packages/jsActions/nanoflow-actions-native/CHANGELOG.md index 5bf32878f..b19e0f991 100644 --- a/packages/jsActions/nanoflow-actions-native/CHANGELOG.md +++ b/packages/jsActions/nanoflow-actions-native/CHANGELOG.md @@ -6,10 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Fixed + +- We've fixed a synchronization issue with Base64 images generated by the Signature widget. + ## [5.2.0] Nanoflow Commons - 2026-1-23 - We've migrated from using @react-native-community/geolocation to react-native-permissions for handling location permissions. -- ## [5.1.6] Nanoflow Commons - 2025-12-05 diff --git a/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts b/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts index f7243f73d..6e37161c9 100644 --- a/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts +++ b/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts @@ -5,7 +5,6 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { Base64 } from "js-base64"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -16,7 +15,7 @@ import { Base64 } from "js-base64"; * @param {MxObject} image * @returns {Promise.} */ -export function Base64DecodeToImage(base64: string, image: mendix.lib.MxObject): Promise { +export async function Base64DecodeToImage(base64: string, image: mendix.lib.MxObject): Promise { // BEGIN USER CODE if (!base64) { @@ -26,7 +25,10 @@ export function Base64DecodeToImage(base64: string, image: mendix.lib.MxObject): throw new Error("image should not be null"); } - const blob = new Blob([Base64.toUint8Array(base64)], { type: "image/png" }); + const dataUri = base64.startsWith("data:") ? base64 : `data:image/png;base64,${base64}`; + + const res = await fetch(dataUri); + const blob = await res.blob(); return new Promise((resolve, reject) => { mx.data.saveDocument(image.getGuid(), "camera image", {}, blob, () => resolve(true), reject); From 15a321dcdcb830e84e2917fc0604bfa9ccf81923 Mon Sep 17 00:00:00 2001 From: Saurabh Chavan Date: Tue, 27 Jan 2026 14:11:02 +0530 Subject: [PATCH 2/4] base 64 decode to image function blob issue fixed --- .../src/other/Base64DecodeToImage.ts | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts b/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts index 6e37161c9..cb035545b 100644 --- a/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts +++ b/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts @@ -5,6 +5,7 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. +import RNBlobUtil from "react-native-blob-util"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -25,14 +26,44 @@ export async function Base64DecodeToImage(base64: string, image: mendix.lib.MxOb throw new Error("image should not be null"); } - const dataUri = base64.startsWith("data:") ? base64 : `data:image/png;base64,${base64}`; - - const res = await fetch(dataUri); - const blob = await res.blob(); - - return new Promise((resolve, reject) => { - mx.data.saveDocument(image.getGuid(), "camera image", {}, blob, () => resolve(true), reject); - }); + try { + // Remove data URI prefix if present (e.g., "data:image/png;base64,") + let cleanBase64 = base64; + if (base64.includes(",")) { + cleanBase64 = base64.split(",")[1]; + } + + // Remove any whitespace/newlines + cleanBase64 = cleanBase64.replace(/\s/g, ""); + + // Validate base64 format + if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleanBase64)) { + throw new Error("Invalid base64 format"); + } + + // Create a temporary file path + const tempPath = `${RNBlobUtil.fs.dirs.CacheDir}/temp_image_${Date.now()}.png`; + + // Write Base64 data to a temporary file + await RNBlobUtil.fs.writeFile(tempPath, cleanBase64, "base64"); + + // Fetch the file as a blob + const res = await fetch(`file://${tempPath}`); + const blob = await res.blob(); + + return new Promise((resolve, reject) => { + mx.data.saveDocument(image.getGuid(), "camera image", {}, blob, () => { + RNBlobUtil.fs.unlink(tempPath).catch(() => {}); + resolve(true); + }, (error) => { + RNBlobUtil.fs.unlink(tempPath).catch(() => {}); + reject(error); + }); + }); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to decode base64 to image: ${errorMessage}`); + } // END USER CODE } From 718ebdec9c9ef1b746c798b5b91050ff6be5d60d Mon Sep 17 00:00:00 2001 From: Saurabh Chavan Date: Wed, 28 Jan 2026 21:03:11 +0530 Subject: [PATCH 3/4] logic implemented for other platforms --- .../src/other/Base64DecodeToImage.ts | 81 ++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts b/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts index cb035545b..21803728f 100644 --- a/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts +++ b/packages/jsActions/nanoflow-actions-native/src/other/Base64DecodeToImage.ts @@ -5,6 +5,7 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. +import { Base64 } from "js-base64"; import RNBlobUtil from "react-native-blob-util"; // BEGIN EXTRA CODE @@ -26,44 +27,52 @@ export async function Base64DecodeToImage(base64: string, image: mendix.lib.MxOb throw new Error("image should not be null"); } - try { - // Remove data URI prefix if present (e.g., "data:image/png;base64,") - let cleanBase64 = base64; - if (base64.includes(",")) { - cleanBase64 = base64.split(",")[1]; - } - - // Remove any whitespace/newlines - cleanBase64 = cleanBase64.replace(/\s/g, ""); - - // Validate base64 format - if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleanBase64)) { - throw new Error("Invalid base64 format"); - } - - // Create a temporary file path - const tempPath = `${RNBlobUtil.fs.dirs.CacheDir}/temp_image_${Date.now()}.png`; - - // Write Base64 data to a temporary file - await RNBlobUtil.fs.writeFile(tempPath, cleanBase64, "base64"); - - // Fetch the file as a blob - const res = await fetch(`file://${tempPath}`); - const blob = await res.blob(); - - return new Promise((resolve, reject) => { - mx.data.saveDocument(image.getGuid(), "camera image", {}, blob, () => { - RNBlobUtil.fs.unlink(tempPath).catch(() => {}); - resolve(true); - }, (error) => { - RNBlobUtil.fs.unlink(tempPath).catch(() => {}); - reject(error); + // Native platform + if (navigator && navigator.product === "ReactNative") { + try { + // Remove data URI prefix if present (e.g., "data:image/png;base64,") + let cleanBase64 = base64; + if (base64.includes(",")) { + cleanBase64 = base64.split(",")[1]; + } + + // Remove any whitespace/newlines + cleanBase64 = cleanBase64.replace(/\s/g, ""); + + // Validate base64 format + if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleanBase64)) { + throw new Error("Invalid base64 format"); + } + + // Create a temporary file path + const tempPath = `${RNBlobUtil.fs.dirs.CacheDir}/temp_image_${Date.now()}.png`; + + // Write Base64 data to a temporary file + await RNBlobUtil.fs.writeFile(tempPath, cleanBase64, "base64"); + + // Fetch the file as a blob + const res = await fetch(`file://${tempPath}`); + const blob = await res.blob(); + + return new Promise((resolve, reject) => { + mx.data.saveDocument(image.getGuid(), "camera image", {}, blob, () => { + RNBlobUtil.fs.unlink(tempPath).catch(() => { }); + resolve(true); + }, (error) => { + RNBlobUtil.fs.unlink(tempPath).catch(() => { }); + reject(error); + }); }); - }); - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - throw new Error(`Failed to decode base64 to image: ${errorMessage}`); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to decode base64 to image: ${errorMessage}`); + } } + // Other platforms + const blob = new Blob([Base64.toUint8Array(base64)], { type: "image/png" }); + return new Promise((resolve, reject) => { + mx.data.saveDocument(image.getGuid(), "camera image", {}, blob, () => resolve(true), reject); + }); // END USER CODE } From 7d0dbc12cb00519ad287c48dfb6b6496f7149149 Mon Sep 17 00:00:00 2001 From: Saurabh Chavan Date: Fri, 30 Jan 2026 15:00:26 +0530 Subject: [PATCH 4/4] chore: update mendix studio pro version to latest --- configs/e2e/mendix-versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/e2e/mendix-versions.json b/configs/e2e/mendix-versions.json index 1bb0404c1..bfaaf752c 100644 --- a/configs/e2e/mendix-versions.json +++ b/configs/e2e/mendix-versions.json @@ -1,3 +1,3 @@ { - "latest": "10.24.4.77222" + "latest": "10.24.14" }