From 0b512c6673ce30b342b0c142b0d4359d61da414d Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Wed, 25 Mar 2026 10:27:33 -0700 Subject: [PATCH 1/7] Update encodeFormDataQuote --- .../components/src/internal/url/utils.test.ts | 22 ++++++++++--------- packages/components/src/internal/url/utils.ts | 8 +++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/components/src/internal/url/utils.test.ts b/packages/components/src/internal/url/utils.test.ts index 6be8439677..ae04662474 100644 --- a/packages/components/src/internal/url/utils.test.ts +++ b/packages/components/src/internal/url/utils.test.ts @@ -8,20 +8,22 @@ describe('encodeFormDataQuote', () => { }); test('no relevant special character', () => { - expect(encodeFormDataQuote('a')).toBe('a') + expect(encodeFormDataQuote('a')).toBe('a'); expect(encodeFormDataQuote('$')).toBe('$'); - expect(encodeFormDataQuote('%')).toBe('%'); - expect(encodeFormDataQuote('%2522')).toBe('%2522'); + expect(encodeFormDataQuote('9')).toBe('9'); + expect(encodeFormDataQuote('[a]')).toBe('[a]'); }); test('encoded', () => { - expect(encodeFormDataQuote('"')).toBe('%22') - expect(encodeFormDataQuote('""')).toBe('%22%22'); - expect(encodeFormDataQuote('"22')).toBe('%2222'); - expect(encodeFormDataQuote('"a"')).toBe('%22a%22'); - expect(encodeFormDataQuote('a%22')).toBe('a%2522'); - expect(encodeFormDataQuote('"a%22')).toBe('%22a%2522'); - expect(encodeFormDataQuote('"a%222')).toBe('%22a%25222'); + expect(encodeFormDataQuote('"')).toBe('%_%22'); + expect(encodeFormDataQuote('%')).toBe('%_%25'); + expect(encodeFormDataQuote('%_beep')).toBe('%_%25_beep'); + expect(encodeFormDataQuote('""')).toBe('%_%22%22'); + expect(encodeFormDataQuote('"22')).toBe('%_%2222'); + expect(encodeFormDataQuote('"a"')).toBe('%_%22a%22'); + expect(encodeFormDataQuote('a%22')).toBe('%_a%2522'); + expect(encodeFormDataQuote('"a%22')).toBe('%_%22a%2522'); + expect(encodeFormDataQuote('"a%222')).toBe('%_%22a%25222'); }); }); diff --git a/packages/components/src/internal/url/utils.ts b/packages/components/src/internal/url/utils.ts index c09453ec17..bbc8818c45 100644 --- a/packages/components/src/internal/url/utils.ts +++ b/packages/components/src/internal/url/utils.ts @@ -6,12 +6,10 @@ export function encodeListResolverPath(containerPath: string): string { return ['$CPS', containerPath?.toLowerCase(), '$CPE'].join(''); } -// Issue 52925, 52119 +// Issue 52925, Issue 52119, Issue 54218 export function encodeFormDataQuote(key: string): string { - if (!key) - return key; - // need to replace %22, before replacing " to %22 - return key?.replaceAll('%22', '%2522').replaceAll('"', '%22'); + if (!key || !/[\\"%]/.test(key)) return key; + return '%_' + encodeURIComponent(key); } export function getIntegerSearchParam(searchParams: URLSearchParams, paramName: string): number { From a69d87eec92d5a36348386ca5a82748e2367cdff Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Thu, 26 Mar 2026 10:54:15 -0700 Subject: [PATCH 2/7] Bump @labkey/api --- packages/components/package-lock.json | 8 ++++---- packages/components/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 79110ee461..adfd21017a 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -10,7 +10,7 @@ "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", - "@labkey/api": "1.49.1", + "@labkey/api": "1.49.2-fb-encodeFormName.0", "@testing-library/dom": "~10.4.1", "@testing-library/jest-dom": "~6.9.1", "@testing-library/react": "~16.3.2", @@ -3746,9 +3746,9 @@ } }, "node_modules/@labkey/api": { - "version": "1.49.1", - "resolved": "https://labkey.jfrog.io/artifactory/api/npm/libs-client/@labkey/api/-/@labkey/api-1.49.1.tgz", - "integrity": "sha512-ClFIyggEDH4PC+HB4tnZpaOfIls4MgJugS4TmE6Y5xmVzBm8L442aF/gJFMqcZQ1MMNTP7swRHbfvSvJN5Cmyw==", + "version": "1.49.2-fb-encodeFormName.0", + "resolved": "https://labkey.jfrog.io/artifactory/api/npm/libs-client/@labkey/api/-/@labkey/api-1.49.2-fb-encodeFormName.0.tgz", + "integrity": "sha512-QEghEbSY+c+GbZc4vF98zyvaWRHgW/R6mt38skV3ZcdysIY1ZONnfCKR696pC+klgGKfus/POGLUDHQ58AOnEA==", "license": "Apache-2.0" }, "node_modules/@labkey/build": { diff --git a/packages/components/package.json b/packages/components/package.json index 7504be8c33..cd3b23a0be 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -53,7 +53,7 @@ "homepage": "https://github.com/LabKey/labkey-ui-components#readme", "dependencies": { "@hello-pangea/dnd": "18.0.1", - "@labkey/api": "1.49.1", + "@labkey/api": "1.49.2-fb-encodeFormName.0", "@testing-library/dom": "~10.4.1", "@testing-library/jest-dom": "~6.9.1", "@testing-library/react": "~16.3.2", From f70353c8de92f6b35f068e93fb178777a819d4d6 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Thu, 26 Mar 2026 10:58:36 -0700 Subject: [PATCH 3/7] Replace encodeFormDataQuote with Utils.encodeFormName --- packages/components/src/index.ts | 3 +- packages/components/src/internal/actions.ts | 8 ++--- .../src/internal/components/user/actions.ts | 8 ++--- .../components/src/internal/url/utils.test.ts | 29 +------------------ packages/components/src/internal/url/utils.ts | 6 ---- 5 files changed, 8 insertions(+), 46 deletions(-) diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 0a550f0493..27e58412fe 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -19,7 +19,7 @@ import { applyURL, AppURL, buildURL, spliceURL } from './internal/url/AppURL'; import { AppLink } from './internal/url/AppLink'; import { useAppNavigate } from './internal/url/useAppNavigate'; import { hasParameter, imageURL, toggleParameter } from './internal/url/ActionURL'; -import { encodeFormDataQuote, getIntegerSearchParam } from './internal/url/utils'; +import { getIntegerSearchParam } from './internal/url/utils'; import { Container } from './internal/components/base/models/Container'; import { hasAllPermissions, hasAnyPermissions, hasPermissions, User } from './internal/components/base/models/User'; import { getTextAlignClassName, GridColumn } from './internal/components/base/models/GridColumn'; @@ -1270,7 +1270,6 @@ export { EditorMode, EditorModel, EMPTY_NS_SEQUENCE_WARNING, - encodeFormDataQuote, encodePart, ensureAllFieldsInAllRows, EntityCreationType, diff --git a/packages/components/src/internal/actions.ts b/packages/components/src/internal/actions.ts index f5b1f06da3..77a10200dd 100644 --- a/packages/components/src/internal/actions.ts +++ b/packages/components/src/internal/actions.ts @@ -45,7 +45,6 @@ import { ViewInfo } from './ViewInfo'; import { createGridModelId } from './models'; import { SAMPLES_KEY } from './app/constants'; import { SCHEMAS } from './schemas'; -import { encodeFormDataQuote } from './url/utils'; export function selectAll( key: string, @@ -255,10 +254,10 @@ export function exportRows(type: EXPORT_TYPES, exportParams: Record const value = exportParams[key]; // Issue 52925: App export to csv/tsv ignores filter with column containing double quote - if (value instanceof Array) { - value.forEach(arrayValue => form.append(encodeFormDataQuote(key), arrayValue)); + if (Array.isArray(value)) { + value.forEach(arrayValue => form.append(Utils.encodeFormName(key), arrayValue)); } else { - form.append(encodeFormDataQuote(key), value); + form.append(Utils.encodeFormName(key), value); } }); @@ -285,7 +284,6 @@ export function exportRows(type: EXPORT_TYPES, exportParams: Record throw new Error('Unknown export type: ' + type); } - form.append('formDataEncoded', 'true'); Ajax.request({ url: ActionURL.buildURL(controller, action, containerPath), method: 'POST', diff --git a/packages/components/src/internal/components/user/actions.ts b/packages/components/src/internal/components/user/actions.ts index 2a5850ffbc..8e93278fec 100644 --- a/packages/components/src/internal/components/user/actions.ts +++ b/packages/components/src/internal/components/user/actions.ts @@ -1,12 +1,10 @@ import { OrderedMap } from 'immutable'; -import { Ajax, PermissionRoles, PermissionTypes, Utils } from '@labkey/api'; +import { Ajax, Utils } from '@labkey/api'; import { buildURL } from '../../url/AppURL'; -import { hasAllPermissions, hasAnyPermissions, User } from '../base/models/User'; +import { User } from '../base/models/User'; import { caseInsensitive } from '../../util/utils'; -import { APPLICATION_SECURITY_ROLES, SITE_SECURITY_ROLES } from '../administration/constants'; - import { formatDate, parseDate } from '../../util/Date'; import { ChangePasswordModel } from './models'; @@ -58,7 +56,7 @@ export function getUserDetailsRowData(user: User, data: OrderedMap, } if (value !== undefined) { - formData.append(key, value); + formData.append(Utils.encodeFormName(key), value); } }); diff --git a/packages/components/src/internal/url/utils.test.ts b/packages/components/src/internal/url/utils.test.ts index ae04662474..4f0ca343eb 100644 --- a/packages/components/src/internal/url/utils.test.ts +++ b/packages/components/src/internal/url/utils.test.ts @@ -1,31 +1,4 @@ -import { encodeFormDataQuote, getIntegerSearchParam } from './utils'; - -describe('encodeFormDataQuote', () => { - test('empty', () => { - expect(encodeFormDataQuote(null)).toBeNull(); - expect(encodeFormDataQuote(undefined)).toBeUndefined(); - expect(encodeFormDataQuote('')).toBe(''); - }); - - test('no relevant special character', () => { - expect(encodeFormDataQuote('a')).toBe('a'); - expect(encodeFormDataQuote('$')).toBe('$'); - expect(encodeFormDataQuote('9')).toBe('9'); - expect(encodeFormDataQuote('[a]')).toBe('[a]'); - }); - - test('encoded', () => { - expect(encodeFormDataQuote('"')).toBe('%_%22'); - expect(encodeFormDataQuote('%')).toBe('%_%25'); - expect(encodeFormDataQuote('%_beep')).toBe('%_%25_beep'); - expect(encodeFormDataQuote('""')).toBe('%_%22%22'); - expect(encodeFormDataQuote('"22')).toBe('%_%2222'); - expect(encodeFormDataQuote('"a"')).toBe('%_%22a%22'); - expect(encodeFormDataQuote('a%22')).toBe('%_a%2522'); - expect(encodeFormDataQuote('"a%22')).toBe('%_%22a%2522'); - expect(encodeFormDataQuote('"a%222')).toBe('%_%22a%25222'); - }); -}); +import { getIntegerSearchParam } from './utils'; describe('getInterSearchParam', () => { test('no param', () => { diff --git a/packages/components/src/internal/url/utils.ts b/packages/components/src/internal/url/utils.ts index bbc8818c45..4e78bf2d01 100644 --- a/packages/components/src/internal/url/utils.ts +++ b/packages/components/src/internal/url/utils.ts @@ -6,12 +6,6 @@ export function encodeListResolverPath(containerPath: string): string { return ['$CPS', containerPath?.toLowerCase(), '$CPE'].join(''); } -// Issue 52925, Issue 52119, Issue 54218 -export function encodeFormDataQuote(key: string): string { - if (!key || !/[\\"%]/.test(key)) return key; - return '%_' + encodeURIComponent(key); -} - export function getIntegerSearchParam(searchParams: URLSearchParams, paramName: string): number { const value = parseInt(searchParams.get(paramName), 10); return isNaN(value) ? undefined : value; From 98f12ad0b83b86193dc6efc2ba78a7f9cac0409f Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Thu, 26 Mar 2026 10:59:27 -0700 Subject: [PATCH 4/7] lint --- packages/components/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 27e58412fe..0b5e09369d 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -1539,7 +1539,6 @@ export { MAX_EDITABLE_GRID_ROWS, MAX_SELECTION_ACTION_ROWS, MEASUREMENT_UNITS, - UNITS_KIND, MemberType, MenuDivider, MenuHeader, @@ -1726,6 +1725,7 @@ export { UnidentifiedPill, UNIQUE_ID_FIND_FIELD, UnitModel, + UNITS_KIND, updateCellKeySampleIdMap, updateCellValuesForSampleIds, updateColumnLookup, From f9c41d4cc015171e12410d6332bc407ab9b1520f Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Mon, 30 Mar 2026 14:44:36 -0700 Subject: [PATCH 5/7] Bump @labkey/api --- packages/components/package-lock.json | 8 ++++---- packages/components/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index adfd21017a..6228a4255f 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -10,7 +10,7 @@ "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", - "@labkey/api": "1.49.2-fb-encodeFormName.0", + "@labkey/api": "1.50.0", "@testing-library/dom": "~10.4.1", "@testing-library/jest-dom": "~6.9.1", "@testing-library/react": "~16.3.2", @@ -3746,9 +3746,9 @@ } }, "node_modules/@labkey/api": { - "version": "1.49.2-fb-encodeFormName.0", - "resolved": "https://labkey.jfrog.io/artifactory/api/npm/libs-client/@labkey/api/-/@labkey/api-1.49.2-fb-encodeFormName.0.tgz", - "integrity": "sha512-QEghEbSY+c+GbZc4vF98zyvaWRHgW/R6mt38skV3ZcdysIY1ZONnfCKR696pC+klgGKfus/POGLUDHQ58AOnEA==", + "version": "1.50.0", + "resolved": "https://labkey.jfrog.io/artifactory/api/npm/libs-client/@labkey/api/-/@labkey/api-1.50.0.tgz", + "integrity": "sha512-1fiVQOP5UXvj1JW0LyJDtu3N8bgP95D9f7E+23w7BapabIT2xCvBj4YGRQZCvgSbW6pa+fH2Ayw542OFDWwfvA==", "license": "Apache-2.0" }, "node_modules/@labkey/build": { diff --git a/packages/components/package.json b/packages/components/package.json index cd3b23a0be..bd64675592 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -53,7 +53,7 @@ "homepage": "https://github.com/LabKey/labkey-ui-components#readme", "dependencies": { "@hello-pangea/dnd": "18.0.1", - "@labkey/api": "1.49.2-fb-encodeFormName.0", + "@labkey/api": "1.50.0", "@testing-library/dom": "~10.4.1", "@testing-library/jest-dom": "~6.9.1", "@testing-library/react": "~16.3.2", From f039039fb2a3998c0f4994825f8518fa6ce4566c Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Mon, 30 Mar 2026 14:45:26 -0700 Subject: [PATCH 6/7] Prepare release notes --- packages/components/releaseNotes/components.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/components/releaseNotes/components.md b/packages/components/releaseNotes/components.md index 498d48d60e..91011dcedc 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -1,6 +1,10 @@ # @labkey/components Components, models, actions, and utility functions for LabKey applications and pages +### version 7.26.1 +*Released*: 30 March 2026 +- Replace `encodeFormDataQuote` with `Utils.encodeFormName` + ### version 7.26.0 *Released*: 30 March 2026 - Update dependencies From 612d9a24065fa8b18340e902a0200ee9412537e0 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Mon, 30 Mar 2026 14:45:44 -0700 Subject: [PATCH 7/7] 7.26.1 --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 6228a4255f..f6b73331a3 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "7.26.0", + "version": "7.26.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "7.26.0", + "version": "7.26.1", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index bd64675592..db2d61ea12 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "7.26.0", + "version": "7.26.1", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [