Browse Source

Merge branch 'master' into feature/scada-symbol

pull/11391/head
Igor Kulikov 2 years ago
parent
commit
e1a0650689
  1. 2
      application/src/main/data/json/system/widget_types/update_server_string_attribute.json
  2. 2
      application/src/main/data/json/system/widget_types/update_shared_string_attribute.json
  3. 2
      application/src/main/data/json/system/widget_types/update_string_timeseries.json
  4. 325
      common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
  5. 134
      common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java
  6. 4
      ui-ngx/src/app/core/services/utils.service.ts
  7. 2
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-with-labels-basic-config.component.html
  8. 24
      ui-ngx/src/app/modules/home/components/widget/lib/cards/unread-notification-widget.component.ts
  9. 2
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-widget.component.ts
  10. 14
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts
  11. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.html
  12. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-bar-settings.component.html
  13. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-fill-settings.component.html
  14. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-fill-settings.component.ts
  15. 1
      ui-ngx/src/app/modules/home/components/widget/widget.component.ts
  16. 2
      ui-ngx/src/app/modules/home/models/widget-component.models.ts
  17. 49
      ui-ngx/src/app/shared/components/entity/entity-list.component.ts

2
application/src/main/data/json/system/widget_types/update_server_string_attribute.json

File diff suppressed because one or more lines are too long

2
application/src/main/data/json/system/widget_types/update_shared_string_attribute.json

File diff suppressed because one or more lines are too long

2
application/src/main/data/json/system/widget_types/update_string_timeseries.json

File diff suppressed because one or more lines are too long

325
common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java

