From e6fe1907d8425622961d1e1ebfa0428798e71ff2 Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Mon, 22 Jun 2026 10:51:00 -0700 Subject: [PATCH 1/3] Fix Mothership container scoping test (#7781) --- .../src/org/labkey/mothership/MothershipController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mothership/src/org/labkey/mothership/MothershipController.java b/mothership/src/org/labkey/mothership/MothershipController.java index 63cde942bb9..4a73310718b 100644 --- a/mothership/src/org/labkey/mothership/MothershipController.java +++ b/mothership/src/org/labkey/mothership/MothershipController.java @@ -1923,8 +1923,9 @@ public void testUpdateInstallationContainerScoping() throws Exception public void testUpdateStackTraceContainerScoping() throws Exception { User admin = getAdmin(); - Container folderA = createContainer("A"); - Container folderB = createContainer("B"); + MothershipModule module = ModuleLoader.getInstance().getModule(MothershipModule.class); + Container folderA = createContainer("A", module); + Container folderB = createContainer("B", module); // An exception stack trace that lives in folder B (StackTraceHash is derived from the stack trace text) ExceptionStackTrace st = new ExceptionStackTrace(); From a7054031bf2339ed5e3fb2a6c9f5f2f4de41308c Mon Sep 17 00:00:00 2001 From: Marty Pradere Date: Sun, 28 Jun 2026 22:18:50 -0600 Subject: [PATCH 2/3] Fix LovCombo dropping string selections under native RegExp.escape (#7796) ## Rationale Newer browsers (Chrome, Firefox 140+) ship a native `RegExp.escape` that throws a `TypeError` on non-String input. `Ext.ux.form.LovCombo.setValue()` passed `JSON.stringify(value)` to `RegExp.escape` to avoid that crash, but `JSON.stringify()` quotes string values, so they no longer matched the raw, unquoted output of `getCheckedValue()` and every selection in a string-valued combo (e.g. the WNPRC EHR Time of Day multi-select) was silently dropped. Using `String()` yields a valid String for `RegExp.escape` without quoting string values, fixing both the numeric-`valueField` crash and the string-`valueField` regression. See https://github.com/LabKey/internal-issues/issues/1266. ## Related Pull Requests - https://github.com/LabKey/wnprc-modules/pull/982 - https://github.com/LabKey/premiumModules/pull/638 ## Changes - `core/webapp/Ext.ux.form.LovCombo.js`: in `setValue()`, pass `String(...)` rather than `JSON.stringify(...)` to `RegExp.escape`. --- core/webapp/Ext.ux.form.LovCombo.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/webapp/Ext.ux.form.LovCombo.js b/core/webapp/Ext.ux.form.LovCombo.js index 88bd0f0011c..5bf01396cb2 100644 --- a/core/webapp/Ext.ux.form.LovCombo.js +++ b/core/webapp/Ext.ux.form.LovCombo.js @@ -293,8 +293,10 @@ Ext.ux.form.LovCombo = Ext.extend(Ext.form.ComboBox, { this.store.suspendEvents(true); this.store.clearFilter(); this.store.each(function (r) { + // GH Issue 1266: String() (not JSON.stringify) so native RegExp.escape doesn't throw on a + // numeric valueField, while string values stay unquoted to match getCheckedValue() output. var checked = !(!v.match( - '(^|' + this.separator + ')' + RegExp.escape(JSON.stringify(r.get(this.valueField))) + '(^|' + this.separator + ')' + RegExp.escape(String(r.get(this.valueField))) + '(' + this.separator + '|$)')); r.set(this.checkField, checked); }, this); From c0ef8ce96d4bc9b5fb475496ca87b71fc147f408 Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Mon, 29 Jun 2026 14:06:38 -0700 Subject: [PATCH 3/3] Fix field error handling in BeanViewForm (#7799) --- api/src/org/labkey/api/data/BeanViewForm.java | 10 ++++++++++ api/src/org/labkey/api/data/TableViewForm.java | 9 +++++++-- api/src/org/labkey/api/query/UserSchemaAction.java | 3 +-- .../labkey/study/pipeline/FileAnalysisDatasetTask.java | 3 +-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/api/src/org/labkey/api/data/BeanViewForm.java b/api/src/org/labkey/api/data/BeanViewForm.java index e098b951fe4..752c04e732f 100644 --- a/api/src/org/labkey/api/data/BeanViewForm.java +++ b/api/src/org/labkey/api/data/BeanViewForm.java @@ -20,7 +20,10 @@ import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.DynaBean; import org.apache.commons.beanutils.DynaClass; +import org.labkey.api.action.BaseViewAction.BeanUtilsPropertyBindingResult; import org.labkey.api.action.HasBindParameters; +import org.labkey.api.action.NullSafeBindException; +import org.springframework.validation.BindException; import java.util.HashMap; import java.util.Map; @@ -86,6 +89,13 @@ public void setBean(K bean) setTypedValues(factory.toMap(bean, null), false); } + @Override + public BindException createErrors() + { + // Teaches Spring to resolve field names via string lookups instead of getters. e.g., errors.rejectValue(). + return new NullSafeBindException(new BeanUtilsPropertyBindingResult(this, "form")); + } + @Override public Map getValuesToBind() { diff --git a/api/src/org/labkey/api/data/TableViewForm.java b/api/src/org/labkey/api/data/TableViewForm.java index 66dcde6349d..36cadf8bf9c 100644 --- a/api/src/org/labkey/api/data/TableViewForm.java +++ b/api/src/org/labkey/api/data/TableViewForm.java @@ -30,7 +30,6 @@ import org.labkey.api.action.NullSafeBindException; import org.labkey.api.action.SpringActionController; import org.labkey.api.collections.CaseInsensitiveHashMap; -import org.labkey.api.ontology.Quantity; import org.labkey.api.query.FieldKey; import org.labkey.api.security.permissions.DeletePermission; import org.labkey.api.security.permissions.InsertPermission; @@ -897,10 +896,16 @@ else if (orig.getName().startsWith(ARRAY_MARKER) && orig.getValue()!=null) setValueToBind(pv.getName(), pv.getValue()); } - BindException errors = new NullSafeBindException(this, "form"); + BindException errors = createErrors(); validateBind(errors); return errors; } + + // Construct and return a BindException that's appropriate for this form + public BindException createErrors() + { + return new NullSafeBindException(this, "form"); + } } diff --git a/api/src/org/labkey/api/query/UserSchemaAction.java b/api/src/org/labkey/api/query/UserSchemaAction.java index 4f267a9c678..f2ba8aea605 100644 --- a/api/src/org/labkey/api/query/UserSchemaAction.java +++ b/api/src/org/labkey/api/query/UserSchemaAction.java @@ -17,7 +17,6 @@ import org.jetbrains.annotations.Nullable; import org.labkey.api.action.FormViewAction; -import org.labkey.api.action.NullSafeBindException; import org.labkey.api.action.SpringActionController; import org.labkey.api.attachments.SpringAttachmentFile; import org.labkey.api.audit.TransactionAuditProvider; @@ -79,7 +78,7 @@ public BindException bindParameters(PropertyValues m) throws Exception QueryUpdateForm command = new QueryUpdateForm(_table, getViewContext(), null); if (command.isBulkUpdate()) command.setValidateRequired(false); - BindException errors = new NullSafeBindException(new BeanUtilsPropertyBindingResult(command, "form")); + BindException errors = command.createErrors(); command.validateBind(errors); return errors; } diff --git a/study/src/org/labkey/study/pipeline/FileAnalysisDatasetTask.java b/study/src/org/labkey/study/pipeline/FileAnalysisDatasetTask.java index 136b69eacc1..bb6dceafc3f 100644 --- a/study/src/org/labkey/study/pipeline/FileAnalysisDatasetTask.java +++ b/study/src/org/labkey/study/pipeline/FileAnalysisDatasetTask.java @@ -16,7 +16,6 @@ package org.labkey.study.pipeline; import org.jetbrains.annotations.NotNull; -import org.labkey.api.action.BaseViewAction; import org.labkey.api.action.NullSafeBindException; import org.labkey.api.admin.PipelineJobLoggerGetter; import org.labkey.api.assay.transform.DataTransformService; @@ -114,7 +113,7 @@ else if (params.containsKey(DataTransformService.ORIGINAL_SOURCE_PATH)) for (String error : readerErrors) _ctx.getLogger().error(error); - BindException errors = new NullSafeBindException(new BaseViewAction.BeanUtilsPropertyBindingResult(this, "pipeline")); + BindException errors = new NullSafeBindException(this, "pipeline"); boolean allowDomainUpdates = true; if (_ctx.getProperties().containsKey(StudyImportContext.ALLOW_DOMAIN_UPDATES)) allowDomainUpdates = Boolean.parseBoolean(_ctx.getProperties().get(StudyImportContext.ALLOW_DOMAIN_UPDATES));