diff --git a/api/src/org/labkey/api/data/CompareType.java b/api/src/org/labkey/api/data/CompareType.java index b9aefae496c..72d9a7085b3 100644 --- a/api/src/org/labkey/api/data/CompareType.java +++ b/api/src/org/labkey/api/data/CompareType.java @@ -91,7 +91,7 @@ public abstract class CompareType public static final CompareType EQUAL = new CompareType("Equals", "eq", "EQUAL", true, " = ?", OperatorType.EQ) { @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new EqualsCompareClause(fieldKey, this, value); } @@ -135,7 +135,7 @@ public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] public static final CompareType NEQ = new CompareType("Does Not Equal", "neq", "NOT_EQUAL", true, " <> ?", OperatorType.NEQ) { @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new NotEqualsCompareClause(fieldKey, this, value); } @@ -383,7 +383,7 @@ public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] { // Each compare type uses CompareClause by default @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { if (value instanceof Collection) { @@ -418,7 +418,7 @@ public String getValueSeparator() { // Each compare type uses CompareClause by default @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { if (value instanceof Collection) { @@ -450,7 +450,7 @@ public String getValueSeparator() { // Each compare type uses CompareClause by default @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { if (value instanceof Collection) { @@ -492,7 +492,7 @@ public String getValueSeparator() { // Each compare type uses CompareClause by default @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { if (value instanceof Collection) { @@ -534,7 +534,7 @@ public String getValueSeparator() { // Each compare type uses CompareClause by default @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { String namedSet = null; if (value != null && StringUtils.isNotBlank(value.toString())) @@ -553,7 +553,7 @@ public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] { // Each compare type uses CompareClause by default @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { String namedSet = null; if (value != null && StringUtils.isNotBlank(value.toString())) @@ -571,7 +571,7 @@ public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] public static final CompareType BETWEEN = new CompareType("Between", "between", "BETWEEN", true, " BETWEEN ? AND ?", OperatorType.BETWEEN) { @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { if (value instanceof Collection) { @@ -622,7 +622,7 @@ public String getValueSeparator() public static final CompareType NOT_BETWEEN = new CompareType("Not Between", "notbetween", "NOT_BETWEEN", true, " NOT BETWEEN ? AND ?", OperatorType.NOTBETWEEN) { @Override - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { if (value instanceof Collection) { @@ -673,7 +673,7 @@ public String getValueSeparator() public static final CompareType MEMBER_OF = new CompareType("Is Member Of", "memberof", "MEMBER_OF", true, " is member of", OperatorType.MEMBEROF) { @Override - protected MemberOfClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public MemberOfClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new MemberOfClause(fieldKey, value); } @@ -736,7 +736,7 @@ public String getFilterValueText() public static final CompareType MV_INDICATOR = new CompareType("Has An MV Indicator", new String[] { "hasmvvalue", "hasqcvalue" }, false, " has a missing value indicator", "MV_INDICATOR", OperatorType.HASMVVALUE) { @Override - protected MvClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public MvClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new MvClause(fieldKey, false); } @@ -751,7 +751,7 @@ public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] public static final CompareType NO_MV_INDICATOR = new CompareType("Does Not Have An MV Indicator", new String[] { "nomvvalue", "noqcvalue" }, false, " does not have a missing value indicator", "NO_MV_INDICATOR", OperatorType.NOMVVALUE) { @Override - protected MvClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public MvClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new MvClause(fieldKey, true); } @@ -771,7 +771,7 @@ public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] public static final CompareType Q = new CompareType("Search", "q", "Q", true /* dataValueRequired */, "sql", OperatorType.Q) { @Override - protected QClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public QClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new QClause((String) value); } @@ -1073,7 +1073,7 @@ public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] } // Each compare type uses CompareClause by default - protected FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new CompareClause(fieldKey, this, value); } @@ -1503,7 +1503,7 @@ public static Calendar addOneDay(Calendar d) assert d.get(Calendar.SECOND) == 0; assert d.get(Calendar.MINUTE) == 0; assert d.get(Calendar.HOUR_OF_DAY) == 0; - + Calendar cal = (Calendar)d.clone(); cal.add(Calendar.DAY_OF_MONTH, 1); return cal; @@ -1670,7 +1670,7 @@ protected boolean meetsCriteria(ColumnRenderProperties col, Object value) return dateValue.compareTo(param) >= 0; } } - + static class DateGteCompareClause extends DateCompareClause { @@ -1967,7 +1967,7 @@ public ContainsClause(FieldKey fieldKey, Object value) @Override String toWhereClause(SqlDialect dialect, String alias) { - return dialect.getColumnSelectName(alias) + " " + dialect.getCaseInsensitiveLikeOperator() + " " + dialect.concatenate("'%'", "?", "'%'") + sqlEscape(); + return dialect.getColumnSelectName(alias) + " " + dialect.getCaseInsensitiveLikeOperator() + " " + dialect.concatenate("'%'", "?", "'%'") + sqlEscape(); } @Override @@ -1997,7 +1997,7 @@ public DoesNotContainClause(FieldKey fieldKey, Object value) @Override String toWhereClause(SqlDialect dialect, String alias) { - return "(" + dialect.getColumnSelectName(alias) + " IS NULL OR " + dialect.getColumnSelectName(alias) + " NOT " + dialect.getCaseInsensitiveLikeOperator() + " " + dialect.concatenate("'%'", "?", "'%'") + sqlEscape() + ")"; + return "(" + dialect.getColumnSelectName(alias) + " IS NULL OR " + dialect.getColumnSelectName(alias) + " NOT " + dialect.getCaseInsensitiveLikeOperator() + " " + dialect.concatenate("'%'", "?", "'%'") + sqlEscape() + ")"; } @Override diff --git a/api/src/org/labkey/api/data/triggers/ScriptTriggerFactory.java b/api/src/org/labkey/api/data/triggers/ScriptTriggerFactory.java index 71c0fd9524a..6752314dff7 100644 --- a/api/src/org/labkey/api/data/triggers/ScriptTriggerFactory.java +++ b/api/src/org/labkey/api/data/triggers/ScriptTriggerFactory.java @@ -98,6 +98,8 @@ private Collection getDefaultTriggers(Container c, TableInfo table, @No FileUtil.makeLegalName(title) + ".js"); Collection titleTriggers = checkPaths(c, table, svc, pathLabel); + // Remove those that might be case-only differences with already resolved scripts + titleTriggers.removeAll(scripts); scripts.addAll(titleTriggers); if (!titleTriggers.isEmpty()) diff --git a/api/src/org/labkey/api/ldk/table/QueryCache.java b/api/src/org/labkey/api/ldk/table/QueryCache.java index f325530bc3c..a0543a114ac 100644 --- a/api/src/org/labkey/api/ldk/table/QueryCache.java +++ b/api/src/org/labkey/api/ldk/table/QueryCache.java @@ -105,7 +105,7 @@ public TableInfo getTableInfo(Container targetContainer, User u, String schemaPa TableInfo ti = qd.getTable(errors, true); if (errors.size() > 0) { - _log.error("Unable to create tabbed report item for query: " + schemaPath + "." + queryName); + _log.error("Unable to create tabbed report item for query: " + schemaPath + "." + queryName + " in " + targetContainer.getPath()); for (QueryException e : errors) { _log.error(e.getMessage(), e); diff --git a/api/src/org/labkey/api/websocket/BrowserEndpoint.java b/api/src/org/labkey/api/websocket/BrowserEndpoint.java index 11e3ea1058c..9492f5cbf8f 100644 --- a/api/src/org/labkey/api/websocket/BrowserEndpoint.java +++ b/api/src/org/labkey/api/websocket/BrowserEndpoint.java @@ -102,7 +102,8 @@ public void onOpen(Session session, EndpointConfig endpointConfig) throws URISyn public void onClose(Session session, CloseReason closeReason) { LOG.debug("BrowserEndpoint.onClose()"); - serverEndpoint.close(); + if (null != serverEndpoint) + serverEndpoint.close(); } @OnError diff --git a/core/resources/styles/js/navigation.js b/core/resources/styles/js/navigation.js index c0d5ff5b602..129d1eb98e6 100644 --- a/core/resources/styles/js/navigation.js +++ b/core/resources/styles/js/navigation.js @@ -379,13 +379,13 @@ // if toggle element is in left half of screen then left align the menu var inLeftHemisphere = (me.offset().left + 100) < (win.width() / 2); - if (spaceDown < 0) { - if (spaceUp > 0 || spaceUp > spaceDown) { - me.removeClass('dropdown').addClass('dropup'); - } else { - me.removeClass('dropup').addClass('dropdown'); - } + // Issue 41102 - See if we have enough space below to render the whole menu + if (spaceDown < 0 && spaceUp > 0) { + // We've got enough space to render up, so use it + me.removeClass('dropdown').addClass('dropup'); } else { + // Whether we have enough space to render down or not, expand downwards because the whole page will extend + // to let the user get to the rest of the menu items as needed me.removeClass('dropup').addClass('dropdown'); } diff --git a/core/resources/styles/scss/labkey/_labkey.scss b/core/resources/styles/scss/labkey/_labkey.scss index eff893fa949..de7207c97cb 100644 --- a/core/resources/styles/scss/labkey/_labkey.scss +++ b/core/resources/styles/scss/labkey/_labkey.scss @@ -38,6 +38,10 @@ legend { margin-top: 8px; } +a:hover { + cursor: pointer; +} + /* Expose the theme color for use with text and borders in labkey pages */ .lk-text-theme-dark { color: $lk-theme-dark-accent; diff --git a/core/src/org/labkey/core/user/UserController.java b/core/src/org/labkey/core/user/UserController.java index cb0b39fe2c2..566b565967e 100644 --- a/core/src/org/labkey/core/user/UserController.java +++ b/core/src/org/labkey/core/user/UserController.java @@ -1022,6 +1022,9 @@ public void validateCommand(QueryUpdateForm form, Errors errors) { for (Map.Entry entry : form.getTypedColumns().entrySet()) { + if (entry.getKey().equals("ExpirationDate") && !AuthenticationManager.canSetUserExpirationDate(getUser(), getContainer())) + errors.reject(ERROR_MSG, "User does not have permission to edit the ExpirationDate field."); + if (entry.getValue() != null) { ColumnInfo col = table.getColumn(FieldKey.fromParts(entry.getKey())); diff --git a/experiment/src/org/labkey/experiment/api/data/ChildOfCompareType.java b/experiment/src/org/labkey/experiment/api/data/ChildOfCompareType.java index 332044fe85b..8dbf07ff211 100644 --- a/experiment/src/org/labkey/experiment/api/data/ChildOfCompareType.java +++ b/experiment/src/org/labkey/experiment/api/data/ChildOfCompareType.java @@ -34,7 +34,7 @@ public ChildOfCompareType() } @Override - protected SimpleFilter.FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public SimpleFilter.FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new ChildOfClause(fieldKey, value); } diff --git a/experiment/src/org/labkey/experiment/api/data/LineageCompareType.java b/experiment/src/org/labkey/experiment/api/data/LineageCompareType.java index e397a2da0cb..a7581a73600 100644 --- a/experiment/src/org/labkey/experiment/api/data/LineageCompareType.java +++ b/experiment/src/org/labkey/experiment/api/data/LineageCompareType.java @@ -26,7 +26,7 @@ public LineageCompareType() } @Override - protected SimpleFilter.FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public SimpleFilter.FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { Object[] values; Object collection; diff --git a/experiment/src/org/labkey/experiment/api/data/ParentOfCompareType.java b/experiment/src/org/labkey/experiment/api/data/ParentOfCompareType.java index 516d489ce9b..5fb6e054dea 100644 --- a/experiment/src/org/labkey/experiment/api/data/ParentOfCompareType.java +++ b/experiment/src/org/labkey/experiment/api/data/ParentOfCompareType.java @@ -34,7 +34,7 @@ public ParentOfCompareType() } @Override - protected SimpleFilter.FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public SimpleFilter.FilterClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new ParentOfClause(fieldKey, value); } diff --git a/query/src/org/labkey/query/QueryServiceImpl.java b/query/src/org/labkey/query/QueryServiceImpl.java index bc7ac80bf38..14dd4beb43f 100644 --- a/query/src/org/labkey/query/QueryServiceImpl.java +++ b/query/src/org/labkey/query/QueryServiceImpl.java @@ -244,7 +244,7 @@ public void moduleChanged(Module module) public static final CompareType WHERE = new CompareType("WHERE", "where", "WHERE", true /* dataValueRequired */, "sql", OperatorType.WHERE) { @Override - protected WhereClause createFilterClause(@NotNull FieldKey fieldKey, Object value) + public WhereClause createFilterClause(@NotNull FieldKey fieldKey, Object value) { return new WhereClause((String) value); }