From 740c27b1ceeebbb9e639be365d3048975f56b100 Mon Sep 17 00:00:00 2001 From: bbimber Date: Wed, 25 Jun 2025 06:28:27 -0700 Subject: [PATCH 1/2] Refactor TabbedReport to allow a distributed provider model --- .../api/laboratory/LaboratoryService.java | 2 + .../api/laboratory/QueryTabbedReportItem.java | 3 +- .../api/laboratory/TabbedReportItem.java | 56 +++---------- .../query/TabbedReportFilterProvider.java | 8 ++ .../web/laboratory/panel/ProjectFilterType.js | 8 +- .../laboratory/LaboratoryController.java | 6 +- .../labkey/laboratory/LaboratoryModule.java | 6 +- .../laboratory/LaboratoryServiceImpl.java | 1 + .../query/ProjectGroupFilterProvider.java | 83 +++++++++++++++++++ .../labkey/laboratory/view/dataBrowser.jsp | 32 +++++-- 10 files changed, 146 insertions(+), 59 deletions(-) create mode 100644 laboratory/src/org/labkey/laboratory/query/ProjectGroupFilterProvider.java diff --git a/laboratory/api-src/org/labkey/api/laboratory/LaboratoryService.java b/laboratory/api-src/org/labkey/api/laboratory/LaboratoryService.java index 48fd1dea..636a6340 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/LaboratoryService.java +++ b/laboratory/api-src/org/labkey/api/laboratory/LaboratoryService.java @@ -128,6 +128,8 @@ static public void setInstance(LaboratoryService instance) abstract public void registerTabbedReportFilterProvider(TabbedReportFilterProvider provider); + abstract public List getTabbedReportFilterProviderProviders(final Container c, final User u); + public static enum NavItemCategory { samples(), diff --git a/laboratory/api-src/org/labkey/api/laboratory/QueryTabbedReportItem.java b/laboratory/api-src/org/labkey/api/laboratory/QueryTabbedReportItem.java index 11a0a883..dc84f851 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/QueryTabbedReportItem.java +++ b/laboratory/api-src/org/labkey/api/laboratory/QueryTabbedReportItem.java @@ -88,14 +88,13 @@ public JSONObject toJSON(Container c, User u) return null; } - inferColumnsFromTable(ti); + inferColumnsFromTable(ti, c, u); JSONObject json = super.toJSON(c, u); json.put("schemaName", getSchemaName()); json.put("queryName", getQueryName()); String viewName = getDefaultViewName(c, getOwnerKey()); - // TODO: should we always override here? if (getViewName() != null) { viewName = getViewName(); diff --git a/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java b/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java index 96507dfe..c8922661 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java +++ b/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java @@ -17,16 +17,16 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.json.JSONArray; import org.json.JSONObject; import org.labkey.api.data.ColumnInfo; import org.labkey.api.data.Container; import org.labkey.api.data.PropertyManager; import org.labkey.api.data.TableInfo; +import org.labkey.api.laboratory.query.TabbedReportFilterProvider; import org.labkey.api.query.FieldKey; import org.labkey.api.security.User; -import org.labkey.api.util.PageFlowUtil; +import java.util.HashMap; import java.util.Map; /** @@ -43,8 +43,7 @@ public class TabbedReportItem extends AbstractNavItem protected FieldKey _subjectIdFieldKey = null; protected FieldKey _sampleDateFieldKey = null; - protected FieldKey _overlappingProjectsFieldKey = null; - protected FieldKey _allProjectsFieldKey = null; + private final Map _additionalKeys = new HashMap<>(); public static final String OVERRIDES_PROP_KEY = "laboratory.tabItemOverride"; protected static final Logger _log = LogManager.getLogger(TabbedReportItem.class); @@ -94,24 +93,18 @@ public JSONObject toJSON(Container c, User u) if (_sampleDateFieldKey != null) json.put("dateFieldName", _sampleDateFieldKey); - if (_overlappingProjectsFieldKey != null) - { - json.put("overlappingProjectsFieldName", _overlappingProjectsFieldKey.toString()); - json.put("overlappingProjectsFieldKeyArray", new JSONArray(_overlappingProjectsFieldKey.getParts())); - } - - if (_allProjectsFieldKey != null) - { - json.put("allProjectsFieldName", _allProjectsFieldKey.toString()); - json.put("allProjectsFieldKeyArray", new JSONArray(_allProjectsFieldKey.getParts())); - } + JSONObject keys = new JSONObject(); + _additionalKeys.forEach((name, fk) -> { + keys.put(name, fk.toString()); + }); + json.put("additionalFieldKeys", keys); json.put("reportType", getReportType()); return json; } - protected void inferColumnsFromTable(TableInfo ti) + protected void inferColumnsFromTable(TableInfo ti, Container c, User u) { for (ColumnInfo ci : ti.getColumns()) { @@ -125,17 +118,9 @@ else if (_sampleDateFieldKey == null && LaboratoryService.SAMPLEDATE_CONCEPT_URI } } - if (_overlappingProjectsFieldKey == null || _allProjectsFieldKey == null) + for (TabbedReportFilterProvider p : LaboratoryService.get().getTabbedReportFilterProviderProviders(c, u)) { - FieldKey overlapKey = FieldKey.fromString("overlappingProjectsPivot"); - FieldKey allKey = FieldKey.fromString("allProjectsPivot"); - - Map colMap = _queryCache.getColumns(ti, PageFlowUtil.set(overlapKey, allKey)); - if (_overlappingProjectsFieldKey == null && colMap.containsKey(overlapKey)) - _overlappingProjectsFieldKey = colMap.get(overlapKey).getFieldKey(); - - if (_allProjectsFieldKey == null && colMap.containsKey(allKey)) - _allProjectsFieldKey = colMap.get(allKey).getFieldKey(); + _additionalKeys.putAll(p.getAdditionalFieldKeys(ti, this, _additionalKeys)); } } @@ -169,24 +154,9 @@ public void setSampleDateFieldKey(FieldKey sampleDateFieldKey) _sampleDateFieldKey = sampleDateFieldKey; } - public FieldKey getOverlappingProjectsFieldKey() - { - return _overlappingProjectsFieldKey; - } - - public void setOverlappingProjectsFieldKey(FieldKey overlappingProjectsFieldKey) - { - _overlappingProjectsFieldKey = overlappingProjectsFieldKey; - } - - public FieldKey getAllProjectsFieldKey() - { - return _allProjectsFieldKey; - } - - public void setAllProjectsFieldKey(FieldKey allProjectsFieldKey) + public void setKeyOverride(String name, FieldKey key) { - _allProjectsFieldKey = allProjectsFieldKey; + _additionalKeys.put(name, key); } public void setVisible(boolean visible) diff --git a/laboratory/api-src/org/labkey/api/laboratory/query/TabbedReportFilterProvider.java b/laboratory/api-src/org/labkey/api/laboratory/query/TabbedReportFilterProvider.java index a47118b6..d81b1984 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/query/TabbedReportFilterProvider.java +++ b/laboratory/api-src/org/labkey/api/laboratory/query/TabbedReportFilterProvider.java @@ -1,10 +1,15 @@ package org.labkey.api.laboratory.query; +import org.jetbrains.annotations.NotNull; import org.labkey.api.data.Container; +import org.labkey.api.data.TableInfo; +import org.labkey.api.laboratory.TabbedReportItem; +import org.labkey.api.query.FieldKey; import org.labkey.api.security.User; import org.labkey.api.view.template.ClientDependency; import java.util.Collection; +import java.util.Map; public interface TabbedReportFilterProvider { @@ -17,4 +22,7 @@ public interface TabbedReportFilterProvider String getLabel(); String getInputValue(); + + @NotNull + Map getAdditionalFieldKeys(TableInfo ti, TabbedReportItem tri, Map overrides); } diff --git a/laboratory/resources/web/laboratory/panel/ProjectFilterType.js b/laboratory/resources/web/laboratory/panel/ProjectFilterType.js index 43250fa0..3ffa08b2 100644 --- a/laboratory/resources/web/laboratory/panel/ProjectFilterType.js +++ b/laboratory/resources/web/laboratory/panel/ProjectFilterType.js @@ -83,10 +83,10 @@ Ext4.define('Laboratory.panel.ProjectFilterType', { var filters = this.getFilters(); var report = tab.report; - var projectFieldName = (filters.projectFilterMode === 'overlappingProjects') ? report.overlappingProjectsFieldName : report.allProjectsFieldName; + var projectFieldName = (filters.projectFilterMode === 'overlappingProjects') ? report.additionalFieldKeys?.overlappingProjectsFieldName : report.additionalFieldKeys?.allProjectsFieldName; if (!projectFieldName){ - if (filters.projectFilterMode === 'overlappingProjects' && !report.overlappingProjectsFieldName){ - projectFieldName = report.allProjectsFieldName; + if (filters.projectFilterMode === 'overlappingProjects' && !report.additionalFieldKeys?.overlappingProjectsFieldName){ + projectFieldName = report.additionalFieldKeys?.allProjectsFieldName; if (projectFieldName) Ext4.Msg.alert('Warning', 'This reports supports project filtering, but cannot filter by overlapping projects, since it lacks a properly configured date field. All animals assigned to the project will be shown'); @@ -125,7 +125,7 @@ Ext4.define('Laboratory.panel.ProjectFilterType', { }, validateReportForFilterType: function(report){ - if (!report.allProjectsFieldName){ + if (!report.additionalFieldKeys?.allProjectsFieldName){ return 'This report cannot be used with the selected filter type, because the report does not contain a field with project information'; } diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index 67501674..afc12fb8 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -2347,8 +2347,10 @@ public ModelAndView getView(Object form, BindException errors) throws Exception JspView view = new JspView<>("/org/labkey/laboratory/view/dataBrowser.jsp", form); view.setTitle("Data Browser"); view.setHidePageTitle(true); - //view.setFrame(WebPartView.FrameType.NONE); - //getPageConfig().setTemplate(PageConfig.Template.None); + + LaboratoryServiceImpl.get().getTabbedReportFilterProviderProviders(getContainer(), getUser()).forEach(p -> { + p.getClientDependencies().forEach(view::addClientDependency); + }); return view; } diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryModule.java b/laboratory/src/org/labkey/laboratory/LaboratoryModule.java index 1721e500..6cb8a7d8 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryModule.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryModule.java @@ -49,6 +49,7 @@ import org.labkey.api.writer.ContainerUser; import org.labkey.laboratory.notification.LabSummaryNotification; import org.labkey.laboratory.query.LaboratoryDemographicsProvider; +import org.labkey.laboratory.query.ProjectGroupFilterProvider; import org.labkey.laboratory.query.WorkbookModel; import org.labkey.laboratory.security.LaboratoryAdminRole; @@ -119,7 +120,9 @@ public WebPartView getWebPartView(@NotNull ViewContext portalCtx, @NotNull Porta { JspView view = new JspView<>("/org/labkey/laboratory/view/dataBrowser.jsp", new Object()); view.setTitle("Laboratory Data Browser"); - //view.setFrame(WebPartView.FrameType.NONE); + LaboratoryServiceImpl.get().getTabbedReportFilterProviderProviders(portalCtx.getContainer(), portalCtx.getUser()).forEach(p -> { + p.getClientDependencies().forEach(view::addClientDependency); + }); if (portalCtx.getContainer().hasPermission(portalCtx.getUser(), LaboratoryAdminPermission.class) || portalCtx.getContainer().hasPermission(portalCtx.getUser(), AdminPermission.class)) { @@ -164,6 +167,7 @@ protected void doStartupAfterSpringConfig(ModuleContext moduleContext) LaboratoryService.get().registerDataProvider(new SampleTypeDataProvider()); LaboratoryService.get().registerDataProvider(new ExtraDataSourcesDataProvider(this)); LaboratoryService.get().registerDemographicsProvider(new LaboratoryDemographicsProvider()); + LaboratoryService.get().registerTabbedReportFilterProvider(new ProjectGroupFilterProvider()); DetailsURL details = DetailsURL.fromString("/laboratory/siteLabSettings.view"); details.setContainerContext(ContainerManager.getSharedContainer()); diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryServiceImpl.java b/laboratory/src/org/labkey/laboratory/LaboratoryServiceImpl.java index 747ae62e..3a5144bc 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryServiceImpl.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryServiceImpl.java @@ -728,6 +728,7 @@ public void registerTabbedReportFilterProvider(TabbedReportFilterProvider provid _tabbedReportFilterProviders.add(provider); } + @Override public List getTabbedReportFilterProviderProviders(final Container c, final User u) { return _tabbedReportFilterProviders.stream().filter(d -> d.isAvailable(c, u)).toList(); diff --git a/laboratory/src/org/labkey/laboratory/query/ProjectGroupFilterProvider.java b/laboratory/src/org/labkey/laboratory/query/ProjectGroupFilterProvider.java new file mode 100644 index 00000000..b429f17c --- /dev/null +++ b/laboratory/src/org/labkey/laboratory/query/ProjectGroupFilterProvider.java @@ -0,0 +1,83 @@ +package org.labkey.laboratory.query; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.ColumnInfo; +import org.labkey.api.data.Container; +import org.labkey.api.data.TableInfo; +import org.labkey.api.laboratory.TabbedReportItem; +import org.labkey.api.laboratory.query.TabbedReportFilterProvider; +import org.labkey.api.module.ModuleLoader; +import org.labkey.api.query.FieldKey; +import org.labkey.api.security.User; +import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.view.template.ClientDependency; +import org.labkey.laboratory.LaboratoryModule; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ProjectGroupFilterProvider implements TabbedReportFilterProvider +{ + @Override + public boolean isAvailable(Container c, User u) + { + return c.getActiveModules().contains(ModuleLoader.getInstance().getModule(LaboratoryModule.class)); + } + + @Override + public Collection getClientDependencies() + { + return List.of(ClientDependency.fromPath("laboratory/panel/ProjectFilterType.js")); + } + + @Override + public String getXType() + { + return "laboratory-projectfiltertype"; + } + + @Override + public String getLabel() + { + return "Subject Groups"; + } + + @Override + public String getInputValue() + { + return "projects"; + } + + @Override + public @NotNull Map getAdditionalFieldKeys(TableInfo ti, TabbedReportItem tri, Map overrides) + { + Map ret = new HashMap<>(); + FieldKey parent = tri.getSubjectIdFieldKey(); + if (parent != null) + { + parent = parent.getParent(); + } + + if (overrides.get("overlappingProjectsFieldKey") == null) + { + FieldKey overlapKey = FieldKey.fromString(parent, "overlappingProjectsPivot"); + + Map colMap = tri.getQueryCache().getColumns(ti, PageFlowUtil.set(overlapKey)); + if (colMap.containsKey(overlapKey)) + ret.put("overlappingProjectsFieldKey", colMap.get(overlapKey).getFieldKey()); + } + + if (overrides.get("allProjectsFieldKey") == null) + { + FieldKey allKey = FieldKey.fromString(parent, "allProjectsPivot"); + + Map colMap = tri.getQueryCache().getColumns(ti, PageFlowUtil.set(allKey)); + if (colMap.containsKey(allKey)) + ret.put("allProjectsFieldKey", colMap.get(allKey).getFieldKey()); + } + + return ret; + } +} diff --git a/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp b/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp index e059779f..35c95e18 100644 --- a/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp +++ b/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp @@ -15,20 +15,42 @@ * limitations under the License. */ %> +<%@ page import="org.json.JSONObject" %> +<%@ page import="org.labkey.api.laboratory.query.TabbedReportFilterProvider" %> <%@ page import="org.labkey.api.view.HttpView" %> <%@ page import="org.labkey.api.view.JspView" %> <%@ page import="org.labkey.api.view.template.ClientDependencies" %> +<%@ page import="org.labkey.laboratory.LaboratoryServiceImpl" %> +<%@ page import="java.lang.Override" %> +<%@ page import="java.lang.String" %> +<%@ page import="java.lang.StringBuilder" %> <%@ page extends="org.labkey.api.jsp.JspBase" %> <%! @Override public void addClientDependencies(ClientDependencies dependencies) { dependencies.add("laboratory.context"); - dependencies.add("laboratory/panel/ProjectFilterType.js"); + } + + private String getFilterConfig() + { + StringBuilder ret = new StringBuilder(); + + for (TabbedReportFilterProvider p : LaboratoryServiceImpl.get().getTabbedReportFilterProviderProviders(getContainer(), getUser())) + { + JSONObject config = new JSONObject(); + config.put("xtype", h(p.getXType())); + config.put("inputValue", h(p.getInputValue())); + config.put("label", h(p.getLabel())); + + ret.append(config).append(","); + } + + return ret.toString(); } %> <% - JspView me = (JspView) HttpView.currentView(); + JspView me = HttpView.currentView(); String wpId = "wp_" + me.getWebPartRowId(); %> @@ -90,11 +112,7 @@ xtype: 'ldk-multisubjectfiltertype', inputValue: LDK.panel.MultiSubjectFilterType.filterName, label: LDK.panel.MultiSubjectFilterType.label - },{ - xtype: 'laboratory-projectfiltertype', - inputValue: Laboratory.panel.ProjectFilterType.filterName, - label: Laboratory.panel.ProjectFilterType.label - },{ + },<%=unsafe(getFilterConfig())%>{ xtype: 'ldk-nofiltersfiltertype', inputValue: LDK.panel.NoFiltersFilterType.filterName, label: LDK.panel.NoFiltersFilterType.label From 4febe636b4f95a5d69f4c0945b6653832bb2ebd8 Mon Sep 17 00:00:00 2001 From: bbimber Date: Wed, 25 Jun 2025 08:03:35 -0700 Subject: [PATCH 2/2] Allow admin to turn tabbed report filter types on/off --- .../api/laboratory/TabbedReportItem.java | 2 + .../query/TabbedReportFilterProvider.java | 47 ++++++++++++++++++- .../laboratory/panel/ItemVisibilityPanel.js | 45 ++++++++++++++++-- .../web/laboratory/panel/ProjectFilterType.js | 8 ++-- .../laboratory/LaboratoryController.java | 34 ++++++++++---- .../query/ProjectGroupFilterProvider.java | 7 ++- .../labkey/laboratory/view/dataBrowser.jsp | 8 ++-- 7 files changed, 128 insertions(+), 23 deletions(-) diff --git a/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java b/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java index c8922661..8859393f 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java +++ b/laboratory/api-src/org/labkey/api/laboratory/TabbedReportItem.java @@ -46,6 +46,8 @@ 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); public TabbedReportItem(DataProvider provider, String name, String label, String reportCategory) diff --git a/laboratory/api-src/org/labkey/api/laboratory/query/TabbedReportFilterProvider.java b/laboratory/api-src/org/labkey/api/laboratory/query/TabbedReportFilterProvider.java index d81b1984..e5a5f006 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/query/TabbedReportFilterProvider.java +++ b/laboratory/api-src/org/labkey/api/laboratory/query/TabbedReportFilterProvider.java @@ -1,9 +1,15 @@ package org.labkey.api.laboratory.query; import org.jetbrains.annotations.NotNull; +import org.json.JSONObject; +import org.labkey.api.collections.CaseInsensitiveHashMap; import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerType; +import org.labkey.api.data.PropertyManager; import org.labkey.api.data.TableInfo; +import org.labkey.api.laboratory.NavItem; import org.labkey.api.laboratory.TabbedReportItem; +import org.labkey.api.module.Module; import org.labkey.api.query.FieldKey; import org.labkey.api.security.User; import org.labkey.api.view.template.ClientDependency; @@ -13,7 +19,12 @@ public interface TabbedReportFilterProvider { - boolean isAvailable(Container c, User u); + default boolean isAvailable(Container c, User u) + { + return c.getActiveModules().contains(getOwningModule()); + } + + Module getOwningModule(); Collection getClientDependencies(); @@ -23,6 +34,40 @@ public interface TabbedReportFilterProvider String getInputValue(); + default JSONObject toJSON(Container c, User u) + { + JSONObject ret = new JSONObject(); + ret.put("xtype", getXType()); + ret.put("label", getLabel()); + ret.put("inputValue", getInputValue()); + ret.put("isAvailable", isAvailable(c, u)); + ret.put("isVisible", isVisible(c, u)); + ret.put("key", getPropertyManagerKey()); + + return ret; + } + + default boolean isVisible(Container c, User u) + { + Container targetContainer = c.getContainerFor(ContainerType.DataType.navVisibility); + if (getOwningModule() != null) + { + if (!targetContainer.getActiveModules().contains(getOwningModule())) + return false; + } + + Map map = new CaseInsensitiveHashMap<>(PropertyManager.getProperties(targetContainer, NavItem.PROPERTY_CATEGORY)); + if (map.containsKey(getPropertyManagerKey())) + return Boolean.parseBoolean(map.get(getPropertyManagerKey())); + + return true; + } + + default String getPropertyManagerKey() + { + return "tabReportFilterProvider||" + getClass().getSimpleName() + "||" + getLabel(); + } + @NotNull Map getAdditionalFieldKeys(TableInfo ti, TabbedReportItem tri, Map overrides); } diff --git a/laboratory/resources/web/laboratory/panel/ItemVisibilityPanel.js b/laboratory/resources/web/laboratory/panel/ItemVisibilityPanel.js index 9cd65920..54134a13 100644 --- a/laboratory/resources/web/laboratory/panel/ItemVisibilityPanel.js +++ b/laboratory/resources/web/laboratory/panel/ItemVisibilityPanel.js @@ -50,16 +50,55 @@ Ext4.define('Laboratory.panel.ItemVisibilityPanel', { this.results = results; for (var i in Laboratory.ITEM_CATEGORY){ - if (Laboratory.ITEM_CATEGORY[i].name == Laboratory.ITEM_CATEGORY.settings.name) + if (Laboratory.ITEM_CATEGORY[i].name === Laboratory.ITEM_CATEGORY.settings.name) continue; this.renderSection(Laboratory.ITEM_CATEGORY[i].name, Laboratory.ITEM_CATEGORY[i].label); } + + if (this.results.tabbedReportFilterProviderProviders) { + this.renderTabbedReportFilterProviderProviders(this.results.tabbedReportFilterProviderProviders) + } + }, + + renderTabbedReportFilterProviderProviders: function(items) { + this.remove(this.down('#loading')); + + var cfg = { + xtype: 'container', + border: false, + defaults: { + border: false + }, + style: 'margin-bottom: 20px;', + itemCategory: 'tabbedReportFilterTypes', + items: [{ + html: 'Tabbed Report Filter Types', + style: 'padding-bottom: 5px;' + }] + } + + var sectionItems = []; + Ext4.each(items, function(item){ + sectionItems.push({ + xtype: 'checkbox', + width: 800, + style: 'margin-left: 5px;', + navItem: item, + boxLabel: item.label, + checked: item.isVisible, + itemCategory: 'tabbedReportFilterTypes' + }); + }, this); + + sectionItems = LDK.Utils.sortByProperty(sectionItems, 'boxLabel'); + cfg.items = cfg.items.concat(sectionItems); + this.add(cfg); }, renderSection: function(name, label){ var items = this.results[name]; - var showReportCategory = name == 'tabbedReports'; + var showReportCategory = name === 'tabbedReports'; this.remove(this.down('#loading')); @@ -92,7 +131,7 @@ Ext4.define('Laboratory.panel.ItemVisibilityPanel', { //if items are marked as children of this item, toggle their visibility. //this is primarily used for reports field.up('form').getForm().getFields().each(function(item){ - if (item.navItem && item.navItem.ownerKey == field.navItem.key){ + if (item.navItem && item.navItem.ownerKey === field.navItem.key){ item.setValue(val); } }, this); diff --git a/laboratory/resources/web/laboratory/panel/ProjectFilterType.js b/laboratory/resources/web/laboratory/panel/ProjectFilterType.js index 3ffa08b2..41ba1ce1 100644 --- a/laboratory/resources/web/laboratory/panel/ProjectFilterType.js +++ b/laboratory/resources/web/laboratory/panel/ProjectFilterType.js @@ -83,10 +83,10 @@ Ext4.define('Laboratory.panel.ProjectFilterType', { var filters = this.getFilters(); var report = tab.report; - var projectFieldName = (filters.projectFilterMode === 'overlappingProjects') ? report.additionalFieldKeys?.overlappingProjectsFieldName : report.additionalFieldKeys?.allProjectsFieldName; + var projectFieldName = (filters.projectFilterMode === 'overlappingProjects') ? report.additionalFieldKeys?.overlappingProjectsFieldKey : report.additionalFieldKeys?.allProjectsFieldKey; if (!projectFieldName){ - if (filters.projectFilterMode === 'overlappingProjects' && !report.additionalFieldKeys?.overlappingProjectsFieldName){ - projectFieldName = report.additionalFieldKeys?.allProjectsFieldName; + if (filters.projectFilterMode === 'overlappingProjects' && !report.additionalFieldKeys?.overlappingProjectsFieldKey){ + projectFieldName = report.additionalFieldKeys?.allProjectsFieldKey; if (projectFieldName) Ext4.Msg.alert('Warning', 'This reports supports project filtering, but cannot filter by overlapping projects, since it lacks a properly configured date field. All animals assigned to the project will be shown'); @@ -125,7 +125,7 @@ Ext4.define('Laboratory.panel.ProjectFilterType', { }, validateReportForFilterType: function(report){ - if (!report.additionalFieldKeys?.allProjectsFieldName){ + if (!report.additionalFieldKeys?.allProjectsFieldKey){ return 'This report cannot be used with the selected filter type, because the report does not contain a field with project information'; } diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index afc12fb8..9dcd76f8 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -59,6 +59,7 @@ import org.labkey.api.laboratory.assay.AssayImportMethod; import org.labkey.api.laboratory.assay.AssayParser; import org.labkey.api.laboratory.query.ContainerIncrementingTable; +import org.labkey.api.laboratory.query.TabbedReportFilterProvider; import org.labkey.api.laboratory.security.LaboratoryAdminPermission; import org.labkey.api.module.Module; import org.labkey.api.module.ModuleHtmlView; @@ -1567,22 +1568,29 @@ public ApiResponse execute(JsonDataForm form, BindException errors) for (String key : json.keySet()) { String providerName = AbstractNavItem.inferDataProviderNameFromKey(key); - DataProvider provider = LaboratoryService.get().getDataProvider(providerName); - - //for some types, no DataProvider, was explicitly registered, such as many assays - //in these cases we cannot infer the owning module. - if (provider != null && provider.getOwningModule() != null) + if ("tabReportFilterProvider".equals(providerName)) + { + // Ignore + } + else { - if (!activeModules.contains(provider.getOwningModule())) + DataProvider provider = LaboratoryService.get().getDataProvider(providerName); + + //for some types, no DataProvider, was explicitly registered, such as many assays + //in these cases we cannot infer the owning module. + if (provider != null && provider.getOwningModule() != null) { - toActivate.add(provider.getOwningModule()); + if (!activeModules.contains(provider.getOwningModule())) + { + toActivate.add(provider.getOwningModule()); + } } } map.put(key, json.get(key) == null ? null : String.valueOf(json.get(key))); } - if (toActivate.size() > 0) + if (!toActivate.isEmpty()) { toActivate.addAll(activeModules); getContainer().setActiveModules(toActivate); @@ -1819,6 +1827,16 @@ public ApiResponse execute(GetDataItemsForm form, BindException errors) results.put(LaboratoryService.NavItemCategory.misc.name(), json); } + List json = new ArrayList<>(); + for (TabbedReportFilterProvider item : LaboratoryService.get().getTabbedReportFilterProviderProviders(getContainer(), getUser())) + { + if (form.isIncludeAll() || item.isAvailable(getContainer(), getUser())) + { + json.add(item.toJSON(getContainer(), getUser())); + } + } + results.put("tabbedReportFilterProviderProviders", json); + results.put("success", true); return new ApiSimpleResponse(results); diff --git a/laboratory/src/org/labkey/laboratory/query/ProjectGroupFilterProvider.java b/laboratory/src/org/labkey/laboratory/query/ProjectGroupFilterProvider.java index b429f17c..918bc617 100644 --- a/laboratory/src/org/labkey/laboratory/query/ProjectGroupFilterProvider.java +++ b/laboratory/src/org/labkey/laboratory/query/ProjectGroupFilterProvider.java @@ -2,13 +2,12 @@ import org.jetbrains.annotations.NotNull; import org.labkey.api.data.ColumnInfo; -import org.labkey.api.data.Container; import org.labkey.api.data.TableInfo; import org.labkey.api.laboratory.TabbedReportItem; import org.labkey.api.laboratory.query.TabbedReportFilterProvider; +import org.labkey.api.module.Module; import org.labkey.api.module.ModuleLoader; import org.labkey.api.query.FieldKey; -import org.labkey.api.security.User; import org.labkey.api.util.PageFlowUtil; import org.labkey.api.view.template.ClientDependency; import org.labkey.laboratory.LaboratoryModule; @@ -21,9 +20,9 @@ public class ProjectGroupFilterProvider implements TabbedReportFilterProvider { @Override - public boolean isAvailable(Container c, User u) + public Module getOwningModule() { - return c.getActiveModules().contains(ModuleLoader.getInstance().getModule(LaboratoryModule.class)); + return ModuleLoader.getInstance().getModule(LaboratoryModule.class); } @Override diff --git a/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp b/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp index 35c95e18..70beda3c 100644 --- a/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp +++ b/laboratory/src/org/labkey/laboratory/view/dataBrowser.jsp @@ -21,9 +21,6 @@ <%@ page import="org.labkey.api.view.JspView" %> <%@ page import="org.labkey.api.view.template.ClientDependencies" %> <%@ page import="org.labkey.laboratory.LaboratoryServiceImpl" %> -<%@ page import="java.lang.Override" %> -<%@ page import="java.lang.String" %> -<%@ page import="java.lang.StringBuilder" %> <%@ page extends="org.labkey.api.jsp.JspBase" %> <%! @Override @@ -38,6 +35,11 @@ for (TabbedReportFilterProvider p : LaboratoryServiceImpl.get().getTabbedReportFilterProviderProviders(getContainer(), getUser())) { + if (!p.isVisible(getContainer(), getUser())) + { + continue; + } + JSONObject config = new JSONObject(); config.put("xtype", h(p.getXType())); config.put("inputValue", h(p.getInputValue()));