Skip to content

Commit

Permalink
Deprecate ancillary study feature (#6392)
Browse files Browse the repository at this point in the history
  • Loading branch information
labkey-adam authored Feb 28, 2025
1 parent a6280c5 commit 7b787fa
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 12 deletions.
2 changes: 1 addition & 1 deletion api/src/org/labkey/api/qc/view/manageQCStates.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<%@ taglib prefix="labkey" uri="http://www.labkey.org/taglib" %>
<%@ page extends="org.labkey.api.jsp.JspBase" %>
<%
JspView<AbstractManageQCStatesBean> me = (JspView<AbstractManageQCStatesBean>) HttpView.currentView();
JspView<AbstractManageQCStatesBean> me = HttpView.currentView();
Container container = getContainer();
AbstractManageQCStatesBean bean = me.getModelBean();
Expand Down
80 changes: 76 additions & 4 deletions study/src/org/labkey/study/StudyModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
import org.labkey.api.admin.notification.NotificationService;
import org.labkey.api.attachments.AttachmentService;
import org.labkey.api.audit.AuditLogService;
import org.labkey.api.collections.LabKeyCollectors;
import org.labkey.api.data.Container;
import org.labkey.api.data.ContainerManager;
import org.labkey.api.data.PropertySchema;
import org.labkey.api.data.SimpleFilter;
import org.labkey.api.data.SqlExecutor;
import org.labkey.api.data.SqlSelector;
import org.labkey.api.data.TableInfo;
Expand All @@ -53,6 +55,7 @@
import org.labkey.api.qc.DataStateManager;
import org.labkey.api.qc.export.DataStateImportExportHelper;
import org.labkey.api.query.DefaultSchema;
import org.labkey.api.query.FieldKey;
import org.labkey.api.query.QueryService;
import org.labkey.api.query.snapshot.QuerySnapshotService;
import org.labkey.api.reports.ReportContentEmailManager;
Expand Down Expand Up @@ -95,8 +98,11 @@
import org.labkey.api.study.security.permissions.ManageStudyPermission;
import org.labkey.api.usageMetrics.UsageMetricsService;
import org.labkey.api.util.HtmlString;
import org.labkey.api.util.HtmlStringBuilder;
import org.labkey.api.util.JspTestCase;
import org.labkey.api.util.Link;
import org.labkey.api.util.PageFlowUtil;
import org.labkey.api.util.StringUtilsLabKey;
import org.labkey.api.util.SystemMaintenance;
import org.labkey.api.util.UsageReportingLevel;
import org.labkey.api.view.ActionURL;
Expand All @@ -110,6 +116,9 @@
import org.labkey.api.view.ViewContext;
import org.labkey.api.view.WebPartFactory;
import org.labkey.api.view.WebPartView;
import org.labkey.api.view.template.WarningProvider;
import org.labkey.api.view.template.WarningService;
import org.labkey.api.view.template.Warnings;
import org.labkey.api.wiki.WikiRenderingService;
import org.labkey.api.writer.ContainerUser;
import org.labkey.study.assay.ExperimentListenerImpl;
Expand All @@ -133,7 +142,26 @@
import org.labkey.study.dataset.DatasetSnapshotProvider;
import org.labkey.study.dataset.DatasetViewProvider;
import org.labkey.study.importer.StudyImporterFactory;
import org.labkey.study.model.*;
import org.labkey.study.model.CohortDomainKind;
import org.labkey.study.model.ContinuousDatasetDomainKind;
import org.labkey.study.model.DatasetDefinition;
import org.labkey.study.model.DateDatasetDomainKind;
import org.labkey.study.model.GroupSecurityType;
import org.labkey.study.model.ImportHelperServiceImpl;
import org.labkey.study.model.Participant;
import org.labkey.study.model.ParticipantGroupManager;
import org.labkey.study.model.ParticipantGroupServiceImpl;
import org.labkey.study.model.ParticipantIdImportHelper;
import org.labkey.study.model.ProtocolDocumentType;
import org.labkey.study.model.SequenceNumImportHelper;
import org.labkey.study.model.StudyDomainKind;
import org.labkey.study.model.StudyImpl;
import org.labkey.study.model.StudyLsidHandler;
import org.labkey.study.model.StudyManager;
import org.labkey.study.model.TestDatasetDomainKind;
import org.labkey.study.model.TreatmentManager;
import org.labkey.study.model.VisitDatasetDomainKind;
import org.labkey.study.model.VisitImpl;
import org.labkey.study.pipeline.StudyPipeline;
import org.labkey.study.qc.StudyQCImportExportHelper;
import org.labkey.study.qc.StudyQCStateHandler;
Expand Down Expand Up @@ -174,6 +202,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -401,9 +430,15 @@ protected void startupAfterSpringConfig(ModuleContext moduleContext)
false, false, FeatureType.Deprecated));

