Skip to content
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

Deprecate ancillary study feature #6392

Merged
merged 4 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine but I probably would have return a List and do the joining in the caller. That avoids the need for the MutableInt. But this short-lived code.

{
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