diff --git a/luminex/src/org/labkey/luminex/query/AnalyteSinglePointControlTable.java b/luminex/src/org/labkey/luminex/query/AnalyteSinglePointControlTable.java
index 5e0d830d33..1f81fed166 100644
--- a/luminex/src/org/labkey/luminex/query/AnalyteSinglePointControlTable.java
+++ b/luminex/src/org/labkey/luminex/query/AnalyteSinglePointControlTable.java
@@ -140,7 +140,7 @@ public void renderGridCellContents(RenderContext ctx, Writer out) throws IOExcep
int analyte = (int)ctx.get("analyte");
int singlePointControl = (int)ctx.get("singlePointControl");
- String linkTag = "";
+ String linkTag = "";
out.write( String.format(linkTag, protocolId, analyte, singlePointControl, "MFI") );
out.write( String.format("
", AppProps.getInstance().getContextPath() + "/luminex/ljPlotIcon.png") );
@@ -165,7 +165,7 @@ public boolean isFilterable()
// set the default columns for this table to be those used for the QC Report
List defaultCols = new ArrayList<>();
defaultCols.add(FieldKey.fromParts("SinglePointControl", "Run", "Name"));
- defaultCols.add(FieldKey.fromParts("LJPlots"));
+ defaultCols.add(FieldKey.fromParts("L-J Plots"));
defaultCols.add(FieldKey.fromParts("SinglePointControl", "Name"));
defaultCols.add(FieldKey.fromParts("SinglePointControl", "Run", "Batch", "Network"));
defaultCols.add(FieldKey.fromParts("SinglePointControl", "Run", "Batch", "CustomProtocol"));
@@ -180,7 +180,7 @@ public boolean isFilterable()
defaultCols.add(FieldKey.fromParts("Analyte", "Properties", "LotNumber"));
defaultCols.add(FieldKey.fromParts("GuideSet", "Created"));
defaultCols.add(FieldKey.fromParts("AverageFiBkgd"));
- defaultCols.add(FieldKey.fromParts("AverageFiBkgdQCFlagsEnabled"));
+ defaultCols.add(FieldKey.fromParts("SinglePointControl", "Run", "QCFlags"));
setDefaultVisibleColumns(defaultCols);
}
diff --git a/luminex/src/org/labkey/luminex/query/AnalyteTitrationTable.java b/luminex/src/org/labkey/luminex/query/AnalyteTitrationTable.java
index cdcdd7b710..262be3ef3f 100644
--- a/luminex/src/org/labkey/luminex/query/AnalyteTitrationTable.java
+++ b/luminex/src/org/labkey/luminex/query/AnalyteTitrationTable.java
@@ -141,7 +141,7 @@ public void renderGridCellContents(RenderContext ctx, Writer out) throws IOExcep
int analyte = (int)ctx.get("analyte");
int titration = (int)ctx.get("titration");
- String jsFuncCall = "javascript:LABKEY.LeveyJenningsPlotHelper.getLeveyJenningsPlotWindow(%d,%d,%d,'%s')";
+ String jsFuncCall = "javascript:LABKEY.LeveyJenningsPlotHelper.getLeveyJenningsPlotWindow(%d,%d,%d,'%s','Titration')";
NavTree ljPlotsNav = new NavTree("Levey-Jennings Plot Menu");
ljPlotsNav.setImage(AppProps.getInstance().getContextPath() + "/luminex/ljPlotIcon.png", 27, 20);
@@ -174,7 +174,7 @@ public boolean isFilterable()
// set the default columns for this table to be those used for the QC Report
List defaultCols = new ArrayList<>();
defaultCols.add(FieldKey.fromParts("Titration", "Run", "Name"));
- defaultCols.add(FieldKey.fromParts("LJPlots"));
+ defaultCols.add(FieldKey.fromParts("L-J Plots"));
defaultCols.add(FieldKey.fromParts("Titration"));
defaultCols.add(FieldKey.fromParts("Titration", "Standard"));
defaultCols.add(FieldKey.fromParts("Titration", "QCControl"));
@@ -196,6 +196,7 @@ public boolean isFilterable()
defaultCols.add(FieldKey.fromParts(StatsService.CurveFitType.FIVE_PARAMETER.getLabel() + "CurveFit", "EC50"));
defaultCols.add(FieldKey.fromParts("MaxFI"));
defaultCols.add(FieldKey.fromParts("TrapezoidalCurveFit", "AUC"));
+ defaultCols.add(FieldKey.fromParts("Titration", "Run", "QCFlags"));
setDefaultVisibleColumns(defaultCols);
}
diff --git a/luminex/src/org/labkey/luminex/view/leveyJenningsReport.jsp b/luminex/src/org/labkey/luminex/view/leveyJenningsReport.jsp
index f232529729..19badf9774 100644
--- a/luminex/src/org/labkey/luminex/view/leveyJenningsReport.jsp
+++ b/luminex/src/org/labkey/luminex/view/leveyJenningsReport.jsp
@@ -21,7 +21,6 @@
*/
%>
-<%@ page import="org.labkey.api.util.PageFlowUtil" %>
<%@ page import="org.labkey.api.view.HttpView" %>
<%@ page import="org.labkey.api.view.JspView" %>
<%@ page import="org.labkey.api.view.template.ClientDependencies" %>
@@ -41,6 +40,13 @@
LeveyJenningsForm bean = me.getModelBean();
%>
+
+
@@ -58,7 +64,7 @@
var $h = Ext.util.Format.htmlEncode;
- // the default number of records to return for the report when no start and end date are provided
+ // the default number of records to return for the report when no filters have been applied
var defaultRowSize = 30;
// local variables for storing the selected graph parameters
@@ -189,15 +195,7 @@
controlType: _controlType,
assayName: _protocolName,
listeners: {
- 'applyGraphBtnClicked': function(analyte, isotype, conjugate){
- _analyte = analyte;
- _isotype = isotype;
- _conjugate = conjugate;
-
- guideSetPanel.graphParamsSelected(analyte, isotype, conjugate);
- trendPlotPanel.graphParamsSelected(analyte, isotype, conjugate);
- trackingDataPanel.graphParamsSelected(analyte, isotype, conjugate, null, null);
- },
+ 'applyGraphBtnClicked': graphParamsSelected,
'graphParamsChanged': function(){
guideSetPanel.disable();
trendPlotPanel.disable();
@@ -231,7 +229,7 @@
'currentGuideSetUpdated': function() {
guideSetPanel.toggleExportBtn(false);
trendPlotPanel.setTrendPlotLoading();
- trackingDataPanel.graphParamsSelected(_analyte, _isotype, _conjugate, trendPlotPanel.getStartDate(), trendPlotPanel.getEndDate());
+ trackingDataPanel.graphParamsSelected(_analyte, _isotype, _conjugate, true);
},
'exportPdfBtnClicked': function() {
trendPlotPanel.exportToPdf();
@@ -255,10 +253,6 @@
has4PLCurveFit: _has4PLCurveFit,
has5PLCurveFit: _has5PLCurveFit,
listeners: {
- 'reportFilterApplied': function(startDate, endDate, network, networkAny, protocol, protocolAny) {
- trendPlotPanel.setTrendPlotLoading();
- trackingDataPanel.graphParamsSelected(_analyte, _isotype, _conjugate, startDate, endDate, network, networkAny, protocol, protocolAny);
- },
'togglePdfBtn': function(toEnable) {
guideSetPanel.toggleExportBtn(toEnable);
}
@@ -268,7 +262,6 @@
// initialize the grid panel to display the tracking data
var trackingDataPanel = new LABKEY.LeveyJenningsTrackingDataPanel({
renderTo: 'trackingDataPanel',
- cls: 'extContainer',
controlName: _controlName,
controlType: _controlType,
assayName: _protocolName,
@@ -281,14 +274,31 @@
'appliedGuideSetUpdated': function() {
guideSetPanel.toggleExportBtn(false);
trendPlotPanel.setTrendPlotLoading();
- trackingDataPanel.graphParamsSelected(_analyte, _isotype, _conjugate, trendPlotPanel.getStartDate(), trendPlotPanel.getEndDate(),
- trendPlotPanel.network, trendPlotPanel.networkAny, trendPlotPanel.protocol, trendPlotPanel.protocolAny);
+ trackingDataPanel.graphParamsSelected(_analyte, _isotype, _conjugate, true);
+ },
+ 'plotDataLoading': function(store, hasGuideSetUpdates) {
+ trendPlotPanel.plotDataLoading(store, hasGuideSetUpdates);
+ },
+ 'plotDataLoaded': function(store, hasReportFilter) {
+ trendPlotPanel.plotDataLoaded(store, hasReportFilter);
},
- 'trackingDataLoaded': function(store) {
- trendPlotPanel.trackingDataLoaded(store);
- }
}
});
+
+ function graphParamsSelected(analyte, isotype, conjugate){
+ _analyte = analyte;
+ _isotype = isotype;
+ _conjugate = conjugate;
+
+ guideSetPanel.graphParamsSelected(analyte, isotype, conjugate);
+ trendPlotPanel.graphParamsSelected(analyte, isotype, conjugate);
+ trackingDataPanel.graphParamsSelected(analyte, isotype, conjugate);
+ }
+
+ var urlParams = LABKEY.ActionURL.getParameters();
+ if (urlParams.hasOwnProperty("analyte") && urlParams.hasOwnProperty("isotype") && urlParams.hasOwnProperty("conjugate")) {
+ graphParamsSelected(urlParams.analyte, urlParams.isotype, urlParams.conjugate);
+ }
}
Ext.onReady(init);
diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetDisablingTest.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetDisablingTest.java
index c20cf3c523..e24891622d 100644
--- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetDisablingTest.java
+++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetDisablingTest.java
@@ -208,10 +208,10 @@ public void verifyQCFlagToggling()
{
// note: this uses the run based guide set
- // simular to verifyHighlightUpdatesAfterQCFlagChange (but not quite the same... not sure how this other place works)
+ // similar to verifyHighlightUpdatesAfterQCFlagChange (but not quite the same... not sure how this other place works)
_guideSetHelper.goToLeveyJenningsGraphPage(TEST_ASSAY_LUM, CONTROL_NAME);
_guideSetHelper.setUpLeveyJenningsGraphParams(RUN_BASED_ANALYTE);
- final String plate1_AUC = "64608.73";
+ final String plate1_AUC = "64608.734";
final String plate2_AUC = "61889.88";
validateFlaggedForQC(plate1_AUC, plate2_AUC);
@@ -244,23 +244,17 @@ public void verifyQCFlagToggling()
private void saveGuideSetParameters()
{
- // Wait for grid to refresh before checking QC flags
- doAndWaitForElementToRefresh(() -> click(Ext4Helper.Locators.windowButton(GUIDE_SET_WINDOW_NAME, "Save")),
- Locator.tagWithId("div", "trackingDataPanel").append(Locator.byClass("x-grid3-row-table")), shortWait());
+ click(Ext4Helper.Locators.windowButton(GUIDE_SET_WINDOW_NAME, "Save"));
_guideSetHelper.waitForGuideSetExtMaskToDisappear();
}
private void validateFlaggedForQC(String... texts)
{
- // NOTE: We sometimes get a bad value here which we are investigating. For now the test will ignore such a value.
- List badVals = Arrays.asList("8.08", "7.90");
-
- Locator redCellLoc = Locator.tagWithId("div", "trackingDataPanel").append(Locator.tagWithClass("div", "x-grid3-cell-inner").withPredicate("contains(@style,'red')"));
- List qcFlaggedCells = redCellLoc.findElements(getDriver());
+ Locator redCellLoc = Locator.tagWithClass("table", "labkey-data-region").append(Locator.xpath("//span[contains(@style,'red')]"));
+ List qcFlaggedCells = isElementPresent(redCellLoc) ? redCellLoc.findElements(getDriver()) : Collections.emptyList();
List expectedQcFlaggedValues = new ArrayList<>(Arrays.asList(texts));
List qcFlaggedValues = getTexts(qcFlaggedCells);
- qcFlaggedValues.removeAll(badVals);
Collections.sort(expectedQcFlaggedValues);
Collections.sort(qcFlaggedValues);
diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetTest.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetTest.java
index 66acb7096f..b5cde4c258 100644
--- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetTest.java
+++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetTest.java
@@ -20,6 +20,7 @@
import org.labkey.test.BaseWebDriverTest;
import org.labkey.test.Locator;
import org.labkey.test.TestFileUtils;
+import org.labkey.test.WebTestHelper;
import org.labkey.test.categories.Assays;
import org.labkey.test.categories.Daily;
import org.labkey.test.pages.ReactAssayDesignerPage;
@@ -33,6 +34,7 @@
import java.io.File;
import java.util.Calendar;
+import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
@@ -139,7 +141,7 @@ private void excludableWellsWithTransformTest()
excludeReplicateGroupFromRun("Guide Set plate 5", "A6,B6", 2, 1);
_guideSetHelper.goToLeveyJenningsGraphPage(TEST_ASSAY_LUM, "Standard1");
_guideSetHelper.setUpLeveyJenningsGraphParams("GS Analyte B");
- assertTextPresent("28040.51");
+ assertTextPresent("28040.512");
}
private void excludeReplicateGroupFromRun(String run, String wells, int jobCount, int jobInfoCount)
@@ -209,62 +211,56 @@ private void guideSetApiTest()
@LogMethod
private void applyStartAndEndDateFilter()
{
- String colValuePrefix = "NETWORK";
-
_guideSetHelper.setUpLeveyJenningsGraphParams("GS Analyte B");
- // check that all 5 runs are present in the grid by clicking on them
- for (int i = 1; i <= 5; i++)
- {
- assertElementPresent(ExtHelper.locateGridRowCheckbox(colValuePrefix + i));
- }
+ // check that all 5 runs are present in the grid and plot
+ DataRegionTable table = _guideSetHelper.getTrackingDataRegion();
+ assertEquals("Initial grid row count not as expected", 5, table.getDataRowCount());
+ assertEquals("Initial plot data point count not as expected", 5, Locator.findElements(getDriver(), Locator.tagWithClass("a", "point")).size());
+
// set start and end date filter
- setFormElement(Locator.name("start-date-field"), "2011-03-26");
- setFormElement(Locator.name("end-date-field"), "2011-03-28");
- waitAndClick(Locator.extButtonEnabled("Apply").index(1));
+ table.setFilter("Analyte/Data/AcquisitionDate", "Is Greater Than or Equal To", "2011-03-26", "Is Less Than or Equal To", "2011-03-28");
_guideSetHelper.waitForLeveyJenningsTrendPlot();
+
// check that only 3 runs are now present
- waitForElementToDisappear(ExtHelper.locateGridRowCheckbox(colValuePrefix + "1"), WAIT_FOR_JAVASCRIPT);
- for (int i = 2; i <= 4; i++)
- {
- waitForElement(ExtHelper.locateGridRowCheckbox(colValuePrefix + i));
- }
- assertElementNotPresent(ExtHelper.locateGridRowCheckbox(colValuePrefix + "5"));
+ assertEquals("Initial grid row count not as expected", 3, table.getDataRowCount());
+ assertEquals("Initial plot data point count not as expected", 3, Locator.findElements(getDriver(), Locator.tagWithClass("a", "point")).size());
+ List rowNetworkValues = table.getColumnDataAsText("Titration/Run/Batch/Network");
+ assertEquals("Filtered grid row value not as expected", "NETWORK4", rowNetworkValues.get(0));
+ assertEquals("Filtered grid row value not as expected", "NETWORK3", rowNetworkValues.get(1));
+ assertEquals("Filtered grid row value not as expected", "NETWORK2", rowNetworkValues.get(2));
+
+ // Clear the filter and check that all rows reappear
+ table.clearAllFilters();
+ _guideSetHelper.waitForLeveyJenningsTrendPlot();
+ assertEquals("Initial grid row count not as expected", 5, table.getDataRowCount());
+ assertEquals("Initial plot data point count not as expected", 5, Locator.findElements(getDriver(), Locator.tagWithClass("a", "point")).size());
}
@LogMethod
private void applyNetworkProtocolFilter()
{
- String colNetworkPrefix = "NETWORK";
- String colProtocolPrefix = "PROTOCOL";
-
_guideSetHelper.setUpLeveyJenningsGraphParams("GS Analyte B");
- // check that all 5 runs are present in the grid by clicking on them
- for (int i = 1; i <= 5; i++)
- {
- assertElementPresent(ExtHelper.locateGridRowCheckbox(colNetworkPrefix + i));
- }
- // set network and protocol filter
- _extHelper.selectComboBoxItem(Locator.xpath("//input[@id='network-combo-box']/.."), colNetworkPrefix + "3");
- _extHelper.selectComboBoxItem(Locator.xpath("//input[@id='protocol-combo-box']/.."), colProtocolPrefix + "3");
+ // check that all 5 runs are present in the grid and plot
+ DataRegionTable table = _guideSetHelper.getTrackingDataRegion();
+ assertEquals("Initial grid row count not as expected", 5, table.getDataRowCount());
+ assertEquals("Initial plot data point count not as expected", 5, Locator.findElements(getDriver(), Locator.tagWithClass("a", "point")).size());
- waitAndClick(Locator.extButtonEnabled("Apply").index(1));
+ // set network and protocol filter
+ table.setFilter("Titration/Run/Batch/Network", "Equals", "NETWORK3");
+ table.setFilter("Titration/Run/Batch/CustomProtocol", "Equals", "PROTOCOL3");
_guideSetHelper.waitForLeveyJenningsTrendPlot();
- // check that only 1 runs are now present
- waitForElementToDisappear(ExtHelper.locateGridRowCheckbox(colNetworkPrefix + "1"), WAIT_FOR_JAVASCRIPT);
- waitForElement(ExtHelper.locateGridRowCheckbox(colNetworkPrefix + "3"));
- assertElementNotPresent(ExtHelper.locateGridRowCheckbox(colNetworkPrefix + "1"));
- assertElementNotPresent(ExtHelper.locateGridRowCheckbox(colNetworkPrefix + "2"));
- assertElementNotPresent(ExtHelper.locateGridRowCheckbox(colNetworkPrefix + "4"));
- assertElementNotPresent(ExtHelper.locateGridRowCheckbox(colNetworkPrefix + "5"));
+ // check that only 1 run is now present
+ assertEquals("Initial grid row count not as expected", 1, table.getDataRowCount());
+ assertEquals("Initial plot data point count not as expected", 1, Locator.findElements(getDriver(), Locator.tagWithClass("a", "point")).size());
+ assertEquals("Filtered grid row value not as expected", "NETWORK3", table.getColumnDataAsText("Titration/Run/Batch/Network").get(0));
+ assertEquals("Filtered grid row value not as expected", "PROTOCOL3", table.getColumnDataAsText("Titration/Run/Batch/CustomProtocol").get(0));
// Clear the filter and check that all rows reappear
- waitAndClick(Locator.extButtonEnabled("Clear"));
+ table.clearAllFilters();
_guideSetHelper.waitForLeveyJenningsTrendPlot();
- for (int i = 1; i <= 5; i++)
- {
- assertElementPresent(ExtHelper.locateGridRowCheckbox(colNetworkPrefix + i));
- }
+ assertEquals("Initial grid row count not as expected", 5, table.getDataRowCount());
+ assertEquals("Initial plot data point count not as expected", 5, Locator.findElements(getDriver(), Locator.tagWithClass("a", "point")).size());
}
private void applyLogYAxisScale()
@@ -280,7 +276,7 @@ private boolean verifyRunFileAssociations(int index)
// verify that the PDF of curves file was generated along with the xls file and the Rout file
DataRegionTable table = new DataRegionTable("Runs", getDriver());
table.setFilter("Name", "Equals", "Guide Set plate " + index);
- clickAndWait(Locator.tagWithAttribute("img", "src", "/labkey/experiment/images/graphIcon.gif"));
+ clickAndWait(Locator.tagWithAttribute("img", "src", WebTestHelper.getContextPath() + "/experiment/images/graphIcon.gif"));
clickAndWait(Locator.linkWithText("Text View"));
waitForElement(Locator.css(".labkey-protocol-applications")); // bottom section of the "Text View" tab for the run details page
waitForElements(Locator.linkWithText("Guide Set plate " + index + ".Standard1_Control_Curves_4PL.pdf"), 3);
@@ -339,9 +335,9 @@ private void verifyExcludingRuns(Map guideSetIds, String[] anal
@LogMethod
private void verifyGuideSetToRun(String network, String comment)
{
- click(ExtHelper.locateGridRowCheckbox(network));
+ DataRegionTable table = _guideSetHelper.getTrackingDataRegion();
+ table.checkCheckbox(table.getRowIndex("Titration/Run/Batch/Network", network));
clickButton("Apply Guide Set", 0);
- waitForElement(ExtHelper.locateGridRowCheckbox(network));
waitForElement(ExtHelper.locateGridRowCheckbox(comment));
sleep(1000);
// deselect the current guide set to test error message
@@ -413,15 +409,16 @@ private void verifyLeveyJenningsPlots()
// TODO: add more validation of the plot SVG
//verify QC flags
+ DataRegionTable table = _guideSetHelper.getTrackingDataRegion();
+ assertTrue(table.getColumnLabels().contains("QC Flags"));
//this locator finds an EC50 flag, then makes sure there's red text outlining
- Locator.XPathLocator l = Locator.xpath("//td/div[contains(@style,'red')]/../../td/div/a[contains(text(),'EC50-4')]");
+ Locator.XPathLocator l = Locator.xpath("//td/span[contains(@style,'red')]/../../td/a[contains(text(),'EC50-4')]");
assertElementPresent(l,2);
- assertTextPresent("QC Flags");
// Verify as much of the Curve Comparison window as we can - most of its content is in the image, so it's opaque to the test
for (int i = 1; i <= 5; i++)
{
- click(ExtHelper.locateGridRowCheckbox("NETWORK" + i));
+ table.checkCheckbox(table.getRowIndex("Titration/Run/Batch/Network", "NETWORK" + i));
}
clickButton("View 4PL Curves", 0);
waitForTextToDisappear("loading curves...", WAIT_FOR_JAVASCRIPT);
@@ -479,9 +476,9 @@ private void verifyQCFlagUpdatesAfterWellChange()
_guideSetHelper.applyGuideSetToRun("NETWORK5", GUIDE_SET_5_COMMENT, false);
//assert ec50 and HMFI red text present
waitForText(newQcFlags);
- assertElementPresent(Locator.xpath("//div[text()='28040.51' and contains(@style,'red')]")); // EC50
- assertElementPresent(Locator.xpath("//div[text()='79121.45' and contains(@style,'red')]")); // AUC
- assertElementPresent(Locator.xpath("//div[text()='32145.80' and contains(@style,'red')]")); // High MFI
+ assertElementPresent(Locator.xpath("//span[text()='28040.512' and contains(@style,'red')]")); // EC50
+ assertElementPresent(Locator.xpath("//span[text()='79121.445' and contains(@style,'red')]")); // AUC
+ assertElementPresent(Locator.xpath("//span[text()='32145.8' and contains(@style,'red')]")); // High MFI
//verify new flags present in run list
goToTestAssayHome();
drt = new DataRegionTable("Runs", getDriver());
@@ -494,28 +491,33 @@ private void verifyQCFlagUpdatesAfterWellChange()
_guideSetHelper.setUpLeveyJenningsGraphParams("GS Analyte B");
_guideSetHelper.applyGuideSetToRun("NETWORK5", GUIDE_SET_5_COMMENT, true);
assertTextNotPresent(newQcFlags);
+ assertElementPresent(Locator.xpath("//td/span[contains(@style,'red')]"),2);
//6. Create new Guide Set for GS Analyte B that includes plate 5 (but not plate 5a)
- // - the AUC QC Flag for plate 5 is removed
+ // - the AUC QC Flag for plate 5 is removed for GS Analyte B but still exists for GS Analyte A
Locator.XPathLocator aucLink = Locator.xpath("//a[contains(text(),'AUC')]");
waitForElement(aucLink);
int aucCount = getElementCount(aucLink);
_guideSetHelper.createGuideSet(false);
_guideSetHelper.editRunBasedGuideSet(new String[]{"allRunsRow_1"}, "Guide set includes plate 5", true);
- assertEquals("Wrong count for AUC flag links", aucCount-1, (getElementCount(aucLink)));
+ assertEquals("Wrong count for AUC flag links", aucCount, (getElementCount(aucLink)));
+ assertElementPresent(Locator.xpath("//td/span[contains(@style,'red')]"),1);
//7. Switch to GS Analyte A, and edit the current guide set to include plate 3
// - the QC Flag for plate 3 (the run included) and the other plates (4, 5, and 5a) are all removed as all values are within the guide set ranges
_guideSetHelper.setUpLeveyJenningsGraphParams("GS Analyte A");
- assertExpectedAnalyte1QCFlagsPresent();
+ assertExpectedAnalyte1QCFlagsInitial();
+ assertElementPresent(Locator.xpath("//td/span[contains(@style,'red')]"),7);
clickButtonContainingText("Edit", 0);
_guideSetHelper.editRunBasedGuideSet(new String[]{"allRunsRow_3"}, "edited analyte 1", false);
- assertQCFlagsNotPresent();
+ assertExpectedAnalyte1QCFlagsUpdated();
+ assertElementPresent(Locator.xpath("//td/span[contains(@style,'red')]"),0);
//8. Edit the GS Analyte A guide set and remove plate 3
// - the QC Flags for plates 3, 4, 5, and 5a return (HMFI for all 4 and AUC for plates 4, 5, and 5a)
removePlate3FromGuideSet();
- assertExpectedAnalyte1QCFlagsPresent();
+ assertExpectedAnalyte1QCFlagsInitial();
+ assertElementPresent(Locator.xpath("//td/span[contains(@style,'red')]"),7);
}
@LogMethod
@@ -528,18 +530,17 @@ private void removePlate3FromGuideSet()
_guideSetHelper.waitForGuideSetExtMaskToDisappear();
}
- private void assertExpectedAnalyte1QCFlagsPresent()
+ private void assertExpectedAnalyte1QCFlagsInitial()
{
waitForElements(Locator.xpath("//a[contains(text(),'HMFI')]"), 4);
- waitForElements(Locator.xpath("//a[contains(text(),'AUC')]"), 3);
+ waitForElements(Locator.xpath("//a[contains(text(),'AUC')]"), 9);
}
- private void assertQCFlagsNotPresent()
+ private void assertExpectedAnalyte1QCFlagsUpdated()
{
- for (String flag : new String[] {"AUC", "HMFI", "EC50-4", "EC50-5", "PCV"})
- {
+ for (String flag : new String[] {"HMFI", "EC50-4", "EC50-5"})
assertElementNotPresent(Locator.xpath("//a[contains(text(),'" + flag + "')]"));
- }
+ waitForElements(Locator.xpath("//a[contains(text(),'AUC')]"), 7);
}
private void importPlateFiveAgain()
diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexRTransformTest.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexRTransformTest.java
index 5e46aa05bb..82b5a787ef 100644
--- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexRTransformTest.java
+++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexRTransformTest.java
@@ -20,6 +20,7 @@
import org.junit.experimental.categories.Category;
import org.labkey.test.BaseWebDriverTest;
import org.labkey.test.Locator;
+import org.labkey.test.WebTestHelper;
import org.labkey.test.categories.Assays;
import org.labkey.test.categories.Daily;
import org.labkey.test.pages.ReactAssayDesignerPage;
@@ -105,7 +106,7 @@ private void verifyScriptVersions()
private void verifyPDFsGenerated()
{
DataRegionTable.DataRegion(getDriver()).find(); // Make sure page is loaded
- WebElement curvePng = Locator.tagWithAttribute("img", "src", "/labkey/_images/sigmoidal_curve.png").findElement(getDriver());
+ WebElement curvePng = Locator.tagWithAttribute("img", "src", WebTestHelper.getContextPath() + "/_images/sigmoidal_curve.png").findElement(getDriver());
shortWait().until(LabKeyExpectedConditions.animationIsDone(curvePng));
File curvePdf = clickAndWaitForDownload(curvePng);
assertEquals("Curve PDF has wrong name: " + curvePdf.getName(), "WithAltNegativeBead.Standard1_Control_Curves_4PL.pdf", curvePdf.getName());
diff --git a/luminex/test/src/org/labkey/test/util/luminex/LuminexGuideSetHelper.java b/luminex/test/src/org/labkey/test/util/luminex/LuminexGuideSetHelper.java
index b4fec1ab79..8d56eda143 100644
--- a/luminex/test/src/org/labkey/test/util/luminex/LuminexGuideSetHelper.java
+++ b/luminex/test/src/org/labkey/test/util/luminex/LuminexGuideSetHelper.java
@@ -89,6 +89,13 @@ public void verifyGuideSetsNotApplied(String assayName)
table.clearFilter("GuideSet/Created");
}
+ public DataRegionTable getTrackingDataRegion()
+ {
+ DataRegionTable table = new DataRegionTable.DataRegionFinder(_test.getDriver()).find();
+ table.setAsync(true);
+ return table;
+ }
+
public void waitForManageGuideSetWindow(boolean creating)
{
WebElement window = _test.shortWait().until(ExpectedConditions.visibilityOfElementLocated(GS_WINDOW_LOC));
@@ -180,8 +187,6 @@ public void waitForGuideSetExtMaskToDisappear()
_test._extHelper.waitForExt3MaskToDisappear(WebDriverWrapper.WAIT_FOR_JAVASCRIPT);
_test.waitForElementToDisappear(GS_WINDOW_LOC);
waitForLeveyJenningsTrendPlot();
- // Wait for the grid to populate as well.
- _test.waitForElements(Locator.xpath("//div[contains(@class, 'x-grid3-row-checker')]"));
}
public void goToLeveyJenningsGraphPage(String assayName, String titrationName)
@@ -207,10 +212,11 @@ public void applyGuideSetToRun(String network, String comment, boolean useCurren
@LogMethod
public void applyGuideSetToRun(@LoggedParam String[] networks, @LoggedParam String comment, boolean useCurrent)
{
+ DataRegionTable table = getTrackingDataRegion();
for (String network : networks)
- _test.click(ExtHelper.locateGridRowCheckbox(network));
+ table.checkCheckbox(table.getRowIndex("Network", network));
- WebElement applyGuideSetButton = _test.scrollIntoView(Locator.button("Apply Guide Set"));
+ WebElement applyGuideSetButton = _test.scrollIntoView(Locator.lkButton("Apply Guide Set"));
_test.doAndWaitForPageSignal(applyGuideSetButton::click, "guideSetSelectionChange");
WebElement applyGuideSetWindow = ExtHelper.Locators.window("Apply Guide Set...").waitForElement(_test.getDriver(), WAIT_FOR_JAVASCRIPT);
diff --git a/luminex/webapp/luminex/ApplyGuideSetPanel.js b/luminex/webapp/luminex/ApplyGuideSetPanel.js
index 4314f3b561..d63155e4df 100644
--- a/luminex/webapp/luminex/ApplyGuideSetPanel.js
+++ b/luminex/webapp/luminex/ApplyGuideSetPanel.js
@@ -110,8 +110,8 @@ LABKEY.ApplyGuideSetPanel = Ext.extend(Ext.FormPanel, {
selectedHeaderCols.push({header:'Acquisition Date', dataIndex:'Analyte/Data/AcquisitionDate', renderer: this.dateRenderer, width:100});
if (this.controlType == 'Titration')
{
- selectedHeaderCols.push({header:'EC50 4PL', dataIndex:'Four ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right'});
- selectedHeaderCols.push({header:'EC50 5PL', dataIndex:'Five ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right'});
+ selectedHeaderCols.push({header:'EC50 4PL', dataIndex:'Four ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right', hidden: !this.has4PLCurveFit});
+ selectedHeaderCols.push({header:'EC50 5PL', dataIndex:'Five ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right', hidden: !this.has5PLCurveFit});
selectedHeaderCols.push({header:'AUC', dataIndex:'TrapezoidalCurveFit/AUC', width:75, renderer: this.numberRenderer, align: 'right'});
selectedHeaderCols.push({header:'High MFI', dataIndex:'MaxFI', width:75, renderer: this.numberRenderer, align: 'right'});
}
@@ -216,8 +216,8 @@ LABKEY.ApplyGuideSetPanel = Ext.extend(Ext.FormPanel, {
];
if (this.controlType == 'Titration')
{
- guideSetColumnModelColumns.push({header: 'Avg EC50 4PL', dataIndex: 'AverageEC504PL', renderer: this.numberRenderer, align: 'right', sortable: false});
- guideSetColumnModelColumns.push({header: 'Avg EC50 5PL', dataIndex: 'AverageEC505PL', renderer: this.numberRenderer, align: 'right', sortable: false});
+ guideSetColumnModelColumns.push({header: 'Avg EC50 4PL', dataIndex: 'AverageEC504PL', renderer: this.numberRenderer, align: 'right', sortable: false, hidden: !this.has4PLCurveFit});
+ guideSetColumnModelColumns.push({header: 'Avg EC50 5PL', dataIndex: 'AverageEC505PL', renderer: this.numberRenderer, align: 'right', sortable: false, hidden: !this.has5PLCurveFit});
guideSetColumnModelColumns.push({header: 'Avg AUC', dataIndex: 'AverageAUC', renderer: this.numberRenderer, align: 'right', sortable: false});
guideSetColumnModelColumns.push({header: 'Avg High MFI', dataIndex: 'AverageMFI', renderer: this.numberRenderer, align: 'right', sortable: false});
}
diff --git a/luminex/webapp/luminex/LeveyJenningsGraphParamsPanel.js b/luminex/webapp/luminex/LeveyJenningsGraphParamsPanel.js
index b4acc32aa0..c127725516 100644
--- a/luminex/webapp/luminex/LeveyJenningsGraphParamsPanel.js
+++ b/luminex/webapp/luminex/LeveyJenningsGraphParamsPanel.js
@@ -52,7 +52,6 @@ LABKEY.LeveyJenningsGraphParamsPanel = Ext.extend(Ext.FormPanel, {
},
initComponent : function() {
- this.paramsToLoad = 3;
var items = [];
// need to distinguish between null analyte/isotype/conjugate on URL and not requested (i.e. not on URL)
@@ -84,7 +83,7 @@ LABKEY.LeveyJenningsGraphParamsPanel = Ext.extend(Ext.FormPanel, {
columns: [{header: '', dataIndex:'value', renderer: this.tooltipRenderer}],
listeners: {
scope: this,
- 'rowClick': function(grid, rowIndex) {
+ 'rowClick': function(grid, record, rowIndex, skipFireEvent) {
if (grid.getSelectionModel().hasSelection())
{
this.analyte = grid.getSelectionModel().getSelected().get("value");
@@ -96,7 +95,9 @@ LABKEY.LeveyJenningsGraphParamsPanel = Ext.extend(Ext.FormPanel, {
this.filterIsotypeCombo();
this.enableApplyGraphButton();
- this.fireEvent('graphParamsChanged');
+ if (!skipFireEvent) {
+ this.fireEvent('graphParamsChanged');
+ }
}
}
});
@@ -105,8 +106,8 @@ LABKEY.LeveyJenningsGraphParamsPanel = Ext.extend(Ext.FormPanel, {
if (this.analyte != undefined && index > -1)
{
this.analyteGrid.getSelectionModel().selectRow(index);
- this.analyteGrid.fireEvent('rowClick', this.analyteGrid, index);
- this.analyteGrid.getView().focusRow(index); // TODO: this doesn't seem to be working
+ this.analyteGrid.fireEvent('rowClick', this.analyteGrid, records[index], index, true);
+ this.analyteGrid.getView().focusRow(index);
}
else
{
@@ -116,12 +117,6 @@ LABKEY.LeveyJenningsGraphParamsPanel = Ext.extend(Ext.FormPanel, {
}
this.analyteGrid.enable();
-
- this.paramsToLoad--;
- if (this.paramsToLoad == 0)
- {
- this.allParamsLoaded();
- }
}, this);
items.push(this.analyteGrid);
@@ -140,19 +135,22 @@ LABKEY.LeveyJenningsGraphParamsPanel = Ext.extend(Ext.FormPanel, {
tpl: '{display:htmlEncode}
',
listeners: {
scope: this,
- 'select': function(combo, record, index) {
+ 'select': function(combo, record, index, skipFireEvent) {
this.isotype = combo.getValue();
this.filterConjugateCombo();
this.enableApplyGraphButton();
- this.fireEvent('graphParamsChanged');
+ if (!skipFireEvent) {
+ this.fireEvent('graphParamsChanged');
+ }
}
}
});
this.isotypeCombobox.getStore().on('load', function(store, records, options) {
- if (this.isotype != undefined && store.findExact('value', this.isotype) > -1)
+ var index = store.findExact('value', this.isotype);
+ if (this.isotype != undefined && index > -1)
{
this.isotypeCombobox.setValue(this.isotype);
- this.isotypeCombobox.fireEvent('select', this.isotypeCombobox);
+ this.isotypeCombobox.fireEvent('select', this.isotypeCombobox, records[index], index, true);
this.isotypeCombobox.enable();
}
else
@@ -162,12 +160,6 @@ LABKEY.LeveyJenningsGraphParamsPanel = Ext.extend(Ext.FormPanel, {
this.conjugateCombobox.clearValue();
this.conjugateCombobox.disable();
}
-
- this.paramsToLoad--;
- if (this.paramsToLoad == 0)
- {
- this.allParamsLoaded();
- }
}, this);
items.push(this.isotypeCombobox);
@@ -203,12 +195,6 @@ LABKEY.LeveyJenningsGraphParamsPanel = Ext.extend(Ext.FormPanel, {
{
this.conjugate = undefined;
}
-
- this.paramsToLoad--;
- if (this.paramsToLoad == 0)
- {
- this.allParamsLoaded();
- }
}, this);
items.push(this.conjugateCombobox);
@@ -326,14 +312,6 @@ LABKEY.LeveyJenningsGraphParamsPanel = Ext.extend(Ext.FormPanel, {
return storeData;
},
- allParamsLoaded: function() {
- if (this.enableApplyGraphButton())
- {
- // fire the applyGraphBtnClicked event so other panels can update based on the selected params
- this.fireEvent('applyGraphBtnClicked', this.analyte, this.isotype, this.conjugate);
- }
- },
-
tooltipRenderer: function(value, p, record) {
var msg = Ext.util.Format.htmlEncode(value);
p.attr = 'ext:qtip="' + msg + '"';
diff --git a/luminex/webapp/luminex/LeveyJenningsGuideSetPanel.js b/luminex/webapp/luminex/LeveyJenningsGuideSetPanel.js
index b65e0705c4..c44be824cf 100644
--- a/luminex/webapp/luminex/LeveyJenningsGuideSetPanel.js
+++ b/luminex/webapp/luminex/LeveyJenningsGuideSetPanel.js
@@ -16,7 +16,7 @@ var $h = Ext.util.Format.htmlEncode;
* Class to create a small panel for displaying the current guide set info for the selected graph parameters
* and to give the user access to the edit guide set and create new guide set buttons
*
- * @params titration
+ * @params titration on single point control
* @params assayName
*/
LABKEY.LeveyJenningsGuideSetPanel = Ext.extend(Ext.FormPanel, {
@@ -59,7 +59,7 @@ LABKEY.LeveyJenningsGuideSetPanel = Ext.extend(Ext.FormPanel, {
this.paramsDisplayField = new Ext.form.DisplayField({
hideLabel: true,
value: "",
- style: "font-size:110%; font-weight:bold",
+ cls: "lj-report-title",
width: 738,
border: true
});
diff --git a/luminex/webapp/luminex/LeveyJenningsPlotHelpers.js b/luminex/webapp/luminex/LeveyJenningsPlotHelpers.js
index 9094763ed6..3f3eb0e9aa 100644
--- a/luminex/webapp/luminex/LeveyJenningsPlotHelpers.js
+++ b/luminex/webapp/luminex/LeveyJenningsPlotHelpers.js
@@ -6,29 +6,71 @@
Ext.namespace('LABKEY', 'Luminex.panel');
LABKEY.LeveyJenningsPlotHelper = {};
-// NOTE: we should be able to avoid passing around values.
-// NOTE: consider setting this up to be config based... potential defaulting values here...
+LABKEY.LeveyJenningsPlotHelper.PlotTypeMap = {
+ EC504PL: 'EC50 - 4PL',
+ EC505PL: 'EC50 - 5PL Rumi',
+ AUC: 'AUC',
+ HighMFI: 'High MFI',
+ MFI: 'MFI' // not sure why we cannot get these named right.
+};
+
+LABKEY.LeveyJenningsPlotHelper.TitrationColumnsMap = {
+ "GuideSetId": "GuideSet",
+ "AcquisitionDate": "Analyte/Data/AcquisitionDate",
+ "LotNumber": "Analyte/Properties/LotNumber",
+ "RunRowId": "Titration/Run/RowId",
+ "AssayId": "Titration/Run/Name",
+ "Network": "Titration/Run/Batch/Network",
+ "NotebookNo": "Analyte/Data/Run/NotebookNo",
+ "AssayType": "Analyte/Data/Run/AssayType",
+ "ExpPerformer": "Analyte/Data/Run/ExpPerformer",
+ "EC504PL": "Four ParameterCurveFit/EC50",
+ "EC505PL": "Five ParameterCurveFit/EC50",
+ "AUC": "TrapezoidalCurveFit/AUC",
+ "HighMFI": "MaxFI",
+};
+
+LABKEY.LeveyJenningsPlotHelper.SinglePointControlColumnsMap = {
+ "GuideSetId": "GuideSet",
+ "AcquisitionDate": "Analyte/Data/AcquisitionDate",
+ "LotNumber": "Analyte/Properties/LotNumber",
+ "RunRowId": "SinglePointControl/Run/RowId",
+ "AssayId": "SinglePointControl/Run/Name",
+ "Network": "SinglePointControl/Run/Batch/Network",
+ "NotebookNo": "SinglePointControl/Run/NotebookNo",
+ "AssayType": "SinglePointControl/Run/AssayType",
+ "ExpPerformer": "SinglePointControl/Run/ExpPerformer",
+ "MFI": "AverageFiBkgd",
+};
+
LABKEY.LeveyJenningsPlotHelper.getTrackingDataStore = function(config)
{
- var controlTypeColName = config.controlType == "SinglePoint" ? "SinglePointControl" : config.controlType;
- var whereClause = " WHERE Analyte.Name='" + config.analyte.replace(/'/g, "''") + "'"
- + " AND " + controlTypeColName + ".Name='" + config.controlName.replace(/'/g, "''") + "'"
- + (config.isotype ? " AND " + controlTypeColName + ".Run.Isotype='" + config.isotype.replace(/'/g, "''") + "'"
- : " AND " + controlTypeColName + ".Run.Isotype IS NULL")
- + (config.conjugate ? " AND " + controlTypeColName + ".Run.Conjugate='" + config.conjugate.replace(/'/g, "''") + "'"
- : " AND " + controlTypeColName + ".Run.Conjugate IS NULL");
-
- if (config.controlType == "Titration") {
- whereClause += " AND Titration.IncludeInQcReport=true";
- }
+ var isSinglePointControl = config.controlType === 'SinglePoint';
+ var controlTypeColName = isSinglePointControl ? 'SinglePointControl' : config.controlType;
+ var columnsMap = isSinglePointControl ? LABKEY.LeveyJenningsPlotHelper.SinglePointControlColumnsMap : LABKEY.LeveyJenningsPlotHelper.TitrationColumnsMap;
- // add on any filtering (from LeveyJenningsTrackingDataPanel.js)
- if (config.whereClause) {
- whereClause += config.whereClause;
+ var store = new LABKEY.ext.Store({
+ autoLoad: true,
+ schemaName: 'assay.Luminex.' + LABKEY.QueryKey.encodePart(config.assayName),
+ queryName: isSinglePointControl ? 'AnalyteSinglePointControl' : 'AnalyteTitration',
+ columns: Object.values(columnsMap).join(','),
+ filterArray: config.filters,
+ sort: config.sort ? config.sort : '-Analyte/Data/AcquisitionDate, -' + controlTypeColName + '/Run/Created',
+ maxRows: config.maxRows ? config.maxRows : -1,
+ containerFilter: LABKEY.Query.containerFilter.allFolders,
+ scope: config.scope
+ });
+
+ if (config.loadListener) {
+ store.addListener('load', config.loadListener, config.scope);
}
- // this version of the guide set range values SQL will prevent the need for multiple LEFT OUTER JOINs to the GuideSetCurveFit table
- var guideSetRangeValuesSQL = "SELECT gs.RowId, gs.Created, gs.ValueBased,\n" +
+ return store;
+};
+
+LABKEY.LeveyJenningsPlotHelper.getGuideSetRangesStore = function(config)
+{
+ var sql = "SELECT gs.RowId, gs.Created, gs.ValueBased,\n" +
" CASE WHEN gs.ValueBased=true THEN gs.EC504PLAverage ELSE cf.EC504PLAverage END AS GuideSetEC504PLAverage,\n" +
" CASE WHEN gs.ValueBased=true THEN gs.EC504PLStdDev ELSE cf.EC504PLStdDev END AS GuideSetEC504PLStdDev,\n" +
" CASE WHEN gs.ValueBased=true THEN gs.EC505PLAverage ELSE cf.EC505PLAverage END AS GuideSetEC505PLAverage,\n" +
@@ -53,103 +95,52 @@ LABKEY.LeveyJenningsPlotHelper.getTrackingDataStore = function(config)
" GROUP BY GuideSetId\n" +
") cf ON gs.RowId = cf.GuideSetId";
- // generate sql for the data store (columns depend on the control type)
- // issue 22267 : add IFDEFINED to "optional" assay design fields
- var sql = "SELECT Analyte"
- + ", " + controlTypeColName + ".Run.Created" // NOTE: necessary for union case
- + ", Analyte.Data.AcquisitionDate"
- + ", IFDEFINED(Analyte.Properties.LotNumber)"
- + ", " + controlTypeColName
- + ", IFDEFINED(" + controlTypeColName + ".Run.Isotype)"
- + ", IFDEFINED(" + controlTypeColName + ".Run.Conjugate)"
- + ", " + controlTypeColName + ".Run.RowId AS RunRowId"
- + ", " + controlTypeColName + ".Run.Name AS RunName"
- + ", " + controlTypeColName + ".Run.Folder.Name AS FolderName"
- + ", " + controlTypeColName + ".Run.Folder.EntityId"
- + ", IFDEFINED(" + controlTypeColName + ".Run.Batch.Network)"
- + ", IFDEFINED(" + controlTypeColName + ".Run.Batch.CustomProtocol)"
- + ", IFDEFINED(" + controlTypeColName + ".Run.NotebookNo)"
- + ", IFDEFINED(" + controlTypeColName + ".Run.AssayType)"
- + ", IFDEFINED(" + controlTypeColName + ".Run.ExpPerformer)"
- + ", GuideSet AS GuideSetId"
- + ", gs.Created AS GuideSetCreated"
- + ", IncludeInGuideSetCalculation"
- + ", gs.ValueBased AS GuideSetValueBased";
- if (config.controlType == "Titration")
- {
- sql += ", \"Four ParameterCurveFit\".EC50 AS EC504PL, \"Four ParameterCurveFit\".EC50QCFlagsEnabled AS EC504PLQCFlagsEnabled"
- + ", \"Five ParameterCurveFit\".EC50 AS EC505PL, \"Five ParameterCurveFit\".EC50QCFlagsEnabled AS EC505PLQCFlagsEnabled"
- + ", TrapezoidalCurveFit.AUC, TrapezoidalCurveFit.AUCQCFlagsEnabled"
- + ", MaxFI AS HighMFI, MaxFIQCFlagsEnabled AS HighMFIQCFlagsEnabled"
- //columns needed for guide set ranges (value based or run based)
- + ", gs.GuideSetEC504PLAverage"
- + ", gs.GuideSetEC504PLStdDev"
- + ", gs.GuideSetEC505PLAverage"
- + ", gs.GuideSetEC505PLStdDev"
- + ", gs.GuideSetAUCAverage"
- + ", gs.GuideSetAUCStdDev"
- + ", gs.GuideSetHighMFIAverage"
- + ", gs.GuideSetHighMFIStdDev"
- + " FROM AnalyteTitration "
- + " LEFT JOIN (" + guideSetRangeValuesSQL + ") AS gs ON GuideSet = gs.RowId"
- + whereClause;
- }
- else if (config.controlType == "SinglePoint")
- {
- sql += ", AverageFiBkgd AS MFI, AverageFiBkgdQCFlagsEnabled AS MFIQCFlagsEnabled"
- //columns needed for guide set ranges (value based or run based)
- + ", gs.GuideSetMFIAverage"
- + ", gs.GuideSetMFIStdDev"
- + " FROM AnalyteSinglePointControl "
- + " LEFT JOIN (" + guideSetRangeValuesSQL + ") AS gs ON GuideSet = gs.RowId"
- + whereClause;
- }
-
var store = new LABKEY.ext.Store({
- autoLoad: false,
+ autoLoad: true,
schemaName: 'assay.Luminex.' + LABKEY.QueryKey.encodePart(config.assayName),
sql: sql,
- sort: config.sort ? config.sort : '-Analyte/Data/AcquisitionDate, -' + controlTypeColName + '/Run/Created',
- maxRows: config.maxRows ? config.maxRows : -1,
+ maxRows: -1,
containerFilter: LABKEY.Query.containerFilter.allFolders,
scope: config.scope
});
- // not assuming scope for now...
if (config.loadListener)
store.addListener('load', config.loadListener, config.scope);
return store;
};
-// consider reducing scope of this object...?
-LABKEY.LeveyJenningsPlotHelper.PlotTypeMap = {
- EC504PL: 'EC50 - 4PL',
- EC505PL: 'EC50 - 5PL Rumi',
- AUC: 'AUC',
- HighMFI: 'High MFI',
- MFI: 'MFI' // not sure why we cannot get these named right.
-};
-
LABKEY.LeveyJenningsPlotHelper.renderPlot = function(config)
{
var plotData = [];
- var records = config.store.getRange();
+ var records = config.dataStore.getRange();
var otherHoverProps = ['Network', 'AssayType', 'ExpPerformer', 'AcquisitionDate'];
+ var columnsMap = config.controlType === 'SinglePoint' ? LABKEY.LeveyJenningsPlotHelper.SinglePointControlColumnsMap : LABKEY.LeveyJenningsPlotHelper.TitrationColumnsMap;
var _pushData = function(record)
{
var data = {
- xLabel: record.get('NotebookNo'),
- pointColor: record.get('LotNumber'),
- value: record.get(config.plotType),
- gsMean: record.get('GuideSet' + config.plotType + 'Average'),
- gsStdDev: record.get('GuideSet' + config.plotType + 'StdDev')
+ xLabel: record.get(columnsMap['NotebookNo']),
+ pointColor: record.get(columnsMap['LotNumber']),
+ value: record.get(columnsMap[config.plotType]),
};
+ // fall back to using the AssayId if the NotebookNo prop doesn't exist
+ if (!record.get(columnsMap['NotebookNo'])) {
+ data.xLabel = record.get(columnsMap['AssayId']);
+ }
+
+ // merge in the guide set range mean and stdDev values
+ var gsRecordIndex = config.guideSetRangeStore ? config.guideSetRangeStore.findExact('RowId', record.get(columnsMap['GuideSetId'])) : -1;
+ if (gsRecordIndex > -1) {
+ var gsRecord = config.guideSetRangeStore.getAt(gsRecordIndex);
+ data['gsMean'] = gsRecord.get('GuideSet' + config.plotType + 'Average');
+ data['gsStdDev'] = gsRecord.get('GuideSet' + config.plotType + 'StdDev');
+ }
+
// add some other values to the data object for the hover display
Ext.each(otherHoverProps, function(prop) {
- var val = record.get(prop);
+ var val = record.get(columnsMap[prop]);
// convert values that are date objects to a display string format
if (val != null && LABKEY.Utils.isDate(val)) {
@@ -170,7 +161,7 @@ LABKEY.LeveyJenningsPlotHelper.renderPlot = function(config)
for (var i = 0; i < records.length; i++)
{
- if (records[i].get('RunRowId') == config.runId)
+ if (records[i].get(columnsMap['RunRowId']) == config.runId)
{
index = i;
break;
@@ -233,7 +224,7 @@ LABKEY.LeveyJenningsPlotHelper.renderPlot = function(config)
colorRange: ['black', 'red', 'green', 'blue', 'purple', 'orange', 'grey', 'brown'],
hoverTextFn: function(row){
var display = 'Notebook: ' + row.xLabel
- + '\nLot Number: ' + row.pointColor
+ + '\nLot Number: ' + (row.pointColor ? row.pointColor : '')
+ '\n' + config.plotType + ': ' + row.value;
// add any of the non-null extra display values to the hover
@@ -269,8 +260,7 @@ LABKEY.LeveyJenningsPlotHelper.renderPlot = function(config)
// plotType: EC504PL, EC505PL, AUC, HighMFI
LABKEY.LeveyJenningsPlotHelper.getLeveyJenningsPlotWindow = function(protocolId, analyteId, typeId, plotType, controlType)
{
- if (controlType == null)
- controlType = 'Titration';
+ var controlTypeColName = controlType === 'SinglePoint' ? 'SinglePointControl' : controlType;
LABKEY.Assay.getById({
id: protocolId,
@@ -282,29 +272,41 @@ LABKEY.LeveyJenningsPlotHelper.getLeveyJenningsPlotWindow = function(protocolId,
var _getConfig = function(assayName)
{
- // note make sure to mix assayName into config...
LABKEY.Query.selectRows({
+ containerFilter: LABKEY.Query.containerFilter.allFolders,
schemaName: 'assay.Luminex.' + LABKEY.QueryKey.encodePart(assayName),
- queryName: 'Analyte'+controlType,
- columns: [controlType+'/Name', 'Analyte/Name', controlType+'/Run/Isotype', controlType+'/Run/Conjugate', controlType+'/Run', 'Analyte/Data/AcquisitionDate'],
+ queryName: 'Analyte'+controlTypeColName,
+ columns: [controlTypeColName+'/Name', 'Analyte/Name', controlTypeColName+'/Run/Isotype', controlTypeColName+'/Run/Conjugate', controlTypeColName+'/Run', 'Analyte/Data/AcquisitionDate'],
filterArray: [
LABKEY.Filter.create('Analyte', analyteId),
- LABKEY.Filter.create(controlType, typeId)
+ LABKEY.Filter.create(controlTypeColName, typeId)
],
success: function(data) {
var row = data.rows[0];
+
+ const filters = [
+ LABKEY.Filter.create('Analyte/Name', row['Analyte/Name']),
+ LABKEY.Filter.create(controlTypeColName + '/Name', row[controlTypeColName+'/Name']),
+ LABKEY.Filter.create(controlTypeColName + '/Run/Isotype', row[controlTypeColName+'/Run/Isotype']),
+ LABKEY.Filter.create(controlTypeColName + '/Run/Conjugate', row[controlTypeColName+'/Run/Conjugate']),
+ ];
+ if (controlType === 'Titration') {
+ filters.push(LABKEY.Filter.create('Titration/IncludeInQcReport', true));
+ }
+
var config = {
assayName: assayName,
- controlName: row[controlType+'/Name'],
- controlType: controlType == "SinglePointControl" ? "SinglePoint" : "Titration",
+ controlName: row[controlTypeColName+'/Name'],
+ controlType: controlType,
analyte: row['Analyte/Name'],
- isotype: row[controlType+'/Run/Isotype'],
- conjugate: row[controlType+'/Run/Conjugate'],
+ isotype: row[controlTypeColName+'/Run/Isotype'],
+ conjugate: row[controlTypeColName+'/Run/Conjugate'],
yAxisScale: 'linear',
- scope: this, // shouldn't matter but might blow up without it.
plotType: plotType,
- runId: row[controlType+'/Run'],
- sort: 'Analyte/Data/AcquisitionDate, ' + controlType + '/Run/Created',
+ runId: row[controlTypeColName+'/Run'],
+ filters: filters,
+ sort: 'Analyte/Data/AcquisitionDate, ' + controlTypeColName + '/Run/Created',
+ scope: this, // shouldn't matter but might blow up without it.
};
_createWindow(config);
@@ -333,17 +335,31 @@ LABKEY.LeveyJenningsPlotHelper.getLeveyJenningsPlotWindow = function(protocolId,
},
listeners : {
afterrender: function() {
-
window.getEl().mask("Loading...", "x-mask-loading");
+ var dataStoreLoaded = false;
+ var guideSetStoreLoaded = false;
config.loadListener = function(store) {
- config.store = store;
- LABKEY.LeveyJenningsPlotHelper.renderPlot(config);
- window.getEl().unmask();
+ dataStoreLoaded = true;
+ config.dataStore = store;
+ if (guideSetStoreLoaded) {
+ LABKEY.LeveyJenningsPlotHelper.renderPlot(config);
+ window.getEl().unmask();
+ }
};
-
- var store = LABKEY.LeveyJenningsPlotHelper.getTrackingDataStore(config);
- store.load()
+ LABKEY.LeveyJenningsPlotHelper.getTrackingDataStore(config);
+
+ LABKEY.LeveyJenningsPlotHelper.getGuideSetRangesStore({
+ assayName: config.assayName,
+ loadListener: function(store) {
+ guideSetStoreLoaded = true;
+ config.guideSetRangeStore = store;
+ if (dataStoreLoaded) {
+ LABKEY.LeveyJenningsPlotHelper.renderPlot(config);
+ window.getEl().unmask();
+ }
+ },
+ });
}
}
}]
diff --git a/luminex/webapp/luminex/LeveyJenningsTrackingDataPanel.js b/luminex/webapp/luminex/LeveyJenningsTrackingDataPanel.js
index f34d93b840..66f4156a6e 100644
--- a/luminex/webapp/luminex/LeveyJenningsTrackingDataPanel.js
+++ b/luminex/webapp/luminex/LeveyJenningsTrackingDataPanel.js
@@ -6,20 +6,15 @@
Ext.namespace('LABKEY');
-/**
- * User: cnathe
- * Date: Sept 21, 2011
- */
-
Ext.QuickTips.init();
/**
- * Class to create a labkey editorGridPanel to display the tracking data for the selected graph parameters
+ * Class to create a QueryWebPart to display the tracking data for the selected graph parameters
*
* @params controlName
* @params assayName
*/
-LABKEY.LeveyJenningsTrackingDataPanel = Ext.extend(Ext.grid.GridPanel, {
+LABKEY.LeveyJenningsTrackingDataPanel = Ext.extend(Ext.Component, {
constructor: function (config)
{
// check that the config properties needed are present
@@ -28,26 +23,10 @@ LABKEY.LeveyJenningsTrackingDataPanel = Ext.extend(Ext.grid.GridPanel, {
if (!config.assayName || config.assayName == "null")
throw "You must specify a assayName!";
- // apply some Ext panel specific properties to the config
- Ext.apply(config, {
- width: 1375,
- autoHeight: true,
- title: $h(config.controlName) + ' Tracking Data',
- loadMask: {msg: "Loading data..."},
- columnLines: true,
- stripeRows: true,
- viewConfig: {
- forceFit: true,
- scrollOffset: 0
- },
- disabled: true,
- analyte: null,
- isotype: null,
- conjugate: null,
- userCanUpdate: LABKEY.user.canUpdate
- });
+ config.html = ''
+ + '';
- this.addEvents('appliedGuideSetUpdated', 'trackingDataLoaded');
+ this.addEvents('appliedGuideSetUpdated', 'plotDataLoading', 'plotDataLoaded');
LABKEY.LeveyJenningsTrackingDataPanel.superclass.constructor.call(this, config);
},
@@ -55,477 +34,414 @@ LABKEY.LeveyJenningsTrackingDataPanel = Ext.extend(Ext.grid.GridPanel, {
initComponent: function ()
{
this.store = new Ext.data.ArrayStore();
- this.selModel = this.getTrackingDataSelModel();
- this.colModel = this.getTrackingDataColModel();
-
- // initialize an export button for the toolbar
- this.exportMenuButton = new Ext.Button({
- text: 'Export',
- menu: [
- {
- text: 'Excel',
- handler: function ()
- {
- this.exportData('excel');
- },
- scope: this
- },
- {
- text: 'TSV',
- handler: function ()
- {
- this.exportData('tsv');
- },
- scope: this
- }
- ]
- });
-
- // initialize the apply guide set button to the toolbar
- this.applyGuideSetButton = new Ext.Button({
- disabled: true,
- text: 'Apply Guide Set',
- handler: this.applyGuideSetClicked,
- scope: this
- });
-
- // initialize the view curves button to the toolbar
- this.viewCurvesButton = new Ext.Button({
- disabled: true,
- text: 'View 4PL Curves',
- tooltip: 'Click to view overlapping curves for the selected runs.',
- handler: this.viewCurvesClicked,
- scope: this
- });
-
- // if the controlType is Titration, show the viewCurves 'View 4PL Curves' button, for Single Point Controls do not
- if (this.controlType == "Titration")
- {
- // if the user has permissions to update in this container, show them the Apply Guide Set button
- this.tbar = this.userCanUpdate ? [this.exportMenuButton, this.applyGuideSetButton, this.viewCurvesButton] : [this.exportMenuButton, this.viewCurvesButton];
- }
- else
- {
- // if the user has permissions to update in this container, show them the Apply Guide Set button
- this.tbar = this.userCanUpdate ? [this.exportMenuButton, this.applyGuideSetButton ] : [this.exportMenuButton];
- }
-
- this.fbar = [
- {xtype: 'label', text: 'Bold values in the "Guide Set Date" column indicate runs that are members of a guide set.'}
- ];
LABKEY.LeveyJenningsTrackingDataPanel.superclass.initComponent.call(this);
},
- getNeworkProtocolFilter: function(name, value) {
- var fieldName = (this.controlType == "Titration" ? "Titration" : "SinglePointControl") + '.Run.Batch.' + name;
- if (value != null) {
- return " AND " + fieldName + " = '" + value.replace(/'/g, "''") + "'";
- }
- else {
- return " AND " + fieldName + " IS NULL";
- }
+ hasReportFilter: function() {
+ var userFilters = this.qwp.getUserFilterArray();
+ return userFilters.length > 0;
},
- storeLoaded: function(store, records, options) {
- this.fireEvent('trackingDataLoaded', store);
- this.loadQCFlags(store, records, options);
- },
-
- getTrackingDataSelModel: function ()
- {
- return new Ext.grid.CheckboxSelectionModel({
- listeners: {
- scope: this,
- 'selectionchange': function (selectionModel)
- {
- if (selectionModel.hasSelection())
- {
- this.applyGuideSetButton.enable();
- this.viewCurvesButton.enable();
- }
- else
- {
- this.applyGuideSetButton.disable();
- this.viewCurvesButton.disable();
- }
- }
- }
+ configurePlotDataStore: function(baseFilters) {
+ this.storeLoading();
+ this.store = LABKEY.LeveyJenningsPlotHelper.getTrackingDataStore({
+ assayName: this.assayName,
+ controlName: this.controlName,
+ controlType: this.controlType,
+ analyte: this.analyte,
+ isotype: this.isotype,
+ conjugate: this.conjugate,
+ filters: baseFilters.concat(this.qwp.getUserFilterArray()),
+ maxRows: !this.hasReportFilter() ? this.defaultRowSize : undefined,
+ scope: this,
+ loadListener: this.storeLoaded,
});
- },
-
- getTrackingDataColModel: function ()
- {
- return new Ext.grid.ColumnModel({
- defaults: {sortable: true},
- columns: this.getTrackingDataColumns(),
- scope: this
+ this.store.on('exception', function(store, type, action, options, response){
+ var errorJson = Ext.util.JSON.decode(response.responseText);
+ if (errorJson.exception) {
+ Ext.get(document.querySelector('.ljTrendPlot').id).update("" + errorJson.exception + "");
+ }
});
},
- getTrackingDataColumns: function ()
- {
- var cols = [
- this.selModel,
- {header: 'Analyte', dataIndex: 'Analyte', hidden: true, renderer: this.encodingRenderer},
- {header: 'Isotype', dataIndex: 'Isotype', hidden: true, renderer: this.encodingRenderer},
- {header: 'Conjugate', dataIndex: 'Conjugate', hidden: true, renderer: this.encodingRenderer},
- {header: 'QC Flags', dataIndex: 'QCFlags', width: 75},
- {header: 'Assay Id', dataIndex: 'RunName', renderer: this.assayIdHrefRenderer, width: 200},
- {header: 'Network', dataIndex: 'Network', width: 75, renderer: this.encodingRenderer, hidden: !this.networkExists},
- {header: 'Protocol', dataIndex: 'CustomProtocol', width: 75, renderer: this.encodingRenderer, hidden: !this.protocolExists},
- {header: 'Folder', dataIndex: 'FolderName', width: 75, renderer: this.encodingRenderer},
- {header: 'Notebook No.', dataIndex: 'NotebookNo', width: 100, renderer: this.encodingRenderer},
- {header: 'Assay Type', dataIndex: 'AssayType', width: 100, renderer: this.encodingRenderer},
- {header: 'Experiment Performer', dataIndex: 'ExpPerformer', width: 100, renderer: this.encodingRenderer},
- {header: 'Acquisition Date', dataIndex: 'AcquisitionDate', renderer: this.dateRenderer, width: 100},
- {header: 'Analyte Lot No.', dataIndex: 'LotNumber', width: 100, renderer: this.encodingRenderer},
- {header: 'Guide Set Start Date', dataIndex: 'GuideSetCreated', renderer: this.formatGuideSetMembers, scope: this, width: 100},
- {header: 'GS Member', dataIndex: 'IncludeInGuideSetCalculation', hidden: true}
- ];
+ storeLoading: function() {
+ this.fireEvent('plotDataLoading', this.store, this.hasGuideSetUpdate);
- if (this.controlType == "Titration")
- {
- cols.splice(2, 0, {header: 'Titration', dataIndex: 'Titration', hidden: true, renderer: this.encodingRenderer});
- cols.push({header: 'EC50 4PL', dataIndex: 'EC504PL', width: 75, renderer: this.outOfRangeRenderer("EC504PLQCFlagsEnabled"), scope: this, align: 'right', hidden: !this.has4PLCurveFit});
- cols.push({header: 'EC50 4PL QC Flags Enabled', dataIndex: 'EC504PLQCFlagsEnabled', hidden: true});
- cols.push({header: 'EC50 5PL', dataIndex: 'EC505PL', width: 75, renderer: this.outOfRangeRenderer("EC505PLQCFlagsEnabled"), scope: this, align: 'right', hidden: !this.has5PLCurveFit});
- cols.push({header: 'EC50 5PL QC Flags Enabled', dataIndex: 'EC505PLQCFlagsEnabled', hidden: true});
- cols.push({header: 'AUC', dataIndex: 'AUC', width: 75, renderer: this.outOfRangeRenderer("AUCQCFlagsEnabled"), scope: this, align: 'right'});
- cols.push({header: 'AUC QC Flags Enabled', dataIndex: 'AUCQCFlagsEnabled', hidden: true});
- cols.push({header: 'High MFI', dataIndex: 'HighMFI', width: 75, renderer: this.outOfRangeRenderer("HighMFIQCFlagsEnabled"), scope: this, align: 'right'});
- cols.push({header: 'High QC Flags Enabled', dataIndex: 'HighMFIQCFlagsEnabled', hidden: true});
- }
- else if (this.controlType == "SinglePoint")
- {
- cols.splice(2, 0, {header: 'SinglePointControl', dataIndex: 'SinglePointControl', hidden: true, renderer: this.encodingRenderer});
- cols.push({header: 'MFI', dataIndex: 'MFI', width: 75, renderer: this.outOfRangeRenderer("MFIQCFlagsEnabled"), scope: this, align: 'right'});
- cols.push({header: 'MFI QC Flags Enabled', dataIndex: 'MFIQCFlagsEnabled', hidden: true});
- }
+ // reset hasGuideSetUpdate so that other grid filter changes won't trigger this as well
+ this.hasGuideSetUpdate = false;
+ },
- return cols;
+ storeLoaded: function() {
+ this.fireEvent('plotDataLoaded', this.store, this.hasReportFilter());
},
// function called by the JSP when the graph params are selected and the "Apply" button is clicked
- graphParamsSelected: function (analyte, isotype, conjugate, startDate, endDate, network, networkAny, protocol, protocolAny)
+ graphParamsSelected: function (analyte, isotype, conjugate, hasGuideSetUpdate)
{
+ var shouldClearSelections = true;
+ this.hasGuideSetUpdate = hasGuideSetUpdate;
+
// store the params locally
this.analyte = analyte;
this.isotype = isotype;
this.conjugate = conjugate;
// set the grid title based on the selected graph params
- this.setTitle($h(this.controlName) + ' Tracking Data for ' + $h(this.analyte)
- + ' - ' + $h(this.isotype == '' ? '[None]' : this.isotype)
- + ' ' + $h(this.conjugate == '' ? '[None]' : this.conjugate));
-
- var whereClause = "";
- var hasReportFilter = false;
- if (startDate)
- {
- hasReportFilter = true;
- whereClause += " AND CAST(Analyte.Data.AcquisitionDate AS DATE) >= '" + startDate + "'";
- }
- if (endDate)
- {
- hasReportFilter = true;
- whereClause += " AND CAST(Analyte.Data.AcquisitionDate AS DATE) <= '" + endDate + "'";
+ document.getElementById('trackingDataPanel_title').innerHTML =
+ $h(this.controlName) + ' Tracking Data for ' + $h(this.analyte)
+ + ' - ' + $h(this.isotype === '' ? '[None]' : this.isotype)
+ + ' ' + $h(this.conjugate === '' ? '[None]' : this.conjugate);
+
+ var controlTypeColName = this.controlType === 'SinglePoint' ? 'SinglePointControl' : this.controlType;
+ const filters = [
+ LABKEY.Filter.create('Analyte/Name', this.analyte),
+ LABKEY.Filter.create(controlTypeColName + '/Name', this.controlName),
+ LABKEY.Filter.create(controlTypeColName + '/Run/Isotype', this.isotype),
+ LABKEY.Filter.create(controlTypeColName + '/Run/Conjugate', this.conjugate),
+ ];
+ if (this.controlType === 'Titration') {
+ filters.push(LABKEY.Filter.create('Titration/IncludeInQcReport', true));
}
- if (Ext.isDefined(network) && !networkAny)
- {
- hasReportFilter = true;
- whereClause += this.getNeworkProtocolFilter("Network", network);
+
+ var buttonBarItems = [
+ LABKEY.QueryWebPart.standardButtons.views,
+ LABKEY.QueryWebPart.standardButtons.exportRows,
+ LABKEY.QueryWebPart.standardButtons.print,
+ ];
+ if (LABKEY.user.canUpdate) {
+ buttonBarItems.push({
+ text: 'Apply Guide Set',
+ requiresSelection: true,
+ handler: this.applyGuideSetClicked,
+ });
}
- if (Ext.isDefined(protocol) && !protocolAny)
- {
- hasReportFilter = true;
- whereClause += this.getNeworkProtocolFilter("CustomProtocol", protocol);
+ if (this.controlType === 'Titration') {
+ buttonBarItems.push({
+ text: 'View 4PL Curves',
+ requiresSelection: true,
+ handler: this.viewCurvesClicked,
+ });
}
- // create a new store now that the graph params are selected and bind it to the grid
- var storeConfig = {
- assayName: this.assayName,
- controlName: this.controlName,
- controlType: this.controlType,
- analyte: this.analyte,
- isotype: this.isotype,
- conjugate: this.conjugate,
- maxRows: !hasReportFilter ? this.defaultRowSize : undefined,
+ this.qwp = new LABKEY.QueryWebPart({
+ renderTo: 'trackingDataPanel_QWP',
+ schemaName: "assay.Luminex." + LABKEY.QueryKey.encodePart(_protocolName),
+ queryName: this.controlType === 'SinglePoint' ? 'AnalyteSinglePointControl' : 'AnalyteTitration',
+ containerFilter: LABKEY.Query.containerFilter.allFolders,
+ maxRows: this.defaultRowSize,
+ showUpdateColumn : false,
+ showImportDataButton : false,
+ showInsertNewButton : false,
+ showDeleteButton : false,
+ showReports : false,
+ frame: 'none',
+ filters: filters,
+ sort: '-Analyte/Data/AcquisitionDate, -' + controlTypeColName + '/Run/Created',
scope: this,
- loadListener: this.storeLoaded,
- };
-
- if (whereClause != "")
- {
- storeConfig['whereClause'] = whereClause;
- }
-
- this.store = LABKEY.LeveyJenningsPlotHelper.getTrackingDataStore(storeConfig);
+ buttonBar: {
+ includeStandardButtons: false,
+ items: buttonBarItems,
+ },
+ listeners: {
+ scope: this,
+ success: function(dataRegion) {
+ // clear selections on each graph param change so we don't inadvertently get selections
+ // row selections from a different analyte/isotype/conjugate
+ if (shouldClearSelections) {
+ dataRegion.clearSelected();
+ shouldClearSelections = false;
+ }
- this.store.on('exception', function(store, type, action, options, response){
- var errorJson = Ext.util.JSON.decode(response.responseText);
- if (errorJson.exception) {
- Ext.get(document.querySelector('.ljTrendPlot').id).update("" + errorJson.exception + "");
+ this.configurePlotDataStore(filters);
+ }
}
});
- var newColModel = this.getTrackingDataColModel();
- this.reconfigure(this.store, newColModel);
- this.store.load();
-
// enable the trending data grid
this.enable();
},
- applyGuideSetClicked: function ()
- {
- // get the selected record list from the grid
- var selection = this.selModel.getSelections();
- var selectedRecords = [];
- // Copy so that it's available in the scope for the callback function
- var controlType = this.controlType;
- Ext.each(selection, function (record)
- {
- var newItem = {Analyte: record.get("Analyte")};
- if (controlType == 'Titration')
- {
- newItem.ControlId = record.get("Titration");
- }
- else
- {
- newItem.ControlId = record.get("SinglePointControl");
+ parseGridSelectionKeys: function(selected, getAnalyteIds) {
+ var isSinglePoint = this.controlType === 'SinglePoint';
+ var selectedRecords = [], analyteIds = [];
+ for (var i = 0; i < selected.length; i++) {
+ var keys = selected[i].split(',');
+ if (keys.length === 3) {
+ // AnalyteTitration selection keys = [Analyte RowId, Titration RowId, Titration RowId]
+ // AnalyteSinglePointControl selection keys = [SinglePointControl RowId, Analyte RowId, SinglePointControl RowId]
+ var analyteId = isSinglePoint ? keys[1] : keys[0];
+ var controlId = isSinglePoint ? keys[0] : keys[1];
+ selectedRecords.push({ Analyte: analyteId, ControlId: controlId });
+ analyteIds.push(analyteId);
}
- selectedRecords.push(newItem);
- });
+ }
+ return getAnalyteIds ? analyteIds : selectedRecords;
+ },
- // create a pop-up window to display the apply guide set UI
- var win = new Ext.Window({
- layout: 'fit',
- width: 1115,
- height: 500,
- closeAction: 'close',
- modal: true,
- padding: 15,
- cls: 'extContainer leveljenningsreport',
- bodyStyle: 'background-color: white;',
- title: 'Apply Guide Set...',
- items: [new LABKEY.ApplyGuideSetPanel({
- assayName: this.assayName,
- controlName: this.controlName,
- controlType: this.controlType,
- analyte: this.analyte,
- isotype: this.isotype,
- conjugate: this.conjugate,
- selectedRecords: selectedRecords,
- networkExists: this.networkExists,
- protocolExists: this.protocolExists,
- listeners: {
- scope: this,
- 'closeApplyGuideSetPanel': function (hasUpdated)
- {
- if (hasUpdated)
- this.fireEvent('appliedGuideSetUpdated');
- win.close();
- }
+ applyGuideSetClicked: function(dataRegion) {
+ var scope = dataRegion.scope;
+
+ // get the selected record list from the grid
+ dataRegion.getSelected({
+ success: function(response) {
+ var selectedRecords = scope.parseGridSelectionKeys(response.selected, false);
+ if (selectedRecords.length === 0) {
+ LABKEY.Utils.alert('Error', 'Please select rows in the tracking data grid before clicking the "Apply Guide Set" button.');
+ return;
}
- })]
- });
- // for testing, narrow window puts left aligned buttons off of the page
- win.on('show', function(cmp) {
- var posArr = cmp.getPosition();
- if (posArr[0] < 0)
- cmp.setPosition(0, posArr[1]);
- });
+ // create a pop-up window to display the apply guide set UI
+ var win = new Ext.Window({
+ layout: 'fit',
+ width: 1115,
+ height: 500,
+ closeAction: 'close',
+ modal: true,
+ padding: 15,
+ cls: 'extContainer leveljenningsreport',
+ bodyStyle: 'background-color: white;',
+ title: 'Apply Guide Set...',
+ items: [new LABKEY.ApplyGuideSetPanel({
+ selectedRecords: selectedRecords,
+ assayName: scope.assayName,
+ controlName: scope.controlName,
+ controlType: scope.controlType,
+ analyte: scope.analyte,
+ isotype: scope.isotype,
+ conjugate: scope.conjugate,
+ networkExists: scope.networkExists,
+ protocolExists: scope.protocolExists,
+ has4PLCurveFit: scope.has4PLCurveFit,
+ has5PLCurveFit: scope.has5PLCurveFit,
+ listeners: {
+ 'closeApplyGuideSetPanel': function (hasUpdated)
+ {
+ if (hasUpdated)
+ scope.fireEvent('appliedGuideSetUpdated');
+ win.close();
+ }
+ }
+ })]
+ });
- win.show(this);
- },
+ // for testing, narrow window puts left aligned buttons off of the page
+ win.on('show', function(cmp) {
+ var posArr = cmp.getPosition();
+ if (posArr[0] < 0)
+ cmp.setPosition(0, posArr[1]);
+ });
- viewCurvesClicked: function ()
- {
- // create a pop-up window to display the plot
- var plotDiv = new Ext.Container({
- height: 600,
- width: 900,
- autoEl: {tag: 'div'}
- });
- var pdfDiv = new Ext.Container({
- hidden: true,
- autoEl: {tag: 'div'}
+ win.show(scope);
+ },
+ failure: function() {
+ LABKEY.Utils.alert('Error', 'Unable to get the tracking data region row selections.');
+ }
});
+ },
- var yAxisScaleDefault = 'Linear';
- var yAxisScaleStore = new Ext.data.ArrayStore({
- fields: ['value'],
- data: [['Linear'], ['Log']]
- });
+ viewCurvesClicked: function(dataRegion) {
+ var scope = dataRegion.scope;
- var yAxisColDefault = 'FIBackground', yAxisColDisplayDefault = 'FI-Bkgd';
- var yAxisColStore = new Ext.data.ArrayStore({
- fields: ['name', 'value'],
- data: [['FI', 'FI'], ['FI-Bkgd', 'FIBackground'], ['FI-Bkgd-Neg', 'FIBackgroundNegative']]
- });
+ // get the selected record list from the grid
+ dataRegion.getSelected({
+ success: function(response) {
+ var analyteIds = scope.parseGridSelectionKeys(response.selected, true);
+ if (analyteIds.length === 0) {
+ LABKEY.Utils.alert('Error', 'Please select rows in the tracking data grid before clicking the "View 4PL Curves" button.');
+ return;
+ }
- var legendColDefault = 'Name';
- var legendColStore = new Ext.data.ArrayStore({
- fields: ['name', 'value'],
- data: [['Assay Type', 'AssayType'], ['Experiment Performer', 'ExpPerformer'], ['Assay Id', 'Name'], ['Notebook No.', 'NotebookNo']]
- });
+ LABKEY.Query.selectRows({
+ schemaName: "assay.Luminex." + LABKEY.QueryKey.encodePart(_protocolName),
+ queryName: this.controlType === 'SinglePoint' ? 'AnalyteSinglePointControl' : 'AnalyteTitration',
+ columns: 'Analyte/Data/Run/RowId',
+ filterArray: [LABKEY.Filter.create('Analyte', analyteIds, LABKEY.Filter.Types.IN)],
+ success: function(data) {
+ var runIds = [];
+ for (var i = 0; i < data.rows.length; i++) {
+ runIds.push(data.rows[i]['Analyte/Data/Run/RowId']);
+ }
- var win = new Ext.Window({
- layout: 'fit',
- width: 900,
- minWidth: 600,
- height: 660,
- minHeight: 500,
- closeAction: 'hide',
- modal: true,
- cls: 'extContainer',
- title: 'Curve Comparison',
- items: [plotDiv, pdfDiv],
- // stash the default values for the plot options on the win component
- yAxisScale: yAxisScaleDefault,
- yAxisCol: yAxisColDefault,
- yAxisDisplay: yAxisColDisplayDefault,
- legendCol: legendColDefault,
- buttonAlign: 'left',
- buttons: [{
- xtype: 'label',
- text: 'Y-Axis:'
- },{
- xtype: 'combo',
- width: 80,
- id: 'curvecomparison-yaxis-combo',
- store: yAxisColStore ,
- displayField: 'name',
- valueField: 'value',
- mode: 'local',
- editable: false,
- forceSelection: true,
- triggerAction: 'all',
- value: yAxisColDefault,
- listeners: {
- scope: this,
- select: function(cmp, record) {
- win.yAxisCol = record.data.value;
- win.yAxisDisplay = record.data.name;
- this.updateCurvesPlot(win, plotDiv.getId(), false);
- }
- }
- },{
- xtype: 'label',
- text: 'Scale:'
- },{
- xtype: 'combo',
- width: 75,
- id: 'curvecomparison-scale-combo',
- store: yAxisScaleStore ,
- displayField: 'value',
- valueField: 'value',
- mode: 'local',
- editable: false,
- forceSelection: true,
- triggerAction: 'all',
- value: yAxisScaleDefault,
- listeners: {
- scope: this,
- select: function(cmp, record) {
- win.yAxisScale = record.data.value;
- this.updateCurvesPlot(win, plotDiv.getId(), false);
- }
- }
- },{
- xtype: 'label',
- text: 'Legend:'
- },{
- xtype: 'combo',
- width: 140,
- id: 'curvecomparison-legend-combo',
- store: legendColStore ,
- displayField: 'name',
- valueField: 'value',
- mode: 'local',
- editable: false,
- forceSelection: true,
- triggerAction: 'all',
- value: legendColDefault,
- listeners: {
- scope: this,
- select: function(cmp, record) {
- win.legendCol = record.data.value;
- this.updateCurvesPlot(win, plotDiv.getId(), false);
+ // create a pop-up window to display the plot
+ var plotDiv = new Ext.Container({
+ height: 600,
+ width: 900,
+ autoEl: {tag: 'div'}
+ });
+ var pdfDiv = new Ext.Container({
+ hidden: true,
+ autoEl: {tag: 'div'}
+ });
+
+ var yAxisScaleDefault = 'Linear';
+ var yAxisScaleStore = new Ext.data.ArrayStore({
+ fields: ['value'],
+ data: [['Linear'], ['Log']]
+ });
+
+ var yAxisColDefault = 'FIBackground', yAxisColDisplayDefault = 'FI-Bkgd';
+ var yAxisColStore = new Ext.data.ArrayStore({
+ fields: ['name', 'value'],
+ data: [['FI', 'FI'], ['FI-Bkgd', 'FIBackground'], ['FI-Bkgd-Neg', 'FIBackgroundNegative']]
+ });
+
+ var legendColDefault = 'Name';
+ var legendColStore = new Ext.data.ArrayStore({
+ fields: ['name', 'value'],
+ data: [['Assay Type', 'AssayType'], ['Experiment Performer', 'ExpPerformer'], ['Assay Id', 'Name'], ['Notebook No.', 'NotebookNo']]
+ });
+
+ var win = new Ext.Window({
+ layout: 'fit',
+ width: 900,
+ minWidth: 600,
+ height: 660,
+ minHeight: 500,
+ closeAction: 'hide',
+ modal: true,
+ cls: 'extContainer',
+ title: 'Curve Comparison',
+ items: [plotDiv, pdfDiv],
+ // stash the default values for the plot options on the win component
+ runIds: runIds,
+ yAxisScale: yAxisScaleDefault,
+ yAxisCol: yAxisColDefault,
+ yAxisDisplay: yAxisColDisplayDefault,
+ legendCol: legendColDefault,
+ buttonAlign: 'left',
+ buttons: [{
+ xtype: 'label',
+ text: 'Y-Axis:'
+ },{
+ xtype: 'combo',
+ width: 80,
+ id: 'curvecomparison-yaxis-combo',
+ store: yAxisColStore ,
+ displayField: 'name',
+ valueField: 'value',
+ mode: 'local',
+ editable: false,
+ forceSelection: true,
+ triggerAction: 'all',
+ value: yAxisColDefault,
+ listeners: {
+ scope: scope,
+ select: function(cmp, record) {
+ win.yAxisCol = record.data.value;
+ win.yAxisDisplay = record.data.name;
+ scope.updateCurvesPlot(win, plotDiv.getId(), false);
+ }
+ }
+ },{
+ xtype: 'label',
+ text: 'Scale:'
+ },{
+ xtype: 'combo',
+ width: 75,
+ id: 'curvecomparison-scale-combo',
+ store: yAxisScaleStore ,
+ displayField: 'value',
+ valueField: 'value',
+ mode: 'local',
+ editable: false,
+ forceSelection: true,
+ triggerAction: 'all',
+ value: yAxisScaleDefault,
+ listeners: {
+ scope: scope,
+ select: function(cmp, record) {
+ win.yAxisScale = record.data.value;
+ scope.updateCurvesPlot(win, plotDiv.getId(), false);
+ }
+ }
+ },{
+ xtype: 'label',
+ text: 'Legend:'
+ },{
+ xtype: 'combo',
+ width: 140,
+ id: 'curvecomparison-legend-combo',
+ store: legendColStore ,
+ displayField: 'name',
+ valueField: 'value',
+ mode: 'local',
+ editable: false,
+ forceSelection: true,
+ triggerAction: 'all',
+ value: legendColDefault,
+ listeners: {
+ scope: scope,
+ select: function(cmp, record) {
+ win.legendCol = record.data.value;
+ scope.updateCurvesPlot(win, plotDiv.getId(), false);
+ }
+ }
+ },
+ '->',
+ {
+ xtype: 'button',
+ text: 'Export to PDF',
+ handler: function (btn) {
+ scope.updateCurvesPlot(win, pdfDiv.getId(), true);
+ },
+ scope: scope
+ }, {
+ xtype: 'button',
+ text: 'Close',
+ handler: function () {
+ win.hide();
+ }
+ }],
+ listeners: {
+ scope: scope,
+ 'resize': function (w, width, height) {
+ // update the curve plot to the new size of the window
+ scope.updateCurvesPlot(win, plotDiv.getId(), false);
+ }
+ }
+ });
+
+ // for testing, narrow window puts left aligned buttons off of the page
+ win.on('show', function(cmp) {
+ var posArr = cmp.getPosition();
+ if (posArr[0] < 0)
+ cmp.setPosition(0, posArr[1]);
+ });
+
+ win.show(scope);
+ },
+ failure: function() {
+ LABKEY.Utils.alert('Error', 'Unable to get the tracking data run RowIds from the selections.');
}
- }
- },
- '->',
- {
- xtype: 'button',
- text: 'Export to PDF',
- handler: function (btn)
- {
- this.updateCurvesPlot(win, pdfDiv.getId(), true);
- },
- scope: this
+ });
},
- {
- xtype: 'button',
- text: 'Close',
- handler: function ()
- {
- win.hide();
- }
- }],
- listeners: {
- scope: this,
- 'resize': function (w, width, height)
- {
- // update the curve plot to the new size of the window
- this.updateCurvesPlot(win, plotDiv.getId(), false);
- }
+ failure: function() {
+ LABKEY.Utils.alert('Error', 'Unable to get the tracking data region row selections.');
}
});
-
- // for testing, narrow window puts left aligned buttons off of the page
- win.on('show', function(cmp) {
- var posArr = cmp.getPosition();
- if (posArr[0] < 0)
- cmp.setPosition(0, posArr[1]);
- });
-
- win.show(this);
-
- this.updateCurvesPlot(win, plotDiv.getId(), false);
},
updateCurvesPlot: function (win, divId, outputPdf)
{
win.getEl().mask("loading curves...", "x-mask-loading");
- // get the selected record list from the grid
- var selection = this.selModel.getSelections();
- var runIds = [];
- Ext.each(selection, function (record)
- {
- runIds.push(record.get("RunRowId"));
- });
-
// build the config object of the properties that will be needed by the R report
var config = {reportId: 'module:luminex/CurveComparisonPlot.r', showSection: 'Curve Comparison Plot'};
- config['RunIds'] = runIds.join(";");
+ config['RunIds'] = win.runIds.join(";");
config['Protocol'] = this.assayName;
config['Titration'] = this.controlName;
config['Analyte'] = this.analyte;
config['YAxisScale'] = !outputPdf ? win.yAxisScale : 'Linear';
- config['YAxisCol'] = win.yAxisCol,
- config['YAxisDisplay'] = win.yAxisDisplay,
- config['LegendCol'] = win.legendCol,
+ config['YAxisCol'] = win.yAxisCol;
+ config['YAxisDisplay'] = win.yAxisDisplay;
+ config['LegendCol'] = win.legendCol;
config['MainTitle'] = $h(this.controlName) + ' 4PL for ' + $h(this.analyte)
+ ' - ' + $h(this.isotype === '' ? '[None]' : this.isotype)
+ ' ' + $h(this.conjugate === '' ? '[None]' : this.conjugate);
config['PlotHeight'] = win.getHeight();
config['PlotWidth'] = win.getWidth();
- if (outputPdf)
- config['PdfOut'] = true;
+ if (outputPdf) config['PdfOut'] = true;
// call and display the Report webpart
new LABKEY.WebPart({
@@ -533,15 +449,12 @@ LABKEY.LeveyJenningsTrackingDataPanel = Ext.extend(Ext.grid.GridPanel, {
renderTo: divId,
frame: 'none',
partConfig: config,
- success: function ()
- {
+ success: function () {
this.getEl().unmask();
- if (outputPdf)
- {
+ if (outputPdf) {
// ugly way of getting the href for the pdf file and open it
- if (Ext.getDom(divId))
- {
+ if (Ext.getDom(divId)) {
var html = Ext.getDom(divId).innerHTML;
html = html.replace(/&/g, "&");
var pdfHref = html.substring(html.indexOf('href="') + 6, html.indexOf('&attachment=true'));
@@ -550,304 +463,13 @@ LABKEY.LeveyJenningsTrackingDataPanel = Ext.extend(Ext.grid.GridPanel, {
}
window.location = pdfHref + "&attachment=true";
}
-
}
},
- failure: function (response)
- {
+ failure: function (response) {
Ext.get(plotDiv.getId()).update("Error: " + response.statusText);
this.getEl().unmask();
},
scope: win
}).render();
},
-
- exportData: function (type)
- {
- // build up the JSON to pass to the export util
- var exportJson = {
- fileName: this.title + ".xls",
- sheets: [
- {
- name: 'data',
- // add a header section to the export with the graph parameter information
- data: [
- [this.controlType == 'Titration' ? 'Titration' : 'SinglePointControl', this.controlName],
- ['Analyte:', this.analyte],
- ['Isotype:', this.isotype],
- ['Conjugate:', this.conjugate],
- ['Export Date:', this.dateRenderer(new Date())],
- []
- ]
- }
- ]
- };
-
- // get all of the columns that are currently being shown in the grid (except for the checkbox column)
- var columns = this.getColumnModel().getColumnsBy(function (c)
- {
- return !c.hidden && c.dataIndex != "";
- });
-
- // add the column header row to the export JSON object
- var rowIndex = exportJson.sheets[0].data.length;
- exportJson.sheets[0].data.push([]);
- Ext.each(columns, function (col)
- {
- exportJson.sheets[0].data[rowIndex].push(col.header);
- });
-
- // loop through the grid store to put the data into the export JSON object
- Ext.each(this.getStore().getRange(), function (row)
- {
- var rowIndex = exportJson.sheets[0].data.length;
- exportJson.sheets[0].data[rowIndex] = [];
-
- // loop through the column list to get the data for each column
- var colIndex = 0;
- Ext.each(columns, function (col)
- {
- // some of the columns may not be defined in the assay design, so set to null
- var value = null;
- if (null != row.get(col.dataIndex))
- {
- value = row.get(col.dataIndex);
- }
-
- // render dates with the proper renderer
- if (value instanceof Date)
- {
- value = this.dateRenderer(value);
- }
- // render numbers with the proper rounding and format
- if (typeof(value) == 'number')
- {
- value = this.numberRenderer(value);
- }
- // render out of range values with an asterisk
- var enabledStates = row.get(col.dataIndex + "QCFlagsEnabled");
- if (enabledStates != null && (enabledStates.indexOf('t') > -1 || enabledStates.indexOf('1') > -1))
- {
- value = "*" + value;
- }
-
- // render the flags in an excel friendly format
- if (col.dataIndex == "QCFlags")
- {
- value = this.flagsExcelRenderer(value);
- }
-
- // Issue 19019: specify that this value should be displayed as a string and not converted to a date
- if (col.dataIndex == "RunName")
- {
- value = {value: value, forceString: true};
- }
-
- exportJson.sheets[0].data[rowIndex][colIndex] = value;
- colIndex++;
- }, this);
- }, this);
-
- if (type == 'excel')
- {
- LABKEY.Utils.convertToExcel(exportJson);
- }
- else
- {
- LABKEY.Utils.convertToTable({
- fileNamePrefix: this.title,
- delim: 'TAB',
- rows: exportJson.sheets[0].data
- });
- }
- },
-
- outOfRangeRenderer: function (enabledDataIndex)
- {
- return function (val, metaData, record)
- {
- if (null == val)
- {
- return null;
- }
-
- // if the record has an enabled QC flag, highlight it in red
- var enabledStates = record.get(enabledDataIndex);
- if (enabledStates != null && (enabledStates.indexOf('t') > -1 || enabledStates.indexOf('1') > -1))
- {
- metaData.attr = "style='color:red'";
- }
-
- // if this is a very small number, display more decimal places
- var precision = this.getPrecision(val);
- return Ext.util.Format.number(Ext.util.Format.round(val, precision), (precision == 6 ? '0.000000' : '0.00'));
- }
- },
-
- getPrecision: function (val)
- {
- return (null != val && val > 0 && val < 1) ? 6 : 2;
- },
-
- formatGuideSetMembers: function (val, metaData, record)
- {
- if (record.get("IncludeInGuideSetCalculation"))
- {
- metaData.attr = "style='font-weight:bold'";
- }
- return this.dateRenderer(val);
- },
-
- loadQCFlags: function (store, records, options)
- {
- // query the server for the QC Flags that match the selected Titration and Analyte and update the grid store accordingly
- this.getEl().mask("loading QC Flags...", "x-mask-loading");
- var prefix = this.controlType == 'Titration' ? 'Titration' : 'SinglePointControl';
- LABKEY.Query.executeSql({
- schemaName: "assay.Luminex." + LABKEY.QueryKey.encodePart(this.assayName),
- sql: 'SELECT DISTINCT x.Run, x.FlagType, x.Enabled, FROM Analyte' + prefix + 'QCFlags AS x '
- + 'WHERE x.Analyte.Name=\'' + this.analyte.replace(/'/g, "''") + '\' AND x.' + prefix + '.Name=\'' + this.controlName.replace(/'/g, "''") + '\' '
- + (this.isotype == '' ? ' AND x.' + prefix + '.Run.Isotype IS NULL ' : ' AND x.' + prefix + '.Run.Isotype=\'' + this.isotype.replace(/'/g, "''") + '\' ')
- + (this.conjugate == '' ? ' AND x.' + prefix + '.Run.Conjugate IS NULL ' : ' AND x.' + prefix + '.Run.Conjugate=\'' + this.conjugate.replace(/'/g, "''") + '\' ')
- + 'ORDER BY x.Run, x.FlagType, x.Enabled LIMIT 10000 ',
- sort: "Run,FlagType,Enabled",
- containerFilter: LABKEY.Query.containerFilter.allFolders,
- success: function (data)
- {
- // put together the flag display for each runId
- var runFlagList = {};
- for (var i = 0; i < data.rows.length; i++)
- {
- var row = data.rows[i];
- if (runFlagList[row.Run] == undefined)
- {
- runFlagList[row.Run] = {id: row.Run, count: 0, value: ""};
- }
-
- // add a comma separator
- if (runFlagList[row.Run].count > 0)
- {
- runFlagList[row.Run].value += ", ";
- }
-
- // add strike-thru for disabled flags
- if (row.Enabled)
- {
- runFlagList[row.Run].value += row.FlagType;
- }
- else
- {
- runFlagList[row.Run].value += '' + row.FlagType + '';
- }
-
- runFlagList[row.Run].count++;
- }
-
- // update the store records with the QC Flag values
- store.each(function (record)
- {
- var runFlag = runFlagList[record.get("RunRowId")];
- if (runFlag)
- {
- record.set("QCFlags", "" + runFlag.value + "");
- }
- }, this);
-
- // add cellclick event to the grid to trigger the QCFlagToggleWindow
- this.on('cellclick', this.showQCFlagToggleWindow, this);
-
- if (this.getEl().isMasked())
- {
- this.getEl().unmask();
- }
- },
- failure: function (info, response, options)
- {
- if (this.getEl().isMasked())
- {
- this.getEl().unmask();
- }
-
- LABKEY.Utils.displayAjaxErrorResponse(response, options);
- },
- scope: this
- })
- },
-
- showQCFlagToggleWindow: function (grid, rowIndex, colIndex, evnt)
- {
- var record = grid.getStore().getAt(rowIndex);
- var fieldName = grid.getColumnModel().getDataIndex(colIndex);
- var value = record.get(fieldName);
- var prefix = this.controlType == 'Titration' ? 'Titration' : 'SinglePointControl';
-
- if (fieldName == "QCFlags" && value != null)
- {
- var win = new LABKEY.QCFlagToggleWindow({
- schemaName: "assay.Luminex." + LABKEY.QueryKey.encodePart(this.assayName),
- queryName: "Analyte" + prefix + "QCFlags",
- runId: record.get("RunRowId"),
- analyte: this.analyte,
- controlName: this.controlName,
- controlType: this.controlType,
- editable: true,
- listeners: {
- scope: this,
- 'saveSuccess': function ()
- {
- grid.getStore().reload();
- win.close();
- }
- }
- });
- win.show();
- }
- },
-
- dateRenderer: function (val)
- {
- return val ? new Date(val).format("Y-m-d") : null;
- },
-
- numberRenderer: function (val)
- {
- // if this is a very small number, display more decimal places
- if (null == val)
- {
- return null;
- }
- else
- {
- if (val > 0 && val < 1)
- {
- return Ext.util.Format.number(Ext.util.Format.round(val, 6), '0.000000');
- }
- else
- {
- return Ext.util.Format.number(Ext.util.Format.round(val, 2), '0.00');
- }
- }
- },
-
- assayIdHrefRenderer: function (val, p, record)
- {
- var msg = Ext.util.Format.htmlEncode(val);
- var url = LABKEY.ActionURL.buildURL('assay', 'assayDetailRedirect', LABKEY.container.path, {runId: record.get('RunRowId')});
- return "" + msg + "";
- },
-
- encodingRenderer: function (value, p, record)
- {
- return $h(value);
- },
-
- flagsExcelRenderer: function (value)
- {
- if (value != null)
- {
- value = value.replace(//gi, "").replace(/<\/a>/gi, "");
- value = value.replace(//gi, "-").replace(/<\/span>/gi, "-");
- }
- return value;
- }
});
diff --git a/luminex/webapp/luminex/LeveyJenningsTrendPlotPanel.js b/luminex/webapp/luminex/LeveyJenningsTrendPlotPanel.js
index 8c7c81a2d2..70b519b9cd 100644
--- a/luminex/webapp/luminex/LeveyJenningsTrendPlotPanel.js
+++ b/luminex/webapp/luminex/LeveyJenningsTrendPlotPanel.js
@@ -14,7 +14,7 @@ Ext.namespace('LABKEY');
/**
* Class to create a tab panel for displaying the R plot for the trending of EC50, AUC, and High MFI values for the selected graph parameters.
*
- * @params titration
+ * @params titration or single point control
* @params assayName
*/
LABKEY.LeveyJenningsTrendPlotPanel = Ext.extend(Ext.FormPanel, {
@@ -29,7 +29,6 @@ LABKEY.LeveyJenningsTrendPlotPanel = Ext.extend(Ext.FormPanel, {
Ext.apply(config, {
items: [],
header: false,
- bodyStyle: 'background-color:#EEEEEE',
labelAlign: 'left',
width: 865,
border: false,
@@ -38,26 +37,24 @@ LABKEY.LeveyJenningsTrendPlotPanel = Ext.extend(Ext.FormPanel, {
yAxisScale: 'linear'
});
- this.addEvents('reportFilterApplied', 'togglePdfBtn');
+ this.addEvents('togglePdfBtn');
LABKEY.LeveyJenningsTrendPlotPanel.superclass.constructor.call(this, config);
},
initComponent : function() {
- var labelStyle = 'font-size: 13px; padding-top: 4px;';
- this.ANY_FIELD = '[ANY]'; // constant value used for turning filtering off
-
- this.startDate = null;
- this.endDate = null;
- this.network = null;
- this.networkAny = true; // false - turns on the filter in R and in Data Panel
- this.protocol = null;
- this.protocolAny = true; // false - turns on the filter in R and in Data Panel
+ this.guideSetRangeStore = LABKEY.LeveyJenningsPlotHelper.getGuideSetRangesStore({
+ assayName: this.assayName,
+ scope: this,
+ loadListener: function() {
+ this.guideSetRangeStoreLoadComplete = true;
+ this.updateTrendPlot();
+ },
+ });
// initialize the y-axis scale combo for the top toolbar
this.scaleLabel = new Ext.form.Label({
text: 'Y-Axis Scale:',
- style: labelStyle
});
this.scaleCombo = new Ext.form.ComboBox({
id: 'scale-combo-box',
@@ -82,190 +79,14 @@ LABKEY.LeveyJenningsTrendPlotPanel = Ext.extend(Ext.FormPanel, {
}
});
- // initialize the date range selection fields for the top toolbar
- this.startDateLabel = new Ext.form.Label({
- text: 'Start Date:',
- style: labelStyle
- });
- this.startDateField = new Ext.form.DateField({
- id: 'start-date-field',
- format: 'Y-m-d', // TODO use LABKEY.extDefaultDateFormat?
- listeners: {
- scope: this,
- 'valid': function (df) {
- if (df.getValue() != '')
- this.applyFilterButton.enable();
- },
- 'invalid': function (df, msg) {
- this.applyFilterButton.disable();
- }
- }
- });
- this.endDateLabel = new Ext.form.Label({
- text: 'End Date:',
- style: labelStyle
- });
- this.endDateField = new Ext.form.DateField({
- id: 'end-date-field',
- format: 'Y-m-d', // TODO use LABKEY.extDefaultDateFormat?
- listeners: {
- scope: this,
- 'valid': function (df) {
- if (df.getValue() != '')
- this.applyFilterButton.enable();
- },
- 'invalid': function (df, msg) {
- this.applyFilterButton.disable();
- }
- }
- });
-
- // Only create the network store and combobox if the Network column exists
- if (this.networkExists) {
- // Add Network field for filtering
- this.networkLabel = new Ext.form.Label({
- text: 'Network:',
- style: labelStyle
- });
- this.networkCombobox = new Ext.form.ComboBox({
- id: 'network-combo-box',
- width: 75,
- listWidth: 180,
- store: new Ext.data.ArrayStore({fields: ['value', 'display']}),
- editable: false,
- triggerAction: 'all',
- mode: 'local',
- valueField: 'value',
- displayField: 'display',
- tpl: '{display:htmlEncode}
',
- listeners: {
- scope: this,
- 'select': function(combo, record, index) {
- if (combo.getValue() == this.ANY_FIELD) {
- this.networkAny = true;
- this.network = null;
- } else {
- this.networkAny = false;
- this.network = combo.getValue();
- }
- this.applyFilterButton.enable();
- }
- }
- });
-
- this.networkCombobox.getStore().on('load', function(store, records, options) {
- if (this.network != undefined && store.findExact('value', this.network) > -1)
- {
- this.networkCombobox.setValue(this.network);
- this.networkCombobox.fireEvent('select', this.networkCombobox);
- this.networkCombobox.enable();
- }
- else
- {
- this.network = undefined;
- }
- }, this);
- }
-
- // Only create the protocol if the CustomProtocol column exists
- if (this.protocolExists) {
- // Add Protocol field for filtering
- this.protocolLabel = new Ext.form.Label({
- text: 'Protocol:',
- style: labelStyle
- });
- this.protocolCombobox = new Ext.form.ComboBox({
- id: 'protocol-combo-box',
- width: 75,
- listWidth: 180,
- store: new Ext.data.ArrayStore({fields: ['value', 'display']}),
- editable: false,
- triggerAction: 'all',
- mode: 'local',
- valueField: 'value',
- displayField: 'display',
- tpl: '{display:htmlEncode}
',
- listeners: {
- scope: this,
- 'select': function(combo, record, index) {
- this.protocol = combo.getValue();
- this.applyFilterButton.enable();
-
- if (combo.getValue() == this.ANY_FIELD) {
- this.protocolAny = true;
- this.protocol = null;
- } else {
- this.protocolAny = false;
- this.protocol = combo.getValue();
- }
- this.applyFilterButton.enable();
- }
- }
- });
-
- this.protocolCombobox.getStore().on('load', function(store, records, options) {
- if (this.protocol != undefined && store.findExact('value', this.protocol) > -1)
- {
- this.protocolCombobox.setValue(this.protocol);
- this.protocolCombobox.fireEvent('select', this.protocolCombobox);
- this.protocolCombobox.enable();
- }
- else
- {
- this.protocol = undefined;
- }
- }, this);
- }
-
- // initialize the refesh graph button
- this.applyFilterButton = new Ext.Button({
- disabled: true,
- text: 'Apply',
- handler: this.applyGraphFilter,
- scope: this
- });
-
- // initialize the clear graph button
- this.clearFilterButton = new Ext.Button({
- disabled: true,
- text: 'Clear',
- handler: function() {
- this.clearGraphFilter(false);
- },
- scope: this
- });
-
- var tbspacer = {xtype: 'tbspacer', width: 5};
-
- var items = [
- this.scaleLabel, tbspacer,
- this.scaleCombo, tbspacer,
- '->',
- this.startDateLabel, tbspacer,
- this.startDateField, tbspacer,
- this.endDateLabel, tbspacer,
- this.endDateField, tbspacer
- ];
- if (this.networkExists) {
- items.push(this.networkLabel);
- items.push(tbspacer);
- items.push(this.networkCombobox);
- items.push(tbspacer);
-
- }
- if (this.protocolExists) {
- items.push(this.protocolLabel);
- items.push(tbspacer);
- items.push(this.protocolCombobox);
- items.push(tbspacer);
- }
- items.push(this.applyFilterButton);
- items.push(tbspacer);
- items.push(this.clearFilterButton);
-
this.tbar = new Ext.Toolbar({
- style: 'border: solid 1px #d0d0d0; padding: 5px 10px;',
- items: items
+ style: 'background-color: #ffffff; padding: 5px 10px; border-color: #d0d0d0; border-width: 1px 1px 0 1px;',
+ items: [
+ '->',
+ this.scaleLabel,
+ {xtype: 'tbspacer', width: 5},
+ this.scaleCombo,
+ ]
});
// initialize the tab panel that will show the trend plots
@@ -321,6 +142,7 @@ LABKEY.LeveyJenningsTrendPlotPanel = Ext.extend(Ext.FormPanel, {
});
this.trendTabPanel = new Ext.TabPanel({
+ style: 'border-style: solid; border-width: 0 1px; border-color: #d0d0d0;',
autoScroll: true,
activeTab: 0,
defaults: {
@@ -332,7 +154,13 @@ LABKEY.LeveyJenningsTrendPlotPanel = Ext.extend(Ext.FormPanel, {
});
this.items.push(this.trendTabPanel);
+ this.fbar = [
+ {xtype: 'label', text: 'The default plot is showing the most recent ' + this.defaultRowSize + ' data points.'},
+ ];
+
LABKEY.LeveyJenningsTrendPlotPanel.superclass.initComponent.call(this);
+
+ this.fbar.hide();
},
// function called by the JSP when the graph params are selected and the "Apply" button is clicked
@@ -342,52 +170,58 @@ LABKEY.LeveyJenningsTrendPlotPanel = Ext.extend(Ext.FormPanel, {
this.isotype = isotype;
this.conjugate = conjugate;
- // remove any previously entered values from the start date, end date, network, etc. fileds
- this.clearGraphFilter(true);
-
- // show the trending tab panel and date range selection toolbar
this.enable();
this.setTrendPlotLoading();
},
- trackingDataLoaded: function(store)
+ plotDataLoading: function(store, hasGuideSetUpdates)
{
- if (this.networkExists)
- {
- this.networkCombobox.getStore().loadData(this.getArrayStoreData(store.collect("Network", true), this.networkCombobox.getValue()));
+ if (hasGuideSetUpdates) {
+ this.guideSetRangeStoreLoadComplete = false;
+ this.guideSetRangeStore.load();
}
- if (this.protocolExists)
- {
- this.protocolCombobox.getStore().loadData(this.getArrayStoreData(store.collect("CustomProtocol", true), this.protocolCombobox.getValue()));
+ this.setTrendPlotLoading();
+ },
+
+ plotDataLoaded: function(store, hasReportFilter)
+ {
+ // stash the store's records so that they can be re-used on tab change
+ if (store) {
+ this.trendDataStore = store;
}
- this.updateTrendPlot(store);
+ this.plotDataLoadComplete = true;
+ this.fbar.setVisible(!hasReportFilter && this.trendDataStore.getTotalCount() >= this.defaultRowSize);
+ this.updateTrendPlot();
},
setTrendPlotLoading: function() {
+ this.plotDataLoadComplete = false;
var plotType = this.trendTabPanel.getActiveTab().itemId;
var trendDiv = plotType + 'TrendPlotDiv';
Ext.get(trendDiv).update('Loading plot...');
this.togglePDFExportBtn(false);
},
- updateTrendPlot: function(store)
+ updateTrendPlot: function()
{
- this.togglePDFExportBtn(false);
-
- // stash the store's records so that they can be re-used on tab change
- if (store) {
- this.trendDataStore = store;
+ // if we are still loading either the guide set range data or the plot data, return without rendering
+ if (!this.guideSetRangeStoreLoadComplete || !this.plotDataLoadComplete) {
+ return;
}
+ this.togglePDFExportBtn(false);
+
var plotType = this.trendTabPanel.getActiveTab().itemId;
var trendDiv = plotType + 'TrendPlotDiv';
var plotConfig = {
- store: this.trendDataStore,
- plotType: plotType,
renderDiv: trendDiv,
+ dataStore: this.trendDataStore,
+ guideSetRangeStore: this.guideSetRangeStore,
+ controlType: this.controlType,
+ plotType: plotType,
assayName: this.assayName,
controlName: this.controlName,
analyte: this.analyte,
@@ -422,96 +256,15 @@ LABKEY.LeveyJenningsTrendPlotPanel = Ext.extend(Ext.FormPanel, {
}
},
- applyGraphFilter: function() {
- // make sure that at least one filter field is not null
- if (this.startDateField.getRawValue() == '' && this.endDateField.getRawValue() == '' && this.networkCombobox.getRawValue() == '' && this.protocolCombobox.getRawValue() == '')
- {
- Ext.Msg.show({
- title:'ERROR',
- msg: 'Please enter a value for filtering.',
- buttons: Ext.Msg.OK,
- icon: Ext.MessageBox.ERROR
- });
- }
- // verify that the start date is not after the end date
- else if (this.startDateField.getValue() > this.endDateField.getValue() && this.endDateField.getValue() != '')
- {
- Ext.Msg.show({
- title:'ERROR',
- msg: 'Please enter an end date that does not occur before the start date.',
- buttons: Ext.Msg.OK,
- icon: Ext.MessageBox.ERROR
- });
- }
- else
- {
- // get date values without the time zone info
- this.startDate = this.startDateField.getRawValue();
- this.endDate = this.endDateField.getRawValue();
- this.clearFilterButton.enable();
-
- this.fireEvent('reportFilterApplied', this.startDate, this.endDate, this.network, this.networkAny, this.protocol, this.protocolAny);
- }
- },
-
- clearGraphFilter: function(clearOnly) {
- this.startDate = null;
- this.startDateField.reset();
- this.endDate = null;
- this.endDateField.reset();
- this.applyFilterButton.disable();
- this.clearFilterButton.disable();
- this.network = null;
- if (this.networkCombobox) {
- this.networkCombobox.reset();
- this.networkCombobox.setValue(this.ANY_FIELD);
- this.networkAny = true;
- this.network = null;
- }
- this.protocol = null;
- if (this.protocolCombobox) {
- this.protocolCombobox.reset();
- this.protocolCombobox.setValue(this.ANY_FIELD);
- this.protocolAny = true;
- this.protocol = null;
- }
-
- if (clearOnly)
- return;
-
- this.fireEvent('reportFilterApplied', this.startDate, this.endDate, this.network, this.networkAny, this.protocol, this.protocolAny);
- },
-
- getStartDate: function() {
- return this.startDate ? this.startDate : null;
- },
-
- getEndDate: function() {
- return this.endDate ? this.endDate : null;
- },
-
- getArrayStoreData: function(arr, prevVal) {
- // if there is a previously selected combo value, make sure it exists in the array data
- if (prevVal && prevVal != '[ANY]' && arr.indexOf(prevVal) == -1){
- arr.push(prevVal);
- }
-
- var storeData = [ [this.ANY_FIELD, this.ANY_FIELD] ];
- Ext.each(arr.sort(), function(value){
- storeData.push([value, value == null ? '[Blank]' : value]);
- });
- return storeData;
- },
-
getTitrationSinglePointControlItems: function() {
- if (this.controlType == "Titration") {
+ if (this.controlType === "Titration") {
var panels = [];
if (this.has4PLCurveFit) panels.push(this.ec504plPanel);
if (this.has5PLCurveFit) panels.push(this.ec505plPanel);
panels.push(this.aucPanel);
panels.push(this.mfiPanel);
return(panels);
- } else if (this.controlType = "SinglePoint") {
+ } else if (this.controlType === "SinglePoint") {
return([this.singlePointControlPanel]);
}
return null;