From 4b2d7f9a6ce66a918516f8aff28d66a29fdada29 Mon Sep 17 00:00:00 2001 From: bbimber Date: Mon, 7 Jul 2025 14:01:26 -0700 Subject: [PATCH 01/18] Read subjectId off URL --- .../web/LDK/panel/TabbedReportPanel.js | 15 ++--- .../web/laboratory/panel/DataBrowserPanel.js | 58 ++++++++++++++++++ .../labkey/laboratory/view/dataBrowser.jsp | 61 ++++--------------- 3 files changed, 74 insertions(+), 60 deletions(-) create mode 100644 laboratory/resources/web/laboratory/panel/DataBrowserPanel.js diff --git a/LDK/resources/web/LDK/panel/TabbedReportPanel.js b/LDK/resources/web/LDK/panel/TabbedReportPanel.js index a910c718..78b0a760 100644 --- a/LDK/resources/web/LDK/panel/TabbedReportPanel.js +++ b/LDK/resources/web/LDK/panel/TabbedReportPanel.js @@ -1071,8 +1071,8 @@ Ext4.define('LDK.panel.TabbedReportPanel', { return filter ? Ext4.apply({}, filter) : null; }, - getFiltersFromUrl: function(){ - var context = {}; + getFiltersFromUrl: function(context){ + context = context || {}; if (document.location.hash){ var token = document.location.hash.split('#'); @@ -1302,18 +1302,11 @@ Ext4.define('LDK.panel.TabbedReportPanel', { if (report) this.silentlySetActiveTab(report); } - else if (this.defaultTab) { - var tab = tabPanel.down('#' + this.defaultTab); - tabPanel.suspendEvents(); - tab.suspendEvents(); - tabPanel.setActiveTab(tab); - tab.resumeEvents(); - tabPanel.resumeEvents(); - } //populate initial fields var shouldChange = true; - this.initialContext = this.getFiltersFromUrl(); + + this.initialContext = this.getFiltersFromUrl(this.initialContext); var filterType = this.initialContext.inputType; if (filterType){ var radio = this.down('#inputType'); diff --git a/laboratory/resources/web/laboratory/panel/DataBrowserPanel.js b/laboratory/resources/web/laboratory/panel/DataBrowserPanel.js new file mode 100644 index 00000000..5c47e0f5 --- /dev/null +++ b/laboratory/resources/web/laboratory/panel/DataBrowserPanel.js @@ -0,0 +1,58 @@ +Ext4.define('Laboratory.panel.DataBrowserPanel', { + extend: 'LDK.panel.TabbedReportPanel', + + initComponent: function(){ + Ext4.ns('Laboratory.tabbedReports'); + + Ext4.apply(this, { + //defaultReport: 'abstract', + reportNamespace: Laboratory.tabbedReports + }); + + Ext4.Msg.wait('Loading...'); + Laboratory.Utils.getDataItems({ + types: ['tabbedReports'], + scope: this, + success: this.onDataLoad, + failure: LDK.Utils.getErrorCallback() + }); + + this.callParent(); + }, + + onDataLoad: function(results){ + Ext4.Msg.hide(); + this.reports = []; + Ext4.each(results.tabbedReports, function(report){ + LDK.Assert.assertNotEmpty('Tabbed Report is null', report); + if (report && report.key){ + report.id = report.key.replace(/:/g, '_'); + report.category = report.reportCategory; + + if (report.targetContainer){ + report.containerPath = report.targetContainer; + } + this.reports.push(report); + } + }, this); + + this.reports = LDK.Utils.sortByProperty(this.reports, 'name', false); + this.reports = LDK.Utils.sortByProperty(this.reports, 'reportCategory', false); + + this.createTabPanel(); + }, + + filterTypes: [{ + xtype: 'ldk-singlesubjectfiltertype', + inputValue: LDK.panel.SingleSubjectFilterType.filterName, + label: LDK.panel.SingleSubjectFilterType.DEFAULT_LABEL + },{ + xtype: 'ldk-multisubjectfiltertype', + inputValue: LDK.panel.MultiSubjectFilterType.filterName, + label: LDK.panel.MultiSubjectFilterType.label + },{ + xtype: 'ldk-nofiltersfiltertype', + inputValue: LDK.panel.NoFiltersFilterType.filterName, + label: LDK.panel.NoFiltersFilterType.label + }] +}); \ No newline at end of file diff --git a/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp b/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp index 70beda3c..137d72de 100644 --- a/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp +++ b/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp @@ -27,6 +27,11 @@ public void addClientDependencies(ClientDependencies dependencies) { dependencies.add("laboratory.context"); + dependencies.add("/laboratory/panel/DataBrowserPanel.js"); + dependencies.add("LDK/panel/AbstractFilterType.js"); + dependencies.add("LDK/panel/SingleSubjectFilterType.js"); + dependencies.add("LDK/panel/MultiSubjectFilterType.js"); + dependencies.add("LDK/panel/NoFiltersFilterType.js"); } private String getFilterConfig() @@ -59,53 +64,13 @@
\ No newline at end of file From fdfdf8d17e79f0ff5284123cbff9c984faf9dbd5 Mon Sep 17 00:00:00 2001 From: bbimber Date: Mon, 7 Jul 2025 14:44:11 -0700 Subject: [PATCH 02/18] Allow admin to set DataBrowser default report --- .../api/laboratory/TabbedReportItem.java | 24 ++++++++-- .../panel/CustomizeDataBrowserPanel.js | 20 ++++++--- .../web/laboratory/panel/DataBrowserPanel.js | 12 ++++- .../laboratory/LaboratoryController.java | 44 +++++++++++++++++-- 4 files changed, 87 insertions(+), 13 deletions(-) diff --git a/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java b/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java index 8859393f..d0dc301a 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java +++ b/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java @@ -46,7 +46,6 @@ public class TabbedReportItem extends AbstractNavItem private final Map _additionalKeys = new HashMap<>(); public static final String OVERRIDES_PROP_KEY = "laboratory.tabItemOverride"; - public static final String FILTER_PROP_KEY = "laboratory.tabItemFilterOverride"; protected static final Logger _log = LogManager.getLogger(TabbedReportItem.class); @@ -177,6 +176,23 @@ public static String getOverridesPropertyKey(NavItem item) return item.getDataProvider().getKey() + "||tabReport||" + item.getReportCategory() + "||" + item.getName() + "||" + item.getLabel(); } + public boolean hasOverride(Container c, String propName) + { + Map map = PropertyManager.getProperties(c, OVERRIDES_PROP_KEY); + if (!map.containsKey(getPropertyManagerKey())) + { + return false; + } + + JSONObject props = new JSONObject(map.get(getPropertyManagerKey())); + if (!props.has(propName)) + { + return false; + } + + return true; + } + public static void applyOverrides(NavItem item, Container c, JSONObject json) { Map map = PropertyManager.getProperties(c, OVERRIDES_PROP_KEY); @@ -188,9 +204,9 @@ public static void applyOverrides(NavItem item, Container c, JSONObject json) if (props.has("reportCategory")) json.put("reportCategory", props.get("reportCategory")); - // retained for settings saved prior to refactor - else if (props.has("category")) - json.put("reportCategory", props.get("category")); + + if (props.has("isDefaultReport")) + json.put("isDefaultReport", props.get("isDefaultReport")); } } } diff --git a/laboratory/resources/web/laboratory/panel/CustomizeDataBrowserPanel.js b/laboratory/resources/web/laboratory/panel/CustomizeDataBrowserPanel.js index 49b3b789..0df95d10 100644 --- a/laboratory/resources/web/laboratory/panel/CustomizeDataBrowserPanel.js +++ b/laboratory/resources/web/laboratory/panel/CustomizeDataBrowserPanel.js @@ -69,6 +69,9 @@ Ext4.define('Laboratory.panel.CustomizeDataBrowserPanel', { },{ html: 'Visible?', style: 'padding-bottom: 5px;margin-left: 5px;' + },{ + html: 'Default Report?', + style: 'padding-bottom: 5px;margin-left: 5px;' }]; items = LDK.Utils.sortByProperty(items, 'name', false); @@ -90,9 +93,14 @@ Ext4.define('Laboratory.panel.CustomizeDataBrowserPanel', { width: 300, value: item.label },{ - xtype: 'displayfield', - value: item.visible, + xtype: 'checkbox', + checked: item.visible, style: 'margin-left: 15px;' + },{ + xtype: 'radio', + name: 'isDefaultReport', + inputValue: true, + checked: item.isDefaultReport }]); }, this); @@ -100,7 +108,7 @@ Ext4.define('Laboratory.panel.CustomizeDataBrowserPanel', { itemId: 'theTable', layout: { type: 'table', - columns: 4 + columns: 5 }, border: false, defaults: { @@ -117,15 +125,17 @@ Ext4.define('Laboratory.panel.CustomizeDataBrowserPanel', { doSave: function(btn){ var toSave = {}; var items = btn.up('form').down('#theTable').items; - var cols = 4; + var cols = 5; var rows = (items.getCount() / cols); for (var i=1;i results = new HashMap<>(); WritablePropertyMap propMap = PropertyManager.getWritableProperties(getContainer(), TabbedReportItem.OVERRIDES_PROP_KEY, true); + WritablePropertyMap visibilityMap = PropertyManager.getWritableProperties(getContainer(), NavItem.PROPERTY_CATEGORY, true); + boolean shouldSaveVisibility = false; List tabbedReports = LaboratoryService.get().getTabbedReportItems(getContainer(), getUser()); Map reportMap = new HashMap(); @@ -1669,7 +1671,7 @@ public ApiResponse execute(JsonDataForm form, BindException errors) JSONObject json = new JSONObject(form.getJsonData()); for (String key : json.keySet()) { - JSONObject toSave= new JSONObject(); + JSONObject toSave = new JSONObject(); TabbedReportItem ti = reportMap.get(key); if (ti == null) @@ -1685,13 +1687,49 @@ public ApiResponse execute(JsonDataForm form, BindException errors) if (reportCategory != null && !ti.getReportCategory().equals(reportCategory)) toSave.put("reportCategory", reportCategory); - if (toSave.keySet().size() > 0) + String isDefaultReport = StringUtils.trimToNull(props.optString("isDefaultReport")); + if (isDefaultReport != null) + { + if (!ti.hasOverride(getContainer(), "isDefaultReport")) + { + if ("true".equals(isDefaultReport)) + { + toSave.put("isDefaultReport", isDefaultReport); + } + } + else + { + toSave.put("isDefaultReport", isDefaultReport); + } + } + + String isVisible = StringUtils.trimToNull(props.optString("isVisible")); + if (isVisible != null) + { + if (!isVisible.equals(visibilityMap.get(ti.getPropertyManagerKey()))) + { + visibilityMap.put(ti.getPropertyManagerKey(), isVisible); + shouldSaveVisibility = true; + } + } + + if (!toSave.isEmpty()) + { propMap.put(key, toSave.toString()); - else propMap.remove(key); + } + else + { + propMap.remove(key); + } } propMap.save(); + if (shouldSaveVisibility) + { + visibilityMap.save(); + } + results.put("success", true); return new ApiSimpleResponse(results); } From c85442de73f63c74d9dc5a6b518559846acea766 Mon Sep 17 00:00:00 2001 From: bbimber Date: Fri, 8 Aug 2025 07:11:56 -0700 Subject: [PATCH 03/18] More visible link to notification service admin --- LDK/src/org/labkey/ldk/LDKModule.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/LDK/src/org/labkey/ldk/LDKModule.java b/LDK/src/org/labkey/ldk/LDKModule.java index 7930a41b..78b1a83b 100644 --- a/LDK/src/org/labkey/ldk/LDKModule.java +++ b/LDK/src/org/labkey/ldk/LDKModule.java @@ -31,6 +31,9 @@ import org.labkey.api.security.permissions.ReadPermission; import org.labkey.api.settings.AdminConsole; import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.view.DeveloperMenuNavTrees; +import org.labkey.api.view.NavTree; +import org.labkey.api.view.PopupDeveloperView; import org.labkey.api.view.WebPartFactory; import org.labkey.ldk.notification.NotificationServiceImpl; import org.labkey.ldk.notification.SiteSummaryNotification; @@ -84,6 +87,17 @@ protected void init() protected void doStartupAfterSpringConfig(ModuleContext moduleContext) { AdminConsole.addLink(AdminConsole.SettingsLinkType.Management, "notification service admin", DetailsURL.fromString("/ldk/notificationSiteAdmin.view").getActionURL(), AdminOperationsPermission.class); + PopupDeveloperView.registerMenuProvider((c, user, trees) -> { + if (c.isRoot() & user.hasSiteAdminPermission()) + { + trees.add(DeveloperMenuNavTrees.Section.tools, new NavTree("Notification Service Admin", DetailsURL.fromString("ldk/notificationSiteAdmin.view", c).getActionURL())); + } + else if (!c.isRoot() & c.hasPermission(user, AdminPermission.class)) + { + trees.add(DeveloperMenuNavTrees.Section.tools, new NavTree("Notification Service Admin", DetailsURL.fromString("ldk/notificationAdmin.view", c).getActionURL())); + } + }); + AdminConsole.addLink(AdminConsole.SettingsLinkType.Management, "file root usage summary", DetailsURL.fromString("/ldk/folderSizeSummary.view").getActionURL(), ReadPermission.class); if (isSqlServer()) From 8c329ce18c8f3cecd4c0ae6482cf5d9060b2002f Mon Sep 17 00:00:00 2001 From: bbimber Date: Tue, 19 Aug 2025 12:43:30 -0700 Subject: [PATCH 04/18] Consider container when truncating data in AbstractDataDefinedTable --- .../org/labkey/api/ldk/table/AbstractDataDefinedTable.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/LDK/api-src/org/labkey/api/ldk/table/AbstractDataDefinedTable.java b/LDK/api-src/org/labkey/api/ldk/table/AbstractDataDefinedTable.java index a974a4d7..cef47256 100644 --- a/LDK/api-src/org/labkey/api/ldk/table/AbstractDataDefinedTable.java +++ b/LDK/api-src/org/labkey/api/ldk/table/AbstractDataDefinedTable.java @@ -194,9 +194,13 @@ protected Map updateRow(User user, Container container, Map Date: Tue, 19 Aug 2025 12:45:08 -0700 Subject: [PATCH 05/18] Avoid hard-coding container --- .../org/labkey/api/ldk/table/AbstractDataDefinedTable.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/LDK/api-src/org/labkey/api/ldk/table/AbstractDataDefinedTable.java b/LDK/api-src/org/labkey/api/ldk/table/AbstractDataDefinedTable.java index cef47256..a4e67d92 100644 --- a/LDK/api-src/org/labkey/api/ldk/table/AbstractDataDefinedTable.java +++ b/LDK/api-src/org/labkey/api/ldk/table/AbstractDataDefinedTable.java @@ -194,9 +194,10 @@ protected Map updateRow(User user, Container container, Map Date: Thu, 21 Aug 2025 08:59:57 -0700 Subject: [PATCH 06/18] Improve LabModulesTest --- .../external/labModules/LabModulesTest.java | 275 +++++++++--------- 1 file changed, 144 insertions(+), 131 deletions(-) diff --git a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java index 9dd1ccb6..9f5065fc 100644 --- a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java +++ b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java @@ -100,93 +100,93 @@ public class LabModulesTest extends BaseWebDriverTest implements AdvancedSqlTest protected static final String IMPORT_DATA_TEXT = "Import Data"; private static final String[][] SUBJECTS = new String[][]{ - {"Participant0001","m","02/03/2001", "02/03/2012"}, - {"Participant0002","f","02/04/2001", null}, - {"Participant0003","f","02/05/2001", null}, - {"Participant0004","f","02/06/2001", null}, - {"Participant0005","m","02/07/2001", null}, - {"Participant0006","m","02/08/2002", null}, - {"Participant0007","m","02/09/2001", null}, - {"Participant0008","f","02/10/2001", null}, - {"Participant0009","m","02/11/2001", null}, - {"Participant0010","m","02/12/2001", null}, - {"Participant0011","f","02/13/2001", null}, - {"Participant0012","f","02/14/2001", null}, - {"Participant0013","f","02/15/2001", null}, - {"Participant0014","f","02/16/2010", null}, - {"Participant0015","f","02/17/2001", null}, - {"Participant0016","f","02/18/2001", null}, - {"Participant0017","f","02/19/2001", null}, - {"Participant0018","m","02/20/2001", null}, - {"Participant0019","m","02/21/2001", null}, - {"Participant0020","m","02/22/2001", null} + {"Participant0001", "m", "02/03/2001", "02/03/2012"}, + {"Participant0002", "f", "02/04/2001", null}, + {"Participant0003", "f", "02/05/2001", null}, + {"Participant0004", "f", "02/06/2001", null}, + {"Participant0005", "m", "02/07/2001", null}, + {"Participant0006", "m", "02/08/2002", null}, + {"Participant0007", "m", "02/09/2001", null}, + {"Participant0008", "f", "02/10/2001", null}, + {"Participant0009", "m", "02/11/2001", null}, + {"Participant0010", "m", "02/12/2001", null}, + {"Participant0011", "f", "02/13/2001", null}, + {"Participant0012", "f", "02/14/2001", null}, + {"Participant0013", "f", "02/15/2001", null}, + {"Participant0014", "f", "02/16/2010", null}, + {"Participant0015", "f", "02/17/2001", null}, + {"Participant0016", "f", "02/18/2001", null}, + {"Participant0017", "f", "02/19/2001", null}, + {"Participant0018", "m", "02/20/2001", null}, + {"Participant0019", "m", "02/21/2001", null}, + {"Participant0020", "m", "02/22/2001", null} }; private static final String[][] SAMPLE_DATA = new String[][]{ - {"Participant0001_RNA","Participant0001","RNA","06/23/2009","Freezer1"}, - {"Participant0002_DNA","Participant0002","DNA","06/23/2005","Freezer1"}, - {"Participant0003_gDNA","Participant0003","gDNA","08/21/2007","Freezer1"}, - {"Participant0004_RNA","Participant0004","RNA","","Freezer1"}, - {"Participant0005_DNA","Participant0005","DNA","08/21/2007","Freezer1"}, - {"Participant0006_gDNA","Participant0006","gDNA","06/23/2009","Freezer1"}, - {"Participant0007_RNA","Participant0007","RNA","","Freezer1"}, - {"Participant0008_DNA","Participant0008","DNA","06/23/2009","Freezer1"}, - {"Participant0009_gDNA","Participant0009","gDNA","","Freezer1"}, - {"Participant0010_RNA","Participant0010","RNA","08/21/2007","Freezer1"}, - {"Participant0011_DNA","Participant0011","DNA","","Freezer1"}, - {"Participant0012_gDNA","Participant0012","gDNA","08/21/2007","Freezer1"}, - {"Participant0013_RNA","Participant0013","RNA","","Freezer1"}, - {"OtherSample","","DNA","","Freezer1"}, - {"Participant0015_gDNA","Participant0015","gDNA","06/23/2009","Freezer1"}, - {"Participant0016_RNA","Participant0016","RNA","08/21/2007","Freezer1"}, - {"Participant0017_DNA","Participant0017","DNA","08/21/2007","Freezer1"}, - {"Participant0018_gDNA","Participant0018","gDNA","02/03/2012","Freezer1"}, - {"OtherSample2","","RNA","","Freezer1"}, - {"Participant0020_DNA","Participant0020","DNA","02/03/2012","Freezer1"}, - {"Participant0001_gDNA","Participant0001","gDNA","04/23/2008","Freezer1"}, - {"Participant0002_RNA","Participant0002","RNA","10/23/2009","Freezer1"}, - {"Participant0003_DNA","Participant0003","DNA","05/02/2001","Freezer1"}, - {"Participant0004_gDNA","Participant0004","gDNA","04/23/2008","Freezer1"} + {"Participant0001_RNA", "Participant0001", "RNA", "06/23/2009", "Freezer1"}, + {"Participant0002_DNA", "Participant0002", "DNA", "06/23/2005", "Freezer1"}, + {"Participant0003_gDNA", "Participant0003", "gDNA", "08/21/2007", "Freezer1"}, + {"Participant0004_RNA", "Participant0004", "RNA", "", "Freezer1"}, + {"Participant0005_DNA", "Participant0005", "DNA", "08/21/2007", "Freezer1"}, + {"Participant0006_gDNA", "Participant0006", "gDNA", "06/23/2009", "Freezer1"}, + {"Participant0007_RNA", "Participant0007", "RNA", "", "Freezer1"}, + {"Participant0008_DNA", "Participant0008", "DNA", "06/23/2009", "Freezer1"}, + {"Participant0009_gDNA", "Participant0009", "gDNA", "", "Freezer1"}, + {"Participant0010_RNA", "Participant0010", "RNA", "08/21/2007", "Freezer1"}, + {"Participant0011_DNA", "Participant0011", "DNA", "", "Freezer1"}, + {"Participant0012_gDNA", "Participant0012", "gDNA", "08/21/2007", "Freezer1"}, + {"Participant0013_RNA", "Participant0013", "RNA", "", "Freezer1"}, + {"OtherSample", "", "DNA", "", "Freezer1"}, + {"Participant0015_gDNA", "Participant0015", "gDNA", "06/23/2009", "Freezer1"}, + {"Participant0016_RNA", "Participant0016", "RNA", "08/21/2007", "Freezer1"}, + {"Participant0017_DNA", "Participant0017", "DNA", "08/21/2007", "Freezer1"}, + {"Participant0018_gDNA", "Participant0018", "gDNA", "02/03/2012", "Freezer1"}, + {"OtherSample2", "", "RNA", "", "Freezer1"}, + {"Participant0020_DNA", "Participant0020", "DNA", "02/03/2012", "Freezer1"}, + {"Participant0001_gDNA", "Participant0001", "gDNA", "04/23/2008", "Freezer1"}, + {"Participant0002_RNA", "Participant0002", "RNA", "10/23/2009", "Freezer1"}, + {"Participant0003_DNA", "Participant0003", "DNA", "05/02/2001", "Freezer1"}, + {"Participant0004_gDNA", "Participant0004", "gDNA", "04/23/2008", "Freezer1"} }; private static final String[][] PROJECT_ENROLLMENT = new String[][]{ - {"Participant0001","Project1","Controls","01/02/2004","08/31/2007"}, - {"Participant0002","Project1","Controls","01/02/2004",""}, - {"Participant0003","Project1","Group A","01/02/2004","9/30/2007"}, - {"Participant0004","Project1","Group A","01/02/2004",""}, - {"Participant0005","Project1","Group A","01/02/2004",""}, - {"Participant0006","Project1","Group B","01/16/2004","9/30/2007"}, - {"Participant0007","Project1","Group B","01/16/2004","12/14/2006"}, - {"Participant0008","Project2","Controls","01/16/2004","12/14/2006"}, - {"Participant0009","Project2","Controls","07/21/2002",""}, - {"Participant0010","Project2","Group A","07/21/2002",""}, - {"Participant0011","Project2","Group A","09/09/2002","09/09/2003"}, - {"Participant0012","Project2","Group A","09/09/2002",""}, - {"Participant0013","Project2","Group B","03/25/2004",""}, - {"Participant0014","Project2","Group B","03/25/2004","03/25/2005"}, - {"Participant0015","Project22","","03/25/2004","03/25/2005"}, - {"Participant0016","Project22","","04/08/2004","04/08/2005"}, - {"Participant0017","Project13","","04/08/2004","04/08/2005"}, - {"Participant0018","Project13","","04/08/2004",""}, - {"Participant0019","Project13","","10/12/2002","10/12/2003"}, - {"Participant0020","Project13","","01/02/2004","01/01/2005"}, - {"Participant0001","Project3","","05/02/2002",""}, - {"Participant0002","Project3","","01/02/2003","08/31/2007"}, - {"Participant0003","Project3","","01/02/2003",""}, - {"Participant0004","Project3","","01/02/2003","9/30/2007"} + {"Participant0001", "Project1", "Controls", "01/02/2004", "08/31/2007"}, + {"Participant0002", "Project1", "Controls", "01/02/2004", ""}, + {"Participant0003", "Project1", "Group A", "01/02/2004", "9/30/2007"}, + {"Participant0004", "Project1", "Group A", "01/02/2004", ""}, + {"Participant0005", "Project1", "Group A", "01/02/2004", ""}, + {"Participant0006", "Project1", "Group B", "01/16/2004", "9/30/2007"}, + {"Participant0007", "Project1", "Group B", "01/16/2004", "12/14/2006"}, + {"Participant0008", "Project2", "Controls", "01/16/2004", "12/14/2006"}, + {"Participant0009", "Project2", "Controls", "07/21/2002", ""}, + {"Participant0010", "Project2", "Group A", "07/21/2002", ""}, + {"Participant0011", "Project2", "Group A", "09/09/2002", "09/09/2003"}, + {"Participant0012", "Project2", "Group A", "09/09/2002", ""}, + {"Participant0013", "Project2", "Group B", "03/25/2004", ""}, + {"Participant0014", "Project2", "Group B", "03/25/2004", "03/25/2005"}, + {"Participant0015", "Project22", "", "03/25/2004", "03/25/2005"}, + {"Participant0016", "Project22", "", "04/08/2004", "04/08/2005"}, + {"Participant0017", "Project13", "", "04/08/2004", "04/08/2005"}, + {"Participant0018", "Project13", "", "04/08/2004", ""}, + {"Participant0019", "Project13", "", "10/12/2002", "10/12/2003"}, + {"Participant0020", "Project13", "", "01/02/2004", "01/01/2005"}, + {"Participant0001", "Project3", "", "05/02/2002", ""}, + {"Participant0002", "Project3", "", "01/02/2003", "08/31/2007"}, + {"Participant0003", "Project3", "", "01/02/2003", ""}, + {"Participant0004", "Project3", "", "01/02/2003", "9/30/2007"} }; private static final String[][] MAJOR_EVENTS = new String[][]{ - {"Participant0001","09/26/2002","Appendectomy","Surgery"}, - {"Participant0002","09/27/2002","Appendectomy","Surgery"}, - {"Participant0003","09/28/2002","Gave Birth","Medical"}, - {"Participant0004","09/29/2002","Vaccination","Medical"}, - {"Participant0005","09/30/2002","Biopsy",""}, - {"Participant0001","11/04/2006","Influenza Infection",""}, - {"Participant0002","11/05/2006","Influenza Infection",""}, - {"Participant0003","11/06/2006","Influenza Infection",""}, - {"Participant0004","11/07/2006","Influenza Infection",""}, - {"Participant0005","11/08/2006","Influenza Infection",""} + {"Participant0001", "09/26/2002", "Appendectomy", "Surgery"}, + {"Participant0002", "09/27/2002", "Appendectomy", "Surgery"}, + {"Participant0003", "09/28/2002", "Gave Birth", "Medical"}, + {"Participant0004", "09/29/2002", "Vaccination", "Medical"}, + {"Participant0005", "09/30/2002", "Biopsy", ""}, + {"Participant0001", "11/04/2006", "Influenza Infection", ""}, + {"Participant0002", "11/05/2006", "Influenza Infection", ""}, + {"Participant0003", "11/06/2006", "Influenza Infection", ""}, + {"Participant0004", "11/07/2006", "Influenza Infection", ""}, + {"Participant0005", "11/08/2006", "Influenza Infection", ""} }; @Override @@ -262,7 +262,7 @@ private void populateData() throws Exception protected void setupAssays() { - for(Pair pair : getAssaysToCreate()) + for (Pair pair : getAssaysToCreate()) { _helper.defineAssay(pair.getKey(), pair.getValue()); } @@ -302,7 +302,7 @@ private void dateParseTest() throws ParseException checkDate("02/20/11", dateFormat3); checkDate("3/5/99", dateFormat3); - String clientFormattedString = (String)executeScript("return Ext4.Date.format(LDK.ConvertUtils.parseDate('2024-01-01', 'c'), 'Y-m-d');"); + String clientFormattedString = (String) executeScript("return Ext4.Date.format(LDK.ConvertUtils.parseDate('2024-01-01', 'c'), 'Y-m-d');"); assertEquals("Incorrect date parsing", "2024-01-01", clientFormattedString); } @@ -314,10 +314,10 @@ private void checkDate(String dateStr, String javaFormatStr) throws ParseExcepti Date expectedDate = format.parse(dateStr); String expectedString = stdFormat.format(expectedDate); - String clientDateStr = (String)executeScript("return (new Date()).toString()"); - String clientFormattedString = (String)executeScript("return Ext4.Date.format(LDK.ConvertUtils.parseDate('" + dateStr + "'), 'Y-m-d');"); + String clientDateStr = (String) executeScript("return (new Date()).toString()"); + String clientFormattedString = (String) executeScript("return Ext4.Date.format(LDK.ConvertUtils.parseDate('" + dateStr + "'), 'Y-m-d');"); - String clientTimezone = (String)executeScript("return Ext4.Date.getTimezone(LDK.ConvertUtils.parseDate('" + dateStr + "'));"); + String clientTimezone = (String) executeScript("return Ext4.Date.getTimezone(LDK.ConvertUtils.parseDate('" + dateStr + "'));"); String serverTimezone = Calendar.getInstance().getTimeZone().getDisplayName(false, TimeZone.SHORT); Date now = new Date(); @@ -347,9 +347,9 @@ private void workbookNumberingTest() throws Exception int idx = 0; for (Map row : resp1.getRows()) { - Integer workbookId = (Integer)row.get("workbookId"); - String container = (String)row.get("container"); - String containerName = (String)row.get("container/name"); + Integer workbookId = (Integer) row.get("workbookId"); + String container = (String) row.get("container"); + String containerName = (String) row.get("container/name"); CreateContainerResponse workbook = workbooks.get(idx); @@ -381,9 +381,9 @@ private void workbookNumberingTest() throws Exception int workbookIdOffset = 1 + highestWorkbookId; for (Map row : resp2.getRows()) { - Integer workbookId = (Integer)row.get("workbookId"); - String container = (String)row.get("container"); - String containerName = (String)row.get("container/name"); + Integer workbookId = (Integer) row.get("workbookId"); + String container = (String) row.get("container"); + String containerName = (String) row.get("container/name"); CreateContainerResponse workbook = workbooks.get(idx); @@ -413,7 +413,7 @@ private int deleteExistingWorkbooks() throws Exception int highestWorkbookId = 0; for (Map row : resp0.getRows()) { - highestWorkbookId = (Integer)row.get("workbookId"); + highestWorkbookId = (Integer) row.get("workbookId"); _apiContainerHelper.deleteWorkbook(getProjectName(), highestWorkbookId, true, 90000); } @@ -429,43 +429,43 @@ private void calculatedColumnsTest() throws Exception Connection cn = WebTestHelper.getRemoteApiConnection(); SelectRowsCommand sr = new SelectRowsCommand("laboratory", "samples"); List columns = Arrays.asList("samplename", "subjectId", "gender", "sampletype", "sampleDate", - "overlappingProjects/projects", "overlappingProjects/groups", - "allProjects/projects", "allProjects/groups", - "majorEvents/Appendectomy::DaysPostEvent", "majorEvents/Appendectomy::YearsPostEvent", "majorEvents/Gave Birth::DaysPostEvent", "majorEvents/Vaccination::YearsPostEventDecimal", "majorEvents/Biopsy::MonthsPostEvent", "majorEvents/Influenza Infection::DaysPostEvent", - "relativeDates/Project1::DaysPostStart", "relativeDates/Project2::MonthsPostStart", "relativeDates/Project3::YearsPostStartDecimal"); + "overlappingProjects/projects", "overlappingProjects/groups", + "allProjects/projects", "allProjects/groups", + "majorEvents/Appendectomy::DaysPostEvent", "majorEvents/Appendectomy::YearsPostEvent", "majorEvents/Gave Birth::DaysPostEvent", "majorEvents/Vaccination::YearsPostEventDecimal", "majorEvents/Biopsy::MonthsPostEvent", "majorEvents/Influenza Infection::DaysPostEvent", + "relativeDates/Project1::DaysPostStart", "relativeDates/Project2::MonthsPostStart", "relativeDates/Project3::YearsPostStartDecimal"); sr.setColumns(columns); sr.setSorts(Arrays.asList(new Sort("samplename"), new Sort("sampleDate"), new Sort("sampleType"))); SelectRowsResponse resp = sr.execute(cn, getProjectName()); assertEquals("Incorrect number of rows returned", SAMPLE_DATA.length, resp.getRowCount().intValue()); - List colOrder = Arrays.asList("samplename","subjectId","sampledate","sampletype","overlappingProjects/projects","overlappingProjects/groups","allProjects/projects","allProjects/groups","majorEvents/Appendectomy::DaysPostEvent","majorEvents/Appendectomy::YearsPostEvent","majorEvents/Gave Birth::DaysPostEvent","majorEvents/Vaccination::YearsPostEventDecimal","majorEvents/Biopsy::MonthsPostEvent","majorEvents/Influenza Infection::DaysPostEvent","relativeDates/Project1::DaysPostStart","relativeDates/Project2::MonthsPostStart","relativeDates/Project3::YearsPostStartDecimal"); + List colOrder = Arrays.asList("samplename", "subjectId", "sampledate", "sampletype", "overlappingProjects/projects", "overlappingProjects/groups", "allProjects/projects", "allProjects/groups", "majorEvents/Appendectomy::DaysPostEvent", "majorEvents/Appendectomy::YearsPostEvent", "majorEvents/Gave Birth::DaysPostEvent", "majorEvents/Vaccination::YearsPostEventDecimal", "majorEvents/Biopsy::MonthsPostEvent", "majorEvents/Influenza Infection::DaysPostEvent", "relativeDates/Project1::DaysPostStart", "relativeDates/Project2::MonthsPostStart", "relativeDates/Project3::YearsPostStartDecimal"); List expected = new ArrayList<>(); - expected.add(new String[]{"OtherSample",null,null,"DNA",null,null,null,null,null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"OtherSample2",null,null,"RNA",null,null,null,null,null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0001_gDNA","Participant0001","04/23/2008","gDNA","Project3",null,"Project1\nProject3","Project1 (Controls)","2036","5",null,null,null,"536",null,null,"5.9",null}); - expected.add(new String[]{"Participant0001_RNA","Participant0001","06/23/2009","RNA","Project3",null,"Project1\nProject3","Project1 (Controls)","2462","6",null,null,null,"962",null,null,"7.1",null}); - expected.add(new String[]{"Participant0002_DNA","Participant0002","06/23/2005","DNA","Project1\nProject3","Project1 (Controls)","Project1\nProject3","Project1 (Controls)","1000","2",null,null,null,"-500","538",null,"2.4",null}); - expected.add(new String[]{"Participant0002_RNA","Participant0002","10/23/2009","RNA","Project1","Project1 (Controls)","Project1\nProject3","Project1 (Controls)","2583","7",null,null,null,"1083","2121",null,null,null}); - expected.add(new String[]{"Participant0003_DNA","Participant0003","05/02/2001","DNA",null,null,"Project1\nProject3","Project1 (Group A)",null,null,"-514",null,null,"-2014",null,null,null,null}); - expected.add(new String[]{"Participant0003_gDNA","Participant0003","08/21/2007","gDNA","Project1\nProject3","Project1 (Group A)","Project1\nProject3","Project1 (Group A)",null,null,"1788",null,null,"288","1327",null,"4.6",null}); - expected.add(new String[]{"Participant0004_gDNA","Participant0004","04/23/2008","gDNA","Project1","Project1 (Group A)","Project1\nProject3","Project1 (Group A)",null,null,null,"5.5",null,"533","1573",null,null,null}); - expected.add(new String[]{"Participant0004_RNA","Participant0004",null,"RNA",null,null,"Project1\nProject3","Project1 (Group A)",null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0005_DNA","Participant0005","08/21/2007","DNA","Project1","Project1 (Group A)","Project1","Project1 (Group A)",null,null,null,null,"58","286","1327",null,null,null}); - expected.add(new String[]{"Participant0006_gDNA","Participant0006","06/23/2009","gDNA",null,null,"Project1","Project1 (Group B)",null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0007_RNA","Participant0007",null,"RNA",null,null,"Project1","Project1 (Group B)",null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0008_DNA","Participant0008","06/23/2009","DNA",null,null,"Project2","Project2 (Controls)",null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0009_gDNA","Participant0009",null,"gDNA",null,null,"Project2","Project2 (Controls)",null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0010_RNA","Participant0010","08/21/2007","RNA","Project2","Project2 (Group A)","Project2","Project2 (Group A)",null,null,null,null,null,null,null,"61",null,null}); - expected.add(new String[]{"Participant0011_DNA","Participant0011",null,"DNA",null,null,"Project2","Project2 (Group A)",null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0012_gDNA","Participant0012","08/21/2007","gDNA","Project2","Project2 (Group A)","Project2","Project2 (Group A)",null,null,null,null,null,null,null,"59",null,null}); - expected.add(new String[]{"Participant0013_RNA","Participant0013",null,"RNA",null,null,"Project2","Project2 (Group B)",null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0015_gDNA","Participant0015","06/23/2009","gDNA",null,null,"Project22",null,null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0016_RNA","Participant0016","08/21/2007","RNA",null,null,"Project22",null,null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0017_DNA","Participant0017","08/21/2007","DNA",null,null,"Project13",null,null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0018_gDNA","Participant0018","02/03/2012","gDNA","Project13",null,"Project13",null,null,null,null,null,null,null,null,null,null,null}); - expected.add(new String[]{"Participant0020_DNA","Participant0020","02/03/2012","DNA",null,null,"Project13",null,null,null,null,null,null,null,null,null,null,null}); + expected.add(new String[]{"OtherSample", null, null, "DNA", null, null, null, null, null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"OtherSample2", null, null, "RNA", null, null, null, null, null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0001_gDNA", "Participant0001", "04/23/2008", "gDNA", "Project3", null, "Project1\nProject3", "Project1 (Controls)", "2036", "5", null, null, null, "536", null, null, "5.9", null}); + expected.add(new String[]{"Participant0001_RNA", "Participant0001", "06/23/2009", "RNA", "Project3", null, "Project1\nProject3", "Project1 (Controls)", "2462", "6", null, null, null, "962", null, null, "7.1", null}); + expected.add(new String[]{"Participant0002_DNA", "Participant0002", "06/23/2005", "DNA", "Project1\nProject3", "Project1 (Controls)", "Project1\nProject3", "Project1 (Controls)", "1000", "2", null, null, null, "-500", "538", null, "2.4", null}); + expected.add(new String[]{"Participant0002_RNA", "Participant0002", "10/23/2009", "RNA", "Project1", "Project1 (Controls)", "Project1\nProject3", "Project1 (Controls)", "2583", "7", null, null, null, "1083", "2121", null, null, null}); + expected.add(new String[]{"Participant0003_DNA", "Participant0003", "05/02/2001", "DNA", null, null, "Project1\nProject3", "Project1 (Group A)", null, null, "-514", null, null, "-2014", null, null, null, null}); + expected.add(new String[]{"Participant0003_gDNA", "Participant0003", "08/21/2007", "gDNA", "Project1\nProject3", "Project1 (Group A)", "Project1\nProject3", "Project1 (Group A)", null, null, "1788", null, null, "288", "1327", null, "4.6", null}); + expected.add(new String[]{"Participant0004_gDNA", "Participant0004", "04/23/2008", "gDNA", "Project1", "Project1 (Group A)", "Project1\nProject3", "Project1 (Group A)", null, null, null, "5.5", null, "533", "1573", null, null, null}); + expected.add(new String[]{"Participant0004_RNA", "Participant0004", null, "RNA", null, null, "Project1\nProject3", "Project1 (Group A)", null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0005_DNA", "Participant0005", "08/21/2007", "DNA", "Project1", "Project1 (Group A)", "Project1", "Project1 (Group A)", null, null, null, null, "58", "286", "1327", null, null, null}); + expected.add(new String[]{"Participant0006_gDNA", "Participant0006", "06/23/2009", "gDNA", null, null, "Project1", "Project1 (Group B)", null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0007_RNA", "Participant0007", null, "RNA", null, null, "Project1", "Project1 (Group B)", null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0008_DNA", "Participant0008", "06/23/2009", "DNA", null, null, "Project2", "Project2 (Controls)", null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0009_gDNA", "Participant0009", null, "gDNA", null, null, "Project2", "Project2 (Controls)", null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0010_RNA", "Participant0010", "08/21/2007", "RNA", "Project2", "Project2 (Group A)", "Project2", "Project2 (Group A)", null, null, null, null, null, null, null, "61", null, null}); + expected.add(new String[]{"Participant0011_DNA", "Participant0011", null, "DNA", null, null, "Project2", "Project2 (Group A)", null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0012_gDNA", "Participant0012", "08/21/2007", "gDNA", "Project2", "Project2 (Group A)", "Project2", "Project2 (Group A)", null, null, null, null, null, null, null, "59", null, null}); + expected.add(new String[]{"Participant0013_RNA", "Participant0013", null, "RNA", null, null, "Project2", "Project2 (Group B)", null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0015_gDNA", "Participant0015", "06/23/2009", "gDNA", null, null, "Project22", null, null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0016_RNA", "Participant0016", "08/21/2007", "RNA", null, null, "Project22", null, null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0017_DNA", "Participant0017", "08/21/2007", "DNA", null, null, "Project13", null, null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0018_gDNA", "Participant0018", "02/03/2012", "gDNA", "Project13", null, "Project13", null, null, null, null, null, null, null, null, null, null, null}); + expected.add(new String[]{"Participant0020_DNA", "Participant0020", "02/03/2012", "DNA", null, null, "Project13", null, null, null, null, null, null, null, null, null, null, null}); assertEquals("Test has bad values for expected data", SAMPLE_DATA.length, expected.size()); @@ -522,7 +522,7 @@ private void insertSubjects() throws Exception for (String[] arr : SUBJECTS) { - Map rowMap = new HashMap<>(); + Map rowMap = new HashMap<>(); rowMap.put("subjectname", arr[0]); rowMap.put("gender", arr[1]); rowMap.put("birth", arr[2]); @@ -542,7 +542,7 @@ private void insertProjectEnrollment() throws Exception for (String[] arr : PROJECT_ENROLLMENT) { - Map rowMap = new HashMap<>(); + Map rowMap = new HashMap<>(); rowMap.put("subjectId", arr[0]); rowMap.put("project", arr[1]); //NOTE: this is deliberately inserting using empty string, not null. LK is expected to convert that to NULL. If this doesnt happen, @@ -586,7 +586,7 @@ private void insertSamples() throws Exception for (String[] arr : SAMPLE_DATA) { - Map rowMap = new HashMap<>(); + Map rowMap = new HashMap<>(); rowMap.put("samplename", arr[0]); rowMap.put("subjectId", arr[1]); rowMap.put("sampleType", arr[2]); @@ -610,7 +610,7 @@ private void insertMajorEvents() throws Exception for (String[] arr : MAJOR_EVENTS) { - Map rowMap = new HashMap<>(); + Map rowMap = new HashMap<>(); rowMap.put("subjectId", arr[0]); rowMap.put("date", arr[1]); rowMap.put("event", arr[2]); @@ -634,7 +634,7 @@ private void overviewUITest() waitForElement(LabModuleHelper.getNavPanelRow("Sequence:"), WAIT_FOR_PAGE); _helper.verifyNavPanelRowItemPresent("Sequence:"); - for(Pair pair : getAssaysToCreate()) + for (Pair pair : getAssaysToCreate()) { _helper.verifyNavPanelRowItemPresent(pair.getValue() + ":"); assertElementNotPresent(LabModuleHelper.getNavPanelItem(pair.getValue() + ":", IMPORT_DATA_TEXT)); @@ -892,8 +892,8 @@ private void dataSourcesTest() throws Exception SelectRowsResponse resp = sr.execute(cn, getProjectName()); List expected = new ArrayList<>(); - expected.add(new String[]{"Participant0001_gDNA","11","m"}); - expected.add(new String[]{"Participant0001_RNA","11","m"}); + expected.add(new String[]{"Participant0001_gDNA", "11", "m"}); + expected.add(new String[]{"Participant0001_RNA", "11", "m"}); assertEquals("Incorrect number of rows returned", expected.size(), resp.getRowCount().intValue()); @@ -989,7 +989,7 @@ private String replaceNonVisibleChars(String value) private void deleteSourceByLabel(String label, String parentItemId) { Ext4CmpRef panel = _ext4Helper.queryOne("#" + parentItemId, Ext4CmpRef.class); - Long idx = (Long)panel.getFnEval("return this.getSourceIdx(arguments[0])", label); + Long idx = (Long) panel.getFnEval("return this.getSourceIdx(arguments[0])", label); if (idx == null) return; @@ -1125,7 +1125,7 @@ private void settingsTest() Ext4FieldRef.getForBoxLabel(this, "Major Events").setValue(true); sleep(100); - assertTrue("Incorrect value for samples checkbox", (Boolean)_ext4Helper.queryOne(samplesSelector, Ext4FieldRef.class).getValue()); + assertTrue("Incorrect value for samples checkbox", (Boolean) _ext4Helper.queryOne(samplesSelector, Ext4FieldRef.class).getValue()); click(Ext4Helper.Locators.ext4Button("Submit")); new Window.WindowFinder(getDriver()).withTitle("Success").waitFor(); @@ -1193,7 +1193,7 @@ private void labToolsWebpartTest() waitAndClick(_helper.toolIcon("Import Data")); assertElementPresent(Ext4Helper.Locators.menuItem("Sequence")); - for(Pair pair : getAssaysToCreate()) + for (Pair pair : getAssaysToCreate()) { assertElementPresent(Ext4Helper.Locators.menuItem(pair.getValue())); } @@ -1217,7 +1217,7 @@ private void labToolsWebpartTest() goToProjectHome(); } - private void workbookCreationTest() + private void workbookCreationTest() throws Exception { _helper.goToLabHome(); @@ -1256,12 +1256,23 @@ private void workbookCreationTest() new Window.WindowFinder(getDriver()).withTitle("Success").waitFor(); assertTextPresent("Your upload was successful"); _oligosTotal++; + verifyOligoCount(_oligosTotal); clickButton("OK", 0); _helper.goToLabHome(); } - private void dnaOligosTableTest() + private void verifyOligoCount(int expected) throws Exception + { + SelectRowsCommand sr = new SelectRowsCommand("laboratory", "dna_oligos"); + sr.setColumns(Arrays.asList("rowid")); + + Connection cn = WebTestHelper.getRemoteApiConnection(); + SelectRowsResponse srr = sr.execute(cn, getCurrentContainerPath()); + Assert.assertEquals(expected, srr.getRowCount().intValue()); + } + + private void dnaOligosTableTest() throws Exception { log("Testing DNA Oligos Table"); _helper.goToLabHome(); @@ -1278,6 +1289,7 @@ private void dnaOligosTableTest() sleep(150); //there's a buffer when committing changes clickButton("Submit", 0); _oligosTotal += 1; + verifyOligoCount(_oligosTotal); _helper.goToLabHome(); _helper.clickNavPanelItem("DNA_Oligos:", IMPORT_DATA_TEXT); @@ -1291,6 +1303,7 @@ private void dnaOligosTableTest() setFormElementJS(Locator.name("text"), "Name\tSequence\nTestPrimer1\tatg\nTestPrimer2\t" + sequence); clickButton("Upload", 0); _oligosTotal += 2; + verifyOligoCount(_oligosTotal); new Window.WindowFinder(getDriver()).withTitle("Success").waitFor(); assertTextPresent("Success! 2 rows inserted."); From 863c37ce92ca774eccc66c5423367a346ee60b5c Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 21 Aug 2025 09:42:32 -0700 Subject: [PATCH 07/18] Further expand test --- .../test/tests/external/labModules/LabModulesTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java index 9f5065fc..49b0dc80 100644 --- a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java +++ b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java @@ -67,6 +67,7 @@ import java.util.Map; import java.util.TimeZone; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -1265,11 +1266,13 @@ private void workbookCreationTest() throws Exception private void verifyOligoCount(int expected) throws Exception { SelectRowsCommand sr = new SelectRowsCommand("laboratory", "dna_oligos"); - sr.setColumns(Arrays.asList("rowid")); + sr.setColumns(Arrays.asList("rowid", "name")); Connection cn = WebTestHelper.getRemoteApiConnection(); SelectRowsResponse srr = sr.execute(cn, getCurrentContainerPath()); - Assert.assertEquals(expected, srr.getRowCount().intValue()); + + String oligoNames = srr.getRows().stream().map(row -> row.get("name").toString()).collect(Collectors.joining(",")); + Assert.assertEquals("Incorrect number of oligos, found: " + oligoNames, expected, srr.getRowCount().intValue()); } private void dnaOligosTableTest() throws Exception From 0488398bb7b69eca24a9a6e9353c891f3324f30c Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 21 Aug 2025 14:22:20 -0700 Subject: [PATCH 08/18] Further expand test --- .../tests/external/labModules/LabModulesTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java index 49b0dc80..b663a681 100644 --- a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java +++ b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java @@ -1265,12 +1265,21 @@ private void workbookCreationTest() throws Exception private void verifyOligoCount(int expected) throws Exception { + log("verifying oligo count, expected: " + expected); + SelectRowsCommand sr = new SelectRowsCommand("laboratory", "dna_oligos"); - sr.setColumns(Arrays.asList("rowid", "name")); + sr.setColumns(Arrays.asList("rowid", "name", "container")); Connection cn = WebTestHelper.getRemoteApiConnection(); SelectRowsResponse srr = sr.execute(cn, getCurrentContainerPath()); + if (expected != srr.getRowCount().intValue()) + { + srr.getRows().forEach(row -> { + log("row: " + row); + }); + } + String oligoNames = srr.getRows().stream().map(row -> row.get("name").toString()).collect(Collectors.joining(",")); Assert.assertEquals("Incorrect number of oligos, found: " + oligoNames, expected, srr.getRowCount().intValue()); } From 83da05fed3d4f9ddef0923179882d3b04c7c6f21 Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 21 Aug 2025 14:31:30 -0700 Subject: [PATCH 09/18] Another oligo validation check --- .../labkey/test/tests/external/labModules/LabModulesTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java index b663a681..9f5f278a 100644 --- a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java +++ b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java @@ -418,6 +418,10 @@ private int deleteExistingWorkbooks() throws Exception _apiContainerHelper.deleteWorkbook(getProjectName(), highestWorkbookId, true, 90000); } + log("resetting oligo count"); + _oligosTotal = 0; + verifyOligoCount(0); + return highestWorkbookId; } From 1a282cbecfefbece9e0b173f2b523cfdfb5f7988 Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 21 Aug 2025 15:49:15 -0700 Subject: [PATCH 10/18] Another oligo validation check --- .../labkey/test/tests/external/labModules/LabModulesTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java index 9f5f278a..bc08ebbb 100644 --- a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java +++ b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java @@ -47,6 +47,7 @@ import org.labkey.test.util.DataRegionTable; import org.labkey.test.util.ExcelHelper; import org.labkey.test.util.Ext4Helper; +import org.labkey.test.util.LogMethod; import org.labkey.test.util.ext4cmp.Ext4CmpRef; import org.labkey.test.util.ext4cmp.Ext4ComboRef; import org.labkey.test.util.ext4cmp.Ext4FieldRef; @@ -1222,6 +1223,7 @@ private void labToolsWebpartTest() goToProjectHome(); } + @LogMethod private void workbookCreationTest() throws Exception { _helper.goToLabHome(); @@ -1288,10 +1290,12 @@ private void verifyOligoCount(int expected) throws Exception Assert.assertEquals("Incorrect number of oligos, found: " + oligoNames, expected, srr.getRowCount().intValue()); } + @LogMethod private void dnaOligosTableTest() throws Exception { log("Testing DNA Oligos Table"); _helper.goToLabHome(); + verifyOligoCount(_oligosTotal); _helper.clickNavPanelItem("DNA_Oligos:", IMPORT_DATA_TEXT); new Window.WindowFinder(getDriver()).withTitle(IMPORT_DATA_TEXT).waitFor(); From 32867f1305f1d81367de1096d813df43a550bd2c Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 21 Aug 2025 16:57:12 -0700 Subject: [PATCH 11/18] Improve use of generics --- .../tests/external/labModules/LabModulesTest.java | 2 +- .../org/labkey/laboratory/LaboratoryUserSchema.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java index bc08ebbb..468bb2ff 100644 --- a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java +++ b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java @@ -1274,7 +1274,7 @@ private void verifyOligoCount(int expected) throws Exception log("verifying oligo count, expected: " + expected); SelectRowsCommand sr = new SelectRowsCommand("laboratory", "dna_oligos"); - sr.setColumns(Arrays.asList("rowid", "name", "container")); + sr.setColumns(Arrays.asList("rowid", "name", "container", "sequence")); Connection cn = WebTestHelper.getRemoteApiConnection(); SelectRowsResponse srr = sr.execute(cn, getCurrentContainerPath()); diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryUserSchema.java b/laboratory/src/org/labkey/laboratory/LaboratoryUserSchema.java index bfefbb45..324a7a2f 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryUserSchema.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryUserSchema.java @@ -67,7 +67,7 @@ else if (LaboratorySchema.TABLE_SAMPLES.equalsIgnoreCase(name)) return super.createWrappedTable(name, sourceTable, cf); } - private SimpleTable getSubjectsTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) + private SimpleTable getSubjectsTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) { return new ContainerScopedTable<>(this, schematable, cf, "subjectname").init(); } @@ -77,27 +77,27 @@ private TableInfo getContainerScopedTable(String name, @NotNull TableInfo schema return new ContainerScopedTable<>(this, schematable, cf, pkCol).init(); } - private SimpleTable getDnaOligosTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) + private SimpleTable getDnaOligosTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) { return new ContainerIncrementingTable(this, schematable, cf, "oligo_id").init(); } - private SimpleTable getSamplesTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) + private SimpleTable getSamplesTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) { return new ContainerIncrementingTable(this, schematable, cf, "freezerid").init(); } - private SimpleTable getPeptideTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) + private SimpleTable getPeptideTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) { return new ContainerIncrementingTable(this, schematable, cf, "peptideId").init(); } - private SimpleTable getAntibodiesTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) + private SimpleTable getAntibodiesTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) { return new ContainerIncrementingTable(this, schematable, cf, "antibodyId").init(); } - private SimpleTable getWorkbooksTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) + private SimpleTable getWorkbooksTable(String name, @NotNull TableInfo schematable, ContainerFilter cf) { return new LaboratoryWorkbooksTable(this, schematable, cf).init(); } From dc2e80b544a25eac89715d16afabd0a95e03ecb2 Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 21 Aug 2025 19:07:30 -0700 Subject: [PATCH 12/18] Improve test timing --- .../test/tests/external/labModules/LabModulesTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java index 468bb2ff..2e858363 100644 --- a/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java +++ b/LDK/test/src/org/labkey/test/tests/external/labModules/LabModulesTest.java @@ -1308,6 +1308,9 @@ private void dnaOligosTableTest() throws Exception setFormElement(Locator.name("oligo_type"), "Type1"); sleep(150); //there's a buffer when committing changes clickButton("Submit", 0); + new Window.WindowFinder(getDriver()).withTitle("Success").waitFor(); + assertTextPresent("Your upload was successful!"); + clickButton("OK"); _oligosTotal += 1; verifyOligoCount(_oligosTotal); @@ -1322,12 +1325,12 @@ private void dnaOligosTableTest() throws Exception String sequence = "tggGg gGAAAAgg"; setFormElementJS(Locator.name("text"), "Name\tSequence\nTestPrimer1\tatg\nTestPrimer2\t" + sequence); clickButton("Upload", 0); - _oligosTotal += 2; - verifyOligoCount(_oligosTotal); new Window.WindowFinder(getDriver()).withTitle("Success").waitFor(); assertTextPresent("Success! 2 rows inserted."); clickButton("OK"); + _oligosTotal += 2; + verifyOligoCount(_oligosTotal); //verify row imported _helper.goToLabHome(); From 507df9a28dbb67ab23226796d39fbbe8c70df996 Mon Sep 17 00:00:00 2001 From: bbimber Date: Thu, 21 Aug 2025 20:24:29 -0700 Subject: [PATCH 13/18] Correct dialog box --- laboratory/resources/web/laboratory/panel/AssayImportPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/laboratory/resources/web/laboratory/panel/AssayImportPanel.js b/laboratory/resources/web/laboratory/panel/AssayImportPanel.js index 34a61bb2..dea79ba4 100644 --- a/laboratory/resources/web/laboratory/panel/AssayImportPanel.js +++ b/laboratory/resources/web/laboratory/panel/AssayImportPanel.js @@ -80,7 +80,7 @@ Ext4.define('Laboratory.panel.AssayImportPanel', { Ext4.Msg.hide(); switch(action.failureType){ case 'client': - Ext4.Msg.alert("One or more fields has a missing or improper value"); + Ext4.Msg.alert("Error", "One or more fields has a missing or improper value"); break; default: this.handleFailure(action.response); From 7098bafefdc1ded7de1ea1d9c48413cccfab5cac Mon Sep 17 00:00:00 2001 From: bbimber Date: Fri, 19 Sep 2025 14:06:06 -0700 Subject: [PATCH 14/18] Clean up trigger/customizer layer code --- .../ldk/query/DefaultTableCustomizer.java | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java b/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java index c49ec53d..37b517a8 100644 --- a/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java +++ b/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java @@ -118,13 +118,19 @@ private void setDetailsUrl(AbstractTableInfo ti) } String schemaName = ti.getUserSchema().getSchemaName(); - assert schemaName != null; - String queryName = ti.getPublicName(); - assert queryName != null; + if (queryName == null) + { + _log.error("TableInfo.getPublicName() was null", new Exception()); + return; + } List keyFields = ti.getPkColumnNames(); - assert !keyFields.isEmpty() : "No key fields found for the table: " + ti.getPublicSchemaName() + "." + ti.getPublicName(); + if (keyFields.isEmpty()) + { + _log.error("No key fields found for the table: " + ti.getPublicSchemaName() + "." + ti.getPublicName()); + return; + } if (_settings.getPrimaryKeyField() != null) { @@ -169,13 +175,19 @@ else if (_settings.isSetEditLinkOverrides()) { //otherwise apply custom urls String schemaName = ti.getUserSchema().getSchemaName(); - assert schemaName != null; - String queryName = ti.getPublicName(); - assert queryName != null; + if (queryName == null) + { + _log.error("TableInfo.getPublicName() was null", new Exception()); + return; + } List keyFields = ti.getPkColumnNames(); - assert !keyFields.isEmpty() : "No key fields found for the table: " + ti.getPublicSchemaName() + "." + ti.getPublicName(); + if (keyFields.isEmpty()) + { + _log.error("No key fields found for the table: " + ti.getPublicSchemaName() + "." + ti.getPublicName()); + return; + } if (_settings.getPrimaryKeyField() != null) { From e0c5f377b887046bf87551552356b351878efdc9 Mon Sep 17 00:00:00 2001 From: bbimber Date: Fri, 19 Sep 2025 15:08:14 -0700 Subject: [PATCH 15/18] Reduce logging --- .../org/labkey/ldk/query/DefaultTableCustomizer.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java b/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java index 37b517a8..2b16fa5b 100644 --- a/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java +++ b/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java @@ -128,7 +128,7 @@ private void setDetailsUrl(AbstractTableInfo ti) List keyFields = ti.getPkColumnNames(); if (keyFields.isEmpty()) { - _log.error("No key fields found for the table: " + ti.getPublicSchemaName() + "." + ti.getPublicName()); + _log.debug("No key fields found for the table, cannot set details URL: " + ti.getPublicSchemaName() + "." + ti.getPublicName()); return; } @@ -185,7 +185,13 @@ else if (_settings.isSetEditLinkOverrides()) List keyFields = ti.getPkColumnNames(); if (keyFields.isEmpty()) { - _log.error("No key fields found for the table: " + ti.getPublicSchemaName() + "." + ti.getPublicName()); + // There does not seem to be a more direct test for 'is editable' + if (ti.getUpdateService() == null) + { + return; + } + + _log.debug("No key fields found for the table, cannot customize edit UI: " + ti.getPublicSchemaName() + "." + ti.getPublicName()); return; } From 73a36f0913bbeeb7eb237643c0c26b23156fb706 Mon Sep 17 00:00:00 2001 From: bbimber Date: Sat, 4 Oct 2025 07:44:18 -0700 Subject: [PATCH 16/18] Build short delay into github triggers to aid cross-repo commits --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5816605b..26976a1e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,11 @@ jobs: if: github.repository == 'BimberLabInternal/LabDevKitModules' runs-on: ubuntu-latest steps: + # Note: use slight delay in case there are associated commits across repos + - name: "Sleep for 30 seconds" + run: sleep 30s + shell: bash + - name: "Build DISCVR" uses: bimberlabinternal/DevOps/githubActions/discvr-build@master with: From 798808bf5e142cdaae8da8c88561f854d8272e04 Mon Sep 17 00:00:00 2001 From: bbimber Date: Fri, 14 Nov 2025 12:30:14 -0800 Subject: [PATCH 17/18] Add manage freezer button and expand TagPcrSummaryStep --- laboratory/src/org/labkey/laboratory/LaboratoryModule.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryModule.java b/laboratory/src/org/labkey/laboratory/LaboratoryModule.java index 6cb8a7d8..d4e111b1 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryModule.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryModule.java @@ -197,6 +197,10 @@ protected void doStartupAfterSpringConfig(ModuleContext moduleContext) LDKService.get().registerQueryButton(btn4, LaboratoryModule.SCHEMA_NAME, LaboratorySchema.TABLE_SAMPLES); LDKService.get().registerQueryButton(new ShowBulkEditButton(this, LaboratoryModule.SCHEMA_NAME, LaboratorySchema.TABLE_SAMPLES), LaboratoryModule.SCHEMA_NAME, LaboratorySchema.TABLE_SAMPLES); + + SimpleButtonConfigFactory btn5 = new SimpleButtonConfigFactory(this, "Manage Freezers", DetailsURL.fromString("/query/executeQuery.view?schemaName=laboratory&query.queryName=freezers")); + btn5.setPermission(LaboratoryAdminPermission.class); + LDKService.get().registerQueryButton(btn5, LaboratoryModule.SCHEMA_NAME, LaboratorySchema.TABLE_SAMPLES); } @Override From 2e42ae06afddfe1ec873455727ec731da02b84e6 Mon Sep 17 00:00:00 2001 From: bbimber Date: Tue, 23 Jun 2026 15:49:06 -0700 Subject: [PATCH 18/18] Use UpdateService instead of raw DbSchema layer for assay_template edits --- .../laboratory/assay/DefaultAssayParser.java | 27 ++++----- .../labkey/laboratory/assay/AssayHelper.java | 57 ++++++++++++++++--- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/laboratory/api-src/org/labkey/api/laboratory/assay/DefaultAssayParser.java b/laboratory/api-src/org/labkey/api/laboratory/assay/DefaultAssayParser.java index bbcd2ac4..f4e27df3 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/assay/DefaultAssayParser.java +++ b/laboratory/api-src/org/labkey/api/laboratory/assay/DefaultAssayParser.java @@ -20,18 +20,18 @@ import org.apache.commons.beanutils.ConversionException; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.json.JSONArray; import org.json.JSONObject; +import org.labkey.api.assay.AssayProvider; +import org.labkey.api.assay.AssayService; import org.labkey.api.collections.CaseInsensitiveHashMap; import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerType; import org.labkey.api.data.ConvertHelper; -import org.labkey.api.data.DbSchema; -import org.labkey.api.data.RuntimeSQLException; import org.labkey.api.data.SimpleFilter; -import org.labkey.api.data.Table; import org.labkey.api.data.TableInfo; import org.labkey.api.data.TableSelector; import org.labkey.api.exp.PropertyDescriptor; @@ -44,14 +44,14 @@ import org.labkey.api.laboratory.LaboratoryService; import org.labkey.api.query.BatchValidationException; import org.labkey.api.query.FieldKey; +import org.labkey.api.query.QueryService; +import org.labkey.api.query.UserSchema; import org.labkey.api.query.ValidationException; import org.labkey.api.reader.ColumnDescriptor; import org.labkey.api.reader.ExcelFactory; import org.labkey.api.reader.Readers; import org.labkey.api.reader.TabLoader; import org.labkey.api.security.User; -import org.labkey.api.assay.AssayProvider; -import org.labkey.api.assay.AssayService; import org.labkey.api.util.FileType; import org.labkey.api.util.JsonUtil; import org.labkey.api.util.Pair; @@ -467,9 +467,10 @@ protected void saveTemplate(ViewContext ctx, int templateId, int runId) throws B try { //validate the template exists - TableInfo ti = DbSchema.get("laboratory").getTable("assay_run_templates"); + UserSchema us = QueryService.get().getUserSchema(ctx.getUser(), ctx.getContainer().getContainerFor(ContainerType.DataType.tabParent), "laboratory"); + TableInfo ti = us.getTable("assay_run_templates"); TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowid"), templateId), null); - if (ts.getRowCount() == 0) + if (!ts.exists()) { throw new BatchValidationException(Collections.singletonList(new ValidationException("Unknown template: " + templateId)), null); } @@ -478,11 +479,11 @@ protected void saveTemplate(ViewContext ctx, int templateId, int runId) throws B row.put("runid", runId); row.put("status", "Complete"); - Table.update(ctx.getUser(), ti, row, templateId); + ti.getUpdateService().updateRows(ctx.getUser(), ctx.getContainer(), Arrays.asList(row), Arrays.asList(Map.of("rowId", templateId)), null, null); } - catch (RuntimeSQLException e) + catch (Exception e) { - throw new BatchValidationException(Collections.singletonList(new ValidationException(e.getSQLException().getMessage())), null); + throw new BatchValidationException(Collections.singletonList(new ValidationException(e.getMessage())), null); } } @@ -584,8 +585,8 @@ protected Map> getTemplateRowMap(ImportContext conte if (templateId == null) return ret; - TableInfo ti = DbSchema.get("laboratory").getTable("assay_run_templates"); - + UserSchema us = QueryService.get().getUserSchema(context.getViewContext().getUser(), context.getViewContext().getContainer().getContainerFor(ContainerType.DataType.tabParent), "laboratory"); + TableInfo ti = us.getTable("assay_run_templates"); TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowid"), templateId), null); Map[] maps = ts.getMapArray(); if (maps.length == 0) diff --git a/laboratory/src/org/labkey/laboratory/assay/AssayHelper.java b/laboratory/src/org/labkey/laboratory/assay/AssayHelper.java index ee4a9816..3076ea5c 100644 --- a/laboratory/src/org/labkey/laboratory/assay/AssayHelper.java +++ b/laboratory/src/org/labkey/laboratory/assay/AssayHelper.java @@ -32,9 +32,9 @@ import org.labkey.api.collections.CollectionUtils; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; -import org.labkey.api.data.RuntimeSQLException; +import org.labkey.api.data.ContainerType; +import org.labkey.api.data.SimpleFilter; import org.labkey.api.data.TSVMapWriter; -import org.labkey.api.data.Table; import org.labkey.api.data.TableInfo; import org.labkey.api.data.TableSelector; import org.labkey.api.exp.ChangePropertyDescriptorException; @@ -51,8 +51,12 @@ import org.labkey.api.laboratory.assay.AssayDataProvider; import org.labkey.api.laboratory.assay.AssayImportMethod; import org.labkey.api.query.BatchValidationException; +import org.labkey.api.query.FieldKey; +import org.labkey.api.query.QueryService; +import org.labkey.api.query.UserSchema; import org.labkey.api.query.ValidationException; import org.labkey.api.security.User; +import org.labkey.api.security.permissions.UpdatePermission; import org.labkey.api.util.FileUtil; import org.labkey.api.util.Pair; import org.labkey.api.view.ActionURL; @@ -66,6 +70,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -125,27 +130,27 @@ public Map saveTemplate(User u, Container c, ExpProtocol protoco { validateTemplate(u, c, protocol, templateId, title, importMethod, json); - TableInfo ti = LaboratorySchema.getInstance().getSchema().getTable(LaboratorySchema.TABLE_ASSAY_RUN_TEMPLATES); + UserSchema us = QueryService.get().getUserSchema(u, c, "laboratory"); + TableInfo ti = us.getTable(LaboratorySchema.TABLE_ASSAY_RUN_TEMPLATES); Map row = new HashMap<>(); row.put("assayId", protocol.getRowId()); row.put("title", title); row.put("importMethod", importMethod); row.put("json", json.toString()); - row.put("container", c.getId()); if (templateId == null) { - row = Table.insert(u, ti, row); + ti.getUpdateService().insertRows(u, c, Arrays.asList(row), null, null, null); } else { row.put("rowid", templateId); - row = Table.update(u, ti, row, templateId); + ti.getUpdateService().updateRows(u, c, Arrays.asList(row), Arrays.asList(Map.of("rowId", templateId)), null, null); } return row; } - catch (RuntimeSQLException e) + catch (Exception e) { _log.error(e.getMessage(), e); errors.addRowError(new ValidationException(e.getMessage())); @@ -153,7 +158,7 @@ public Map saveTemplate(User u, Container c, ExpProtocol protoco } } - public void validateTemplate(User u, Container c, ExpProtocol protocol, Integer templateId, String title, String importMethod, JSONObject json) throws BatchValidationException + public void validateTemplate(User u, Container c, ExpProtocol protocol, @Nullable Integer templateId, String title, String importMethod, JSONObject json) throws BatchValidationException { BatchValidationException errors = new BatchValidationException(); @@ -178,6 +183,42 @@ public void validateTemplate(User u, Container c, ExpProtocol protocol, Integer throw errors; } + // Verify if this template exists and permissions: + if (templateId != null) + { + UserSchema us = QueryService.get().getUserSchema(u, c.getContainerFor(ContainerType.DataType.tabParent), "laboratory"); + TableInfo ti = us.getTable("assay_run_templates"); + TableSelector ts = new TableSelector(ti, new SimpleFilter(FieldKey.fromString("rowId"), templateId), null); + if (ts.exists()) + { + Container rowContainer = ContainerManager.getForId(ts.getObject(String.class)); + if (rowContainer == null) + { + errors.addRowError(new ValidationException("Unable to determine the container for template: " + templateId)); + throw errors; + } + + if (!rowContainer.hasPermission("AssayHelper.validateTemplate()", u, UpdatePermission.class)) + { + errors.addRowError(new ValidationException("The current user does not have permission to edit template: " + templateId)); + throw errors; + } + } + else + { + errors.addRowError(new ValidationException("Unable to find template with ID: " + templateId)); + throw errors; + } + } + else + { + if (!c.hasPermission("AssayHelper.validateTemplate()", u, UpdatePermission.class)) + { + errors.addRowError(new ValidationException("The current user does not have permission to creates templates in folder: " + c.getName())); + throw errors; + } + } + method.validateTemplate(u, c, protocol, templateId, title, json, errors); if (errors.hasErrors())