From 375d5cc56ccb222ee525368a72ffc17b815e98ce Mon Sep 17 00:00:00 2001 From: Lum Date: Thu, 2 Apr 2026 16:53:13 -0700 Subject: [PATCH 1/2] Use product container filter when available. --- .../org/labkey/study/assay/StudyPublishManager.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/study/src/org/labkey/study/assay/StudyPublishManager.java b/study/src/org/labkey/study/assay/StudyPublishManager.java index 8a30d5c44e7..c8d97795542 100644 --- a/study/src/org/labkey/study/assay/StudyPublishManager.java +++ b/study/src/org/labkey/study/assay/StudyPublishManager.java @@ -1126,6 +1126,11 @@ public void autoLinkDerivedSamples(ExpSampleType sampleType, List keys, Co qs.setQueryName(sampleType.getName()); qs.setBaseFilter(new SimpleFilter().addInClause(FieldKey.fromParts("RowId"), keys)); + // issue 901 : lineage sourced subject or timepoint information are not resolving in cross folder configurations + ContainerFilter.Type cf = QueryService.get().getContainerFilterTypeForLookups(container); + if (cf != null) + qs.setContainerFilterName(cf.name()); + Map fieldKeyMap = StudyPublishService.get().getSamplePublishFieldKeys(user, container, sampleType, qs); UserSchema userSchema = QueryService.get().getUserSchema(user, container, SamplesSchema.SCHEMA_NAME); QueryView view = new QueryView(userSchema, qs, null); @@ -1231,15 +1236,18 @@ public void autoLinkSamples(ExpSampleType sampleType, List for (Map row : results) { Object timePointValue = getTimepointValue(row, publishKeys, visitBased, translateMap); - if (row.containsKey(publishKeys.get(LinkToStudyKeys.ParticipantId)) && timePointValue != null) + Object subjectId = row.get(publishKeys.get(LinkToStudyKeys.ParticipantId)); + if (subjectId != null && timePointValue != null) { dataMaps.add(Map.of( - LinkToStudyKeys.ParticipantId.name(), row.get(publishKeys.get(LinkToStudyKeys.ParticipantId)), + LinkToStudyKeys.ParticipantId.name(), subjectId, timePointPropName, timePointValue, StudyPublishService.ROWID_PROPERTY_NAME, row.get(FieldKey.fromParts(StudyPublishService.ROWID_PROPERTY_NAME)), StudyPublishService.SOURCE_LSID_PROPERTY_NAME, sampleType.getLSID() )); } + else + LOG.error("Failed to auto link samples to study for folder {}. Timepoint and subject ID were both not resolved.", container.getPath()); } } From 57607da92d267e1a9c24eba839a04f0ae922702b Mon Sep 17 00:00:00 2001 From: Lum Date: Mon, 6 Apr 2026 11:07:11 -0700 Subject: [PATCH 2/2] Set the container filter for auto-linking samples from product folders. Implement server side getContainerFilterForFolder method. --- .../org/labkey/api/query/QueryService.java | 34 ++++++++++++++++--- .../org/labkey/query/QueryServiceImpl.java | 34 +++++++++++++++++++ .../study/assay/StudyPublishManager.java | 6 ++-- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/api/src/org/labkey/api/query/QueryService.java b/api/src/org/labkey/api/query/QueryService.java index f4506494969..1d2205dbdc2 100644 --- a/api/src/org/labkey/api/query/QueryService.java +++ b/api/src/org/labkey/api/query/QueryService.java @@ -16,18 +16,38 @@ package org.labkey.api.query; +import jakarta.servlet.http.HttpSession; import org.apache.commons.collections4.SetValuedMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.json.JSONObject; import org.labkey.api.audit.AuditHandler; import org.labkey.api.audit.DetailedAuditTypeEvent; +import org.labkey.api.data.ColumnHeaderType; +import org.labkey.api.data.ColumnInfo; +import org.labkey.api.data.CompareType; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerFilter; +import org.labkey.api.data.DbSchema; +import org.labkey.api.data.DisplayColumn; +import org.labkey.api.data.Filter; +import org.labkey.api.data.JdbcType; +import org.labkey.api.data.MethodInfo; +import org.labkey.api.data.MutableColumnInfo; +import org.labkey.api.data.ParameterDescription; +import org.labkey.api.data.ParameterDescriptionImpl; +import org.labkey.api.data.QueryLogging; +import org.labkey.api.data.Results; +import org.labkey.api.data.SQLFragment; +import org.labkey.api.data.Sort; +import org.labkey.api.data.SqlSelector; +import org.labkey.api.data.TableInfo; +import org.labkey.api.data.TableSelector; +import org.labkey.api.data.dialect.SqlDialect; import org.labkey.api.gwt.client.model.GWTPropertyDescriptor; +import org.labkey.api.module.Module; import org.labkey.api.pipeline.PipelineJob; import org.labkey.api.query.column.ColumnInfoTransformer; -import org.labkey.api.data.*; -import org.labkey.api.data.dialect.SqlDialect; -import org.labkey.api.module.Module; import org.labkey.api.query.column.ConceptURIColumnInfoTransformer; import org.labkey.api.query.snapshot.QuerySnapshotDefinition; import org.labkey.api.security.User; @@ -41,7 +61,6 @@ import org.labkey.data.xml.TableType; import org.springframework.web.servlet.mvc.Controller; -import jakarta.servlet.http.HttpSession; import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; @@ -653,6 +672,13 @@ default MutableColumnInfo applyColumnTransformer(MutableColumnInfo col) @Nullable ContainerFilter getContainerFilterForLookups(Container container, User user); + /** + * Provides the configured ContainerFilter to utilize when requesting data that is being read + * within a folder context. Equivalent to the client side function in @labkey/components + */ + @Nullable + ContainerFilter getContainerFilterForFolder(Container container, User user); + interface SelectBuilder { diff --git a/query/src/org/labkey/query/QueryServiceImpl.java b/query/src/org/labkey/query/QueryServiceImpl.java index ecf58bc27d8..749bbb656d8 100644 --- a/query/src/org/labkey/query/QueryServiceImpl.java +++ b/query/src/org/labkey/query/QueryServiceImpl.java @@ -3516,6 +3516,40 @@ public ContainerFilter getContainerFilterForLookups(Container container, User us return type.create(container, user); } + @Override + @Nullable + public ContainerFilter getContainerFilterForFolder(Container container, User user) + { + // Check to see if product folders support is enabled. + if (container == null || !container.isProductFoldersEnabled()) + return null; + + if (isProductFoldersDataListingScopedToProject()) + { + // When requesting data from a top-level folder context the ContainerFilter filters + // "down" the folder hierarchy for data. + if (container.isProject()) + { + if (isProductFoldersAllFolderScopeEnabled()) + return ContainerFilter.Type.AllInProjectPlusShared.create(container, user); + return ContainerFilter.Type.CurrentAndSubfoldersPlusShared.create(container, user); + } + + // When listing data in a folder scope return data scoped to the current + // folder when the experimental feature is enabled. + return ContainerFilter.Type.Current.create(container, user); + } + + // When requesting data from a top-level folder context the ContainerFilter filters + // "down" the folder hierarchy for data. + if (container.isProject()) + return ContainerFilter.Type.CurrentAndSubfoldersPlusShared.create(container, user); + + // When requesting data from a sub-folder context the ContainerFilter filters + // "up" the folder hierarchy for data. + return ContainerFilter.Type.CurrentPlusProjectAndShared.create(container, user); + } + @Override @Nullable public ContainerFilter.Type getContainerFilterTypeForLookups(Container container) diff --git a/study/src/org/labkey/study/assay/StudyPublishManager.java b/study/src/org/labkey/study/assay/StudyPublishManager.java index c8d97795542..dca8ef3396c 100644 --- a/study/src/org/labkey/study/assay/StudyPublishManager.java +++ b/study/src/org/labkey/study/assay/StudyPublishManager.java @@ -1126,10 +1126,10 @@ public void autoLinkDerivedSamples(ExpSampleType sampleType, List keys, Co qs.setQueryName(sampleType.getName()); qs.setBaseFilter(new SimpleFilter().addInClause(FieldKey.fromParts("RowId"), keys)); - // issue 901 : lineage sourced subject or timepoint information are not resolving in cross folder configurations - ContainerFilter.Type cf = QueryService.get().getContainerFilterTypeForLookups(container); + // issue GH901 : lineage sourced subject or timepoint information are not resolving in cross folder configurations + ContainerFilter cf = QueryService.get().getContainerFilterForFolder(container, user); if (cf != null) - qs.setContainerFilterName(cf.name()); + qs.setContainerFilterName(cf.getType().name()); Map fieldKeyMap = StudyPublishService.get().getSamplePublishFieldKeys(user, container, sampleType, qs); UserSchema userSchema = QueryService.get().getUserSchema(user, container, SamplesSchema.SCHEMA_NAME);