diff --git a/changelog/entries/unreleased/bug/5230_fix_richeditor_display_in_row_comment_notifications.json b/changelog/entries/unreleased/bug/5230_fix_richeditor_display_in_row_comment_notifications.json
new file mode 100644
index 0000000000..e27bcc6dc6
--- /dev/null
+++ b/changelog/entries/unreleased/bug/5230_fix_richeditor_display_in_row_comment_notifications.json
@@ -0,0 +1,9 @@
+{
+ "type": "bug",
+ "message": "Fix RichTextEditor display in row comment notifications",
+ "issue_origin": "github",
+ "issue_number": 5230,
+ "domain": "core",
+ "bullet_points": [],
+ "created_at": "2026-04-20"
+}
\ No newline at end of file
diff --git a/changelog/entries/unreleased/bug/fixes_if_formulas_in_the_application_builder_silently_render.json b/changelog/entries/unreleased/bug/fixes_if_formulas_in_the_application_builder_silently_render.json
new file mode 100644
index 0000000000..5324205a48
--- /dev/null
+++ b/changelog/entries/unreleased/bug/fixes_if_formulas_in_the_application_builder_silently_render.json
@@ -0,0 +1,9 @@
+{
+ "type": "bug",
+ "message": "Fixes if() formulas in the Application Builder silently rendering nothing when the condition references an empty field",
+ "issue_origin": "github",
+ "issue_number": null,
+ "domain": "builder",
+ "bullet_points": [],
+ "created_at": "2026-04-21"
+}
\ No newline at end of file
diff --git a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentMentionNotification.vue b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentMentionNotification.vue
index f71d976183..5de6492fa6 100644
--- a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentMentionNotification.vue
+++ b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentMentionNotification.vue
@@ -27,7 +27,7 @@
diff --git a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentNotification.vue b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentNotification.vue
index 7af1f98b08..c85791d938 100644
--- a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentNotification.vue
+++ b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentNotification.vue
@@ -25,7 +25,7 @@
diff --git a/web-frontend/modules/core/utils/object.js b/web-frontend/modules/core/utils/object.js
index ba6095b0ee..80bc1a6ba6 100644
--- a/web-frontend/modules/core/utils/object.js
+++ b/web-frontend/modules/core/utils/object.js
@@ -111,12 +111,12 @@ export function isPromise(p) {
/**
* Get the value at `path` of `obj`, similar to Lodash `get` function.
*
- * @param {Object} obj The object that holds the value
+ * @param {Object} context The object that holds the value
* @param {string | Array[string]} path The path to the value or a list with the path parts
- * @param {any} defaultValue The value to return if the path is not found
- * @return {Object} The value held by the path
+ * @param {any} defaultValue The value to return if the path is not found (defaults to `null`)
+ * @return {Object} The value held by the path, or `defaultValue` if not found
*/
-export function getValueAtPath(context, path) {
+export function getValueAtPath(context, path, defaultValue = null) {
function _getValueAtPath(obj, keys) {
const [first, ...rest] = keys
if (first === undefined || first === null) {
@@ -124,13 +124,18 @@ export function getValueAtPath(context, path) {
}
if (obj === null || obj === undefined) {
- throw new Error(`Path '${path}' not found in context '${obj}'`)
+ return defaultValue
}
if (first in obj) {
return _getValueAtPath(obj[first], rest)
}
if (Array.isArray(obj) && first === '*') {
+ // When wildcarding an empty array with no remaining path parts,
+ // return an empty list (mirrors the backend's `get_value_at_path`).
+ if (obj.length === 0 && rest.length === 0) {
+ return []
+ }
const results = obj
// Call recursively this function transforming the `*` in the path in a list
// of indexes present in the object, e.g:
@@ -139,10 +144,9 @@ export function getValueAtPath(context, path) {
// Remove empty results
// Note: Don't exclude false values such as booleans, empty strings, etc.
.filter((result) => result !== null && result !== undefined)
- // Return null in case there are no results
- return results.length ? results : null
+ return results.length ? results : defaultValue
}
- return null
+ return defaultValue
}
const keys = typeof path === 'string' ? _.toPath(path) : path
return _getValueAtPath(context, keys)
diff --git a/web-frontend/test/unit/core/utils/object.spec.js b/web-frontend/test/unit/core/utils/object.spec.js
index 50e63ec8e9..618f37a1ea 100644
--- a/web-frontend/test/unit/core/utils/object.spec.js
+++ b/web-frontend/test/unit/core/utils/object.spec.js
@@ -110,4 +110,86 @@ describe('test utils object', () => {
}
expect(getValueAtPath(obj, path)).toStrictEqual(result)
})
+
+ describe('getValueAtPath defaultValue', () => {
+ const obj = {
+ a: { b: { c: 123 } },
+ nullable: null,
+ list: [{ d: 456 }, { d: 789, e: 111 }],
+ nested: [{ nested: [{ a: 1 }, { a: 2 }] }, { nested: [{ a: 3 }] }],
+ }
+
+ test('returns null by default when the path is not found', () => {
+ expect(getValueAtPath(obj, 'a.b.x')).toBe(null)
+ expect(getValueAtPath(obj, 'a.x.b')).toBe(null)
+ expect(getValueAtPath(obj, 'list.5.d')).toBe(null)
+ expect(getValueAtPath(obj, 'list.0.x')).toBe(null)
+ expect(getValueAtPath(obj, 'nested.0.nested.5.a')).toBe(null)
+ expect(getValueAtPath(obj, 'nested.5.nested.0.a')).toBe(null)
+ })
+
+ test('returns the provided default value when the path is not found', () => {
+ expect(getValueAtPath(obj, 'a.b.x', 'fallback')).toBe('fallback')
+ expect(getValueAtPath(obj, 'a.b.x', 0)).toBe(0)
+ expect(getValueAtPath(obj, 'a.b.x', '')).toBe('')
+ expect(getValueAtPath(obj, 'a.b.x', false)).toBe(false)
+ expect(getValueAtPath(obj, 'list.5.d', 'fallback')).toBe('fallback')
+ expect(getValueAtPath(obj, 'list.0.x', 'fallback')).toBe('fallback')
+ expect(getValueAtPath(obj, 'nested.0.nested.5.a', 'fallback')).toBe(
+ 'fallback'
+ )
+ expect(getValueAtPath(obj, 'nested.5.nested.0.a', 'fallback')).toBe(
+ 'fallback'
+ )
+ })
+ })
+
+ describe('getValueAtPath defaultValue with wildcards', () => {
+ const obj = {
+ list: [{ d: 456 }, { d: 789, e: 111 }],
+ nested: [{ nested: [{ a: 1 }, { a: 2 }] }, { nested: [{ a: 3 }] }],
+ empty: [],
+ }
+
+ test('returns null when every wildcard branch misses (default)', () => {
+ expect(getValueAtPath(obj, 'list.*.x')).toBe(null)
+ expect(getValueAtPath(obj, 'nested.*.nested.*.x')).toBe(null)
+ })
+
+ test('substitutes the default value at every missing leaf (backend-aligned)', () => {
+ expect(getValueAtPath(obj, 'list.*.x', 'fallback')).toStrictEqual([
+ 'fallback',
+ 'fallback',
+ ])
+ expect(
+ getValueAtPath(obj, 'nested.*.nested.*.x', 'fallback')
+ ).toStrictEqual([['fallback', 'fallback'], ['fallback']])
+ })
+
+ test('mixes existing values with the default value when only some branches miss', () => {
+ expect(getValueAtPath(obj, 'list.*.e', 'fallback')).toStrictEqual([
+ 'fallback',
+ 111,
+ ])
+ })
+
+ test('does not substitute the default value when wildcard branches all exist', () => {
+ expect(getValueAtPath(obj, 'list.*.d', 'fallback')).toStrictEqual([
+ 456, 789,
+ ])
+ expect(
+ getValueAtPath(obj, 'nested.*.nested.*.a', 'fallback')
+ ).toStrictEqual([[1, 2], [3]])
+ })
+
+ test('returns an empty list when wildcarding an empty array with no remaining path', () => {
+ expect(getValueAtPath(obj, 'empty.*')).toStrictEqual([])
+ expect(getValueAtPath(obj, 'empty.*', 'fallback')).toStrictEqual([])
+ })
+
+ test('returns the default value when wildcarding an empty array with a remaining path', () => {
+ expect(getValueAtPath(obj, 'empty.*.x')).toBe(null)
+ expect(getValueAtPath(obj, 'empty.*.x', 'fallback')).toBe('fallback')
+ })
+ })
})