Skip to content
2 changes: 1 addition & 1 deletion src/org/labkey/test/components/domain/DomainFieldRow.java
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ public DomainFieldRow clickRemoveOntologyConcept()
public void setAllowMultipleSelections(Boolean allowMultipleSelections)
{
WebDriverWrapper.waitFor(() -> elementCache().allowMultipleSelectionsCheckbox.isDisplayed(),
"Allow Multiple Selections checkbox did not become visible", 2000);
"Allow Multiple Selections checkbox did not become visible", 1000);
elementCache().allowMultipleSelectionsCheckbox.set(allowMultipleSelections);
}

Expand Down
34 changes: 34 additions & 0 deletions src/org/labkey/test/components/ui/grids/EditableGrid.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import static org.labkey.test.BaseWebDriverTest.WAIT_FOR_JAVASCRIPT;
import static org.labkey.test.WebDriverWrapper.waitFor;
import static org.labkey.test.util.TestLogger.log;
import static org.labkey.test.util.data.TestArrayDataUtils.formatMultiValueText;
import static org.labkey.test.util.selenium.ScrollUtils.Alignment.center;
import static org.labkey.test.util.selenium.WebDriverUtils.MODIFIER_KEY;

Expand Down Expand Up @@ -921,6 +922,39 @@ public EditableGrid pasteMultipleCells(String pasteText, int startRowIndex, Char
return this;
}

/**
* Format data for pasting into an editable grid. List elements in each row are quoted and separated by commas.
* This allows values containing commas to be pasted into multi-value columns. Even single-selections for these
* types of columns should be passed in as Lists to ensure they are quoted properly.
*
* @param rows values for pasting into an editable grid.
* @return rows formatted for pasting into an editable grid.
*/
public static String formatForPaste(List<List<?>> rows)
{
StringBuilder sb = new StringBuilder();
for (List<?> row : rows)
{
if (!sb.isEmpty())
sb.append("\n");

boolean firstVal = true;
for (Object value : row)
{
if (!firstVal)
sb.append("\t");
else
firstVal = false;

if (value instanceof List<?> l)
sb.append(formatMultiValueText(l));
else
sb.append(value);
}
}
return sb.toString();
}

/**
* Copies text from the grid, b
* @param startRowIndex Index of the top-left cell's row
Expand Down
7 changes: 7 additions & 0 deletions src/org/labkey/test/pages/assay/AssayRunsPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ public void clickEditAssayDesign()
elementCache().manageMenu.doMenuAction("Edit Assay Design");
}

//Method for Standard assays only.
public AssayImportPage clickImportData()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this method didn't exist before because many assay types have custom import pages that aren't compatible with the standard AssayImportPage. I think it's fine to have this method but it should be documented that it only works for Standard assays.

{
clickAndWait(Locator.linkWithText("Import Data"));
return new AssayImportPage(getDriver());
}

@Override
protected ElementCache newElementCache()
{
Expand Down
37 changes: 29 additions & 8 deletions src/org/labkey/test/util/data/TestArrayDataUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,35 @@ public static <T> Map<String, List<String>> filterMap(Map<String, T> map, List<S
.filter(entry -> isMatch(entry.getValue(), searchValues, filterType))
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().stream()
// Standard alphabetical sort that accounts for symbols and numbers.
// But uppercase letters are positioned before lowercase letters.
.sorted(Comparator
.comparing((String s) -> s.substring(0, 1).toLowerCase())
.thenComparing(s -> s.substring(0, 1))
.thenComparing(s -> s))
.collect(Collectors.toList()),
e -> sortValues(e.getValue()),
(e1, e2) -> e1,
LinkedHashMap::new
));
}

/**
* Standard alphabetical sort that accounts for symbols and numbers.
* Uppercase letters are positioned before lowercase letters.
*/
public static List<String> sortValues(List<String> values)
{
return values.stream()
.peek(s -> { if (s.isEmpty()) throw new IllegalArgumentException("Empty values aren't allowed: " + values);})
.sorted(Comparator
.comparing((String s) -> s.substring(0, 1).toLowerCase())
.thenComparing(s -> s.substring(0, 1))
.thenComparing(s -> s))
.collect(Collectors.toList());
}

/**
* Sorts values alphabetically and joins them with the given separator.
*/
public static String sortAndJoin(List<String> values, String separator)
{
return String.join(separator, sortValues(values));
}

public static Map<String, String> prepareMapForCheck(Map<String, List<String>> map)
{
return map.entrySet().stream()
Expand Down Expand Up @@ -87,6 +103,11 @@ public static List<String> parseMultiValueText(String multiValueString) throws I
}
}

public static <T> String formatMultiValueText(List<T> values)
{
return values.stream().map(CSVFormat.DEFAULT::format).collect(Collectors.joining(","));
}

private static boolean isMatch(List<String> actualValues, List<String> searchValues, Filter.Operator type)
{
return switch (type)
Expand Down
Loading