You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by kb...@apache.org on 2020/08/14 09:14:48 UTC
[atlas] branch master updated (83e9c21 -> 41eebcf)
This is an automated email from the ASF dual-hosted git repository.
kbhatt pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git.
from 83e9c21 ATLAS-3875: updated sample client to improve logging
new 1b41b98 ATLAS-3892 : Basic search enhanced Feature - Search history
new 41eebcf ATLAS-3900: UI: Allow user to select the date range for date attribute in basic search
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../org/apache/atlas/repository/Constants.java | 1 +
dashboardv2/package-lock.json | 6 +-
dashboardv2/package.json | 2 +-
dashboardv2/public/css/scss/override.scss | 24 ++-
dashboardv2/public/js/utils/CommonViewFunction.js | 89 ++++----
dashboardv2/public/js/utils/Enums.js | 37 +++-
.../public/js/views/search/QueryBuilderView.js | 236 ++++++++++++++------
dashboardv3/package-lock.json | 6 +-
dashboardv3/package.json | 2 +-
dashboardv3/public/css/scss/override.scss | 22 +-
dashboardv3/public/js/main.js | 1 -
.../search/SearchDefaultLayoutView_tmpl.html | 6 +-
dashboardv3/public/js/utils/CommonViewFunction.js | 88 ++++----
dashboardv3/public/js/utils/Enums.js | 37 +++-
.../public/js/views/search/QueryBuilderView.js | 236 ++++++++++++++------
.../js/views/search/tree/EntityTreeLayoutView.js | 3 +-
.../atlas/model/discovery/SearchParameters.java | 5 +
.../apache/atlas/discovery/SearchProcessor.java | 181 ++++++++++++++--
.../org/apache/atlas/util/SearchPredicateUtil.java | 58 ++++-
.../atlas/discovery/EntitySearchProcessorTest.java | 238 +++++++++++++++++++++
20 files changed, 1004 insertions(+), 274 deletions(-)
[atlas] 01/02: ATLAS-3892 : Basic search enhanced Feature - Search
history
Posted by kb...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
kbhatt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git
commit 1b41b980415961419bb4af8710bd82f34395779c
Author: chaitali borole <ch...@cloudera.com>
AuthorDate: Mon Aug 10 20:01:00 2020 +0530
ATLAS-3892 : Basic search enhanced Feature - Search history
Signed-off-by: kevalbhatt <kb...@apache.org>
---
.../org/apache/atlas/repository/Constants.java | 1 +
.../atlas/model/discovery/SearchParameters.java | 5 +
.../apache/atlas/discovery/SearchProcessor.java | 181 ++++++++++++++--
.../org/apache/atlas/util/SearchPredicateUtil.java | 58 ++++-
.../atlas/discovery/EntitySearchProcessorTest.java | 238 +++++++++++++++++++++
5 files changed, 468 insertions(+), 15 deletions(-)
diff --git a/common/src/main/java/org/apache/atlas/repository/Constants.java b/common/src/main/java/org/apache/atlas/repository/Constants.java
index a71787b..61abfca 100644
--- a/common/src/main/java/org/apache/atlas/repository/Constants.java
+++ b/common/src/main/java/org/apache/atlas/repository/Constants.java
@@ -188,6 +188,7 @@ public final class Constants {
public static final String TERM_ASSIGNMENT_LABEL = "r:AtlasGlossarySemanticAssignment";
public static final String ATTRIBUTE_INDEX_PROPERTY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "index");
public static final String ATTRIBUTE_KEY_PROPERTY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "key");
+ public static final String ATTRIBUTE_VALUE_DELIMITER = ",";
public static final String VERTEX_ID_IN_IMPORT_KEY = "__vIdInImport";
public static final String EDGE_ID_IN_IMPORT_KEY = "__eIdInImport";
diff --git a/intg/src/main/java/org/apache/atlas/model/discovery/SearchParameters.java b/intg/src/main/java/org/apache/atlas/model/discovery/SearchParameters.java
index fcc4494..367c5b8 100644
--- a/intg/src/main/java/org/apache/atlas/model/discovery/SearchParameters.java
+++ b/intg/src/main/java/org/apache/atlas/model/discovery/SearchParameters.java
@@ -443,6 +443,10 @@ public class SearchParameters implements Serializable {
* Logical comparision operators can only be used with numbers or dates
* IN, LIKE, startsWith, endsWith, CONTAINS can only be used with strings or text
*/
+
+ /**
+ * NOTE : The names added in the String array should always contain first value in lower case
+ */
public enum Operator {
LT(new String[]{"<", "lt"}),
GT(new String[]{">", "gt"}),
@@ -460,6 +464,7 @@ public class SearchParameters implements Serializable {
CONTAINS_ALL(new String[]{"containsAll", "CONTAINSALL", "contains_all", "CONTAINS_ALL"}),
IS_NULL(new String[]{"isNull", "ISNULL", "is_null", "IS_NULL"}),
NOT_NULL(new String[]{"notNull", "NOTNULL", "not_null", "NOT_NULL"}),
+ TIME_RANGE(new String[]{"timerange", "TIMERANGE","time_range","TIME_RANGE"})
;
static final Map<String, Operator> operatorsMap = new HashMap<>();
diff --git a/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java b/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java
index c5e3d6f..da9dd66 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/SearchProcessor.java
@@ -17,6 +17,7 @@
*/
package org.apache.atlas.discovery;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasException;
import org.apache.atlas.SortOrder;
@@ -46,6 +47,8 @@ import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
@@ -121,6 +124,9 @@ public abstract class SearchProcessor {
OPERATOR_MAP.put(SearchParameters.Operator.NOT_NULL, INDEX_SEARCH_PREFIX + "\"%s\":[* TO *]");
OPERATOR_PREDICATE_MAP.put(SearchParameters.Operator.NOT_NULL, getNotNullPredicateGenerator());
+
+ OPERATOR_MAP.put(SearchParameters.Operator.TIME_RANGE, INDEX_SEARCH_PREFIX + "\"%s\": [%s TO %s]");
+ OPERATOR_PREDICATE_MAP.put(SearchParameters.Operator.TIME_RANGE, getInRangePredicateGenerator());
}
protected final SearchContext context;
@@ -523,6 +529,9 @@ public abstract class SearchProcessor {
}
} else if (StringUtils.isNotEmpty(criteria.getAttributeName())) {
try {
+ if (criteria.getOperator() == SearchParameters.Operator.TIME_RANGE) {
+ criteria = processDateRange(criteria);
+ }
ArrayList<String> orExpQuery = new ArrayList<>();
for (AtlasStructType structType : structTypes) {
String name = structType.getVertexPropertyName(criteria.getAttributeName());
@@ -584,6 +593,10 @@ public abstract class SearchProcessor {
String attrValue = criteria.getAttributeValue();
SearchParameters.Operator operator = criteria.getOperator();
+ if (operator == SearchParameters.Operator.TIME_RANGE) {
+ FilterCriteria processedRangeCriteria = processDateRange(criteria);
+ attrValue = processedRangeCriteria.getAttributeValue();
+ }
//process attribute value and attribute operator for pipeSeperated fields
if (isPipeSeparatedSystemAttribute(attrName)) {
FilterCriteria processedCriteria = processPipeSeperatedSystemAttribute(attrName, operator, attrValue);
@@ -610,6 +623,115 @@ public abstract class SearchProcessor {
return null;
}
+ @VisibleForTesting
+ public FilterCriteria processDateRange(FilterCriteria criteria) {
+ String attrName = criteria.getAttributeName();
+ SearchParameters.Operator op = criteria.getOperator();
+ String attrVal = criteria.getAttributeValue();
+ FilterCriteria ret = new FilterCriteria();
+ final LocalDateTime now = LocalDateTime.now();
+ final LocalDateTime startTime;
+ final LocalDateTime endTime;
+
+ switch (attrVal) {
+ case "LAST_7_DAYS":
+ startTime = now.minusDays(6).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusDays(7).minusNanos(1);
+ break;
+
+ case "LAST_30_DAYS":
+ startTime = now.minusDays(29).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusDays(30).minusNanos(1);
+ break;
+
+ case "LAST_MONTH":
+ startTime = now.minusMonths(1).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusMonths(1).minusNanos(1);
+ break;
+
+ case "THIS_MONTH":
+ startTime = now.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusMonths(1).minusNanos(1);
+ break;
+
+ case "TODAY":
+ startTime = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusDays(1).minusNanos(1);
+ break;
+
+ case "YESTERDAY":
+ startTime = now.minusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusDays(1).minusNanos(1);
+ break;
+
+ case "THIS_YEAR":
+ startTime = now.withDayOfYear(1).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusYears(1).minusNanos(1);
+ break;
+
+ case "LAST_YEAR":
+ startTime = now.minusYears(1).withDayOfYear(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusYears(1).minusNanos(1);
+ break;
+
+ case "THIS_QUARTER":
+ startTime = now.minusMonths(1).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusMonths(3).minusNanos(1);
+ break;
+
+ case "LAST_QUARTER":
+ startTime = now.minusMonths(4).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusMonths(3).minusNanos(1);
+ break;
+
+ case "LAST_3_MONTHS":
+ startTime = now.minusMonths(3).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusMonths(3).minusNanos(1);
+ break;
+
+ case "LAST_6_MONTHS":
+ startTime = now.minusMonths(6).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusMonths(6).minusNanos(1);
+ break;
+
+ case "LAST_12_MONTHS":
+ startTime = now.minusMonths(12).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
+ endTime = startTime.plusMonths(12).minusNanos(1);
+ break;
+
+ default:
+ startTime = null;
+ endTime = null;
+ break;
+ }
+
+ if (startTime == null || endTime == null) {
+ String[] rangeAttr = attrVal.split(ATTRIBUTE_VALUE_DELIMITER);
+ boolean numeric = true;
+ if (rangeAttr.length != 2) {
+ LOG.error("Separator invalid");
+ } else {
+ try {
+ Long parsestartTime = Long.parseLong(String.valueOf(rangeAttr[0]));
+ Long parseendTime = Long.parseLong(String.valueOf(rangeAttr[1]));
+ } catch (NumberFormatException e) {
+ numeric = false;
+ if (!numeric) {
+ LOG.error("Attributes passed need to be LONG");
+ }
+ }
+ }
+ }else {
+ attrVal = Timestamp.valueOf(startTime).getTime() + ATTRIBUTE_VALUE_DELIMITER + Timestamp.valueOf(endTime).getTime();
+ }
+
+ ret.setAttributeName(attrName);
+ ret.setOperator(op);
+ ret.setAttributeValue(attrVal);
+
+ return ret;
+ }
+
private FilterCriteria processPipeSeperatedSystemAttribute(String attrName, SearchParameters.Operator op, String attrVal) {
FilterCriteria ret = new FilterCriteria();
@@ -648,20 +770,32 @@ public abstract class SearchProcessor {
return ret;
}
- private String toIndexExpression(AtlasStructType type, String attrName, SearchParameters.Operator op, String attrVal) {
+ private String toIndexExpression(AtlasStructType type, String attrName, SearchParameters.Operator op, String attrVal) throws AtlasBaseException{
String ret = EMPTY_STRING;
try {
if (OPERATOR_MAP.get(op) != null) {
- String qualifiedName = type.getVertexPropertyName(attrName);
- String escapeIndexQueryValue = AtlasAttribute.escapeIndexQueryValue(attrVal);
-
- // map '__customAttributes' 'CONTAINS' operator to 'EQ' operator (solr limitation for json serialized string search)
- // map '__customAttributes' value from 'key1=value1' to '\"key1\":\"value1\"' (escape special characters and surround with quotes)
- if (attrName.equals(CUSTOM_ATTRIBUTES_PROPERTY_KEY) && op == SearchParameters.Operator.CONTAINS) {
- ret = String.format(OPERATOR_MAP.get(op), qualifiedName, getCustomAttributeIndexQueryValue(escapeIndexQueryValue, false));
+ String rangeStart = "";
+ String rangeEnd = "";
+ String qualifiedName = type.getVertexPropertyName(attrName);
+ if (op == SearchParameters.Operator.TIME_RANGE) {
+ String[] parts = attrVal.split(ATTRIBUTE_VALUE_DELIMITER);
+ if (parts.length == 2) {
+ rangeStart = parts[0];
+ rangeEnd = parts[1];
+ String rangeStartIndexQueryValue = AtlasAttribute.escapeIndexQueryValue(rangeStart);
+ String rangeEndIndexQueryValue = AtlasAttribute.escapeIndexQueryValue(rangeEnd);
+ ret = String.format(OPERATOR_MAP.get(op), qualifiedName, rangeStartIndexQueryValue, rangeEndIndexQueryValue);
+ }
} else {
- ret = String.format(OPERATOR_MAP.get(op), qualifiedName, escapeIndexQueryValue);
+ // map '__customAttributes' 'CONTAINS' operator to 'EQ' operator (solr limitation for json serialized string search)
+ // map '__customAttributes' value from 'key1=value1' to '\"key1\":\"value1\"' (escape special characters and surround with quotes)
+ String escapeIndexQueryValue = AtlasAttribute.escapeIndexQueryValue(attrVal);
+ if (attrName.equals(CUSTOM_ATTRIBUTES_PROPERTY_KEY) && op == SearchParameters.Operator.CONTAINS) {
+ ret = String.format(OPERATOR_MAP.get(op), qualifiedName, getCustomAttributeIndexQueryValue(escapeIndexQueryValue, false));
+ } else {
+ ret = String.format(OPERATOR_MAP.get(op), qualifiedName, escapeIndexQueryValue);
+ }
}
}
} catch (AtlasBaseException ex) {
@@ -695,7 +829,6 @@ public abstract class SearchProcessor {
private Predicate toInMemoryPredicate(AtlasStructType type, String attrName, SearchParameters.Operator op, String attrVal) {
Predicate ret = null;
-
AtlasAttribute attribute = type.getAttribute(attrName);
ElementAttributePredicateGenerator predicate = OPERATOR_PREDICATE_MAP.get(op);
@@ -703,6 +836,7 @@ public abstract class SearchProcessor {
final AtlasType attrType = attribute.getAttributeType();
final Class attrClass;
final Object attrValue;
+ Object attrValue2 = null;
// Some operators support null comparison, thus the parsing has to be conditional
switch (attrType.getTypeName()) {
@@ -733,7 +867,21 @@ public abstract class SearchProcessor {
case AtlasBaseTypeDef.ATLAS_TYPE_LONG:
case AtlasBaseTypeDef.ATLAS_TYPE_DATE:
attrClass = Long.class;
- attrValue = StringUtils.isEmpty(attrVal) ? null : Long.parseLong(attrVal);
+ String rangeStart = "";
+ String rangeEnd = "";
+ if (op == SearchParameters.Operator.TIME_RANGE) {
+ String[] parts = attrVal.split(ATTRIBUTE_VALUE_DELIMITER);
+ if (parts.length == 2) {
+ rangeStart = parts[0];
+ rangeEnd = parts[1];
+ }
+ }
+ if (StringUtils.isNotEmpty(rangeStart) && StringUtils.isNotEmpty(rangeEnd)) {
+ attrValue = Long.parseLong(rangeStart);
+ attrValue2 = Long.parseLong(rangeEnd);
+ } else {
+ attrValue = StringUtils.isEmpty(attrVal) ? null : Long.parseLong(attrVal);
+ }
break;
case AtlasBaseTypeDef.ATLAS_TYPE_FLOAT:
attrClass = Float.class;
@@ -761,9 +909,14 @@ public abstract class SearchProcessor {
}
String vertexPropertyName = attribute.getVertexPropertyName();
- ret = predicate.generatePredicate(
- StringUtils.isEmpty(vertexPropertyName) ? attribute.getQualifiedName() : vertexPropertyName,
- attrValue, attrClass);
+ if (attrValue != null && attrValue2 != null) {
+ ret = predicate.generatePredicate(StringUtils.isEmpty(vertexPropertyName) ? attribute.getQualifiedName() : vertexPropertyName,
+ attrValue, attrValue2, attrClass);
+ } else {
+ ret = predicate.generatePredicate(
+ StringUtils.isEmpty(vertexPropertyName) ? attribute.getQualifiedName() : vertexPropertyName,
+ attrValue, attrClass);
+ }
}
return ret;
diff --git a/repository/src/main/java/org/apache/atlas/util/SearchPredicateUtil.java b/repository/src/main/java/org/apache/atlas/util/SearchPredicateUtil.java
index cf158cd..9c29756 100644
--- a/repository/src/main/java/org/apache/atlas/util/SearchPredicateUtil.java
+++ b/repository/src/main/java/org/apache/atlas/util/SearchPredicateUtil.java
@@ -179,6 +179,40 @@ public class SearchPredicateUtil {
return ret;
}
+ public static ElementAttributePredicateGenerator getInRangePredicateGenerator() {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> getInRangePredicateGenerator");
+ }
+
+ ElementAttributePredicateGenerator ret = new ElementAttributePredicateGenerator() {
+
+ @Override
+ public Predicate generatePredicate(String attrName, Object attrVal, Class attrClass) {
+ return generatePredicate(attrName, attrVal, attrVal, attrClass);
+ }
+
+ @Override
+ public Predicate generatePredicate(String attrName, Object attrVal, Object attrVal2, Class attrClass) {
+ final Predicate ret;
+
+ if (attrName == null || attrClass == null || attrVal == null || attrVal2 == null) {
+ ret = ALWAYS_FALSE;
+ } else if (Long.class.isAssignableFrom(attrClass)) {
+ ret = LongPredicate.getInRangePredicate(attrName, attrClass, (Long) attrVal, (Long) attrVal2);
+ } else {
+ ret = ALWAYS_FALSE;
+ }
+ return ret;
+ }
+ };
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== getInRangePredicateGenerator");
+ }
+
+ return ret;
+ }
+
public static ElementAttributePredicateGenerator getGTEPredicateGenerator() {
if (LOG.isDebugEnabled()) {
LOG.debug("==> getGTEPredicateGenerator");
@@ -768,6 +802,9 @@ public class SearchPredicateUtil {
public interface ElementAttributePredicateGenerator {
Predicate generatePredicate(String attrName, Object attrVal, Class attrClass);
+ default Predicate generatePredicate(String attrName, Object attrVal, Object attrVal2, Class attrClass) {
+ return generatePredicate(attrName, attrVal, attrClass);
+ }
}
static abstract class ElementAttributePredicate implements Predicate {
@@ -969,16 +1006,27 @@ public class SearchPredicateUtil {
static abstract class LongPredicate extends ElementAttributePredicate {
final Long value;
+ final Long value2;
LongPredicate(String attrName, Class attrClass, Long value) {
super(attrName, attrClass);
this.value = value;
+ this.value2 = null;
+
}
- LongPredicate(String attrName, Class attrClass, Long value, boolean isNullValid) {
+ LongPredicate(String attrName, Class attrClass, Long value, Long value2, boolean isNullValid) {
super(attrName, attrClass, isNullValid);
this.value = value;
+ this.value2 = value2;
+
+ }
+
+ LongPredicate(String attrName, Class attrClass, Long value, boolean isNullValid) {
+ super(attrName, attrClass, isNullValid);
+ this.value = value;
+ this.value2 = null;
}
static ElementAttributePredicate getEQPredicate(String attrName, Class attrClass, Long value) {
@@ -1028,6 +1076,14 @@ public class SearchPredicateUtil {
}
};
}
+
+ static ElementAttributePredicate getInRangePredicate(String attrName, Class attrClass, Long rangeStart, Long rangeEnd) {
+ return new LongPredicate(attrName, attrClass, rangeStart, rangeEnd, false) {
+ protected boolean compareValue(Object vertexAttrVal) {
+ return ((Long) vertexAttrVal).compareTo(value) >= 0 && ((Long) vertexAttrVal).compareTo(value2) <= 0;
+ }
+ };
+ }
}
static abstract class FloatPredicate extends ElementAttributePredicate {
diff --git a/repository/src/test/java/org/apache/atlas/discovery/EntitySearchProcessorTest.java b/repository/src/test/java/org/apache/atlas/discovery/EntitySearchProcessorTest.java
index 7b40c21..db107b3 100644
--- a/repository/src/test/java/org/apache/atlas/discovery/EntitySearchProcessorTest.java
+++ b/repository/src/test/java/org/apache/atlas/discovery/EntitySearchProcessorTest.java
@@ -35,16 +35,23 @@ import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import javax.inject.Inject;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@Guice(modules = TestModules.TestOnlyModule.class)
public class EntitySearchProcessorTest extends BasicTestSetup {
+ private static final Logger LOG = LoggerFactory.getLogger(EntitySearchProcessorTest.class);
+ private final SimpleDateFormat formattedDate = new SimpleDateFormat("dd-MMM-yyyy");
@Inject
private AtlasGraph graph;
@@ -360,4 +367,235 @@ public class EntitySearchProcessorTest extends BasicTestSetup {
AtlasGraphProvider.cleanup();
}
+ @Test
+ public void testLast7Days() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("LAST_7_DAYS",typeRegistry,graph);
+ ret.setAttributeName("createTime");
+ GregorianCalendar startDate = new GregorianCalendar();
+ GregorianCalendar endDate = new GregorianCalendar();
+ startDate.add(Calendar.DATE, -6);
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(startDate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(endDate.getTime()));
+ }
+
+ @Test
+ public void testLastMonth() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("LAST_MONTH", typeRegistry,graph);
+ Calendar originalstartdate = Calendar.getInstance();
+ Calendar originalenddate = Calendar.getInstance();
+
+ originalstartdate.add(Calendar.MONTH, -1);
+ originalstartdate.set(Calendar.DAY_OF_MONTH, originalstartdate.getActualMinimum(Calendar.DAY_OF_MONTH));
+ originalenddate.add(Calendar.MONTH, -1);
+ originalenddate.set(Calendar.DAY_OF_MONTH, originalenddate.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(originalstartdate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(originalenddate.getTime()));
+ }
+
+ @Test
+ public void testLast30Days() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("LAST_30_DAYS", typeRegistry,graph);
+ GregorianCalendar startDate = new GregorianCalendar();
+ GregorianCalendar endDate = new GregorianCalendar();
+ startDate.add(Calendar.DATE, -29);
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(startDate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(endDate.getTime()));
+ }
+
+ @Test
+ public void testYesterday() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("YESTERDAY", typeRegistry,graph);
+ GregorianCalendar yesterdayDate = new GregorianCalendar();
+ yesterdayDate.add(Calendar.DATE, -1);
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(yesterdayDate.getTime()));
+ }
+
+ @Test
+ public void testThisMonth() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("THIS_MONTH", typeRegistry,graph);
+ Calendar originalstartdate = Calendar.getInstance();
+ Calendar originalenddate = Calendar.getInstance();
+
+ originalstartdate.set(Calendar.DAY_OF_MONTH, originalstartdate.getActualMinimum(Calendar.DAY_OF_MONTH));
+ originalenddate.set(Calendar.DAY_OF_MONTH, originalenddate.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(originalstartdate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(originalenddate.getTime()));
+ }
+
+ @Test
+ public void testThisQuarter() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("THIS_QUARTER", typeRegistry,graph);
+ Calendar originalstartdate = Calendar.getInstance();
+ Calendar originalenddate = Calendar.getInstance();
+ originalstartdate.add(Calendar.MONTH, -1);
+ originalstartdate.set(Calendar.DAY_OF_MONTH, originalstartdate.getActualMinimum(Calendar.DAY_OF_MONTH));
+ originalenddate.add(Calendar.MONTH, 1);
+ originalenddate.set(Calendar.DAY_OF_MONTH, originalenddate.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(originalstartdate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(originalenddate.getTime()));
+ }
+
+ @Test
+ public void testLastQuarter() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("LAST_QUARTER", typeRegistry,graph);
+ Calendar originalstartdate = Calendar.getInstance();
+ Calendar originalenddate = Calendar.getInstance();
+ originalstartdate.add(Calendar.MONTH, -4);
+ originalstartdate.set(Calendar.DAY_OF_MONTH, originalstartdate.getActualMinimum(Calendar.DAY_OF_MONTH));
+ originalenddate.add(Calendar.MONTH, -2);
+ originalenddate.set(Calendar.DAY_OF_MONTH, originalenddate.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(originalstartdate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(originalenddate.getTime()));
+ }
+
+
+ @Test
+ public void testLast3Months() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("LAST_3_MONTHS", typeRegistry,graph);
+ Calendar originalstartdate = Calendar.getInstance();
+ Calendar originalenddate = Calendar.getInstance();
+
+ originalstartdate.add(Calendar.MONTH, -3);
+ originalstartdate.set(Calendar.DAY_OF_MONTH, originalstartdate.getActualMinimum(Calendar.DAY_OF_MONTH));
+ originalenddate.add(Calendar.MONTH, -1);
+ originalenddate.set(Calendar.DAY_OF_MONTH, originalenddate.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(originalstartdate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(originalenddate.getTime()));
+ }
+
+ @Test
+ public void testThisYear() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("THIS_YEAR",typeRegistry,graph);
+ Calendar originalstartdate = Calendar.getInstance();
+ Calendar originalenddate = Calendar.getInstance();
+
+ originalstartdate.set(Calendar.MONTH, 0);
+ originalstartdate.set(Calendar.DAY_OF_MONTH, originalstartdate.getActualMinimum(Calendar.DAY_OF_MONTH));
+
+ originalenddate.set(Calendar.MONTH, 11);
+ originalenddate.set(Calendar.DAY_OF_MONTH, originalenddate.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(originalstartdate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(originalenddate.getTime()));
+ }
+
+ @Test
+ public void testLastYear() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("LAST_YEAR",typeRegistry,graph);
+ Calendar originalstartdate = Calendar.getInstance();
+ Calendar originalenddate = Calendar.getInstance();
+
+ originalstartdate.add(Calendar.YEAR, -1);
+ originalstartdate.set(Calendar.MONTH, 0);
+ originalstartdate.set(Calendar.DAY_OF_MONTH, originalstartdate.getActualMinimum(Calendar.DAY_OF_MONTH));
+
+ originalenddate.add(Calendar.YEAR, -1);
+ originalenddate.set(Calendar.MONTH, 11);
+ originalenddate.set(Calendar.DAY_OF_MONTH, originalenddate.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(originalstartdate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(originalenddate.getTime()));
+ }
+
+ @Test
+ public void testLast12Months() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("LAST_12_MONTHS",typeRegistry,graph);
+ Calendar originalstartdate = Calendar.getInstance();
+ Calendar originalenddate = Calendar.getInstance();
+
+ originalstartdate.add(Calendar.MONTH, -12);
+ originalstartdate.set(Calendar.DAY_OF_MONTH, originalstartdate.getActualMinimum(Calendar.DAY_OF_MONTH));
+
+ originalenddate.add(Calendar.MONTH, -1);
+ originalenddate.set(Calendar.DAY_OF_MONTH, originalenddate.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(originalstartdate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(originalenddate.getTime()));
+ }
+
+ @Test
+ public void testLast6Months() throws AtlasBaseException {
+ SearchParameters.FilterCriteria ret = filtercriteriaDateRange("LAST_6_MONTHS",typeRegistry,graph);
+ Calendar originalstartdate = Calendar.getInstance();
+ Calendar originalenddate = Calendar.getInstance();
+
+ originalstartdate.add(Calendar.MONTH, -6);
+ originalstartdate.set(Calendar.DAY_OF_MONTH, originalstartdate.getActualMinimum(Calendar.DAY_OF_MONTH));
+
+ originalenddate.add(Calendar.MONTH, -1);
+ originalenddate.set(Calendar.DAY_OF_MONTH, originalenddate.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+ String[] dates = ret.getAttributeValue().split(",");
+ String attrValue1 = dates[0];
+ String attrValue2 = dates[1];
+
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue1)))), formattedDate.format(originalstartdate.getTime()));
+ assertEquals(formattedDate.format(new Date((Long.parseLong(attrValue2)))), formattedDate.format(originalenddate.getTime()));
+ }
+
+ private static SearchParameters.FilterCriteria filtercriteriaDateRange(String attributeValue, AtlasTypeRegistry typeRegistry, AtlasGraph graph) throws AtlasBaseException {
+ SearchParameters params = new SearchParameters();
+ params.setTypeName(HIVE_TABLE_TYPE);
+ SearchParameters.FilterCriteria filterCriteria = new SearchParameters.FilterCriteria();
+ params.setEntityFilters(filterCriteria);
+ params.setLimit(20);
+ SearchContext context = new SearchContext(params, typeRegistry, graph, Collections.<String>emptySet());
+ EntitySearchProcessor processor = new EntitySearchProcessor(context);
+ filterCriteria.setCondition(SearchParameters.FilterCriteria.Condition.AND);
+ filterCriteria.setOperator(SearchParameters.Operator.TIME_RANGE);
+ filterCriteria.setAttributeValue(attributeValue);
+ SearchParameters.FilterCriteria ret = processor.processDateRange(filterCriteria);
+ return ret;
+ }
}
[atlas] 02/02: ATLAS-3900: UI: Allow user to select the date range
for date attribute in basic search
Posted by kb...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
kbhatt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git
commit 41eebcf4cf435d37c5e67aea916513eac36e3ee5
Author: kevalbhatt <kb...@apache.org>
AuthorDate: Fri Aug 7 18:16:33 2020 +0530
ATLAS-3900: UI: Allow user to select the date range for date attribute in basic search
---
dashboardv2/package-lock.json | 6 +-
dashboardv2/package.json | 2 +-
dashboardv2/public/css/scss/override.scss | 24 ++-
dashboardv2/public/js/utils/CommonViewFunction.js | 89 ++++----
dashboardv2/public/js/utils/Enums.js | 37 +++-
.../public/js/views/search/QueryBuilderView.js | 236 +++++++++++++++------
dashboardv3/package-lock.json | 6 +-
dashboardv3/package.json | 2 +-
dashboardv3/public/css/scss/override.scss | 22 +-
dashboardv3/public/js/main.js | 1 -
.../search/SearchDefaultLayoutView_tmpl.html | 6 +-
dashboardv3/public/js/utils/CommonViewFunction.js | 88 ++++----
dashboardv3/public/js/utils/Enums.js | 37 +++-
.../public/js/views/search/QueryBuilderView.js | 236 +++++++++++++++------
.../js/views/search/tree/EntityTreeLayoutView.js | 3 +-
15 files changed, 536 insertions(+), 259 deletions(-)
diff --git a/dashboardv2/package-lock.json b/dashboardv2/package-lock.json
index afc9fb3..b0afc0b 100644
--- a/dashboardv2/package-lock.json
+++ b/dashboardv2/package-lock.json
@@ -357,9 +357,9 @@
"integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E="
},
"bootstrap-daterangepicker": {
- "version": "2.1.25",
- "resolved": "https://registry.npmjs.org/bootstrap-daterangepicker/-/bootstrap-daterangepicker-2.1.25.tgz",
- "integrity": "sha1-/Ni6C3VaBU0zDXo7fE3Yu4Vc/7c=",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bootstrap-daterangepicker/-/bootstrap-daterangepicker-3.1.0.tgz",
+ "integrity": "sha512-oaQZx6ZBDo/dZNyXGVi2rx5GmFXThyQLAxdtIqjtLlYVaQUfQALl5JZMJJZzyDIX7blfy4ppZPAJ10g8Ma4d/g==",
"requires": {
"jquery": ">=1.10",
"moment": "^2.9.0"
diff --git a/dashboardv2/package.json b/dashboardv2/package.json
index e0809d3..1c17c67 100644
--- a/dashboardv2/package.json
+++ b/dashboardv2/package.json
@@ -29,7 +29,7 @@
"backgrid-select-all": "0.3.5",
"backgrid-sizeable-columns": "0.1.1",
"bootstrap": "3.3.7",
- "bootstrap-daterangepicker": "2.1.25",
+ "bootstrap-daterangepicker": "3.1.0",
"d3": "3.5.17",
"d3-tip": "0.6.8",
"dagre-d3": "0.6.4",
diff --git a/dashboardv2/public/css/scss/override.scss b/dashboardv2/public/css/scss/override.scss
index 2bcfde9..de5462c 100644
--- a/dashboardv2/public/css/scss/override.scss
+++ b/dashboardv2/public/css/scss/override.scss
@@ -300,7 +300,7 @@
}
.rule-operator-container {
- width: 105px;
+ width: 150px;
.form-control {
width: 100% !important;
@@ -507,4 +507,26 @@ div.columnmanager-dropdown-container {
overflow: hidden;
text-overflow: ellipsis;
}
+}
+
+.daterangepicker {
+ max-height: 400px;
+ overflow-y: scroll;
+
+ .ranges {
+ max-height: 328px;
+ overflow: auto;
+ }
+
+ .ranges li.active,
+ td.active {
+ background-color: $color_havelock_blue_approx;
+ }
+
+ .drp-buttons {
+ .applyBtn {
+ background-color: $color_havelock_blue_approx;
+ border-color: $color_havelock_blue_approx;
+ }
+ }
}
\ No newline at end of file
diff --git a/dashboardv2/public/js/utils/CommonViewFunction.js b/dashboardv2/public/js/utils/CommonViewFunction.js
index a1c5ad3..4d10fa6 100644
--- a/dashboardv2/public/js/utils/CommonViewFunction.js
+++ b/dashboardv2/public/js/utils/CommonViewFunction.js
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enums', 'moment', 'utils/Globals'], function(require, Utils, Modal, Messages, Enums, moment, Globals) {
+define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enums', 'moment', 'utils/Globals', 'moment-timezone'], function(require, Utils, Modal, Messages, Enums, moment, Globals) {
'use strict';
var CommonViewFunction = {};
@@ -387,9 +387,13 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
function objToString(filterObj) {
var generatedQuery = _.map(filterObj.rules, function(obj, key) {
+ var obj = $.extend(true, {}, obj); // not to update the timezone abbr on original obj , copy of obj is used
if (_.has(obj, 'condition')) {
return ' <span class="operator">' + obj.condition + '</span> ' + '(' + objToString(obj) + ')';
} else {
+ if (obj.type === "date") {
+ obj.value = obj.value + " (" + moment.tz(moment.tz.guess()).zoneAbbr() + ")";
+ }
return '<span class="key">' + (Enums.systemAttributes[obj.id] ? Enums.systemAttributes[obj.id] : _.escape(obj.id)) + '</span> <span class="operator">' + _.escape(obj.operator) + '</span> <span class="value">' + (Enums[obj.id] ? Enums[obj.id][obj.value] : _.escape(obj.value)) + "</span>";
}
});
@@ -487,6 +491,9 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
if (Globals[value[skey].typeName]) {
attributeDefs = Globals[value[skey].typeName].attributeDefs;
}
+ if (Globals._ALL_CLASSIFICATION_TYPES && Globals._ALL_CLASSIFICATION_TYPES.attributeDefs) {
+ attributeDefs = attributeDefs.concat(Globals._ALL_CLASSIFICATION_TYPES.attributeDefs);
+ }
}
val = CommonViewFunction.attributeFilter.generateUrl({ "value": val, "attributeDefs": attributeDefs });
} else if (k == "entityFilters") {
@@ -503,6 +510,9 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
if (Globals[value[skey].typeName]) {
attributeDefs = Globals[value[skey].typeName].attributeDefs;
}
+ if (Globals._ALL_ENTITY_TYPES && Globals._ALL_ENTITY_TYPES.attributeDefs) {
+ attributeDefs = attributeDefs.concat(Globals._ALL_ENTITY_TYPES.attributeDefs);
+ }
}
val = CommonViewFunction.attributeFilter.generateUrl({ "value": val, "attributeDefs": attributeDefs });
} else if (_.contains(["includeDE", "excludeST", "excludeSC"], k)) {
@@ -544,7 +554,18 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
var type = (obj.type || obj.attributeType),
//obj.value will come as an object when selected type is Date and operator is isNull or not_null;
value = ((_.isString(obj.value) && _.contains(["is_null", "not_null"], obj.operator) && type === 'date') || _.isObject(obj.value) ? "" : _.trim(obj.value || obj.attributeValue)),
- url = [(obj.id || obj.attributeName), mapApiOperatorToUI(obj.operator), (type === 'date' && formatedDateToLong && value.length ? Date.parse(value) : value)];
+ url = [(obj.id || obj.attributeName), mapApiOperatorToUI(obj.operator), value];
+ if (obj.operator === "TIME_RANGE") {
+ if (value.indexOf("-") > -1) {
+ url[2] = value.split('-').map(function(udKey) {
+ return Date.parse(udKey.trim()).toString()
+ }).join(",")
+ } else {
+ url[2] = Enums.queryBuilderDateRangeUIValueToAPI[_.trim(value)] || value;
+ }
+ } else if (value.length && type === 'date' && formatedDateToLong) {
+ url[2] = Date.parse(value);
+ }
if (type) {
url.push(type);
}
@@ -561,30 +582,8 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
}
function mapApiOperatorToUI(oper) {
- if (oper == "eq") {
- return "=";
- } else if (oper == "neq") {
- return "!=";
- } else if (oper == "lt") {
- return "<";
- } else if (oper == "lte") {
- return "<=";
- } else if (oper == "gt") {
- return ">";
- } else if (oper == "gte") {
- return ">=";
- } else if (oper == "startsWith") {
- return "begins_with";
- } else if (oper == "endsWith") {
- return "ends_with";
- } else if (oper == "contains") {
- return "contains";
- } else if (oper == "notNull") {
- return "not_null";
- } else if (oper == "isNull") {
- return "is_null";
- }
- return oper;
+ // Enum will be in effect once we click on save search.
+ return Enums.queryBuilderApiOperatorToUI[oper] || oper;
}
},
extractUrl: function(options) {
@@ -594,30 +593,7 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
spliter = 1,
apiObj = options.apiObj,
mapUiOperatorToAPI = function(oper) {
- if (oper == "=") {
- return "eq";
- } else if (oper == "!=") {
- return "neq";
- } else if (oper == "<") {
- return "lt";
- } else if (oper == "<=") {
- return "lte";
- } else if (oper == ">") {
- return "gt";
- } else if (oper == ">=") {
- return "gte";
- } else if (oper == "begins_with") {
- return "startsWith";
- } else if (oper == "ends_with") {
- return "endsWith";
- } else if (oper == "contains") {
- return "contains";
- } else if (oper == "not_null") {
- return "notNull";
- } else if (oper == "is_null") {
- return "isNull";
- }
- return oper;
+ return Enums.queryBuilderUIOperatorToAPI[oper] || oper;
},
createObject = function(urlObj) {
var finalObj = {};
@@ -636,13 +612,24 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
rule = {};
if (apiObj) {
rule = { attributeName: temp[0], operator: mapUiOperatorToAPI(temp[1]), attributeValue: _.trim(temp[2]) }
+
rule.attributeValue = rule.type === 'date' && formatDate && rule.attributeValue.length ? moment(parseInt(rule.attributeValue)).format(Globals.dateTimeFormat) : rule.attributeValue;
} else {
rule = { id: temp[0], operator: temp[1], value: _.trim(temp[2]) }
if (temp[3]) {
rule['type'] = temp[3];
}
- rule.value = rule.type === 'date' && formatDate && rule.value.length ? moment(parseInt(rule.value)).format(Globals.dateTimeFormat) : rule.value;
+ if (rule.operator === "TIME_RANGE") {
+ if (temp[2].indexOf(",") > -1) {
+ rule.value = temp[2].split(",").map(function(udKey) {
+ return moment(parseInt(udKey.trim())).format(Globals.dateTimeFormat)
+ }).join(" - ")
+ } else {
+ rule.value = Enums.queryBuilderDateRangeAPIValueToUI[_.trim(rule.value)] || rule.value;
+ }
+ } else if (rule.type === 'date' && formatDate && rule.value.length) {
+ rule.value = moment(parseInt(rule.value)).format(Globals.dateTimeFormat)
+ }
}
return rule;
}
diff --git a/dashboardv2/public/js/utils/Enums.js b/dashboardv2/public/js/utils/Enums.js
index 24ec36b..131a08f 100644
--- a/dashboardv2/public/js/utils/Enums.js
+++ b/dashboardv2/public/js/utils/Enums.js
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-define(['require'], function(require) {
+define(["require", "backbone"], function(require) {
'use strict';
var Enums = {};
@@ -219,5 +219,40 @@ define(['require'], function(require) {
0: "false",
1: "true"
};
+
+ Enums.queryBuilderUIOperatorToAPI = {
+ "=": "eq",
+ "!=": "neq",
+ "<": "lt",
+ "<=": "lte",
+ ">": "gt",
+ ">=": "gte",
+ "begins_with": "startsWith",
+ "ends_with": "endsWith",
+ "not_null": "notNull",
+ "is_null": "isNull",
+ "TIME_RANGE": "timerange"
+ };
+
+ Enums.queryBuilderApiOperatorToUI = _.invert(Enums.queryBuilderUIOperatorToAPI);
+
+ Enums.queryBuilderDateRangeUIValueToAPI = {
+ "Today": "TODAY",
+ "Yesterday": "YESTERDAY",
+ "Last 7 Days": "LAST_7_DAYS",
+ "Last 30 Days": "LAST_30_DAYS",
+ "This Month": "THIS_MONTH",
+ "Last Month": "LAST_MONTH",
+ "This Quarter": "THIS_QUARTER",
+ "Last Quarter":"LAST_QUARTER",
+ "This Year": "THIS_YEAR",
+ "Last Year": "LAST_YEAR",
+ "Last 3 Months": "LAST_3_MONTHS",
+ "Last 6 Months": "LAST_6_MONTHS",
+ "Last 12 Months": "LAST_12_MONTHS"
+ };
+
+ Enums.queryBuilderDateRangeAPIValueToUI = _.invert(Enums.queryBuilderDateRangeUIValueToAPI);
+
return Enums;
});
\ No newline at end of file
diff --git a/dashboardv2/public/js/views/search/QueryBuilderView.js b/dashboardv2/public/js/views/search/QueryBuilderView.js
index dc36ffe..ba6cf0d 100644
--- a/dashboardv2/public/js/views/search/QueryBuilderView.js
+++ b/dashboardv2/public/js/views/search/QueryBuilderView.js
@@ -24,9 +24,10 @@ define(['require',
'utils/CommonViewFunction',
'utils/Enums',
'utils/Globals',
+ 'moment',
'query-builder',
'daterangepicker'
-], function(require, Backbone, QueryBuilderTmpl, UserDefineTmpl, Utils, CommonViewFunction, Enums, Globals) {
+], function(require, Backbone, QueryBuilderTmpl, UserDefineTmpl, Utils, CommonViewFunction, Enums, Globals, moment) {
var QueryBuilderView = Backbone.Marionette.LayoutView.extend(
/** @lends QueryBuilderView */
@@ -58,6 +59,22 @@ define(['require',
_.extend(this, _.pick(options, 'attrObj', 'value', 'typeHeaders', 'entityDefCollection', 'enumDefCollection', 'classificationDefCollection', 'businessMetadataDefCollection', 'tag', 'type', 'searchTableFilters', 'systemAttrArr', 'adminAttrFilters'));
this.attrObj = _.sortBy(this.attrObj, 'name');
this.filterType = this.tag ? 'tagFilters' : 'entityFilters';
+ this.defaultRange = "Last 7 Days";
+ this.dateRangesMap = {
+ 'Today': [moment(), moment()],
+ 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
+ 'Last 7 Days': [moment().subtract(6, 'days'), moment()],
+ 'Last 30 Days': [moment().subtract(29, 'days'), moment()],
+ 'This Month': [moment().startOf('month'), moment().endOf('month')],
+ 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
+ 'Last 3 Months': [moment().subtract(3, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
+ 'Last 6 Months': [moment().subtract(6, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
+ 'Last 12 Months': [moment().subtract(12, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
+ 'This Quarter': [moment().startOf('quarter'), moment().endOf('quarter')],
+ 'Last Quarter': [moment().subtract(1, 'quarter').startOf('quarter'), moment().subtract(1, 'quarter').endOf('quarter')],
+ 'This Year': [moment().startOf('year'), moment().endOf('year')],
+ 'Last Year': [moment().subtract(1, 'year').startOf('year'), moment().subtract(1, 'year').endOf('year')]
+ }
},
bindEvents: function() {},
getOperator: function(type, skipDefault) {
@@ -71,7 +88,7 @@ define(['require',
}
}
if (type === "date") {
- obj.operators = ['>', '<'];
+ obj.operators = ['=', '!=', '>', '<', '>=', '<=', 'TIME_RANGE'];
}
if (type === "int" || type === "byte" || type === "short" || type === "long" || type === "float" || type === "double") {
obj.operators = ['=', '!=', '>', '<', '>=', '<='];
@@ -266,20 +283,7 @@ define(['require',
}
if (obj.type === "date") {
obj['plugin'] = 'daterangepicker';
- obj['plugin_config'] = {
- "singleDatePicker": true,
- "showDropdowns": true,
- "timePicker": true,
- locale: {
- format: Globals.dateTimeFormat
- }
- };
- if (rules) {
- var valueObj = _.find(rules, { id: obj.id });
- if (valueObj) {
- obj.plugin_config["startDate"] = valueObj.value;
- }
- }
+ obj['plugin_config'] = this.getDateConfig(rules, obj.id);
_.extend(obj, this.getOperator(obj.type));
return obj;
}
@@ -316,6 +320,86 @@ define(['require',
return obj;
}
},
+ getDateConfig: function(ruleObj, id, operator) {
+ var valueObj = ruleObj ? (_.find(ruleObj.rules, { id: id }) || {}) : {},
+ isTimeRange = (valueObj.operator && valueObj.operator === "TIME_RANGE" && operator === "TIME_RANGE") || (operator === "TIME_RANGE"),
+ obj = {
+ opens: "center",
+ autoApply: true,
+ autoUpdateInput: false,
+ timePickerSeconds: true,
+ timePicker: true,
+ locale: {
+ format: Globals.dateTimeFormat
+ }
+ };
+
+ if (isTimeRange) {
+ var defaultRangeDate = this.dateRangesMap[this.defaultRange];
+ obj.startDate = defaultRangeDate[0];
+ obj.endDate = defaultRangeDate[1];
+ obj.singleDatePicker = false;
+ obj.ranges = this.dateRangesMap;
+ } else {
+ obj.singleDatePicker = true;
+ obj.startDate = moment();
+ obj.endDate = obj.startDate;
+ }
+
+ if (!_.isEmpty(valueObj) && operator === valueObj.operator) {
+ if (isTimeRange) {
+ if (valueObj.value.indexOf("-") > -1) {
+ var dates = valueObj.value.split("-");
+ obj.startDate = dates[0].trim();
+ obj.endDate = dates[1].trim();
+ } else {
+ var dates = this.dateRangesMap[valueObj.value]
+ obj.startDate = dates[0];
+ obj.endDate = dates[1];
+ }
+ obj.singleDatePicker = false;
+ } else {
+ obj.startDate = moment(valueObj.value);
+ obj.endDate = moment(valueObj.value);
+ obj.singleDatePicker = true;
+ }
+ }
+
+ return obj;
+ },
+ setDateValue: function(rule, rules_widgets) {
+ if (rule.filter.type === "date" && rule.operator.nb_inputs) {
+ var inputEl = rule.$el.find(".rule-value-container").find("input"),
+ datepickerEl = rule.$el.find(".rule-value-container").find("input").data("daterangepicker")
+ inputEl.attr('readonly', true);
+ if (datepickerEl) {
+ datepickerEl.remove();
+ var configObj = this.getDateConfig(rules_widgets, rule.filter.id, rule.operator.type)
+ inputEl.daterangepicker(configObj);
+ if (rule.operator.type === "TIME_RANGE") {
+ rule.value = this.defaultRange;
+ } else {
+ rule.value = configObj.startDate.format(Globals.dateTimeFormat);
+ }
+ inputEl.on('apply.daterangepicker', function(ev, picker) {
+ picker.setStartDate(picker.startDate);
+ picker.setEndDate(picker.endDate);
+ var valueString = "";
+ if (picker.chosenLabel) {
+ if (picker.chosenLabel === "Custom Range") {
+ valueString = picker.startDate.format(Globals.dateTimeFormat) + " - " + picker.endDate.format(Globals.dateTimeFormat);
+ } else {
+ valueString = picker.chosenLabel;
+ }
+ } else {
+ valueString = picker.startDate.format(Globals.dateTimeFormat);
+ }
+ picker.element.val(valueString);
+ rule.value = valueString;
+ });
+ }
+ }
+ },
onRender: function() {
var that = this,
filters = [],
@@ -339,7 +423,7 @@ define(['require',
rules_widgets = CommonViewFunction.attributeFilter.extractUrl({ "value": this.searchTableFilters ? this.searchTableFilters["adminAttrFilters"] : null, "formatDate": true });;
} else {
if (this.value) {
- var rules_widgets = CommonViewFunction.attributeFilter.extractUrl({ "value": this.searchTableFilters[this.filterType][(this.tag ? this.value.tag : this.value.type)], "formatDate": true });
+ rules_widgets = CommonViewFunction.attributeFilter.extractUrl({ "value": this.searchTableFilters[this.filterType][(this.tag ? this.value.tag : this.value.type)], "formatDate": true });
}
_.each(this.attrObj, function(obj) {
var type = that.tag ? that.value.tag : that.value.type;
@@ -415,16 +499,20 @@ define(['require',
}
filters = _.uniq(filters, 'id');
if (filters && !_.isEmpty(filters)) {
- this.ui.builder.queryBuilder({
- plugins: ['bt-tooltip-errors'],
- filters: filters,
- select_placeholder: placeHolder,
- allow_empty: true,
- conditions: ['AND', 'OR'],
- allow_groups: true,
- allow_empty: true,
- templates: {
- rule: '<div id="{{= it.rule_id }}" class="rule-container"> \
+ this.ui.builder.off()
+ .on("afterUpdateRuleOperator.queryBuilder", function(e, rule) {
+ that.setDateValue(rule, rules_widgets);
+ })
+ .queryBuilder({
+ plugins: ['bt-tooltip-errors'],
+ filters: filters,
+ select_placeholder: placeHolder,
+ allow_empty: true,
+ conditions: ['AND', 'OR'],
+ allow_groups: true,
+ allow_empty: true,
+ templates: {
+ rule: '<div id="{{= it.rule_id }}" class="rule-container"> \
<div class="values-box"><div class="rule-filter-container"></div> \
<div class="rule-operator-container"></div> \
<div class="rule-value-container"></div></div> \
@@ -439,50 +527,58 @@ define(['require',
<div class="error-container"><i class="{{= it.icons.error }}"></i> <span></span></div> \
{{?}} \
</div>'
- },
- operators: [
- { type: '=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
- { type: '!=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
- { type: '>', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
- { type: '<', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
- { type: '>=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
- { type: '<=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
- { type: 'contains', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'like', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'in', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'begins_with', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'ends_with', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'is_null', nb_inputs: false, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
- { type: 'not_null', nb_inputs: false, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] }
- ],
- lang: {
- add_rule: 'Add filter',
- add_group: 'Add filter group',
- operators: {
- not_null: 'is not null'
+ },
+ operators: [
+ { type: '=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
+ { type: '!=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
+ { type: '>', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
+ { type: '<', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
+ { type: '>=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
+ { type: '<=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
+ { type: 'contains', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'like', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'in', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'begins_with', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'ends_with', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'is_null', nb_inputs: false, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
+ { type: 'not_null', nb_inputs: false, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
+ { type: 'TIME_RANGE', nb_inputs: 1, multiple: false, apply_to: ['date'] }
+ ],
+ lang: {
+ add_rule: 'Add filter',
+ add_group: 'Add filter group',
+ operators: {
+ not_null: 'is not null',
+ TIME_RANGE: "Time Range"
+ }
+ },
+ icons: {
+ add_rule: 'fa fa-plus',
+ remove_rule: 'fa fa-times',
+ error: 'fa fa-exclamation-triangle'
+ },
+ rules: rules_widgets
+ })
+ .on("afterCreateRuleInput.queryBuilder", function(e, rule) {
+ rule.error = null;
+ if (rule.operator.nb_inputs && rule.filter.id === "__customAttributes") {
+ rule.$el.addClass("user-define");
+ } else if (rule.$el.hasClass("user-define")) {
+ rule.$el.removeClass("user-define");
}
- },
- icons: {
- add_rule: 'fa fa-plus',
- remove_rule: 'fa fa-times',
- error: 'fa fa-exclamation-triangle'
- },
- rules: rules_widgets
- }).on("afterCreateRuleInput.queryBuilder", function(e, rule) {
- rule.error = null;
- if (rule.operator.nb_inputs && rule.filter.id === "__customAttributes") {
- rule.$el.addClass("user-define");
- } else if (rule.$el.hasClass("user-define")) {
- rule.$el.removeClass("user-define");
- }
- }).on('validationError.queryBuilder', function(e, rule, error, value) {
- // never display error for my custom filter
- var errorMsg = error[0];
- if (that.queryBuilderLang && that.queryBuilderLang.errors && that.queryBuilderLang.errors[errorMsg]) {
- errorMsg = that.queryBuilderLang.errors[errorMsg];
- }
- rule.$el.find(".error-container span").html(errorMsg);
- });
+ if (rule.filter.type === "date") {
+ rule.$el.find('.rule-value-container >input').attr('readonly', true)
+ }
+ that.setDateValue(rule, rules_widgets);
+ })
+ .on('validationError.queryBuilder', function(e, rule, error, value) {
+ // never display error for my custom filter
+ var errorMsg = error[0];
+ if (that.queryBuilderLang && that.queryBuilderLang.errors && that.queryBuilderLang.errors[errorMsg]) {
+ errorMsg = that.queryBuilderLang.errors[errorMsg];
+ }
+ rule.$el.find(".error-container span").html(errorMsg);
+ });
var queryBuilderEl = that.ui.builder.data("queryBuilder");
if (queryBuilderEl && queryBuilderEl.lang) {
this.queryBuilderLang = queryBuilderEl.lang;
diff --git a/dashboardv3/package-lock.json b/dashboardv3/package-lock.json
index a9c0764..9721967 100644
--- a/dashboardv3/package-lock.json
+++ b/dashboardv3/package-lock.json
@@ -357,9 +357,9 @@
"integrity": "sha1-WjiTlFSfIzMIdaOxUGVldPip63E="
},
"bootstrap-daterangepicker": {
- "version": "2.1.25",
- "resolved": "https://registry.npmjs.org/bootstrap-daterangepicker/-/bootstrap-daterangepicker-2.1.25.tgz",
- "integrity": "sha1-/Ni6C3VaBU0zDXo7fE3Yu4Vc/7c=",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bootstrap-daterangepicker/-/bootstrap-daterangepicker-3.1.0.tgz",
+ "integrity": "sha512-oaQZx6ZBDo/dZNyXGVi2rx5GmFXThyQLAxdtIqjtLlYVaQUfQALl5JZMJJZzyDIX7blfy4ppZPAJ10g8Ma4d/g==",
"requires": {
"jquery": ">=1.10",
"moment": "^2.9.0"
diff --git a/dashboardv3/package.json b/dashboardv3/package.json
index cab875d..43ae1bb 100644
--- a/dashboardv3/package.json
+++ b/dashboardv3/package.json
@@ -29,7 +29,7 @@
"backgrid-select-all": "0.3.5",
"backgrid-sizeable-columns": "0.1.1",
"bootstrap": "3.3.7",
- "bootstrap-daterangepicker": "2.1.25",
+ "bootstrap-daterangepicker": "3.1.0",
"d3": "3.5.17",
"d3-tip": "0.6.8",
"dagre-d3": "0.6.4",
diff --git a/dashboardv3/public/css/scss/override.scss b/dashboardv3/public/css/scss/override.scss
index 7499894..1c8fcfc 100644
--- a/dashboardv3/public/css/scss/override.scss
+++ b/dashboardv3/public/css/scss/override.scss
@@ -304,7 +304,7 @@
}
.rule-operator-container {
- width: 105px;
+ width: 150px;
.form-control {
width: 100% !important;
@@ -511,4 +511,24 @@ div.columnmanager-dropdown-container {
overflow: hidden;
text-overflow: ellipsis;
}
+}
+
+.daterangepicker {
+
+ .ranges {
+ max-height: 328px;
+ overflow: auto;
+ }
+
+ .ranges li.active,
+ td.active {
+ background-color: $color_havelock_blue_approx;
+ }
+
+ .drp-buttons {
+ .applyBtn {
+ background-color: $color_havelock_blue_approx;
+ border-color: $color_havelock_blue_approx;
+ }
+ }
}
\ No newline at end of file
diff --git a/dashboardv3/public/js/main.js b/dashboardv3/public/js/main.js
index d5c6787..9f9747f 100644
--- a/dashboardv3/public/js/main.js
+++ b/dashboardv3/public/js/main.js
@@ -348,7 +348,6 @@ require(['App',
startApp();
}
});
-
this.businessMetadataDefCollection.fetch({
complete: function() {
that.businessMetadataDefCollection.fullCollection.comparator = function(model) {
diff --git a/dashboardv3/public/js/templates/search/SearchDefaultLayoutView_tmpl.html b/dashboardv3/public/js/templates/search/SearchDefaultLayoutView_tmpl.html
index 23ad9a8..1ce1218 100644
--- a/dashboardv3/public/js/templates/search/SearchDefaultLayoutView_tmpl.html
+++ b/dashboardv3/public/js/templates/search/SearchDefaultLayoutView_tmpl.html
@@ -30,7 +30,7 @@
<button class="btn-action btn-sm attribute-filter-text" data-id='attrFilter'> <i class="fa fa-angle-right"></i> Filters</button>
<button class='btn-action btn-sm' data-id='clearQuerySearch'>Clear</button>
<div class="attribute-filter-container hide">
- <div class="panel panel-default expand_collapse_panel-icon" data-id="includeExclude">
+ <div class="panel panel-default expand_collapse_panel-icon" data-id="includeExclude" style="margin-bottom: 0px;">
<div class="panel-heading" data-toggle="collapse" href="#collapseIncludeExclude" aria-expanded="true">
<h4 class="panel-title">
<a>Include/Exclude</a>
@@ -40,8 +40,8 @@
</div>
</div>
<div id="collapseIncludeExclude" class="panel-collapse collapse in">
- <div class="panel-body">
- <div class="form-group filter-box">
+ <div class="panel-body" style="padding: 4px 15px;">
+ <div class="form-group filter-box" style="margin: 0;">
<div class="entity-detail-table-toggle">
<div class="pretty p-switch p-fill">
<input type="checkbox" data-id="checkDeletedEntity" data-value="includeDE" id="historicalentities" />
diff --git a/dashboardv3/public/js/utils/CommonViewFunction.js b/dashboardv3/public/js/utils/CommonViewFunction.js
index dd3818b..670e509 100644
--- a/dashboardv3/public/js/utils/CommonViewFunction.js
+++ b/dashboardv3/public/js/utils/CommonViewFunction.js
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enums', 'moment', 'utils/Globals'], function(require, Utils, Modal, Messages, Enums, moment, Globals) {
+define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enums', 'moment', 'utils/Globals', 'moment-timezone'], function(require, Utils, Modal, Messages, Enums, moment, Globals) {
'use strict';
var CommonViewFunction = {};
@@ -387,10 +387,14 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
function objToString(filterObj, type) {
var generatedQuery = _.map(filterObj.rules, function(obj, key) {
+ var obj = $.extend(true, {}, obj); // not to update the timezone abbr on original obj , copy of obj is used
if (_.has(obj, 'condition')) {
return '<span class="operator">' + obj.condition + '</span>' + '(' + objToString(obj).join("") + ')';
} else {
if (isCapsuleView) {
+ if (obj.type === "date") {
+ obj.value = obj.value + " (" + moment.tz(moment.tz.guess()).zoneAbbr() + ")";
+ }
return '<div class="capsuleView"><span class="key">' + (Enums.systemAttributes[obj.id] ? Enums.systemAttributes[obj.id] : _.escape(obj.id)) + '</span><span class="operator">' + _.escape(obj.operator) + '</span><span class="value">' + (Enums[obj.id] ? Enums[obj.id][obj.value] : _.escape(obj.value)) + "</span><div class='fa fa-close clear-attr' data-type=" + type + " data-id=" + _.escape(obj.id) + "></div></div>";
}
return '<span class="key">' + (Enums.systemAttributes[obj.id] ? Enums.systemAttributes[obj.id] : _.escape(obj.id)) + '</span><span class="operator">' + _.escape(obj.operator) + '</span><span class="value">' + (Enums[obj.id] ? Enums[obj.id][obj.value] : _.escape(obj.value)) + "</span>";
@@ -507,6 +511,9 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
if (Globals[value[skey].typeName]) {
attributeDefs = Globals[value[skey].typeName].attributeDefs;
}
+ if (Globals._ALL_CLASSIFICATION_TYPES && Globals._ALL_CLASSIFICATION_TYPES.attributeDefs) {
+ attributeDefs = attributeDefs.concat(Globals._ALL_CLASSIFICATION_TYPES.attributeDefs);
+ }
}
val = CommonViewFunction.attributeFilter.generateUrl({ "value": val, "attributeDefs": attributeDefs });
} else if (k == "entityFilters") {
@@ -523,6 +530,9 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
if (Globals[value[skey].typeName]) {
attributeDefs = Globals[value[skey].typeName].attributeDefs;
}
+ if (Globals._ALL_ENTITY_TYPES && Globals._ALL_ENTITY_TYPES.attributeDefs) {
+ attributeDefs = attributeDefs.concat(Globals._ALL_ENTITY_TYPES.attributeDefs);
+ }
}
val = CommonViewFunction.attributeFilter.generateUrl({ "value": val, "attributeDefs": attributeDefs });
} else if (_.contains(["includeDE", "excludeST", "excludeSC"], k)) {
@@ -564,7 +574,18 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
var type = (obj.type || obj.attributeType),
//obj.value will come as an object when selected type is Date and operator is isNull or not_null;
value = ((_.isString(obj.value) && _.contains(["is_null", "not_null"], obj.operator) && type === 'date') || _.isObject(obj.value) ? "" : _.trim(obj.value || obj.attributeValue)),
- url = [(obj.id || obj.attributeName), mapApiOperatorToUI(obj.operator), (type === 'date' && formatedDateToLong && value.length ? Date.parse(value) : value)];
+ url = [(obj.id || obj.attributeName), mapApiOperatorToUI(obj.operator), value];
+ if (obj.operator === "TIME_RANGE") {
+ if (value.indexOf("-") > -1) {
+ url[2] = value.split('-').map(function(udKey) {
+ return Date.parse(udKey.trim()).toString()
+ }).join(",")
+ } else {
+ url[2] = Enums.queryBuilderDateRangeUIValueToAPI[_.trim(value)] || value;
+ }
+ } else if (value.length && type === 'date' && formatedDateToLong) {
+ url[2] = Date.parse(value);
+ }
if (type) {
url.push(type);
}
@@ -581,30 +602,8 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
}
function mapApiOperatorToUI(oper) {
- if (oper == "eq") {
- return "=";
- } else if (oper == "neq") {
- return "!=";
- } else if (oper == "lt") {
- return "<";
- } else if (oper == "lte") {
- return "<=";
- } else if (oper == "gt") {
- return ">";
- } else if (oper == "gte") {
- return ">=";
- } else if (oper == "startsWith") {
- return "begins_with";
- } else if (oper == "endsWith") {
- return "ends_with";
- } else if (oper == "contains") {
- return "contains";
- } else if (oper == "notNull") {
- return "not_null";
- } else if (oper == "isNull") {
- return "is_null";
- }
- return oper;
+ // Enum will be in effect once we click on save search.
+ return Enums.queryBuilderApiOperatorToUI[oper] || oper;
}
},
extractUrl: function(options) {
@@ -614,30 +613,7 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
spliter = 1,
apiObj = options.apiObj,
mapUiOperatorToAPI = function(oper) {
- if (oper == "=") {
- return "eq";
- } else if (oper == "!=") {
- return "neq";
- } else if (oper == "<") {
- return "lt";
- } else if (oper == "<=") {
- return "lte";
- } else if (oper == ">") {
- return "gt";
- } else if (oper == ">=") {
- return "gte";
- } else if (oper == "begins_with") {
- return "startsWith";
- } else if (oper == "ends_with") {
- return "endsWith";
- } else if (oper == "contains") {
- return "contains";
- } else if (oper == "not_null") {
- return "notNull";
- } else if (oper == "is_null") {
- return "isNull";
- }
- return oper;
+ return Enums.queryBuilderUIOperatorToAPI[oper] || oper;
},
createObject = function(urlObj) {
var finalObj = {};
@@ -662,7 +638,17 @@ define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enum
if (temp[3]) {
rule['type'] = temp[3];
}
- rule.value = rule.type === 'date' && formatDate && rule.value.length ? moment(parseInt(rule.value)).format(Globals.dateTimeFormat) : rule.value;
+ if (rule.operator === "TIME_RANGE") {
+ if (temp[2].indexOf(",") > -1) {
+ rule.value = temp[2].split(",").map(function(udKey) {
+ return moment(parseInt(udKey.trim())).format(Globals.dateTimeFormat)
+ }).join(" - ")
+ } else {
+ rule.value = Enums.queryBuilderDateRangeAPIValueToUI[_.trim(rule.value)] || rule.value;
+ }
+ } else if (rule.type === 'date' && formatDate && rule.value.length) {
+ rule.value = moment(parseInt(rule.value)).format(Globals.dateTimeFormat)
+ }
}
return rule;
}
diff --git a/dashboardv3/public/js/utils/Enums.js b/dashboardv3/public/js/utils/Enums.js
index 24ec36b..131a08f 100644
--- a/dashboardv3/public/js/utils/Enums.js
+++ b/dashboardv3/public/js/utils/Enums.js
@@ -16,7 +16,7 @@
* limitations under the License.
*/
-define(['require'], function(require) {
+define(["require", "backbone"], function(require) {
'use strict';
var Enums = {};
@@ -219,5 +219,40 @@ define(['require'], function(require) {
0: "false",
1: "true"
};
+
+ Enums.queryBuilderUIOperatorToAPI = {
+ "=": "eq",
+ "!=": "neq",
+ "<": "lt",
+ "<=": "lte",
+ ">": "gt",
+ ">=": "gte",
+ "begins_with": "startsWith",
+ "ends_with": "endsWith",
+ "not_null": "notNull",
+ "is_null": "isNull",
+ "TIME_RANGE": "timerange"
+ };
+
+ Enums.queryBuilderApiOperatorToUI = _.invert(Enums.queryBuilderUIOperatorToAPI);
+
+ Enums.queryBuilderDateRangeUIValueToAPI = {
+ "Today": "TODAY",
+ "Yesterday": "YESTERDAY",
+ "Last 7 Days": "LAST_7_DAYS",
+ "Last 30 Days": "LAST_30_DAYS",
+ "This Month": "THIS_MONTH",
+ "Last Month": "LAST_MONTH",
+ "This Quarter": "THIS_QUARTER",
+ "Last Quarter":"LAST_QUARTER",
+ "This Year": "THIS_YEAR",
+ "Last Year": "LAST_YEAR",
+ "Last 3 Months": "LAST_3_MONTHS",
+ "Last 6 Months": "LAST_6_MONTHS",
+ "Last 12 Months": "LAST_12_MONTHS"
+ };
+
+ Enums.queryBuilderDateRangeAPIValueToUI = _.invert(Enums.queryBuilderDateRangeUIValueToAPI);
+
return Enums;
});
\ No newline at end of file
diff --git a/dashboardv3/public/js/views/search/QueryBuilderView.js b/dashboardv3/public/js/views/search/QueryBuilderView.js
index dc36ffe..06ecd01 100644
--- a/dashboardv3/public/js/views/search/QueryBuilderView.js
+++ b/dashboardv3/public/js/views/search/QueryBuilderView.js
@@ -24,9 +24,10 @@ define(['require',
'utils/CommonViewFunction',
'utils/Enums',
'utils/Globals',
+ 'moment',
'query-builder',
'daterangepicker'
-], function(require, Backbone, QueryBuilderTmpl, UserDefineTmpl, Utils, CommonViewFunction, Enums, Globals) {
+], function(require, Backbone, QueryBuilderTmpl, UserDefineTmpl, Utils, CommonViewFunction, Enums, Globals, moment) {
var QueryBuilderView = Backbone.Marionette.LayoutView.extend(
/** @lends QueryBuilderView */
@@ -58,6 +59,22 @@ define(['require',
_.extend(this, _.pick(options, 'attrObj', 'value', 'typeHeaders', 'entityDefCollection', 'enumDefCollection', 'classificationDefCollection', 'businessMetadataDefCollection', 'tag', 'type', 'searchTableFilters', 'systemAttrArr', 'adminAttrFilters'));
this.attrObj = _.sortBy(this.attrObj, 'name');
this.filterType = this.tag ? 'tagFilters' : 'entityFilters';
+ this.defaultRange = "Last 7 Days";
+ this.dateRangesMap = {
+ 'Today': [moment(), moment()],
+ 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
+ 'Last 7 Days': [moment().subtract(6, 'days'), moment()],
+ 'Last 30 Days': [moment().subtract(29, 'days'), moment()],
+ 'This Month': [moment().startOf('month'), moment().endOf('month')],
+ 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
+ 'Last 3 Months': [moment().subtract(3, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
+ 'Last 6 Months': [moment().subtract(6, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
+ 'Last 12 Months': [moment().subtract(12, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
+ 'This Quarter': [moment().startOf('quarter'), moment().endOf('quarter')],
+ 'Last Quarter': [moment().subtract(1, 'quarter').startOf('quarter'), moment().subtract(1, 'quarter').endOf('quarter')],
+ 'This Year': [moment().startOf('year'), moment().endOf('year')],
+ 'Last Year': [moment().subtract(1, 'year').startOf('year'), moment().subtract(1, 'year').endOf('year')]
+ }
},
bindEvents: function() {},
getOperator: function(type, skipDefault) {
@@ -71,7 +88,7 @@ define(['require',
}
}
if (type === "date") {
- obj.operators = ['>', '<'];
+ obj.operators = ['=', '!=', '>', '<', '>=', '<=', 'TIME_RANGE'];
}
if (type === "int" || type === "byte" || type === "short" || type === "long" || type === "float" || type === "double") {
obj.operators = ['=', '!=', '>', '<', '>=', '<='];
@@ -266,20 +283,7 @@ define(['require',
}
if (obj.type === "date") {
obj['plugin'] = 'daterangepicker';
- obj['plugin_config'] = {
- "singleDatePicker": true,
- "showDropdowns": true,
- "timePicker": true,
- locale: {
- format: Globals.dateTimeFormat
- }
- };
- if (rules) {
- var valueObj = _.find(rules, { id: obj.id });
- if (valueObj) {
- obj.plugin_config["startDate"] = valueObj.value;
- }
- }
+ obj['plugin_config'] = this.getDateConfig(rules, obj.id);
_.extend(obj, this.getOperator(obj.type));
return obj;
}
@@ -316,6 +320,86 @@ define(['require',
return obj;
}
},
+ getDateConfig: function(ruleObj, id, operator) {
+ var valueObj = ruleObj ? (_.find(ruleObj.rules, { id: id }) || {}) : {},
+ isTimeRange = (valueObj.operator && valueObj.operator === "TIME_RANGE" && operator === "TIME_RANGE") || (operator === "TIME_RANGE"),
+ obj = {
+ opens: "center",
+ autoApply: true,
+ autoUpdateInput: false,
+ timePickerSeconds: true,
+ timePicker: true,
+ locale: {
+ format: Globals.dateTimeFormat
+ }
+ };
+
+ if (isTimeRange) {
+ var defaultRangeDate = this.dateRangesMap[this.defaultRange];
+ obj.startDate = defaultRangeDate[0];
+ obj.endDate = defaultRangeDate[1];
+ obj.singleDatePicker = false;
+ obj.ranges = this.dateRangesMap;
+ } else {
+ obj.singleDatePicker = true;
+ obj.startDate = moment();
+ obj.endDate = obj.startDate;
+ }
+
+ if (!_.isEmpty(valueObj) && operator === valueObj.operator) {
+ if (isTimeRange) {
+ if (valueObj.value.indexOf("-") > -1) {
+ var dates = valueObj.value.split("-");
+ obj.startDate = dates[0].trim();
+ obj.endDate = dates[1].trim();
+ } else {
+ var dates = this.dateRangesMap[valueObj.value]
+ obj.startDate = dates[0];
+ obj.endDate = dates[1];
+ }
+ obj.singleDatePicker = false;
+ } else {
+ obj.startDate = moment(valueObj.value);
+ obj.endDate = moment(valueObj.value);
+ obj.singleDatePicker = true;
+ }
+ }
+
+ return obj;
+ },
+ setDateValue: function(rule, rules_widgets) {
+ if (rule.filter.type === "date" && rule.operator.nb_inputs) {
+ var inputEl = rule.$el.find(".rule-value-container").find("input"),
+ datepickerEl = rule.$el.find(".rule-value-container").find("input").data("daterangepicker")
+ inputEl.attr('readonly', true);
+ if (datepickerEl) {
+ datepickerEl.remove();
+ var configObj = this.getDateConfig(rules_widgets, rule.filter.id, rule.operator.type)
+ inputEl.daterangepicker(configObj);
+ if (rule.operator.type === "TIME_RANGE") {
+ rule.value = this.defaultRange;
+ } else {
+ rule.value = configObj.startDate.format(Globals.dateTimeFormat);
+ }
+ inputEl.on('apply.daterangepicker', function(ev, picker) {
+ picker.setStartDate(picker.startDate);
+ picker.setEndDate(picker.endDate);
+ var valueString = "";
+ if (picker.chosenLabel) {
+ if (picker.chosenLabel === "Custom Range") {
+ valueString = picker.startDate.format(Globals.dateTimeFormat) + " - " + picker.endDate.format(Globals.dateTimeFormat);
+ } else {
+ valueString = picker.chosenLabel;
+ }
+ } else {
+ valueString = picker.startDate.format(Globals.dateTimeFormat);
+ }
+ picker.element.val(valueString);
+ rule.value = valueString;
+ });
+ }
+ }
+ },
onRender: function() {
var that = this,
filters = [],
@@ -339,7 +423,7 @@ define(['require',
rules_widgets = CommonViewFunction.attributeFilter.extractUrl({ "value": this.searchTableFilters ? this.searchTableFilters["adminAttrFilters"] : null, "formatDate": true });;
} else {
if (this.value) {
- var rules_widgets = CommonViewFunction.attributeFilter.extractUrl({ "value": this.searchTableFilters[this.filterType][(this.tag ? this.value.tag : this.value.type)], "formatDate": true });
+ rules_widgets = CommonViewFunction.attributeFilter.extractUrl({ "value": this.searchTableFilters[this.filterType][(this.tag ? this.value.tag : this.value.type)], "formatDate": true });
}
_.each(this.attrObj, function(obj) {
var type = that.tag ? that.value.tag : that.value.type;
@@ -415,16 +499,20 @@ define(['require',
}
filters = _.uniq(filters, 'id');
if (filters && !_.isEmpty(filters)) {
- this.ui.builder.queryBuilder({
- plugins: ['bt-tooltip-errors'],
- filters: filters,
- select_placeholder: placeHolder,
- allow_empty: true,
- conditions: ['AND', 'OR'],
- allow_groups: true,
- allow_empty: true,
- templates: {
- rule: '<div id="{{= it.rule_id }}" class="rule-container"> \
+ this.ui.builder.off()
+ .on("afterUpdateRuleOperator.queryBuilder", function(e, rule) {
+ that.setDateValue(rule, rules_widgets);
+ })
+ .queryBuilder({
+ plugins: ['bt-tooltip-errors'],
+ filters: filters,
+ select_placeholder: placeHolder,
+ allow_empty: true,
+ conditions: ['AND', 'OR'],
+ allow_groups: true,
+ allow_empty: true,
+ templates: {
+ rule: '<div id="{{= it.rule_id }}" class="rule-container"> \
<div class="values-box"><div class="rule-filter-container"></div> \
<div class="rule-operator-container"></div> \
<div class="rule-value-container"></div></div> \
@@ -439,50 +527,58 @@ define(['require',
<div class="error-container"><i class="{{= it.icons.error }}"></i> <span></span></div> \
{{?}} \
</div>'
- },
- operators: [
- { type: '=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
- { type: '!=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
- { type: '>', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
- { type: '<', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
- { type: '>=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
- { type: '<=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
- { type: 'contains', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'like', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'in', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'begins_with', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'ends_with', nb_inputs: 1, multiple: false, apply_to: ['string'] },
- { type: 'is_null', nb_inputs: false, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
- { type: 'not_null', nb_inputs: false, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] }
- ],
- lang: {
- add_rule: 'Add filter',
- add_group: 'Add filter group',
- operators: {
- not_null: 'is not null'
+ },
+ operators: [
+ { type: '=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
+ { type: '!=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
+ { type: '>', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
+ { type: '<', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
+ { type: '>=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
+ { type: '<=', nb_inputs: 1, multiple: false, apply_to: ['number', 'string', 'boolean'] },
+ { type: 'contains', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'like', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'in', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'begins_with', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'ends_with', nb_inputs: 1, multiple: false, apply_to: ['string'] },
+ { type: 'is_null', nb_inputs: false, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
+ { type: 'not_null', nb_inputs: false, multiple: false, apply_to: ['number', 'string', 'boolean', 'enum'] },
+ { type: 'TIME_RANGE', nb_inputs: 1, multiple: false, apply_to: ['date'] }
+ ],
+ lang: {
+ add_rule: 'Add filter',
+ add_group: 'Add filter group',
+ operators: {
+ not_null: 'is not null',
+ TIME_RANGE: "Time Range"
+ }
+ },
+ icons: {
+ add_rule: 'fa fa-plus',
+ remove_rule: 'fa fa-times',
+ error: 'fa fa-exclamation-triangle'
+ },
+ rules: rules_widgets
+ })
+ .on("afterCreateRuleInput.queryBuilder", function(e, rule) {
+ rule.error = null;
+ if (rule.operator.nb_inputs && rule.filter.id === "__customAttributes") {
+ rule.$el.addClass("user-define");
+ } else if (rule.$el.hasClass("user-define")) {
+ rule.$el.removeClass("user-define");
}
- },
- icons: {
- add_rule: 'fa fa-plus',
- remove_rule: 'fa fa-times',
- error: 'fa fa-exclamation-triangle'
- },
- rules: rules_widgets
- }).on("afterCreateRuleInput.queryBuilder", function(e, rule) {
- rule.error = null;
- if (rule.operator.nb_inputs && rule.filter.id === "__customAttributes") {
- rule.$el.addClass("user-define");
- } else if (rule.$el.hasClass("user-define")) {
- rule.$el.removeClass("user-define");
- }
- }).on('validationError.queryBuilder', function(e, rule, error, value) {
- // never display error for my custom filter
- var errorMsg = error[0];
- if (that.queryBuilderLang && that.queryBuilderLang.errors && that.queryBuilderLang.errors[errorMsg]) {
- errorMsg = that.queryBuilderLang.errors[errorMsg];
- }
- rule.$el.find(".error-container span").html(errorMsg);
- });
+ if (rule.filter.type === "date") {
+ rule.$el.find('.rule-value-container >input').attr('readonly', true);
+ }
+ that.setDateValue(rule, rules_widgets);
+ })
+ .on('validationError.queryBuilder', function(e, rule, error, value) {
+ // never display error for my custom filter
+ var errorMsg = error[0];
+ if (that.queryBuilderLang && that.queryBuilderLang.errors && that.queryBuilderLang.errors[errorMsg]) {
+ errorMsg = that.queryBuilderLang.errors[errorMsg];
+ }
+ rule.$el.find(".error-container span").html(errorMsg);
+ });
var queryBuilderEl = that.ui.builder.data("queryBuilder");
if (queryBuilderEl && queryBuilderEl.lang) {
this.queryBuilderLang = queryBuilderEl.lang;
diff --git a/dashboardv3/public/js/views/search/tree/EntityTreeLayoutView.js b/dashboardv3/public/js/views/search/tree/EntityTreeLayoutView.js
index f2111ca..a859ea0 100644
--- a/dashboardv3/public/js/views/search/tree/EntityTreeLayoutView.js
+++ b/dashboardv3/public/js/views/search/tree/EntityTreeLayoutView.js
@@ -242,7 +242,8 @@ define([
params["entityFilters"] = null;
}
}
-
+ var getUrl = Utils.getUrlState.isSearchTab();
+ if (!getUrl) { that.typeId = null; }
if (that.typeId != selectedNodeId) {
that.typeId = selectedNodeId;
typeValue = name;