From a8c92cdfec0bff87aa51436dab8a398498dcfdc2 Mon Sep 17 00:00:00 2001 From: alanv Date: Mon, 22 Jun 2026 13:59:02 -0500 Subject: [PATCH 1/8] LaboratoryController::EnsureAssayFieldsAction - Use HtmlStringBuilder --- .../org/labkey/laboratory/LaboratoryController.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index 20d2a874..f8256128 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -80,6 +80,7 @@ import org.labkey.api.util.ErrorRenderer; import org.labkey.api.util.ExceptionUtil; import org.labkey.api.util.FileUtil; +import org.labkey.api.util.HtmlStringBuilder; import org.labkey.api.util.JsonUtil; import org.labkey.api.util.Pair; import org.labkey.api.util.URLHelper; @@ -232,17 +233,19 @@ public ModelAndView getConfirmView(EnsureAssayFieldsForm form, BindException err { try { - StringBuilder sb = new StringBuilder(); - sb.append("This action will iterate all protocols for the assay " + form.getProviderName() + " and append any columns present in the definition, but lacking from that instance of the assay. The following changes will be made:

"); + HtmlStringBuilder sb = HtmlStringBuilder.of(); + sb.append("This action will iterate all protocols for the assay ") + .append(form.getProviderName()) + .unsafeAppend(" and append any columns present in the definition, but lacking from that instance of the assay. The following changes will be made:

"); List messages = AssayHelper.ensureAssayFields(getUser(), form.getProviderName(), form.isRenameConflicts(), true); for (String msg : messages) { - sb.append(msg).append("

"); + sb.append(msg).unsafeAppend("

"); } - sb.append("
Do you want to continue?"); + sb.unsafeAppend("
Do you want to continue?"); - return new HtmlView(sb.toString()); + return new HtmlView(sb.getHtmlString()); } catch (ChangePropertyDescriptorException e) { From 0be954c33d358431066f839b8066c55def403b96 Mon Sep 17 00:00:00 2001 From: alanv Date: Mon, 22 Jun 2026 13:59:38 -0500 Subject: [PATCH 2/8] LaboratoryController::SetTableIncrementValueAction - Use HtmlStringBuilder --- .../labkey/laboratory/LaboratoryController.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index f8256128..8c37ca86 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -311,25 +311,25 @@ public void validateCommand(SetTableIncrementForm form, Errors errors) @Override public ModelAndView getConfirmView(SetTableIncrementForm form, BindException errors) throws Exception { - StringBuilder sb = new StringBuilder(); - sb.append("This allows you to reset the current value for an auto-incrementing table

"); - sb.append(""); + HtmlStringBuilder sb = HtmlStringBuilder.of(); + sb.unsafeAppend("This allows you to reset the current value for an auto-incrementing table

"); + sb.unsafeAppend("
"); String schema = form.getSchemaName() == null ? "" : form.getSchemaName(); - sb.append(""); + sb.unsafeAppend(""); String query = form.getQueryName() == null ? "" : form.getQueryName(); - sb.append(""); + sb.unsafeAppend(""); ContainerIncrementingTable ti = getTable(schema, query, errors, false); Integer value = null; if (ti != null) value = ti.getCurrentId(getContainer()); - sb.append(""); - sb.append("
Schema:
Schema:
Query:
Query:
Value:

Do you want to continue?"); + sb.unsafeAppend("Value:"); + sb.unsafeAppend("
Do you want to continue?"); - return new HtmlView(sb.toString()); + return new HtmlView(sb.getHtmlString()); } @Override From bd8be1d6736cf9aaeffafd5f769dc923a2cc92d2 Mon Sep 17 00:00:00 2001 From: alanv Date: Mon, 22 Jun 2026 14:01:08 -0500 Subject: [PATCH 3/8] LaboratoryController::InitContainerIncrementingTableAction - Use HtmlStringBuilder --- .../labkey/laboratory/LaboratoryController.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index 8c37ca86..9f5970cf 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -510,20 +510,20 @@ public void validateCommand(SetTableIncrementForm form, Errors errors) @Override public ModelAndView getConfirmView(SetTableIncrementForm form, BindException errors) throws Exception { - StringBuilder sb = new StringBuilder(); - sb.append("This allows you to initialize the autoincrementing column for the provided schema/query

"); - sb.append("This is very rarely required and was created as a helper for admins with a good deal of knowledge about this module. Under most cases these columns will be automatically populated and you will not need to worry about this. If you are unsure about this page, please post on the LabKey help forums, which are read by the authors of this module.

"); - sb.append(""); + HtmlStringBuilder sb = HtmlStringBuilder.of(); + sb.unsafeAppend("This allows you to initialize the autoincrementing column for the provided schema/query

"); + sb.unsafeAppend("This is very rarely required and was created as a helper for admins with a good deal of knowledge about this module. Under most cases these columns will be automatically populated and you will not need to worry about this. If you are unsure about this page, please post on the LabKey help forums, which are read by the authors of this module.

"); + sb.unsafeAppend("
"); String schema = form.getSchemaName() == null ? "" : form.getSchemaName(); - sb.append(""); + sb.unsafeAppend(""); String query = form.getQueryName() == null ? "" : form.getQueryName(); - sb.append(""); + sb.unsafeAppend(""); - sb.append("
Schema:
Schema:
Query:
Query:

Do you want to continue?"); + sb.unsafeAppend("
Do you want to continue?"); - return new HtmlView(sb.toString()); + return new HtmlView(sb.getHtmlString()); } From 3b0f72bd14f6c7665cf8b5d780aac341a304cf69 Mon Sep 17 00:00:00 2001 From: alanv Date: Mon, 22 Jun 2026 14:16:02 -0500 Subject: [PATCH 4/8] LaboratoryController::EnsureIndexesAction - Use HtmlStringBuilder --- .../org/labkey/laboratory/LaboratoryController.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index 9f5970cf..9d1bec9a 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -80,6 +80,7 @@ import org.labkey.api.util.ErrorRenderer; import org.labkey.api.util.ExceptionUtil; import org.labkey.api.util.FileUtil; +import org.labkey.api.util.HtmlString; import org.labkey.api.util.HtmlStringBuilder; import org.labkey.api.util.JsonUtil; import org.labkey.api.util.Pair; @@ -174,15 +175,17 @@ public void validateCommand(Object form, Errors errors) @Override public ModelAndView getConfirmView(Object form, BindException errors) throws Exception { - StringBuilder msg = new StringBuilder(); - msg.append("Certain assays can have performance improved by the addition of indexes, which can be suggested by modules. The following indexes are recommended for the assays installed on this server:

"); + HtmlStringBuilder sb = HtmlStringBuilder.of(); + sb.append("Certain assays can have performance improved by the addition of indexes, which can be suggested by modules. The following indexes are recommended for the assays installed on this server:

"); List msgs = LaboratoryManager.get().createIndexes(getUser(), false, false); - msg.append(StringUtils.join(msgs, "
")); - msg.append("

Do you want to continue?"); + for (String msg : msgs) + sb.append(msg).unsafeAppend("
"); + + sb.unsafeAppend("

Do you want to continue?

"); - return new HtmlView(msg.toString()); + return new HtmlView(sb.getHtmlString()); } @Override From f68e76fe9ff923e5e3fd5114c2310a9bc02d6bd4 Mon Sep 17 00:00:00 2001 From: alanv Date: Mon, 22 Jun 2026 14:16:33 -0500 Subject: [PATCH 5/8] LaboratoryController::PrepareExptRunAction - Use HtmlString --- .../src/org/labkey/laboratory/LaboratoryController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index 9d1bec9a..0250ee46 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -129,13 +129,13 @@ public ModelAndView getView(PlanExptRunForm form, BindException errors) throws E Integer assayId = form.getAssayId(); if (assayId == null) { - return new HtmlView("Error: must provide a rowId for the assay"); + return new HtmlView(HtmlString.of("Error: must provide a rowId for the assay")); } AssayDataProvider ad = LaboratoryService.get().getDataProviderForAssay(assayId); if (ad == null || !ad.supportsRunTemplates()) { - return new HtmlView("Error: this assay does not support requests"); + return new HtmlView(HtmlString.of("Error: this assay does not support requests")); } Module labModule = ModuleLoader.getInstance().getModule(LaboratoryModule.NAME); From 362afe8419a7cb96663ee2275c6a14942123d060 Mon Sep 17 00:00:00 2001 From: alanv Date: Mon, 22 Jun 2026 14:16:45 -0500 Subject: [PATCH 6/8] LaboratoryController::InitWorkbooksAction - Use HtmlString --- laboratory/src/org/labkey/laboratory/LaboratoryController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index 0250ee46..017b8857 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -474,7 +474,7 @@ public void validateCommand(Object form, Errors errors) @Override public ModelAndView getConfirmView(Object form, BindException errors) throws Exception { - return new HtmlView("This action will iterate all workbooks in the current folder and create laboratory experiments for them as needed"); + return new HtmlView(HtmlString.of("This action will iterate all workbooks in the current folder and create laboratory experiments for them as needed")); } @Override From 3f25e2b1a927019d0a3c67ca7ec27694613c5b11 Mon Sep 17 00:00:00 2001 From: alanv Date: Mon, 22 Jun 2026 14:16:55 -0500 Subject: [PATCH 7/8] LaboratoryController::ResetLaboratoryFoldersAction - Use HtmlString --- laboratory/src/org/labkey/laboratory/LaboratoryController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index 017b8857..566281f1 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -585,7 +585,8 @@ public void validateCommand(Object form, Errors errors) @Override public ModelAndView getConfirmView(Object form, BindException errors) throws Exception { - return new HtmlView("This action will reset webparts and tabs for the current folder and all children to the default Laboratory FolderType, if these folders are either Laboratory Folders or Expt Workbooks"); + HtmlString message = HtmlString.of("This action will reset webparts and tabs for the current folder and all children to the default Laboratory FolderType, if these folders are either Laboratory Folders or Expt Workbooks"); + return new HtmlView(message); } @Override From 95253b1991bfe919065ce280915b534b2d4d5b7d Mon Sep 17 00:00:00 2001 From: alanv Date: Mon, 22 Jun 2026 14:57:38 -0500 Subject: [PATCH 8/8] LaboratoryController: Use java DOM API instead of HtmlStringBuilder with unsafeAppend --- .../laboratory/LaboratoryController.java | 86 +++++++++---------- 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index 566281f1..7f80a6db 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -81,7 +81,6 @@ import org.labkey.api.util.ExceptionUtil; import org.labkey.api.util.FileUtil; import org.labkey.api.util.HtmlString; -import org.labkey.api.util.HtmlStringBuilder; import org.labkey.api.util.JsonUtil; import org.labkey.api.util.Pair; import org.labkey.api.util.URLHelper; @@ -109,6 +108,16 @@ import java.util.Map; import java.util.Set; +import static org.labkey.api.util.DOM.BR; +import static org.labkey.api.util.DOM.INPUT; +import static org.labkey.api.util.DOM.P; +import static org.labkey.api.util.DOM.TABLE; +import static org.labkey.api.util.DOM.TD; +import static org.labkey.api.util.DOM.TR; +import static org.labkey.api.util.DOM.at; +import static org.labkey.api.util.DOM.createHtmlFragment; +import static org.labkey.api.util.DOM.Attribute.style; + public class LaboratoryController extends SpringActionController { @@ -175,17 +184,13 @@ public void validateCommand(Object form, Errors errors) @Override public ModelAndView getConfirmView(Object form, BindException errors) throws Exception { - HtmlStringBuilder sb = HtmlStringBuilder.of(); - sb.append("Certain assays can have performance improved by the addition of indexes, which can be suggested by modules. The following indexes are recommended for the assays installed on this server:

"); - List msgs = LaboratoryManager.get().createIndexes(getUser(), false, false); - for (String msg : msgs) - sb.append(msg).unsafeAppend("
"); - - sb.unsafeAppend("

Do you want to continue?

"); - - return new HtmlView(sb.getHtmlString()); + return new HtmlView(createHtmlFragment( + "Certain assays can have performance improved by the addition of indexes, which can be suggested by modules. The following indexes are recommended for the assays installed on this server:", + P(msgs.stream().map(msg -> createHtmlFragment(msg, BR()))), + P("Do you want to continue?") + )); } @Override @@ -236,19 +241,12 @@ public ModelAndView getConfirmView(EnsureAssayFieldsForm form, BindException err { try { - HtmlStringBuilder sb = HtmlStringBuilder.of(); - sb.append("This action will iterate all protocols for the assay ") - .append(form.getProviderName()) - .unsafeAppend(" and append any columns present in the definition, but lacking from that instance of the assay. The following changes will be made:

"); List messages = AssayHelper.ensureAssayFields(getUser(), form.getProviderName(), form.isRenameConflicts(), true); - for (String msg : messages) - { - sb.append(msg).unsafeAppend("

"); - } - - sb.unsafeAppend("
Do you want to continue?"); - - return new HtmlView(sb.getHtmlString()); + return new HtmlView(createHtmlFragment( + "This action will iterate all protocols for the assay " + form.getProviderName() + " and append any columns present in the definition, but lacking from that instance of the assay. The following changes will be made:", BR(), BR(), + messages.stream().map(msg -> createHtmlFragment(msg, BR(), BR())), + BR(), "Do you want to continue?" + )); } catch (ChangePropertyDescriptorException e) { @@ -314,25 +312,23 @@ public void validateCommand(SetTableIncrementForm form, Errors errors) @Override public ModelAndView getConfirmView(SetTableIncrementForm form, BindException errors) throws Exception { - HtmlStringBuilder sb = HtmlStringBuilder.of(); - sb.unsafeAppend("This allows you to reset the current value for an auto-incrementing table

"); - sb.unsafeAppend(""); - String schema = form.getSchemaName() == null ? "" : form.getSchemaName(); - sb.unsafeAppend(""); - String query = form.getQueryName() == null ? "" : form.getQueryName(); - sb.unsafeAppend(""); ContainerIncrementingTable ti = getTable(schema, query, errors, false); - Integer value = null; + Integer currentId = null; if (ti != null) - value = ti.getCurrentId(getContainer()); - - sb.unsafeAppend(""); - sb.unsafeAppend("
Schema:
Query:
Value:

Do you want to continue?"); + currentId = ti.getCurrentId(getContainer()); - return new HtmlView(sb.getHtmlString()); + return new HtmlView(createHtmlFragment( + "This allows you to reset the current value for an auto-incrementing table", BR(), BR(), + TABLE(at(style, "border-collapse: collapse;"), + TR(TD("Schema:"), TD(INPUT(at().name("schema").value(schema)))), + TR(TD("Query:"), TD(INPUT(at().name("query").value(query)))), + TR(TD("Value:"), TD(INPUT(at().name("value").value(currentId == null ? "" : currentId.toString())))) + ), + BR(), "Do you want to continue?" + )); } @Override @@ -513,20 +509,18 @@ public void validateCommand(SetTableIncrementForm form, Errors errors) @Override public ModelAndView getConfirmView(SetTableIncrementForm form, BindException errors) throws Exception { - HtmlStringBuilder sb = HtmlStringBuilder.of(); - sb.unsafeAppend("This allows you to initialize the autoincrementing column for the provided schema/query

"); - sb.unsafeAppend("This is very rarely required and was created as a helper for admins with a good deal of knowledge about this module. Under most cases these columns will be automatically populated and you will not need to worry about this. If you are unsure about this page, please post on the LabKey help forums, which are read by the authors of this module.

"); - sb.unsafeAppend(""); - String schema = form.getSchemaName() == null ? "" : form.getSchemaName(); - sb.unsafeAppend(""); - String query = form.getQueryName() == null ? "" : form.getQueryName(); - sb.unsafeAppend(""); - - sb.unsafeAppend("
Schema:
Query:

Do you want to continue?"); - return new HtmlView(sb.getHtmlString()); + return new HtmlView(createHtmlFragment( + "This allows you to initialize the autoincrementing column for the provided schema/query", BR(), BR(), + "This is very rarely required and was created as a helper for admins with a good deal of knowledge about this module. Under most cases these columns will be automatically populated and you will not need to worry about this. If you are unsure about this page, please post on the LabKey help forums, which are read by the authors of this module.", BR(), BR(), + TABLE(at(style, "border-collapse: collapse;"), + TR(TD("Schema:"), TD(INPUT(at().name("schema").value(schema)))), + TR(TD("Query:"), TD(INPUT(at().name("query").value(query)))) + ), + BR(), "Do you want to continue?" + )); }