@ -61,6 +61,7 @@ public class TbUtils {
private static final int HEX_LEN_MIN = -1;
private static final int HEX_LEN_INT_MAX = 8;
private static final int HEX_LEN_LONG_MAX = 16;
private static final int BYTES_LEN_INT_MAX = 4;
private static final int BYTES_LEN_LONG_MAX = 8;
private static final LinkedHashMap<String, String> mdnEncodingReplacements = new LinkedHashMap<>();
@ -117,6 +118,8 @@ public class TbUtils {
String.class)));
parserConfig.addImport("parseFloat", new MethodStub(TbUtils.class.getMethod("parseFloat",
String.class, int.class)));
parserConfig.addImport("parseHexIntLongToFloat", new MethodStub(TbUtils.class.getMethod("parseHexIntLongToFloat",
String.class, boolean.class)));
parserConfig.addImport("parseDouble", new MethodStub(TbUtils.class.getMethod("parseDouble",
String.class)));
parserConfig.addImport("parseLittleEndianHexToInt", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToInt",
@ -127,10 +130,18 @@ public class TbUtils {
String.class)));
parserConfig.addImport("parseHexToInt", new MethodStub(TbUtils.class.getMethod("parseHexToInt",
String.class, boolean.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
List.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
List.class, int.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
List.class, int.class, int.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
List.class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
byte[].class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
byte[].class, int.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
byte[].class, int.class, int.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
@ -143,10 +154,18 @@ public class TbUtils {
String.class)));
parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong",
String.class, boolean.class)));
parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong",
List.class)));
parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong",
List.class, int.class)));
parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong",
List.class, int.class, int.class)));
parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong",
List.class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong",
byte[].class)));
parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong",
byte[].class, int.class)));
parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong",
byte[].class, int.class, int.class)));
parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong",
@ -160,13 +179,21 @@ public class TbUtils {
parserConfig.addImport("parseHexToFloat", new MethodStub(TbUtils.class.getMethod("parseHexToFloat",
String.class, boolean.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
byte[].class, int.class, boolean.class)));
List.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
List.class, int.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
List.class, int.class, int.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
List.class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
byte[].class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
byte[].class, int.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
List.class, int.class, boolean.class)));
byte[].class, int.class, int.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
List.class, int.class)));
byte[].class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseLittleEndianHexToDouble", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToDouble",
String.class)));
parserConfig.addImport("parseBigEndianHexToDouble", new MethodStub(TbUtils.class.getMethod("parseBigEndianHexToDouble",
@ -176,13 +203,21 @@ public class TbUtils {
parserConfig.addImport("parseHexToDouble", new MethodStub(TbUtils.class.getMethod("parseHexToDouble",
String.class, boolean.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
byte[].class, int.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
byte[].class, int.class, boolean.class)));
List.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
List.class, int.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
List.class, int.class, boolean.class)));
List.class, int.class, int.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
List.class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
byte[].class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
byte[].class, int.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
byte[].class, int.class, int.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
byte[].class, int.class, int.class, boolean.class)));
parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed",
double.class, int.class)));
parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed",
@ -201,17 +236,17 @@ public class TbUtils {
Long.class)));
parserConfig.addImport("longToHex", new MethodStub(TbUtils.class.getMethod("longToHex",
Long.class, boolean.class)));
parserConfig.addImport("longToHex", new MethodStub(TbUtils.class.getMethod("longToHex",
parserConfig.addImport("longToHex", new MethodStub(TbUtils.class.getMethod("longToHex",
Long.class, boolean.class, boolean.class)));
parserConfig.addImport("longToHex", new MethodStub(TbUtils.class.getMethod("longToHex",
parserConfig.addImport("longToHex", new MethodStub(TbUtils.class.getMethod("longToHex",
Long.class, boolean.class, boolean.class, int.class)));
parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
Long.class)));
parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
Long.class, int.class)));
parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
Long.class, int.class, boolean.class)));
parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
Long.class, int.class, boolean.class, boolean.class)));
parserConfig.addImport("floatToHex", new MethodStub(TbUtils.class.getMethod("floatToHex",
Float.class)));
@ -334,10 +369,14 @@ public class TbUtils {
}
public static Integer parseInt(String value, int radix) {
if (StringUtils.isNotBlank(value)) {
String valueP = prepareNumberString(value);
return parseInt(value, radix, true);
}
private static Integer parseInt(String value, int radix, boolean bigEndian) {
String valueP = prepareNumberString(value, bigEndian);
if (valueP != null) {
int radixValue = isValidStringAndRadix(valueP, radix, value);
if (radixValue >= 25 && radixValue <= MAX_RADIX) {
if (radixValue >= 25 && radixValue <= MAX_RADIX) {
return (Integer) compareIntLongValueMinMax(valueP, radixValue, Integer.MAX_VALUE, Integer.MIN_VALUE);
}
return switch (radixValue) {
@ -354,10 +393,14 @@ public class TbUtils {
}
public static Long parseLong(String value, int radix) {
if (StringUtils.isNotBlank(value)) {
String valueP = prepareNumberString(value);
return parseLong(value, radix, true);
}
private static Long parseLong(String value, int radix, boolean bigEndian) {
String valueP = prepareNumberString(value, bigEndian);
if (valueP != null) {
int radixValue = isValidStringAndRadix(valueP, radix, value);
if (radixValue >= 25 && radixValue <= MAX_RADIX) {
if (radixValue >= 25 && radixValue <= MAX_RADIX) {
return (Long) compareIntLongValueMinMax(valueP, radixValue, Long.MAX_VALUE, Long.MIN_VALUE);
}
return switch (radixValue) {
@ -385,6 +428,7 @@ public class TbUtils {
return Integer.parseInt(binaryString, MIN_RADIX);
}
}
private static long parseBinaryStringAsSignedLong(String binaryString) {
if (binaryString.length() != 64) {
// Pad the binary string to 64 bits if it is not already
@ -420,34 +464,58 @@ public class TbUtils {
}
public static Float parseFloat(String value) {
return parseFloat(value, 0);
return parseFloat(value, ZERO_RADIX);
}
public static Float parseFloat(String value, int radix) {
if (StringUtils.isNotBlank(value)) {
String valueP = prepareNumberString(value);
int radixValue = isValidStringAndRadix(valueP, radix, value);
if (radixValue == DEC_RADIX) {
return Float.parseFloat(value);
} else {
int bits = Integer.parseUnsignedInt(valueP, HEX_RADIX);
return Float.intBitsToFloat(bits);
String valueP = prepareNumberString(value, true);
if (valueP != null) {
return parseFloatFromString(value, valueP, radix);
}
return null;
}
private static Float parseFloatFromString(String value, String valueP, int radix) {
int radixValue = isValidStringAndRadix(valueP, radix, value);
if (radixValue == HEX_RADIX) {
int bits = (int) Long.parseLong(valueP, HEX_RADIX);
// Hex representation is a standard IEEE 754 float value (eg "0x41200000" for 10.0f).
return Float.intBitsToFloat(bits);
} else {
return Float.parseFloat(value);
}
}
public static Float parseHexIntLongToFloat(String value, boolean bigEndian) {
String valueP = prepareNumberString(value, bigEndian);
if (valueP != null) {
int radixValue = isValidStringAndRadix(valueP, HEX_RADIX, value);
if (radixValue == HEX_RADIX) {
int bits = (int) Long.parseLong(valueP, HEX_RADIX);
// If the length is not equal to 8 characters, we process it as an integer (eg "0x0A" for 10.0f).
float floatValue = (float) bits;
return Float.valueOf(floatValue);
}
}
return null;
}
public static Double parseDouble(String value) {
int radix = getRadix10_16(value);
return parseDouble(value, radix);
}
public static Double parseDouble(String value, int radix) {
if (value != null) {
String valueP = prepareNumberString(value);
return parseDouble(value, radix, true);
}
private static Double parseDouble(String value, int radix, boolean bigEndian) {
String valueP = prepareNumberString(value, bigEndian);
if (valueP != null) {
int radixValue = isValidStringAndRadix(valueP, radix, value);
if (radixValue == DEC_RADIX) {
return Double.parseDouble(prepareNumberString(value));
return Double.parseDouble(valueP);
} else {
long bits = Long.parseUnsignedLong(valueP, HEX_RADIX);
return Double.longBitsToDouble(bits);
@ -469,9 +537,7 @@ public class TbUtils {
}
public static Integer parseHexToInt(String value, boolean bigEndian) {
String hexValue = prepareNumberString(value);
String hex = bigEndian ? hexValue : reverseHexStringByOrder(hexValue);
return parseInt(hex, HEX_RADIX);
return parseInt(value, HEX_RADIX, bigEndian);
}
public static long parseLittleEndianHexToLong(String hex) {
@ -487,9 +553,7 @@ public class TbUtils {
}
public static Long parseHexToLong(String value, boolean bigEndian) {
String hexValue = prepareNumberString(value);
String hex = bigEndian ? value : reverseHexStringByOrder(hexValue);
return parseLong(hex, HEX_RADIX);
return parseLong(value, HEX_RADIX, bigEndian);
}
public static float parseLittleEndianHexToFloat(String hex) {
@ -505,9 +569,11 @@ public class TbUtils {
}
public static Float parseHexToFloat(String value, boolean bigEndian) {
String hexValue = prepareNumberString(value);
String hex = bigEndian ? value : reverseHexStringByOrder(hexValue);
return parseFloat(hex, HEX_RADIX);
String valueP = prepareNumberString(value, bigEndian);
if (valueP != null) {
return parseFloatFromString(value, valueP, HEX_RADIX);
}
return null;
}
public static double parseLittleEndianHexToDouble(String hex) {
@ -523,13 +589,11 @@ public class TbUtils {
}
public static double parseHexToDouble(String value, boolean bigEndian) {
String hexValue = prepareNumberString(value);
String hex = bigEndian ? value : reverseHexStringByOrder(hexValue);
return parseDouble(hex, HEX_RADIX);
return parseDouble(value, HEX_RADIX, bigEndian);
}
public static ExecutionArrayList<Byte> hexToBytes(ExecutionContext ctx, String value) {
String hex = prepareNumberString(value);
String hex = prepareNumberString(value, true);
int len = hex.length();
if (len % 2 > 0) {
throw new IllegalArgumentException("Hex string must be even-length.");
@ -575,6 +639,7 @@ public class TbUtils {
public static String longToHex(Long l) {
return prepareNumberHexString(l, true, false, HEX_LEN_MIN, HEX_LEN_LONG_MAX);
}
public static String longToHex(Long l, boolean bigEndian) {
return prepareNumberHexString(l, bigEndian, false, HEX_LEN_MIN, HEX_LEN_LONG_MAX);
}
@ -604,7 +669,7 @@ public class TbUtils {
return Long.toString(number, radix);
}
return switch (radix) {
case MIN_RADIX -> Long.toBinaryString(number);
case MIN_RADIX -> Long.toBinaryString(number);
case OCTAL_RADIX -> Long.toOctalString(number);
case DEC_RADIX -> Long.toString(number);
case HEX_RADIX -> prepareNumberHexString(number, bigEndian, pref, -1, -1);
@ -646,13 +711,13 @@ public class TbUtils {
private static String removeLeadingZero_FF(String hex, Long number, int hexLenMax) {
String hexWithoutZero = hex.replaceFirst("^0+(?!$)", ""); // Remove leading zeros except for the last one
hexWithoutZero = hexWithoutZero.length() % 2 > 0 ? "0" + hexWithoutZero : hexWithoutZero;
hexWithoutZero = hexWithoutZero.length() % 2 > 0 ? "0" + hexWithoutZero : hexWithoutZero;
if (number >= 0) {
return hexWithoutZero;
} else {
String hexWithoutZeroFF = hexWithoutZero.replaceFirst("^F+(?!$)", "");
hexWithoutZeroFF = hexWithoutZeroFF.length() % 2 > 0 ? "F" + hexWithoutZeroFF : hexWithoutZeroFF;
if (hexWithoutZeroFF.length() > hexLenMax) {
hexWithoutZeroFF = hexWithoutZeroFF.length() % 2 > 0 ? "F" + hexWithoutZeroFF : hexWithoutZeroFF;
if (hexWithoutZeroFF.length() > hexLenMax) {
return hexWithoutZeroFF.substring(hexWithoutZeroFF.length() - hexLenMax);
} else if (hexWithoutZeroFF.length() == hexLenMax) {
return hexWithoutZeroFF;
@ -668,7 +733,7 @@ public class TbUtils {
public static String floatToHex(Float f, boolean bigEndian) {
// Convert the float to its raw integer bits representation
int bits = Float.floatToRawIntBits(f);
int bits = Float.floatToIntBits(f);
// Format the integer bits as a hexadecimal string
String result = String.format("0x%08X", bits);
@ -699,16 +764,28 @@ public class TbUtils {
return Base64.getDecoder().decode(input);
}
public static int parseBytesToInt(List<Byte> data) {
return parseBytesToInt(Bytes.toArray(data));
}
public static int parseBytesToInt(List<Byte> data, int offset) {
return parseBytesToInt(Bytes.toArray(data), offset);
}
public static int parseBytesToInt(List<Byte> data, int offset, int length) {
return parseBytesToInt(data, offset, length, true);
return parseBytesToInt(Bytes.toArray(data), offset, length);
}
public static int parseBytesToInt(List<Byte> data, int offset, int length, boolean bigEndian) {
final byte[] bytes = new byte[data.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = data.get(i);
}
return parseBytesToInt(bytes, offset, length, bigEndian);
return parseBytesToInt(Bytes.toArray(data), offset, length, bigEndian);
}
public static int parseBytesToInt(byte[] data) {
return parseBytesToInt(data, 0);
}
public static int parseBytesToInt(byte[] data, int offset) {
return parseBytesToInt(data, offset, BYTES_LEN_INT_MAX);
}
public static int parseBytesToInt(byte[] data, int offset, int length) {
@ -719,7 +796,7 @@ public class TbUtils {
if (offset > data.length) {
throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!");
}
if (length > 4) {
if (length > BYTES_LEN_INT_MAX) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum 4 bytes is allowed!");
}
if (offset + length > data.length) {
@ -735,16 +812,28 @@ public class TbUtils {
return bb.getInt();
}
public static long parseBytesToLong(List<Byte> data) {
return parseBytesToLong(Bytes.toArray(data));
}
public static long parseBytesToLong(List<Byte> data, int offset) {
return parseBytesToLong(Bytes.toArray(data), offset);
}
public static long parseBytesToLong(List<Byte> data, int offset, int length) {
return parseBytesToLong(data, offset, length, true);
return parseBytesToLong(Bytes.toArray(data), offset, length);
}
public static long parseBytesToLong(List<Byte> data, int offset, int length, boolean bigEndian) {
final byte[] bytes = new byte[data.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = data.get(i);
}
return parseBytesToLong(bytes, offset, length, bigEndian);
return parseBytesToLong(Bytes.toArray(data), offset, length, bigEndian);
}
public static long parseBytesToLong(byte[] data) {
return parseBytesToLong(data, 0);
}
public static long parseBytesToLong(byte[] data, int offset) {
return parseBytesToLong(data, offset, BYTES_LEN_LONG_MAX);
}
public static long parseBytesToLong(byte[] data, int offset, int length) {
@ -761,49 +850,118 @@ public class TbUtils {
if (offset + length > data.length) {
throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!");
}
var bb = ByteBuffer.allocate(8);
var bb = ByteBuffer.allocate(BYTES_LEN_LONG_MAX);
if (!bigEndian) {
bb.order(ByteOrder.LITTLE_ENDIAN);
}
bb.position(bigEndian ? 8 - length : 0);
bb.position(bigEndian ? BYTES_LEN_LONG_MAX - length : 0);
bb.put(data, offset, length);
bb.position(0);
return bb.getLong();
}
public static float parseBytesToFloat(byte[] data, int offset) {
return parseBytesToFloat(data, offset, true);
public static float parseBytesToFloat(List data) {
return parseBytesToFloat(Bytes.toArray(data), 0);
}
public static float parseBytesToFloat(List data, int offset) {
return parseBytesToFloat(data, offset, true);
return parseBytesToFloat(Bytes.toArray(data), offset, BYTES_LEN_INT_MAX);
}
public static float parseBytesToFloat(List data, int offset, boolean bigEndian) {
return parseBytesToFloat(Bytes.toArray(data), offset, bigEndian);
public static float parseBytesToFloat(List data, int offset, int length) {
return parseBytesToFloat(Bytes.toArray(data), offset, length, true);
}
public static float parseBytesToFloat(byte[] data, int offset, boolean bigEndian) {
byte[] bytesToNumber = prepareBytesToNumber(data, offset, 4, bigEndian);
return ByteBuffer.wrap(bytesToNumber).getFloat();
public static float parseBytesToFloat(List data, int offset, int length, boolean bigEndian) {
return parseBytesToFloat(Bytes.toArray(data), offset, length, bigEndian);
}
public static float parseBytesToFloat(byte[] data) {
return parseBytesToFloat(data, 0);
}
public static double parseBytesToDouble(byte[] data, int offset) {
return parseBytesToDouble(data, offset, true);
public static float parseBytesToFloat(byte[] data, int offset) {
return parseBytesToFloat(data, offset, BYTES_LEN_INT_MAX);
}
public static float parseBytesToFloat(byte[] data, int offset, int length) {
return parseBytesToFloat(data, offset, length, true);
}
public static float parseBytesToFloat(byte[] data, int offset, int length, boolean bigEndian) {
if (length > BYTES_LEN_INT_MAX) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum " + BYTES_LEN_INT_MAX + " bytes is allowed!");
}
if (offset + length > data.length) {
throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!");
}
byte[] bytesToNumber = prepareBytesToNumber(data, offset, length, bigEndian);
if (bytesToNumber.length < BYTES_LEN_INT_MAX) {
byte[] extendedBytes = new byte[BYTES_LEN_INT_MAX];
Arrays.fill(extendedBytes, (byte) 0);
System.arraycopy(bytesToNumber, 0, extendedBytes, 0, bytesToNumber.length);
bytesToNumber = extendedBytes;
}
float floatValue = ByteBuffer.wrap(bytesToNumber).getFloat();
if (!Float.isNaN(floatValue)) {
return floatValue;
} else {
long longValue = parseBytesToLong(bytesToNumber, 0, BYTES_LEN_INT_MAX);
BigDecimal bigDecimalValue = new BigDecimal(longValue);
return bigDecimalValue.floatValue();
}
}
public static double parseBytesToDouble(List data) {
return parseBytesToDouble(Bytes.toArray(data));
}
public static double parseBytesToDouble(List data, int offset) {
return parseBytesToDouble(data, offset, true);
return parseBytesToDouble(Bytes.toArray(data), offset);
}
public static double parseBytesToDouble(List data, int offset, int length) {
return parseBytesToDouble(Bytes.toArray(data), offset, length);
}
public static double parseBytesToDouble(List data, int offset, int length, boolean bigEndian) {
return parseBytesToDouble(Bytes.toArray(data), offset, length, bigEndian);
}
public static double parseBytesToDouble(List data, int offset, boolean bigEndian) {
return parseBytesToDouble(Bytes.toArray(data), offset, bigEndian);
public static double parseBytesToDouble(byte[] data) {
return parseBytesToDouble(data, 0);
}
public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) {
byte[] bytesToNumber = prepareBytesToNumber(data, offset, BYTES_LEN_LONG_MAX, bigEndian);
return ByteBuffer.wrap(bytesToNumber).getDouble();
public static double parseBytesToDouble(byte[] data, int offset) {
return parseBytesToDouble(data, offset, BYTES_LEN_LONG_MAX);
}
public static double parseBytesToDouble(byte[] data, int offset, int length) {
return parseBytesToDouble(data, offset, length, true);
}
public static double parseBytesToDouble(byte[] data, int offset, int length, boolean bigEndian) {
if (length > BYTES_LEN_LONG_MAX) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum " + BYTES_LEN_LONG_MAX + " bytes is allowed!");
}
if (offset + length > data.length) {
throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!");
}
byte[] bytesToNumber = prepareBytesToNumber(data, offset, length, bigEndian);
if (bytesToNumber.length < BYTES_LEN_LONG_MAX) {
byte[] extendedBytes = new byte[BYTES_LEN_LONG_MAX];
Arrays.fill(extendedBytes, (byte) 0);
System.arraycopy(bytesToNumber, 0, extendedBytes, 0, bytesToNumber.length);
bytesToNumber = extendedBytes;
}
double doubleValue = ByteBuffer.wrap(bytesToNumber).getDouble();
if (!Double.isNaN(doubleValue)) {
return doubleValue;
} else {
BigInteger bigInt = new BigInteger(1, bytesToNumber);
BigDecimal bigDecimalValue = new BigDecimal(bigInt);
return bigDecimalValue.doubleValue();
}
}
private static byte[] prepareBytesToNumber(byte[] data, int offset, int length, boolean bigEndian) {
@ -931,14 +1089,15 @@ public class TbUtils {
}
}
private static String prepareNumberString(String value) {
if (value != null) {
private static String prepareNumberString(String value, boolean bigEndian) {
if (StringUtils.isNotBlank(value)) {
value = value.trim();
value = value.replace("0x", "");
value = value.replace("0X", "");
value = value.replace(",", ".");
return bigEndian ? value : reverseHexStringByOrder(value);
}
return value;
return null;
}
private static int isValidStringAndRadix(String valueP, int radix, String value) {

134
common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java

@ -30,6 +30,7 @@ import org.mvel2.execution.ExecutionArrayList;
import org.mvel2.execution.ExecutionHashMap;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@ -47,7 +48,7 @@ public class TbUtilsTest {
private ExecutionContext ctx;
private final float floatVal = 29.29824f;
private final Float floatVal = 29.29824f;
private final float floatValRev = -5.948442E7f;
@ -256,7 +257,7 @@ public class TbUtilsTest {
@Test
public void parseFloat() {
String floatValStr = "29.29824";
String floatValStr = floatVal.toString();
Assertions.assertEquals(java.util.Optional.of(floatVal).get(), TbUtils.parseFloat(floatValStr));
String floatValHex = "41EA62CC";
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseHexToFloat(floatValHex)));
@ -274,14 +275,49 @@ public class TbUtilsTest {
}
@Test
public void arseBytesToFloat() {
public void parseBytesToFloat() {
byte[] floatValByte = {65, -22, 98, -52};
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValByte, 0)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValByte, 0, false)));
List<Byte> floatVaList = Bytes.asList(floatValByte);
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatVaList, 0)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatVaList, 0, false)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValByte, 0, 4, false)));
List<Byte> floatValList = Bytes.asList(floatValByte);
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValList, 0)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValList, 0, 4, false)));
// 4 294 967 295L == {0xFF, 0xFF, 0xFF, 0xFF}
floatValByte = new byte[]{-1, -1, -1, -1};
float floatExpectedBe = 4294.9673f;
float floatExpectedLe = 4.2949673E9f;
float actualBe = TbUtils.parseBytesToFloat(floatValByte, 0, 4, true);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValByte, 0, 4, false)));
floatValList = Bytes.asList(floatValByte);
actualBe = TbUtils.parseBytesToFloat(floatValList, 0);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValList, 0, 4, false)));
// 2 143 289 344L == {0x7F, 0xC0, 0x00, 0x00}
floatValByte = new byte[]{0x7F, (byte) 0xC0, (byte) 0xFF, 0x00};
floatExpectedBe = 2143.3547f;
floatExpectedLe = -3.984375f;
actualBe = TbUtils.parseBytesToFloat(floatValByte, 0, 4, true);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValByte, 0, 2, false)));
floatValList = Bytes.asList(floatValByte);
floatExpectedLe = 4.2908055E9f;
actualBe = TbUtils.parseBytesToFloat(floatValList, 0);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValList, 0, 3, false)));
// "01752B0367FA000500010488 FFFFFFFF FFFFFFFF 33";
String intToHexBe = "01752B0367FA000500010488FFFFFFFFFFFFFFFF33";
floatExpectedLe = 4294.9673f;
floatValList = TbUtils.hexToBytes(ctx, intToHexBe);
float actualLe = TbUtils.parseBytesToFloat(floatValList, 12, 4, false);
Assertions.assertEquals(0, Float.compare(floatExpectedLe, actualLe / 1000000));
actualLe = TbUtils.parseBytesToFloat(floatValList, 12 + 4, 4, false);
Assertions.assertEquals(0, Float.compare(floatExpectedLe, actualLe / 1000000));
}
@Test
@ -356,11 +392,40 @@ public class TbUtilsTest {
public void parseBytesToDouble() {
byte[] doubleValByte = {64, -101, 4, -79, 12, -78, -107, -22};
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValByte, 0)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, false)));
List<Byte> doubleVaList = Bytes.asList(doubleValByte);
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleVaList, 0)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleVaList, 0, false)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, 8, false)));
List<Byte> doubleValList = Bytes.asList(doubleValByte);
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValList, 0)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValList, 0, 8, false)));
// 4 294 967 295L == {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
doubleValByte = new byte[]{-1, -1, -1, -1, -1, -1, -1, -1};
double doubleExpectedBe = 18446.744073709553d;
double doubleExpectedLe = 1.8446744073709552E19d;
double actualBe = TbUtils.parseBytesToDouble(doubleValByte, 0, 8, true);
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, actualBe / 1000000000000000L));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValByte, 0, 8, false)));
doubleValList = Bytes.asList(doubleValByte);
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, TbUtils.parseBytesToDouble(doubleValList, 0) / 1000000000000000L));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValList, 0, 8, false)));
doubleValByte = new byte[]{0x7F, (byte) 0xC0, (byte) 0xFF, 0x00, 0x7F, (byte) 0xC0, (byte) 0xFF, 0x00};
doubleExpectedBe = 2387013.651780523d;
doubleExpectedLe = 7.234601680440024E-304d;
actualBe = TbUtils.parseBytesToDouble(doubleValByte, 0, 8, true);
BigDecimal bigDecimal = new BigDecimal(actualBe);
// We move the decimal point to the left by 301 positions
actualBe = bigDecimal.movePointLeft(301).doubleValue();
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, actualBe));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValByte, 0, 8, false)));
doubleValList = Bytes.asList(doubleValByte);
doubleExpectedLe = 5.828674572203954E303d;
actualBe = TbUtils.parseBytesToDouble(doubleValList, 0);
bigDecimal = new BigDecimal(actualBe);
actualBe = bigDecimal.movePointLeft(301).doubleValue();
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, actualBe));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValList, 0, 5, false)));
}
@Test
@ -605,15 +670,52 @@ public class TbUtilsTest {
@Test
public void floatToHex_Test() {
Float value = 20.89f;
String expectedHex = "0x41A71EB8";
String valueHexRev = "0xB81EA741";
Float value = 123456789.00f;
String expectedHex = "0x4CEB79A3";
String valueHexRev = "0xA379EB4C";
String actual = TbUtils.floatToHex(value);
Assertions.assertEquals(expectedHex, actual);
Float valueActual = TbUtils.parseHexToFloat(actual);
Assertions.assertEquals(value, valueActual);
valueActual = TbUtils.parseHexToFloat(valueHexRev, false);
Assertions.assertEquals(value, valueActual);
value = 123456789.67f;
expectedHex = "0x4CEB79A3";
valueHexRev = "0xA379EB4C";
actual = TbUtils.floatToHex(value);
Assertions.assertEquals(expectedHex, actual);
valueActual = TbUtils.parseHexToFloat(actual);
Assertions.assertEquals(value, valueActual);
valueActual = TbUtils.parseHexToFloat(valueHexRev, false);
Assertions.assertEquals(value, valueActual);
value = 10.0f;
expectedHex = "0x41200000";
valueHexRev = "0x00002041";
actual = TbUtils.floatToHex(value);
Assertions.assertEquals(expectedHex, actual);
valueActual = TbUtils.parseHexToFloat(actual);
Assertions.assertEquals(value, valueActual);
valueActual = TbUtils.parseHexToFloat(valueHexRev, false);
Assertions.assertEquals(value, valueActual);
}
// If the length is not equal to 8 characters, we process it as an integer (eg "0x0A" for 10.0f).
@Test
public void parseHexIntLongToFloat_Test() {
Float valueExpected = 10.0f;
Float valueActual = TbUtils.parseHexIntLongToFloat("0x0A", true);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseHexIntLongToFloat("0x0A", false);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseHexIntLongToFloat("0x00000A", true);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseHexIntLongToFloat("0x0A0000", false);
Assertions.assertEquals(valueExpected, valueActual);
valueExpected = 2570.0f;
valueActual = TbUtils.parseHexIntLongToFloat("0x000A0A", true);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseHexIntLongToFloat("0x0A0A00", false);
Assertions.assertEquals(valueExpected, valueActual);
}
@Test

4
ui-ngx/src/app/core/services/utils.service.ts

@ -456,6 +456,10 @@ export class UtilsService {
return isDefined(value);
}
public isDefinedAndNotNull(value: any): boolean {
return isDefinedAndNotNull(value);
}
public defaultValue(value: any, defaultValue: any): any {
if (isDefinedAndNotNull(value)) {
return value;

2
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-with-labels-basic-config.component.html

@ -160,7 +160,7 @@
</div>
<tb-chart-fill-settings
formControlName="barBackgroundSettings"
title="widgets.chart.background"
titleText="widgets.chart.background"
fillNoneTitle="widgets.chart.fill-type-solid">
</tb-chart-fill-settings>
<tb-time-series-no-aggregation-bar-width-settings

24
ui-ngx/src/app/modules/home/components/widget/lib/cards/unread-notification-widget.component.ts

@ -203,23 +203,29 @@ export class UnreadNotificationWidgetComponent implements OnInit, OnDestroy {
}
markAsRead(id: string) {
const cmd = NotificationSubscriber.createMarkAsReadCommand(this.notificationWsService, [id]);
cmd.subscribe();
if (!this.ctx.isEdit && !this.ctx.isPreview) {
const cmd = NotificationSubscriber.createMarkAsReadCommand(this.notificationWsService, [id]);
cmd.subscribe();
}
}
markAsAllRead($event: Event) {
if ($event) {
$event.stopPropagation();
if (!this.ctx.isEdit && !this.ctx.isPreview) {
if ($event) {
$event.stopPropagation();
}
const cmd = NotificationSubscriber.createMarkAllAsReadCommand(this.notificationWsService);
cmd.subscribe();
}
const cmd = NotificationSubscriber.createMarkAllAsReadCommand(this.notificationWsService);
cmd.subscribe();
}
viewAll($event: Event) {
if ($event) {
$event.stopPropagation();
if (!this.ctx.isEdit && !this.ctx.isPreview) {
if ($event) {
$event.stopPropagation();
}
this.router.navigateByUrl(this.router.parseUrl('/notification/inbox')).then(() => {});
}
this.router.navigateByUrl(this.router.parseUrl('/notification/inbox')).then(() => {});
}
trackById(index: number, item: NotificationRequest): string {

2
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-widget.component.ts

@ -171,6 +171,6 @@ export class TimeSeriesChartWidgetComponent implements OnInit, OnDestroy, AfterV
}
public toggleLegendKey(legendKey: LegendKey) {
this.timeSeriesChart.toggleKey(legendKey.dataKey);
this.timeSeriesChart.toggleKey(legendKey.dataKey, legendKey.dataIndex);
}
}

14
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts

@ -56,7 +56,14 @@ import {
measureAxisNameSize
} from '@home/components/widget/lib/chart/echarts-widget.models';
import { DateFormatProcessor, ValueSourceType } from '@shared/models/widget-settings.models';
import { formattedDataFormDatasourceData, formatValue, isDefinedAndNotNull, isEqual, mergeDeep } from '@core/utils';
import {
formattedDataFormDatasourceData,
formatValue,
isDefined,
isDefinedAndNotNull,
isEqual,
mergeDeep
} from '@core/utils';
import { DataKey, Datasource, DatasourceType, FormattedData, widgetType } from '@shared/models/widget.models';
import * as echarts from 'echarts/core';
import { CallbackDataParams, PiecewiseVisualMapOption } from 'echarts/types/dist/shared';
@ -300,7 +307,7 @@ export class TbTimeSeriesChart {
}
}
public toggleKey(dataKey: DataKey): void {
public toggleKey(dataKey: DataKey, dataIndex?: number): void {
const enable = dataKey.hidden;
const dataItem = this.dataItems.find(d => d.dataKey === dataKey);
if (dataItem) {
@ -320,6 +327,9 @@ export class TbTimeSeriesChart {
this.timeSeriesChart.setOption(this.timeSeriesChartOptions, this.stackMode ? {notMerge: true} : {replaceMerge: mergeList});
this.updateAxes();
dataKey.hidden = !enable;
if (isDefined(dataIndex)) {
this.ctx.defaultSubscription.updateDataVisibility(dataIndex);
}
if (enable) {
this.timeSeriesChart.dispatchAction({
type: 'highlight',

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.html

@ -79,7 +79,7 @@
</div>
<tb-chart-fill-settings
formControlName="barBackgroundSettings"
title="widgets.chart.background"
titleText="widgets.chart.background"
fillNoneTitle="widgets.chart.fill-type-solid">
</tb-chart-fill-settings>
<tb-time-series-no-aggregation-bar-width-settings

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-bar-settings.component.html

@ -77,7 +77,7 @@
</div>
<tb-chart-fill-settings
formControlName="backgroundSettings"
title="widgets.chart.background"
titleText="widgets.chart.background"
fillNoneTitle="widgets.chart.fill-type-solid">
</tb-chart-fill-settings>
</ng-container>

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-fill-settings.component.html

@ -18,7 +18,7 @@
<ng-container [formGroup]="fillSettingsFormGroup">
<div class="tb-form-row column">
<div class="tb-form-row no-border no-padding space-between">
<div>{{ title | translate }}</div>
<div>{{ titleText | translate }}</div>
<tb-toggle-select formControlName="type">
<tb-toggle-option *ngFor="let type of chartFillTypes" [value]="type">{{ chartFillTypeTranslationMap.get(type) | translate }}</tb-toggle-option>
</tb-toggle-select>

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/chart-fill-settings.component.ts

@ -55,7 +55,7 @@ export class ChartFillSettingsComponent implements OnInit, ControlValueAccessor
disabled: boolean;
@Input()
title = 'widgets.chart.fill';
titleText = 'widgets.chart.fill';
@Input()
fillNoneTitle = 'widgets.chart.fill-type-none';

1
ui-ngx/src/app/modules/home/components/widget/widget.component.ts

@ -488,6 +488,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
}
if (!this.widgetContext.inited && this.isReady()) {
this.widgetContext.inited = true;
this.widgetContext.destroyed = false;
this.dashboardWidget.updateWidgetParams();
this.widgetContext.detectContainerChanges();
if (this.cafs.init) {

2
ui-ngx/src/app/modules/home/models/widget-component.models.ts

@ -449,6 +449,8 @@ export class WidgetContext {
labelPattern.destroy();
}
this.labelPatterns.clear();
this.width = undefined;
this.height = undefined;
this.destroyed = true;
}

49
ui-ngx/src/app/shared/components/entity/entity-list.component.ts

@ -25,11 +25,17 @@ import {
SimpleChanges,
ViewChild
} from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import {
ControlValueAccessor,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
UntypedFormBuilder,
UntypedFormGroup,
ValidationErrors,
Validators
} from '@angular/forms';
import { Observable } from 'rxjs';
import { filter, map, mergeMap, share, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { EntityType } from '@shared/models/entity-type.models';
import { BaseData } from '@shared/models/base-data';
@ -49,6 +55,11 @@ import { SubscriptSizing } from '@angular/material/form-field';
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => EntityListComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => EntityListComponent),
multi: true
}
]
})
@ -56,7 +67,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
entityListFormGroup: UntypedFormGroup;
modelValue: Array<string> | null;
private modelValue: Array<string> | null;
@Input()
entityType: EntityType;
@ -108,17 +119,16 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
private propagateChange = (v: any) => { };
constructor(private store: Store<AppState>,
public translate: TranslateService,
constructor(public translate: TranslateService,
private entityService: EntityService,
private fb: UntypedFormBuilder) {
this.entityListFormGroup = this.fb.group({
entities: [this.entities, this.required ? [Validators.required] : []],
entities: [this.entities],
entity: [null]
});
}
updateValidators() {
private updateValidators() {
this.entityListFormGroup.get('entities').setValidators(this.required ? [Validators.required] : []);
this.entityListFormGroup.get('entities').updateValueAndValidity();
}
@ -189,7 +199,13 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
this.dirty = true;
}
reset() {
validate(): ValidationErrors | null {
return this.entityListFormGroup.valid ? null : {
entities: {valid: false}
};
}
private reset() {
this.entities = [];
this.entityListFormGroup.get('entities').setValue(this.entities);
this.modelValue = null;
@ -201,7 +217,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
this.dirty = true;
}
add(entity: BaseData<EntityId>): void {
private add(entity: BaseData<EntityId>): void {
if (!this.modelValue || this.modelValue.indexOf(entity.id.id) === -1) {
if (!this.modelValue) {
this.modelValue = [];
@ -214,7 +230,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
this.clear();
}
remove(entity: BaseData<EntityId>) {
public remove(entity: BaseData<EntityId>) {
let index = this.entities.indexOf(entity);
if (index >= 0) {
this.entities.splice(index, 1);
@ -229,11 +245,11 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
}
}
displayEntityFn(entity?: BaseData<EntityId>): string | undefined {
public displayEntityFn(entity?: BaseData<EntityId>): string | undefined {
return entity ? entity.name : undefined;
}
fetchEntities(searchText?: string): Observable<Array<BaseData<EntityId>>> {
private fetchEntities(searchText?: string): Observable<Array<BaseData<EntityId>>> {
this.searchText = searchText;
return this.entityService.getEntitiesByNameFilter(this.entityType, searchText,
@ -241,14 +257,14 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
map((data) => data ? data : []));
}
onFocus() {
public onFocus() {
if (this.dirty) {
this.entityListFormGroup.get('entity').updateValueAndValidity({onlySelf: true, emitEvent: true});
this.dirty = false;
}
}
clear(value: string = '') {
private clear(value: string = '') {
this.entityInput.nativeElement.value = value;
this.entityListFormGroup.get('entity').patchValue(value, {emitEvent: true});
setTimeout(() => {
@ -257,8 +273,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV
}, 0);
}
textIsNotEmpty(text: string): boolean {
public textIsNotEmpty(text: string): boolean {
return (text && text.length > 0);
}
}

Loading…
Cancel
Save