Skip to content

Merge 25.3 to develop #366

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Jul 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b6245d3
Read laboratory reports from the database as well
bbimber Jun 18, 2025
6f70971
Cleanup in NavItems / TabbedReports
bbimber Jun 18, 2025
83a1ac1
More cleanup in NavItems / TabbedReports
bbimber Jun 18, 2025
5015497
Add debug logging
bbimber Jun 20, 2025
00cbd18
Initialize schema to manage studies/cohorts/timepoints (#335)
bbimber Jun 20, 2025
446cbd2
Increase test wait
bbimber Jun 20, 2025
89da394
Add stubs for studies module customizer
bbimber Jun 21, 2025
0db6830
Add stubs for studies webpart
bbimber Jun 22, 2025
bade9bd
Add stub for manage study view
bbimber Jun 22, 2025
85a45dc
Add studies trigger
bbimber Jun 23, 2025
7a59e9c
Add AbstractIntegrationTest
bbimber Jun 23, 2025
2f871b6
Update dependencies
bbimber Jun 23, 2025
8b1bdbd
Add new dataset and perform code cleanup
bbimber Jun 23, 2025
cc7cd52
Bugfix to StudiesTriggerFactory
bbimber Jun 23, 2025
c65afbf
Refinements to customizer code, and many new SIV-related ETLs
bbimber Jun 24, 2025
a20e803
Expand SIV Queries
bbimber Jun 24, 2025
5db8f70
Case-insensitive check for field name
bbimber Jun 24, 2025
167faa4
Create annotation to track UtilityActions and Admin Console page to l…
bbimber Jun 25, 2025
f68bc4b
Better handling of job cancel
bbimber Jun 25, 2025
317ce54
Refactor TabbedReport to allow a distributed provider model (#338)
bbimber Jun 25, 2025
550e2a6
Fix error in column datatype
bbimber Jun 25, 2025
88a482a
Add columns for DPI
bbimber Jun 26, 2025
a9fb5b0
Add column
bbimber Jun 28, 2025
f1bf398
Allow use to specify clusterResolutions
bbimber Jun 28, 2025
3ce4da8
Cache unmodifiableMaps
bbimber Jun 30, 2025
29d244b
Fix merge conflicts
bbimber Jun 30, 2025
085e4cb
Update DiscvrCoreController.java
bbimber Jun 30, 2025
48e39df
Update SequenceAnalysisController.java
bbimber Jun 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions SequenceAnalysis/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ dependencies {
BuildUtils.addLabKeyDependency(project: project, config: "apiImplementation", depProjectPath: ":server:modules:LabDevKitModules:laboratory", depProjectConfig: "apiJarFile")
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: ":server:modules:LabDevKitModules:LDK", depProjectConfig: "apiJarFile")
BuildUtils.addLabKeyDependency(project: project, config: "apiImplementation", depProjectPath: ":server:modules:LabDevKitModules:LDK", depProjectConfig: "apiJarFile")
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: ":server:modules:DiscvrLabKeyModules:discvrcore", depProjectConfig: "apiJarFile")
BuildUtils.addExternalDependency(
project,
new ExternalDependency(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import org.labkey.api.data.Table;
import org.labkey.api.data.TableInfo;
import org.labkey.api.data.TableSelector;
import org.labkey.api.discvrcore.annotation.UtilityAction;
import org.labkey.api.exceptions.OptimisticConflictException;
import org.labkey.api.exp.ExperimentException;
import org.labkey.api.exp.api.DataType;
Expand Down Expand Up @@ -427,7 +428,8 @@ public void addNavTrail(NavTree tree)
tree.addChild("Analyze Alignments");
}
}


@UtilityAction(label = "Find Orphan Files", description = "This will start a pipeline job that will inspect all files in this folder to identify potential orphan or otherwise unnecessary files")
@RequiresPermission(ReadPermission.class)
public static class FindOrphanFilesAction extends ConfirmAction<Object>
{
Expand Down Expand Up @@ -4955,6 +4957,7 @@ public void setOutputFileIds(Integer[] outputFileIds)
}
}

