diff --git a/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java b/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java index 42941678..db2bc47d 100644 --- a/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java +++ b/LDK/src/org/labkey/ldk/query/DefaultTableCustomizer.java @@ -83,6 +83,12 @@ public DefaultTableCustomizer(MultiValuedMap props) @Override public void customize(TableInfo table) { + if (table.isLocked()) + { + _log.debug("DefaultTableCustomizer called on a locked table: " + table.getPublicSchemaName() + " / " + table.getName(), new Exception()); + return; + } + if (table instanceof SchemaTableInfo) _log.error("Table customizer is being passed a SchemaTableInfo for: " + table.getPublicSchemaName() + "." + table.getPublicName()); else if (table instanceof AbstractTableInfo) diff --git a/laboratory/api-src/org/labkey/api/laboratory/DemographicsProvider.java b/laboratory/api-src/org/labkey/api/laboratory/DemographicsProvider.java new file mode 100644 index 00000000..08abecda --- /dev/null +++ b/laboratory/api-src/org/labkey/api/laboratory/DemographicsProvider.java @@ -0,0 +1,68 @@ +package org.labkey.api.laboratory; + +import org.jetbrains.annotations.Nullable; +import org.labkey.api.data.Container; +import org.labkey.api.module.Module; +import org.labkey.api.security.User; + + +public class DemographicsProvider +{ + private final Module _owningModule; + private final String _schemaName; + private final String _queryName; + private final String _subjectField; + + public DemographicsProvider(Module owningModule, String schemaName, String queryName, String subjectField) + { + _owningModule = owningModule; + _schemaName = schemaName; + _queryName = queryName; + _subjectField = subjectField; + } + + public String getSchema() + { + return _schemaName; + } + + public String getQuery() + { + return _queryName; + } + + public String getSubjectField() + { + return _subjectField; + } + + public @Nullable String getMotherField() + { + return null; + } + + public @Nullable String getFatherField() + { + return null; + } + + public @Nullable String getSexField() + { + return null; + } + + public boolean isAvailable(Container c, User u) + { + return c.getActiveModules().contains(_owningModule); + } + + public String getLabel() + { + return getSchema() + "." + getQuery(); + } + + public boolean isValidForPedigree() + { + return getMotherField() != null && getFatherField() != null && getSexField() != null; + } +} \ No newline at end of file diff --git a/laboratory/api-src/org/labkey/api/laboratory/LaboratoryService.java b/laboratory/api-src/org/labkey/api/laboratory/LaboratoryService.java index 3a7f35f5..f94f6c3d 100644 --- a/laboratory/api-src/org/labkey/api/laboratory/LaboratoryService.java +++ b/laboratory/api-src/org/labkey/api/laboratory/LaboratoryService.java @@ -15,6 +15,7 @@ */ package org.labkey.api.laboratory; +import org.jetbrains.annotations.Nullable; import org.json.JSONObject; import org.labkey.api.assay.AssayProvider; import org.labkey.api.data.Container; @@ -116,6 +117,12 @@ static public void setInstance(LaboratoryService instance) abstract public void registerTableCustomizer(Module owner, Class customizerClass, String schemaName, String queryName); + abstract public void registerDemographicsProvider(DemographicsProvider provider); + + abstract public List getDemographicsProviders(Container c, User u); + + abstract public @Nullable DemographicsProvider getDemographicsProviderByName(Container c, User u, String name); + public static enum NavItemCategory { samples(), diff --git a/laboratory/resources/web/laboratory/field/PedigreeSelectorField.js b/laboratory/resources/web/laboratory/field/PedigreeSelectorField.js new file mode 100644 index 00000000..ebb4d95b --- /dev/null +++ b/laboratory/resources/web/laboratory/field/PedigreeSelectorField.js @@ -0,0 +1,45 @@ +Ext4.define('Laboratory.field.PedigreeSelectorField', { + extend: 'LABKEY.ext4.ComboBox', + alias: 'widget.laboratory-pedigreeselectorfield', + + forceSelection: true, + typeAhead: true, + queryMode: 'local', + triggerAction: 'all', + + initComponent: function(){ + Ext4.apply(this, { + displayField: 'value', + valueField: 'value', + store: { + type: 'array', + fields: ['value'] + } + }); + + this.callParent(arguments); + + this.loadData(); + }, + + loadData: function(){ + LABKEY.Ajax.request({ + url: LABKEY.ActionURL.buildURL('laboratory', 'getDemographicsProviders', Laboratory.Utils.getQueryContainerPath()), + method : 'POST', + scope: this, + failure: LDK.Utils.getErrorCallback(), + success: LABKEY.Utils.getCallbackWrapper(function(response){ + console.log(response); + Ext4.Array.forEach(response.providers, function(d){ + if (d.isValidForPedigree) { + this.store.add(this.store.createModel({value: d.label})); + } + }, this); + }, this) + }); + }, + + getToolParameterValue : function(){ + return this.getSubmitValue(); + } +}); diff --git a/laboratory/resources/web/laboratory/panel/WorkbookHeaderPanel.js b/laboratory/resources/web/laboratory/panel/WorkbookHeaderPanel.js index afb5dee5..5d16cc5c 100644 --- a/laboratory/resources/web/laboratory/panel/WorkbookHeaderPanel.js +++ b/laboratory/resources/web/laboratory/panel/WorkbookHeaderPanel.js @@ -6,43 +6,49 @@ */ Ext4.define('Laboratory.panel.WorkbookHeaderPanel', { extend: 'LDK.panel.WebpartPanel', + panelTitle: 'Details', + initComponent: function(){ Ext4.apply(this, { - title: 'Details', + title: this.panelTitle, defaults: { border: false }, - items: [{ - html: 'Description:', - style: 'font-weight: bold;' - }, - this.getFieldCfg('description', this.description) - ,{ - html: 'Materials:', - style: 'font-weight: bold;padding-top: 10px;' - }, - this.getFieldCfg('materials', this.materials) - ,{ - html: 'Methods:', - style: 'font-weight: bold;padding-top: 10px;' - }, - this.getFieldCfg('methods', this.methods) - ,{ - html: 'Results:', - style: 'font-weight: bold;padding-top: 10px;' - }, - this.getFieldCfg('results', this.results) - ,{ - html: 'Tags:', - style: 'font-weight: bold;padding-top: 10px;' - }, - this.getTagFieldCfg() - ] + items: this.getPanelItems() }); this.callParent(arguments); }, + getPanelItems: function() { + return [{ + html: 'Description:', + style: 'font-weight: bold;' + }, + this.getFieldCfg('description', this.description) + ,{ + html: 'Materials:', + style: 'font-weight: bold;padding-top: 10px;' + }, + this.getFieldCfg('materials', this.materials) + ,{ + html: 'Methods:', + style: 'font-weight: bold;padding-top: 10px;' + }, + this.getFieldCfg('methods', this.methods) + ,{ + html: 'Results:', + style: 'font-weight: bold;padding-top: 10px;' + }, + this.getFieldCfg('results', this.results) + ,{ + html: 'Tags:', + style: 'font-weight: bold;padding-top: 10px;' + }, + this.getTagFieldCfg() + ]; + }, + getTagFieldCfg: function(){ var cfg = { layout: 'hbox', diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryController.java b/laboratory/src/org/labkey/laboratory/LaboratoryController.java index bbf2114a..c3335d39 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryController.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryController.java @@ -773,6 +773,33 @@ public ApiResponse execute(UpdateWorkbookForm form, BindException errors) throws } } + @RequiresPermission(ReadPermission.class) + public class GetDemographicsProvidersAction extends ReadOnlyApiAction + { + @Override + public ApiResponse execute(Object form, BindException errors) throws Exception + { + Map results = new HashMap<>(); + + Container target = getContainer().isWorkbook() ? getContainer().getParent() : getContainer(); + + JSONArray providers = new JSONArray(); + + LaboratoryService.get().getDemographicsProviders(target, getUser()).forEach(d -> { + JSONObject json = new JSONObject(); + json.put("label", d.getLabel()); + json.put("isValidForPedigree", d.isValidForPedigree()); + + providers.put(json); + }); + + results.put("success", true); + results.put("providers", providers); + + return new ApiSimpleResponse(results); + } + } + @RequiresPermission(UpdatePermission.class) public class UpdateWorkbookTagsAction extends MutatingApiAction { diff --git a/laboratory/src/org/labkey/laboratory/LaboratoryModule.java b/laboratory/src/org/labkey/laboratory/LaboratoryModule.java index 45896999..15fbffd0 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryModule.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryModule.java @@ -48,6 +48,7 @@ import org.labkey.api.view.template.ClientDependency; import org.labkey.api.writer.ContainerUser; import org.labkey.laboratory.notification.LabSummaryNotification; +import org.labkey.laboratory.query.LaboratoryDemographicsProvider; import org.labkey.laboratory.query.WorkbookModel; import org.labkey.laboratory.security.LaboratoryAdminRole; @@ -162,6 +163,7 @@ protected void doStartupAfterSpringConfig(ModuleContext moduleContext) LaboratoryService.get().registerDataProvider(new LaboratoryDataProvider(this)); LaboratoryService.get().registerDataProvider(new SampleTypeDataProvider()); LaboratoryService.get().registerDataProvider(new ExtraDataSourcesDataProvider(this)); + LaboratoryService.get().registerDemographicsProvider(new LaboratoryDemographicsProvider()); 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 29d8dc14..64c3358b 100644 --- a/laboratory/src/org/labkey/laboratory/LaboratoryServiceImpl.java +++ b/laboratory/src/org/labkey/laboratory/LaboratoryServiceImpl.java @@ -17,6 +17,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.jetbrains.annotations.Nullable; import org.json.JSONObject; import org.labkey.api.assay.AssayFileWriter; import org.labkey.api.assay.AssayProvider; @@ -35,6 +36,7 @@ import org.labkey.api.exp.api.ExpRun; import org.labkey.api.exp.api.ExperimentService; import org.labkey.api.laboratory.DataProvider; +import org.labkey.api.laboratory.DemographicsProvider; import org.labkey.api.laboratory.LaboratoryService; import org.labkey.api.laboratory.NavItem; import org.labkey.api.laboratory.TabbedReportItem; @@ -80,6 +82,7 @@ public class LaboratoryServiceImpl extends LaboratoryService private final Map>> _assayButtons = new CaseInsensitiveHashMap<>(); private final Map _dataProviders = new HashMap<>(); private final Map>>>> _tableCustomizers = new CaseInsensitiveHashMap<>(); + private final List _demographicsProviders = new ArrayList<>(); public static final String DEMOGRAPHICS_PROPERTY_CATEGORY = "laboratory.demographicsSource"; public static final String DATASOURCE_PROPERTY_CATEGORY = "laboratory.additionalDataSource"; @@ -677,4 +680,35 @@ private TableCustomizer instantiateCustomizer(Class c return null; } + + @Override + public void registerDemographicsProvider(DemographicsProvider provider) + { + _demographicsProviders.add(provider); + } + + @Override + public List getDemographicsProviders(final Container c, final User u) + { + return _demographicsProviders.stream().filter(d -> d.isAvailable(c, u)).toList(); + } + + @Override + public @Nullable DemographicsProvider getDemographicsProviderByName(Container c, User u, String name) + { + if (name == null) + { + throw new IllegalArgumentException("The DemographicsProvider name cannot be null"); + } + + for (DemographicsProvider d : getDemographicsProviders(c, u)) + { + if (name.equals(d.getLabel())) + { + return d; + } + } + + return null; + } } diff --git a/laboratory/src/org/labkey/laboratory/query/LaboratoryDemographicsProvider.java b/laboratory/src/org/labkey/laboratory/query/LaboratoryDemographicsProvider.java new file mode 100644 index 00000000..c97cc4da --- /dev/null +++ b/laboratory/src/org/labkey/laboratory/query/LaboratoryDemographicsProvider.java @@ -0,0 +1,36 @@ +package org.labkey.laboratory.query; + +import org.jetbrains.annotations.Nullable; +import org.labkey.api.laboratory.DemographicsProvider; +import org.labkey.api.module.ModuleLoader; +import org.labkey.laboratory.LaboratoryModule; +import org.labkey.laboratory.LaboratorySchema; + +public class LaboratoryDemographicsProvider extends DemographicsProvider +{ + public LaboratoryDemographicsProvider() + { + super(ModuleLoader.getInstance().getModule(LaboratoryModule.class), LaboratoryModule.SCHEMA_NAME, LaboratorySchema.TABLE_SUBJECTS, "subjectname"); + } + + @Nullable + @Override + public String getMotherField() + { + return "mother"; + } + + @Nullable + @Override + public String getFatherField() + { + return "father"; + } + + @Nullable + @Override + public String getSexField() + { + return "gender"; + } +} diff --git a/laboratory/src/org/labkey/laboratory/view/workbookHeader.jsp b/laboratory/src/org/labkey/laboratory/view/workbookHeader.jsp index c53b089b..8fe8b6d7 100644 --- a/laboratory/src/org/labkey/laboratory/view/workbookHeader.jsp +++ b/laboratory/src/org/labkey/laboratory/view/workbookHeader.jsp @@ -36,7 +36,7 @@ } %> <% - JspView me = (JspView) HttpView.currentView(); + JspView me = (JspView) HttpView.currentView(); WorkbookModel model = (WorkbookModel)me.getModelBean(); Integer workbookId = model.getWorkbookId(); String wpId = "wp_" + me.getWebPartRowId();