AdminConsole.addExperimentalFeatureFlag(DatasetQueryView.EXPERIMENTAL_QUERY_DATASETS,
"Allow query based dataset snapshots",
"Allow unprovisioned, query-based dataset snapshots to be created.",
false);
"Allow query based dataset snapshots",
"Allow unprovisioned, query-based dataset snapshots to be created.",
false);

AdminConsole.addOptionalFeatureFlag(new OptionalFeatureFlag(StudyManager.ENABLE_ANCILLARY_STUDIES,
"Restore ability to create ancillary studies",
"This option and all support for creating ancillary studies will be removed in LabKey Server v25.4.",
false, false, FeatureType.Deprecated
));

ReportAndDatasetChangeDigestProvider.get().addNotificationInfoProvider(new DatasetNotificationInfoProvider());

Expand All @@ -429,6 +464,9 @@ protected void startupAfterSpringConfig(ModuleContext moduleContext)
metric.put("linkedAssayDatasetCount", new SqlSelector(StudySchema.getInstance().getSchema(), "SELECT COUNT(PublishSourceType) FROM study.dataset WHERE PublishSourceType = 'Assay'").getObject(Long.class));

metric.put("redcapCount", new SqlSelector(PropertySchema.getInstance().getSchema(), "SELECT COUNT(*) FROM prop.PropertySets WHERE Category = 'RedcapConfigurationSettings'").getObject(Long.class));

// Note: study.StudySnapshot maintains a rows for deleted child studies (allowing re-creation of those child studies).
// In that case, Destination is set to null. COUNT(DISTINCT) skips these null values, so this returns the count of existing child studies.
metric.put("publishStudyCount", new SqlSelector(PropertySchema.getInstance().getSchema(), "SELECT COUNT(DISTINCT destination) FROM study.StudySnapshot WHERE Type = 'publish'").getObject(Long.class));
metric.put("ancillaryStudyCount", new SqlSelector(PropertySchema.getInstance().getSchema(), "SELECT COUNT(DISTINCT destination) FROM study.StudySnapshot WHERE Type = 'ancillary'").getObject(Long.class));

Expand Down Expand Up @@ -504,6 +542,40 @@ protected void startupAfterSpringConfig(ModuleContext moduleContext)

AdminConsole.addLink(AdminConsole.SettingsLinkType.Premium, "Master Patient Index", new ActionURL(StudyController.MasterPatientProviderAction.class, ContainerManager.getRoot()), AdminPermission.class);
DataStateImportExportHelper.registerProvider(new StudyQCImportExportHelper());