@UtilityAction(label = "Update ExpData Path", description = "This will update the DataFileUrl on the selected ExpData to the path provided")
@RequiresSiteAdmin
public static class UpdateExpDataPathAction extends ConfirmAction<UpdateExpDataPathForm>
{
Expand Down Expand Up @@ -5241,4 +5244,4 @@ public void setDataFileUrl(String dataFileUrl)
_dataFileUrl = dataFileUrl;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ private void processContainer(Container c, Logger log) throws IOException, Pipel
if (root != null && !root.isCloudRoot())
{
//first sequences
log.debug("Inspecting sequences");
File sequenceDir = new File(root.getRootPath(), ".sequences");
TableInfo tableRefNtSequences = SequenceAnalysisSchema.getTable(SequenceAnalysisSchema.TABLE_REF_NT_SEQUENCES);
TableSelector ntTs = new TableSelector(tableRefNtSequences, new SimpleFilter(FieldKey.fromString("container"), c.getId()), null);
Expand Down Expand Up @@ -342,6 +343,7 @@ private void processContainer(Container c, Logger log) throws IOException, Pipel
}

//then libraries
log.debug("Inspecting genomes");
File libraryDir = SequenceAnalysisManager.get().getReferenceLibraryDir(c);
if (libraryDir != null && libraryDir.exists())
{
Expand Down Expand Up @@ -516,6 +518,7 @@ private void processContainer(Container c, Logger log) throws IOException, Pipel
}

//finally outputfiles
log.debug("Inspecting outputs");
TableInfo ti = SequenceAnalysisSchema.getTable(SequenceAnalysisSchema.TABLE_OUTPUTFILES);
TableSelector ts = new TableSelector(ti, Collections.singleton("dataid"), new SimpleFilter(FieldKey.fromString("container"), c.getId()), null);
Set<String> expectedFileNames = new HashSet<>();
Expand Down Expand Up @@ -563,6 +566,8 @@ private void processContainer(Container c, Logger log) throws IOException, Pipel
}
}
}

log.debug("done");
}

