Skip to content
This repository was archived by the owner on Feb 9, 2026. It is now read-only.

Commit e77083a

Browse files
Item 7348 : Front Page, ETL & Breadcrumbs on Reports (#272)
- Feature Request 39428: Modify home page to clarify for HIV: Font updates. - Feature Request 36306: Update virus metadata in Learn - Assays: ETL file name change from VirusPanel_Metadata.txt to VirusPanel.txt, and PK updates to cds.import_nabantigen and cds.nabantigen tables. - Feature Request 39429: Enable more than 2 reports in MAB section: add breadcrumbs on reports page. - Secure Issue 40526: Invalid param value for 'study' throws NPE : show error message instead of NPE.
1 parent 155678e commit e77083a

20 files changed

Lines changed: 216 additions & 53 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
ALTER TABLE cds.import_nabantigen DROP CONSTRAINT import_nabantigen_pkey;
2+
ALTER TABLE cds.import_nabantigen ADD PRIMARY KEY (container, assay_identifier, cds_virus_id);
3+
4+
ALTER TABLE cds.nabantigen DROP CONSTRAINT nabantigen_pkey;
5+
ALTER TABLE cds.nabantigen ADD PRIMARY KEY (container, assay_identifier, cds_virus_id);

src/org/labkey/cds/CDSController.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,7 +1036,6 @@ else if (isPost())
10361036
@RequiresPermission(ReadPermission.class)
10371037
public static class GetStudyDocumentAction extends SimpleViewAction<StudyDocumentForm>
10381038
{
1039-
@Override
10401039
public NavTree appendNavTrail(NavTree root)
10411040
{
10421041
return null;
@@ -1067,7 +1066,12 @@ public ModelAndView getView(StudyDocumentForm form, BindException errors) throws
10671066

10681067
if (!errors.hasErrors() && !StringUtils.isBlank(filename))
10691068
{
1070-
if (form.isPublicAccess() || CDSManager.get().isStudyDocumentAccessible(form.getStudy(), form.getDocumentId(), getUser(), getContainer()))
1069+
//fix for Secure Issue 40526: Invalid param value for 'study' throws NPE
1070+
if (null != form.getStudy() && null != form.getDocumentId() && !CDSManager.get().isParamValueValid(form.getStudy(), form.getDocumentId(), getUser(), getContainer()))
1071+
{
1072+
errors.reject(ERROR_MSG, "Invalid parameter value(s) for 'study' and/or 'documentId'.");
1073+
}
1074+
else if (form.isPublicAccess() || CDSManager.get().isStudyDocumentAccessible(form.getStudy(), form.getDocumentId(), getUser(), getContainer()))
10711075
{
10721076
WebdavService service = ServiceRegistry.get().getService(WebdavService.class);
10731077
WebdavResource resource = service.lookup(Path.parse(basePath + filename));

src/org/labkey/cds/CDSManager.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.labkey.cds;
1818

1919
import org.apache.commons.lang3.StringUtils;
20+
import org.jetbrains.annotations.NotNull;
2021
import org.labkey.api.data.Container;
2122
import org.labkey.api.data.ContainerManager;
2223
import org.labkey.api.data.CoreSchema;
@@ -244,16 +245,32 @@ public void setActiveUserProperties(User user, Container container, Map<String,
244245
}
245246

246247
public boolean isStudyDocumentAccessible(String studyName, String docId, User user, Container container)
248+
{
249+
TableSelector selector = getDocumentsForStudiesTableSelector(studyName, docId, user, container);
250+
return selector.getObject(Boolean.class);
251+
}
252+
253+
@NotNull
254+
private TableSelector getDocumentsForStudiesTableSelector(String studyName, String docId, User user, Container container)
247255
{
248256
TableInfo tableInfo = getCDSQueryTableInfo("learn_documentsforstudies", user, container);
249257
SimpleFilter filter = new SimpleFilter();
250258
filter.addCondition(FieldKey.fromParts("prot"), studyName);
251259
filter.addCondition(FieldKey.fromParts("document_id"), docId);
252260

253-
TableSelector selector = new TableSelector(tableInfo, Collections.singleton("accessible"), filter, null);
254-
return selector.getObject(Boolean.class);
261+
return new TableSelector(tableInfo, Collections.singleton("accessible"), filter, null);
255262
}
256263

264+
public boolean isParamValueValid(String studyName, String docId, User user, Container container)
265+
{
266+
TableSelector selector = getDocumentsForStudiesTableSelector(studyName, docId, user, container);
267+
268+
if (null == selector.getObject(Boolean.class))
269+
{
270+
return false;
271+
}
272+
return selector.getObject(Boolean.class);
273+
}
257274

258275
public static TableInfo getCDSQueryTableInfo(String queryName, User user, Container container)
259276
{

src/org/labkey/cds/CDSModule.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public String getName()
170170
@Override
171171
public @Nullable Double getSchemaVersion()
172172
{
173-
return 20.003;
173+
return 20.004;
174174
}
175175

176176
@Override

src/org/labkey/cds/data/steps/CDSImportTask.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public class CDSImportTask extends TaskRefTaskImpl
9393
new TSVCopyConfig("NAbAntigen", "AssayNABAntigen_Metadata"),
9494
new TSVCopyConfig("BAMAAntigen", "AssayBAMAAntigen_Metadata"),
9595
new TSVCopyConfig("antigenPanel", "AntigenPanel_Metadata"),
96-
new TSVCopyConfig("virusPanel", "VirusPanel_Metadata"),
96+
new TSVCopyConfig("virusPanel", "VirusPanel"),
9797

9898
// Datasets
9999
new TSVCopyConfig("ICS", "AssayICS"),

src/org/labkey/cds/view/template/FrontPage.jsp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,11 +536,16 @@
536536
<span>Don't have an account?</span>
537537
<a href="#" class="register-modal-trigger front-page-button">Register Here</a>
538538
</div>
539-
<div class="welcome">
540-
<div class="title">
539+
<div class="welcome" style="margin-bottom: unset">
540+
<div class="title" style="margin-bottom: unset">
541+
<h1></h1>
541542
<h1>Welcome to the</h1>
542543
<h1>CAVD DataSpace</h1>
543-
<h1>A data sharing and discovery tool for HIV vaccine research</h1>
544+
</div>
545+
</div>
546+
<div class="learn-more" style="max-width:unset;">
547+
<div class="container" style="margin-top: unset;">
548+
<h3>A data sharing and discovery tool for HIV vaccine research</h3>
544549
</div>
545550
</div>
546551
<div class="video-container">

test/sampledata/dataspace/cdsimport/VirusPanel_Metadata.txt renamed to test/sampledata/dataspace/cdsimport/VirusPanel.txt

File renamed without changes.

test/src/org/labkey/test/tests/cds/CDSMAbTest.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,24 @@
2222
import org.junit.experimental.categories.Category;
2323
import org.junit.rules.Timeout;
2424
import org.labkey.test.Locator;
25+
import org.labkey.test.TestFileUtils;
2526
import org.labkey.test.pages.cds.AntigenFilterPanel;
2627
import org.labkey.test.pages.cds.CDSExport;
2728
import org.labkey.test.pages.cds.InfoPane;
2829
import org.labkey.test.pages.cds.MAbDataGrid;
2930
import org.labkey.test.util.cds.CDSHelper;
3031
import org.openqa.selenium.WebElement;
3132

33+
import java.io.File;
3234
import java.io.IOException;
3335
import java.util.ArrayList;
3436
import java.util.Arrays;
3537
import java.util.List;
3638
import java.util.concurrent.TimeUnit;
3739

40+
import static org.junit.Assert.assertEquals;
41+
import static org.junit.Assert.assertFalse;
42+
import static org.junit.Assert.assertTrue;
3843
import static org.labkey.test.pages.cds.MAbDataGrid.ANTIGEN_BINDING_COL;
3944
import static org.labkey.test.pages.cds.MAbDataGrid.CLADES_COL;
4045
import static org.labkey.test.pages.cds.MAbDataGrid.GEOMETRIC_MEAN_IC50_COL;
@@ -227,7 +232,7 @@ public void testMAbSearchFilter()
227232
}
228233

229234
@Test
230-
public void testMAbReports()
235+
public void testMAbReports() throws IOException
231236
{
232237
CDSHelper.NavigationLink.MABGRID.makeNavigationSelection(this);
233238
MAbDataGrid grid = new MAbDataGrid(getGridEl(), this, this);
@@ -284,6 +289,42 @@ public void testMAbReports()
284289
log("Verify the 2nd R report");
285290
grid.openIC50Report();
286291
Assert.assertTrue("Report image is not rendered", isElementPresent(grid.getReportImageOut()));
292+
293+
verifyBreadCrumbs(grid);
294+
}
295+
296+
private void verifyBreadCrumbs(MAbDataGrid grid) throws IOException
297+
{
298+
log("Verify header breadcrumbs from the Reports view");
299+
clickExportCSVBreadCrumb();
300+
clickExportExcelBreadCrumb();
301+
clickViewGrid(grid);
302+
}
303+
304+
private void clickViewGrid(MAbDataGrid grid)
305+
{
306+
log("Verify 'View Grid' button takes user back to MAb grid.");
307+
Locator.XPathLocator viewGridBtn = Locator.tagWithId("a", "mabgridcolumnsbtn-breadcrumb");
308+
click(viewGridBtn);
309+
assertTrue("Unable to get back to the grid, MAb report buttons not present",
310+
isElementPresent(grid.getDilutionReportBtn()) && isElementPresent(grid.getIC50ReportBtn()));
311+
}
312+
313+
private void clickExportExcelBreadCrumb()
314+
{
315+
log("Verify 'Export CSV' button downloads the zip from Reports view.");
316+
Locator.XPathLocator exportExcelBtn = Locator.tagWithId("a", "gridexportexcelbtn-breadcrumb");
317+
File exceldownload = clickAndWaitForDownload(exportExcelBtn);
318+
String fileContents = TestFileUtils.getFileContents(exceldownload);
319+
assertTrue("Empty file", fileContents.length() > 0);
320+
}
321+
322+
private void clickExportCSVBreadCrumb() throws IOException
323+
{
324+
Locator.XPathLocator exportCSVBtn = Locator.tagWithId("a", "gridexportcsvbtn-breadcrumb");
325+
File csvZipArchive = clickAndWaitForDownload(exportCSVBtn);
326+
assertEquals("Zip archive file count mismatch (expected these files in the zip archive: Assays.csv, MAbs.csv, Metadata.txt, NAB MAB.csv, Studies.csv, Study and MAbs.csv, Variable definitions.csv)", 7,
327+
TestFileUtils.getFilesInZipArchive(csvZipArchive).size());
287328
}
288329

289330
private void verifyReportContent(List<String> expectedContent, String reportContent)

test/src/org/labkey/test/tests/cds/CDSTestLearnAbout.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,8 @@ private void verifyNonIntegratedDetailFieldValues(String value, String suffix)
11361136
private void verifyNonIntegratedDownloadLink(String altText, String documentName)
11371137
{
11381138
Locator.XPathLocator downloadLinkLocator = Locator.tagWithAttributeContaining("img", "alt", altText);
1139-
File downloadedFile = clickAndWaitForDownload(downloadLinkLocator, 1)[0];
1139+
scrollIntoView(downloadLinkLocator);
1140+
File downloadedFile = clickAndWaitForDownload(downloadLinkLocator);
11401141
assertTrue(downloadedFile + " not downloaded.", downloadedFile.getName().contains(documentName));
11411142
}
11421143

@@ -1149,7 +1150,7 @@ private void verifyNonIntegratedDataHeader(String studyName)
11491150

11501151
verifySectionHeaders("Non-integrated data");
11511152

1152-
Locator.XPathLocator nonIntegratedDataElement = Locator.tagWithAttributeContaining("div", "id", "nonintegrateddataavailability");
1153+
Locator.XPathLocator nonIntegratedDataElement = Locator.tagWithAttributeContaining("div", "id", "studynonintegrateddata");
11531154
assertElementPresent(nonIntegratedDataElement);
11541155

11551156
Locator.XPathLocator instructions = nonIntegratedDataElement.withDescendant(Locator.tag("p")).containing("Download individual files");
@@ -1676,18 +1677,21 @@ public void validateReportsDocumentLinks()
16761677
documentLink = CDSHelper.Locators.studyReportLink("Epitope Mapping Results Summary").findElement(getDriver());
16771678
assertTrue("Was not able to find link to the Powerpoint document for study '" + studyName + "'.", documentLink != null);
16781679
documentName = "cvd260_CAVIMC 031 Linear Epitope Mapping_BaselineSubtracted-3.pptx";
1680+
scrollIntoView(documentLink);
16791681
cds.validateDocLink(documentLink, documentName);
16801682

16811683
log("Now check the Excel link.");
16821684
documentLink = CDSHelper.Locators.studyReportLink("NAB Data Summary 2").findElement(getDriver());
16831685
assertTrue("Was not able to find link to the Excel document for study '" + studyName + "'.", documentLink != null);
16841686
documentName = "cvd260_CAVIMC-031 Neutralization Data with AUC 3 May 2011-6.xlsx";
1687+
scrollIntoView(documentLink);
16851688
cds.validateDocLink(documentLink, documentName);
16861689

16871690
log("Finally for this study validate the pdf file.");
16881691
documentLink = CDSHelper.Locators.studyReportLink("NAB Data Summary 1").findElement(getDriver());
16891692
assertTrue("Was not able to find link to the PDF document for study '" + studyName + "'.", documentLink != null);
16901693
documentName = "cvd260_McElrath_Seder_Antibody Responses 1.1 01Jun11.pdf";
1694+
scrollIntoView(documentLink);
16911695
cds.validatePDFLink(documentLink, documentName);
16921696

16931697
cds.viewLearnAboutPage("Studies");
@@ -1706,12 +1710,14 @@ public void validateReportsDocumentLinks()
17061710
documentLink = CDSHelper.Locators.studyReportLink("CFSE Results Summary").findElement(getDriver());
17071711
assertTrue("Was not able to find link to the Word Document document for study '" + studyName + "'.", documentLink != null);
17081712
documentName = "cvd264_DCVax001_CFSE_Memo_JUL13_v4.docx";
1713+
scrollIntoView(documentLink);
17091714
cds.validateDocLink(documentLink, documentName);
17101715

17111716
log("Now check one of the PDF link.");
17121717
documentLink = CDSHelper.Locators.studyReportLink("ICS Data Summary").findElement(getDriver());
17131718
assertTrue("Was not able to find link to the PDF document for study '" + studyName + "'.", documentLink != null);
17141719
documentName = "cvd264_ICS_LAB_REPORT_19APR13_n24fcm_fh_IL2_CD154_MIMOSA.pdf";
1720+
scrollIntoView(documentLink);
17151721
cds.validatePDFLink(documentLink, documentName);
17161722

17171723
cds.viewLearnAboutPage("Studies");

webapp/Connector/src/app/store/Publication.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ Ext.define('Connector.app.store.Publication', {
151151
}, this);
152152

153153
// map the docs to each publication
154-
let publicationMap = {};
154+
var publicationMap = {};
155155
Ext.each(documents, function (doc) {
156156
publicationMap[doc.publication_id] = publicationMap[doc.publication_id] || [];
157157
publicationMap[doc.publication_id].push(doc);

0 commit comments

Comments
 (0)