WarningService.get().register(new WarningProvider()
{
@Override
public void addStaticWarnings(@NotNull Warnings warnings, boolean showAllWarnings)
{
MutableInt count = new MutableInt(0);
HtmlString links = getAncillaryStudies(count);
if (showAllWarnings || !links.isEmpty())
{
HtmlStringBuilder builder = HtmlStringBuilder.of(
"Support for ancillary studies will be removed in the next release of LabKey Server. This " +
"server has " + StringUtilsLabKey.pluralize(count.getValue(), "ancillary study",
"ancillary studies") + ": [")
.append(links)
.append("]. Contact your LabKey Account Manager if you have any concerns about this change.");
warnings.add(builder);
}
}

private HtmlString getAncillaryStudies(MutableInt count)
{
StudyUrls urls = PageFlowUtil.urlProvider(StudyUrls.class);
TableInfo studySnapshot = StudySchema.getInstance().getTableInfoStudySnapshot();
FieldKey type = studySnapshot.getColumn("Type").getFieldKey();
return new TableSelector(studySnapshot, Collections.singleton("Destination"), new SimpleFilter(type, "ancillary"), null).stream(String.class)
.filter(Objects::nonNull)
.map(ContainerManager::getForId)
.filter(Objects::nonNull)
.map(c -> new Link.LinkBuilder(c.getPath()).href(urls.getBeginURL(c)).clearClasses().build().getHtmlString())
.peek(h -> count.increment())
.collect(LabKeyCollectors.joining(HtmlString.of(", ")));
}
});
}

@Override
Expand Down
5 changes: 5 additions & 0 deletions study/src/org/labkey/study/controllers/StudyController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3573,6 +3573,11 @@ public void setShowPrivateDataByDefault(boolean showPrivateDataByDefault)
}
}

public static ActionURL getManageQCStatesURL(Container c, @NotNull ActionURL returnUrl)
{
return new ActionURL(ManageQCStatesAction.class, c).addReturnURL(returnUrl);
}

