From 1a6c44ea4f034a2ffcb940fb5df8178979e10ed9 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Tue, 25 Aug 2026 09:37:34 -0700 Subject: [PATCH 1/4] Declare optional feature flag --- .../api-src/org/labkey/api/assay/plate/PlateService.java | 7 +++++++ assay/src/org/labkey/assay/AssayModule.java | 8 ++++++++ assay/src/org/labkey/assay/plate/PlateManager.java | 3 +++ 3 files changed, 18 insertions(+) diff --git a/assay/api-src/org/labkey/api/assay/plate/PlateService.java b/assay/api-src/org/labkey/api/assay/plate/PlateService.java index 230088b14e7..2633b918c96 100644 --- a/assay/api-src/org/labkey/api/assay/plate/PlateService.java +++ b/assay/api-src/org/labkey/api/assay/plate/PlateService.java @@ -30,6 +30,7 @@ import org.labkey.api.query.ValidationException; import org.labkey.api.security.User; import org.labkey.api.services.ServiceRegistry; +import org.labkey.api.settings.OptionalFeatureService; import org.labkey.api.view.ActionURL; import java.sql.SQLException; @@ -38,6 +39,7 @@ public interface PlateService { long NO_RUNID = -1; + String DEPRECATE_PRIMARY_PLATE_SET_FLAG = "primaryPlateSets"; class NameConflictException extends Exception { @@ -272,4 +274,9 @@ interface PlateDetailsResolver */ ActionURL getDetailsURL(Plate plate); } + + static boolean isPrimaryPlateSetsEnabled() + { + return OptionalFeatureService.get().isFeatureEnabled(DEPRECATE_PRIMARY_PLATE_SET_FLAG); + } } diff --git a/assay/src/org/labkey/assay/AssayModule.java b/assay/src/org/labkey/assay/AssayModule.java index 64adeea58f8..062512e22d9 100644 --- a/assay/src/org/labkey/assay/AssayModule.java +++ b/assay/src/org/labkey/assay/AssayModule.java @@ -201,6 +201,14 @@ protected void init() false, false, OptionalFeatureService.FeatureType.Deprecated)); + + OptionalFeatureService.get().addFeatureFlag(new OptionalFeatureFlag( + PlateService.DEPRECATE_PRIMARY_PLATE_SET_FLAG, + "Allow for Primary Plate Sets to be created", + "Enables the creation of Primary Plate Sets. This option will be removed in a future release of LabKey Server.", + false, + false, + OptionalFeatureService.FeatureType.Deprecated)); } @Override diff --git a/assay/src/org/labkey/assay/plate/PlateManager.java b/assay/src/org/labkey/assay/plate/PlateManager.java index 5c904cf209a..a94f2902eb4 100644 --- a/assay/src/org/labkey/assay/plate/PlateManager.java +++ b/assay/src/org/labkey/assay/plate/PlateManager.java @@ -121,6 +121,7 @@ import org.labkey.api.security.permissions.Permission; import org.labkey.api.security.permissions.ReadPermission; import org.labkey.api.security.permissions.UpdatePermission; +import org.labkey.api.settings.OptionalFeatureService; import org.labkey.api.sql.LabKeySql; import org.labkey.api.util.GUID; import org.labkey.api.util.PageFlowUtil; @@ -2886,6 +2887,8 @@ public PlateSetImpl createPlateSet( if (plateSet.getType() == null) plateSet.setType(PlateSetType.assay); + if (!PlateService.isPrimaryPlateSetsEnabled() && plateSet.getType() == PlateSetType.primary) + throw new ValidationException("The primary plate set feature is not enabled."); try (DbScope.Transaction tx = ensureTransaction()) { From 2c4820ae9850fb4bbc112d68379aae6061783b92 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Tue, 25 Aug 2026 10:46:58 -0700 Subject: [PATCH 2/4] PlateManagerTest --- .../labkey/assay/plate/PlateManagerTest.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/assay/src/org/labkey/assay/plate/PlateManagerTest.java b/assay/src/org/labkey/assay/plate/PlateManagerTest.java index 0846613c2c8..dcbb0c1fd73 100644 --- a/assay/src/org/labkey/assay/plate/PlateManagerTest.java +++ b/assay/src/org/labkey/assay/plate/PlateManagerTest.java @@ -24,6 +24,7 @@ import org.labkey.api.assay.plate.Plate; import org.labkey.api.assay.plate.PlateCustomField; import org.labkey.api.assay.plate.PlateLayoutHandler; +import org.labkey.api.assay.plate.PlateService; import org.labkey.api.assay.plate.PlateSet; import org.labkey.api.assay.plate.PlateSetType; import org.labkey.api.assay.plate.PlateType; @@ -55,6 +56,7 @@ import org.labkey.api.query.QueryUpdateService; import org.labkey.api.query.ValidationException; import org.labkey.api.security.User; +import org.labkey.api.settings.OptionalFeatureService; import org.labkey.api.util.JunitUtil; import org.labkey.api.util.Pair; import org.labkey.api.util.TestContext; @@ -99,6 +101,7 @@ public final class PlateManagerTest private static Container container; private static ExpSampleType sampleType; private static User user; + private static boolean primaryPlateSetFlag; private enum PlateMetadataFields { @@ -126,6 +129,10 @@ public static void setupTest() throws Exception container.setActiveModules(newActiveModules); } + // Configure optional feature flag + primaryPlateSetFlag = OptionalFeatureService.get().isFeatureEnabled(PlateService.DEPRECATE_PRIMARY_PLATE_SET_FLAG); + OptionalFeatureService.get().setFeatureEnabled(PlateService.DEPRECATE_PRIMARY_PLATE_SET_FLAG, true, user); + Domain domain = PlateManager.get().getPlateMetadataDomain(container, user); if (domain != null) domain.delete(user); @@ -201,11 +208,33 @@ public static void setupTest() throws Exception @AfterClass public static void cleanup() { + // Restore optional feature flag + OptionalFeatureService.get().setFeatureEnabled(PlateService.DEPRECATE_PRIMARY_PLATE_SET_FLAG, primaryPlateSetFlag, user); + deleteTestContainer(); container = null; user = null; } + @Test + public void testDeprecatePrimaryPlateSetFlag() + { + try + { + OptionalFeatureService.get().setFeatureEnabled(PlateService.DEPRECATE_PRIMARY_PLATE_SET_FLAG, false, user); + + PlateSetImpl plateSetImpl = new PlateSetImpl(); + plateSetImpl.setType(PlateSetType.primary); + plateSetImpl.setName("testDeprecatePrimaryPlateSetFlag"); + + assertCreatePlateSetThrows("The primary plate set feature is not enabled.", plateSetImpl, null, null); + } + finally + { + OptionalFeatureService.get().setFeatureEnabled(PlateService.DEPRECATE_PRIMARY_PLATE_SET_FLAG, true, user); + } + } + @Test public void testCreatePlateTemplate() throws Exception { From 860c782958578a9307a93fe19f246d2a86db1a70 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Tue, 25 Aug 2026 11:03:28 -0700 Subject: [PATCH 3/4] PlateSetPerfTest: opt-into optional feature flag --- .../labkey/assay/data/generator/PlateSetDataGenerator.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assay/src/org/labkey/assay/data/generator/PlateSetDataGenerator.java b/assay/src/org/labkey/assay/data/generator/PlateSetDataGenerator.java index 55be38c2279..19a952ad39d 100644 --- a/assay/src/org/labkey/assay/data/generator/PlateSetDataGenerator.java +++ b/assay/src/org/labkey/assay/data/generator/PlateSetDataGenerator.java @@ -23,6 +23,7 @@ import org.labkey.api.assay.plate.AssayPlateMetadataService; import org.labkey.api.assay.plate.Plate; import org.labkey.api.assay.plate.PlateCustomField; +import org.labkey.api.assay.plate.PlateService; import org.labkey.api.assay.plate.PlateSet; import org.labkey.api.assay.plate.PlateSetType; import org.labkey.api.assay.plate.PlateType; @@ -77,6 +78,12 @@ public PlateSetDataGenerator(PipelineJob job, PlateSetDataGenerator.Config confi public void generatePlateSets() { + if (!PlateService.isPrimaryPlateSetsEnabled()) + { + _log.error("PlateSetDataGenerator is not able to generate plate sets when primary plate sets are disabled."); + return; + } + Config config = getConfig(); if (validateConfiguration(config)) { From 3f3263c774bdc97016949b4c045352e54831c81d Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Tue, 25 Aug 2026 11:06:04 -0700 Subject: [PATCH 4/4] Unused import --- assay/src/org/labkey/assay/plate/PlateManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/assay/src/org/labkey/assay/plate/PlateManager.java b/assay/src/org/labkey/assay/plate/PlateManager.java index a94f2902eb4..39c29f1c289 100644 --- a/assay/src/org/labkey/assay/plate/PlateManager.java +++ b/assay/src/org/labkey/assay/plate/PlateManager.java @@ -121,7 +121,6 @@ import org.labkey.api.security.permissions.Permission; import org.labkey.api.security.permissions.ReadPermission; import org.labkey.api.security.permissions.UpdatePermission; -import org.labkey.api.settings.OptionalFeatureService; import org.labkey.api.sql.LabKeySql; import org.labkey.api.util.GUID; import org.labkey.api.util.PageFlowUtil;