for (Container child : c.getChildren())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,30 +217,38 @@ public List<NavItem> getSubjectIdSummary(Container c, User u, String subjectId)
@Override
public List<TabbedReportItem> getTabbedReportItems(Container c, User u)
{
if (!c.getActiveModules().contains(getOwningModule()))
{
return Collections.emptyList();
}

List<TabbedReportItem> items = new ArrayList<>();

NavItem owner = getDataNavItems(c, u).get(0);
NavItem owner = getReportItems(c, u).get(0);
String category = "Sequence Data";
QueryCache cache = new QueryCache();

TabbedReportItem readsets = new QueryTabbedReportItem(cache, this, SequenceAnalysisSchema.SCHEMA_NAME, SequenceAnalysisSchema.TABLE_READSETS, "Sequence Readsets", category);
readsets.setOwnerKey(owner.getPropertyManagerKey());
readsets.setVisible(owner.isVisible(c, u));
items.add(readsets);

TabbedReportItem analyses = new QueryTabbedReportItem(cache, this, SequenceAnalysisSchema.SCHEMA_NAME, SequenceAnalysisSchema.TABLE_ANALYSES, "Sequence Analyses", category);
analyses.setSubjectIdFieldKey(FieldKey.fromString("readset/subjectid"));
analyses.setSampleDateFieldKey(FieldKey.fromString("readset/sampledate"));
analyses.setAllProjectsFieldKey(FieldKey.fromString("readset/allProjectsPivot"));
analyses.setOverlappingProjectsFieldKey(FieldKey.fromString("readset/overlappingProjectsPivot"));
analyses.setKeyOverride("allProjectsFieldName", FieldKey.fromString("readset/allProjectsPivot"));
analyses.setKeyOverride("overlappingProjectsFieldName", FieldKey.fromString("readset/overlappingProjectsPivot"));
analyses.setOwnerKey(owner.getPropertyManagerKey());
analyses.setVisible(owner.isVisible(c, u));
items.add(analyses);

TabbedReportItem outputs = new QueryTabbedReportItem(cache, this, SequenceAnalysisSchema.SCHEMA_NAME, SequenceAnalysisSchema.TABLE_OUTPUTFILES, "Sequence Outputs", category);
outputs.setSubjectIdFieldKey(FieldKey.fromString("readset/subjectid"));
outputs.setSampleDateFieldKey(FieldKey.fromString("readset/sampledate"));
outputs.setAllProjectsFieldKey(FieldKey.fromString("readset/allProjectsPivot"));
outputs.setOverlappingProjectsFieldKey(FieldKey.fromString("readset/overlappingProjectsPivot"));
outputs.setKeyOverride("allProjectsFieldName", FieldKey.fromString("readset/allProjectsPivot"));
outputs.setKeyOverride("overlappingProjectsFieldName", FieldKey.fromString("readset/overlappingProjectsPivot"));
outputs.setOwnerKey(owner.getPropertyManagerKey());
outputs.setVisible(owner.isVisible(c, u));
items.add(outputs);

return items;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ public void getOrphanFilesForContainer(Container c, User u, Set<File> orphanFile
return;
}


getJob().updateStatusForTask();
if (getJob().isCancelled())
{
throw new CancelledException();
Expand Down
1 change: 1 addition & 0 deletions Studies/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
resources/credits/jars.txt
9 changes: 9 additions & 0 deletions Studies/api-src/org/labkey/api/studies/StudiesService.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.labkey.api.studies;

import org.labkey.api.data.Container;
import org.labkey.api.data.TableCustomizer;
import org.labkey.api.module.Module;
import org.labkey.api.resource.Resource;
import org.labkey.api.security.User;
import org.labkey.api.studies.study.EventProvider;
import org.labkey.api.util.Path;

import java.io.IOException;
import java.util.List;

/**
* Created by bimber on 11/3/2016.
Expand All @@ -28,4 +31,10 @@ static public void setInstance(StudiesService instance)
abstract public void importFolderDefinition(Container container, User user, Module m, Path sourceFolderDirPath) throws IOException;

abstract public void loadTsv(Resource tsv, String schemaName, User u, Container c);

abstract public void registerEventProvider(EventProvider ep);

abstract public List<EventProvider> getEventProviders(Container c);

abstract public TableCustomizer getStudiesTableCustomizer();
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.labkey.studies.query;
package org.labkey.api.studies.query;

import org.apache.commons.lang3.StringUtils;
import org.labkey.api.data.ColumnInfo;
Expand All @@ -9,9 +9,9 @@
import java.text.DecimalFormat;
import java.util.Set;

public class ResultsOOODisplayColumn extends DataColumn
public class ResultsOORDisplayColumn extends DataColumn
{
public ResultsOOODisplayColumn(ColumnInfo col)
public ResultsOORDisplayColumn(ColumnInfo col)
{
super(col);
}
Expand Down Expand Up @@ -48,15 +48,15 @@ public Object getDisplayValue(RenderContext ctx)

private FieldKey getOOR()
{
FieldKey oor = FieldKey.fromString("resultOOOIndicator");
if (getBoundColumn() != null)
ColumnInfo col = getBoundColumn();
if (col == null)
{
return FieldKey.fromParts(getBoundColumn().getFieldKey().getParent(), oor);
}
else
{
return oor;
return null;
}

FieldKey oor = FieldKey.fromString(col.getFieldKey().getName() + "OORIndicator");

return getBoundColumn().getFieldKey().getParent() == null ? oor : FieldKey.fromParts(getBoundColumn().getFieldKey().getParent(), oor);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.labkey.api.studies.study;

import org.jetbrains.annotations.Nullable;
import org.labkey.api.data.Container;
import org.labkey.api.data.TableInfo;
import org.labkey.api.module.Module;
import org.labkey.api.query.QueryService;
import org.labkey.api.query.UserSchema;
import org.labkey.api.security.User;
import org.labkey.api.security.permissions.ReadPermission;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public abstract class AbstractEventProvider implements EventProvider
{
private final String _name;
private final String _label;
private final String _description;
private final Module _owner;

public AbstractEventProvider(String name, String label, String description, Module owner)
{
_name = name;
_label = label;
_description = description;
_owner = owner;
}

@Override
public String getDescription()
{
return _description;
}

@Override
public String getLabel()
{
return _label;
}

@Override
public String getName()
{
return _name;
}

@Override
public boolean isAvailable(Container c)
{
return c.getActiveModules().contains(_owner);
}

@Override
public final Map<String, Date> inferDates(Collection<String> subjectList, Container c, User u)
{
Map<String, Date> result = new HashMap<>(inferDatesRaw(subjectList, c, u));
subjectList.forEach(x -> {
if (!result.containsKey(x))
{
result.put(x, null);
}
});

return result;
}

abstract protected Map<String, Date> inferDatesRaw(Collection<String> subjectList, Container c, User u);

protected @Nullable TableInfo getTable(Container c, User u, String schema, String table)
{
UserSchema us = QueryService.get().getUserSchema(u, c, schema);
if (us == null)
{
return null;
}

TableInfo ti = us.getTable("assignment");
if (ti == null || !ti.hasPermission(u, ReadPermission.class))
{
return null;
}

return ti;
}
}
26 changes: 26 additions & 0 deletions Studies/api-src/org/labkey/api/studies/study/EventProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.labkey.api.studies.study;

import org.labkey.api.data.Container;
import org.labkey.api.security.User;

import java.util.Collection;
import java.util.Date;
import java.util.Map;

/**
* Each study will have a handful of important dates, which are used to define relative dates for each subject/participant.
* The EventProvider classes provide a code-based way to establish the handful of critical dates. This code is executed to populate
* the KeyEvents table, which maps subject/event to date.
*/
public interface EventProvider
{
boolean isAvailable(Container c);

String getName();

String getLabel();

String getDescription();

Map<String, Date> inferDates(Collection<String> subjectList, Container c, User u);
}
15 changes: 15 additions & 0 deletions Studies/build.gradle
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import org.labkey.gradle.util.BuildUtils;
import org.labkey.gradle.util.ExternalDependency;

plugins {
id 'org.labkey.build.module'
}

dependencies
{
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: ":server:modules:DiscvrLabKeyModules:discvrcore", depProjectConfig: "apiJarFile")
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: ":server:modules:LabDevKitModules:laboratory", depProjectConfig: "apiJarFile")
BuildUtils.addLabKeyDependency(project: project, config: "implementation", depProjectPath: ":server:modules:LabDevKitModules:LDK", depProjectConfig: "apiJarFile")

BuildUtils.addLabKeyDependency(project: project, config: "modules", depProjectPath: ":server:modules:LabDevKitModules:laboratory", depProjectConfig: "published", depExtension: "module")
BuildUtils.addLabKeyDependency(project: project, config: "modules", depProjectPath: ":server:modules:LabDevKitModules:LDK", depProjectConfig: "published", depExtension: "module")

BuildUtils.addLabKeyDependency(project: project, config: "modules", depProjectPath: ":server:modules:DiscvrLabKeyModules:discvrcore", depProjectConfig: "published", depExtension: "module")

BuildUtils.addExternalDependency(
project,
new ExternalDependency(
"com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}",
"jackson-databind",
"jackson-databind",
"https://github.com/FasterXML/jackson-databind",
ExternalDependency.APACHE_2_LICENSE_NAME,
ExternalDependency.APACHE_2_LICENSE_URL,
"Parsing JSON Data"
)
)
}

Loading