@RequiresPermission(AdminPermission.class)
public class ManageQCStatesAction extends AbstractManageQCStatesAction<ManageQCStatesForm>
{
Expand Down
3 changes: 1 addition & 2 deletions study/src/org/labkey/study/model/StudyManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@
import org.labkey.api.data.TableInfo;
import org.labkey.api.data.TableSelector;
import org.labkey.api.data.UpdateableTableInfo;
import org.labkey.api.data.UpgradeCode;
import org.labkey.api.data.dialect.SqlDialect;
import org.labkey.api.dataiterator.BeanDataIterator;
import org.labkey.api.dataiterator.DataIteratorBuilder;
Expand Down Expand Up @@ -103,7 +102,6 @@
import org.labkey.api.exp.property.SystemProperty;
import org.labkey.api.gwt.client.AuditBehaviorType;
import org.labkey.api.module.Module;
import org.labkey.api.module.ModuleContext;
import org.labkey.api.module.ModuleHtmlView;
import org.labkey.api.module.ModuleLoader;
import org.labkey.api.portal.ProjectUrls;
Expand Down Expand Up @@ -234,6 +232,7 @@ public class StudyManager
{
public static final SearchService.SearchCategory datasetCategory = new SearchService.SearchCategory("dataset", "Study Datasets");
public static final SearchService.SearchCategory subjectCategory = new SearchService.SearchCategory("subject", "Study Subjects");
public static final String ENABLE_ANCILLARY_STUDIES = "enableAncillaryStudies";

private static final Logger _log = LogManager.getLogger(StudyManager.class);
private static final StudyManager _instance = new StudyManager();
Expand Down
3 changes: 1 addition & 2 deletions study/src/org/labkey/study/query/DatasetQueryView.java
Original file line number Diff line number Diff line change
Expand Up @@ -612,8 +612,7 @@ private MenuButton createQCStateButton()
{
if (!addSeparator)
button.addSeparator();
button.addMenuItem("Manage states", new ActionURL(StudyController.ManageQCStatesAction.class,
getContainer()).addReturnURL(getViewContext().getActionURL()));
button.addMenuItem("Manage states", StudyController.getManageQCStatesURL(getContainer(), getViewContext().getActionURL()));
}
return button;
}
Expand Down
8 changes: 5 additions & 3 deletions study/src/org/labkey/study/view/manageStudy.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<%@ page import="org.labkey.api.security.User" %>
<%@ page import="org.labkey.api.security.permissions.AdminPermission" %>
<%@ page import="org.labkey.api.security.permissions.ReadPermission" %>
<%@ page import="org.labkey.api.settings.OptionalFeatureService" %>
<%@ page import="org.labkey.api.study.Dataset" %>
<%@ page import="org.labkey.api.study.FolderArchiveSource" %>
<%@ page import="org.labkey.api.study.Study" %>
Expand All @@ -36,19 +37,20 @@
<%@ page import="org.labkey.api.study.TimepointType" %>
<%@ page import="org.labkey.api.study.Visit" %>
<%@ page import="org.labkey.api.study.model.ParticipantGroup" %>
<%@ page import="org.labkey.api.util.HtmlString" %>
<%@ page import="org.labkey.api.view.ActionURL" %>
<%@ page import="org.labkey.api.view.HttpView" %>
<%@ page import="org.labkey.api.view.template.ClientDependencies" %>
<%@ page import="org.labkey.study.StudyInternalServiceImpl" %>
<%@ page import="org.labkey.study.controllers.CohortController.ManageCohortsAction" %>
<%@ page import="org.labkey.study.controllers.StudyController" %>
<%@ page import="org.labkey.study.controllers.StudyController.ConfigureMasterPatientSettingsAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.DeleteStudyAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.DemoModeAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.ManageExternalReloadAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.ManageLocationsAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.ManageParticipantCategoriesAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.ManageParticipantsAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.ManageQCStatesAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.ManageStudyPropertiesAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.ManageTypesAction" %>
<%@ page import="org.labkey.study.controllers.StudyController.ManageVisitsAction" %>
Expand Down Expand Up @@ -251,7 +253,7 @@
<tr>
<td class="lk-study-prop-label">Quality Control States</td>
<td class="lk-study-prop-desc">Manage QC states for datasets in this study</td>
<td><%=link("Manage Dataset QC States", ManageQCStatesAction.class) %></td>
<td><%=link("Manage Dataset QC States", StudyController.getManageQCStatesURL(getContainer(), getActionURL())) %></td>
</tr>
<tr>
<td class="lk-study-prop-label">Study Products</td>
Expand Down Expand Up @@ -338,7 +340,7 @@
if (study.allowExport(getUser()))
{
%>
<%= button("Create Ancillary Study").onClick("showCreateStudyWizard('ancillary'); return false;") %>
<%= OptionalFeatureService.get().isFeatureEnabled(StudyManager.ENABLE_ANCILLARY_STUDIES) ? button("Create Ancillary Study").onClick("showCreateStudyWizard('ancillary'); return false;") : HtmlString.EMPTY_STRING%>
<%= button("Publish Study").onClick("showCreateStudyWizard('publish'); return false;") %>
<%
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.labkey.test.categories.Daily;
import org.labkey.test.tests.StudyBaseTest;
import org.labkey.test.util.DataRegionTable;
import org.labkey.test.util.OptionalFeatureHelper;
import org.labkey.test.util.StudyHelper;
import org.labkey.test.util.WikiHelper;

Expand Down Expand Up @@ -75,6 +76,7 @@ public void doCleanup(boolean afterTest) throws TestTimeoutException
{
_containerHelper.deleteProject(getProjectName(), afterTest);
TestFileUtils.deleteDir(new File(StudyHelper.getStudySubfolderPath(), "export"));
OptionalFeatureHelper.disableOptionalFeature(createDefaultConnection(), "enableAncillaryStudies");
}

@Override
Expand All @@ -101,6 +103,7 @@ public void doCreateSteps()

private void createAncillaryStudy()
{
OptionalFeatureHelper.enableOptionalFeature(createDefaultConnection(), "enableAncillaryStudies");
navigateToFolder(PROJECT_NAME, getFolderName());
clickTab("Manage");

Expand Down

0 comments on commit 7b787fa

Please sign in to comment.