support filtering transaction description using regular expressions in insights explorer

This commit is contained in:
MaysWind
2026-04-12 00:40:33 +08:00
parent f2b633cc7b
commit 721384b9cc
21 changed files with 87 additions and 10 deletions
+4
View File
@@ -93,6 +93,8 @@ export enum TransactionExplorerConditionOperatorType {
NotStartsWith = 'notStartsWith',
EndsWith = 'endsWith',
NotEndsWith = 'notEndsWith',
RegexMatch = 'regexMatch',
NotRegexMatch = 'notRegexMatch',
LatitudeBetween = 'latitudeBetween',
LatitudeNotBetween = 'latitudeNotBetween',
LongitudeBetween = 'longitudeBetween',
@@ -123,6 +125,8 @@ export class TransactionExplorerConditionOperator implements NameValue {
public static readonly NotStartsWith = new TransactionExplorerConditionOperator('Does not start with', TransactionExplorerConditionOperatorType.NotStartsWith);
public static readonly EndsWith = new TransactionExplorerConditionOperator('Ends with', TransactionExplorerConditionOperatorType.EndsWith);
public static readonly NotEndsWith = new TransactionExplorerConditionOperator('Does not end with', TransactionExplorerConditionOperatorType.NotEndsWith);
public static readonly RegexMatch = new TransactionExplorerConditionOperator('Matches regex', TransactionExplorerConditionOperatorType.RegexMatch);
public static readonly NotRegexMatch = new TransactionExplorerConditionOperator('Does not match regex', TransactionExplorerConditionOperatorType.NotRegexMatch);
public static readonly LatitudeBetween = new TransactionExplorerConditionOperator('Latitude is between', TransactionExplorerConditionOperatorType.LatitudeBetween);
public static readonly LatitudeNotBetween = new TransactionExplorerConditionOperator('Latitude is not between', TransactionExplorerConditionOperatorType.LatitudeNotBetween);
public static readonly LongitudeBetween = new TransactionExplorerConditionOperator('Longitude is between', TransactionExplorerConditionOperatorType.LongitudeBetween);
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Beginnt nicht mit",
"Ends with": "Endet mit",
"Does not end with": "Endet nicht mit",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Breitengrad zwischen",
"Latitude is not between": "Breitengrad nicht zwischen",
"Longitude is between": "Längengrad zwischen",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "No empieza por",
"Ends with": "Termina en",
"Does not end with": "No termina en",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Não começa com",
"Ends with": "Termina com",
"Does not end with": "Não termina com",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude entre",
"Latitude is not between": "Latitude não entre",
"Longitude is between": "Longitude entre",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Не начинается с",
"Ends with": "Заканчивается с",
"Does not end with": "Не заканчивается с",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Se ne začne z",
"Ends with": "Se konča z",
"Does not end with": "Se ne konča z",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "தொடங்கவில்லை",
"Ends with": "முடிகிறது",
"Does not end with": "முடியவில்லை",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "Does not start with",
"Ends with": "Ends with",
"Does not end with": "Does not end with",
"Matches regex": "Matches regex",
"Does not match regex": "Does not match regex",
"Latitude is between": "Latitude is between",
"Latitude is not between": "Latitude is not between",
"Longitude is between": "Longitude is between",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "开头不是",
"Ends with": "结尾是",
"Does not end with": "结尾不是",
"Matches regex": "正则匹配",
"Does not match regex": "不匹配正则",
"Latitude is between": "纬度介于",
"Latitude is not between": "纬度不介于",
"Longitude is between": "经度介于",
+2
View File
@@ -1571,6 +1571,8 @@
"Does not start with": "開頭不是",
"Ends with": "結尾是",
"Does not end with": "結尾不是",
"Matches regex": "正則匹配",
"Does not match regex": "不匹配正則",
"Latitude is between": "緯度介於",
"Latitude is not between": "緯度不介於",
"Longitude is between": "經度介於",
+45 -10
View File
@@ -1499,7 +1499,9 @@ type DescriptionConditionOperator = TransactionExplorerConditionOperatorType.IsE
TransactionExplorerConditionOperatorType.StartsWith |
TransactionExplorerConditionOperatorType.NotStartsWith |
TransactionExplorerConditionOperatorType.EndsWith |
TransactionExplorerConditionOperatorType.NotEndsWith;
TransactionExplorerConditionOperatorType.NotEndsWith |
TransactionExplorerConditionOperatorType.RegexMatch |
TransactionExplorerConditionOperatorType.NotRegexMatch;
export class TransactionExplorerDescriptionCondition implements TransactionExplorerCondition<TransactionExplorerConditionFieldType.Description, string> {
public static readonly supportedOperators: PartialRecord<TransactionExplorerConditionOperatorType, true> = {
@@ -1512,8 +1514,13 @@ export class TransactionExplorerDescriptionCondition implements TransactionExplo
[TransactionExplorerConditionOperatorType.StartsWith]: true,
[TransactionExplorerConditionOperatorType.NotStartsWith]: true,
[TransactionExplorerConditionOperatorType.EndsWith]: true,
[TransactionExplorerConditionOperatorType.NotEndsWith]: true
[TransactionExplorerConditionOperatorType.NotEndsWith]: true,
[TransactionExplorerConditionOperatorType.RegexMatch]: true,
[TransactionExplorerConditionOperatorType.NotRegexMatch]: true
};
private static cachedRegex: RegExp | undefined = undefined;
private static cachedRegexPattern: string | undefined = undefined;
public readonly field = TransactionExplorerConditionFieldType.Description;
public readonly operator: DescriptionConditionOperator = TransactionExplorerConditionOperatorType.Contains;
public value: string;
@@ -1554,34 +1561,62 @@ export class TransactionExplorerDescriptionCondition implements TransactionExplo
return description.endsWith(this.value);
} else if (this.operator === TransactionExplorerConditionOperatorType.NotEndsWith) {
return !description.endsWith(this.value);
} else if (this.operator === TransactionExplorerConditionOperatorType.RegexMatch) {
return this.getCachedRegex()?.test(description) ?? false;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotRegexMatch) {
return !(this.getCachedRegex()?.test(description) ?? false);
}
return false;
}
public toExpression(): string {
const escapedValue = this.value.replace(/'/g, "''");
if (this.operator === TransactionExplorerConditionOperatorType.IsEmpty) {
return `description IS EMPTY`;
} else if (this.operator === TransactionExplorerConditionOperatorType.IsNotEmpty) {
return `description IS NOT EMPTY`;
} else if (this.operator === TransactionExplorerConditionOperatorType.Equals) {
return `description = '${this.value.replace(/'/g, "''")}'`;
return `description = '${escapedValue}'`;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotEquals) {
return `description <> '${this.value.replace(/'/g, "''")}'`;
return `description <> '${escapedValue}'`;
} else if (this.operator === TransactionExplorerConditionOperatorType.Contains) {
return `description CONTAINS '${this.value.replace(/'/g, "''")}'`;
return `description CONTAINS '${escapedValue}'`;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotContains) {
return `description NOT CONTAINS '${this.value.replace(/'/g, "''")}'`;
return `description NOT CONTAINS '${escapedValue}'`;
} else if (this.operator === TransactionExplorerConditionOperatorType.StartsWith) {
return `description STARTS WITH '${this.value.replace(/'/g, "''")}'`;
return `description STARTS WITH '${escapedValue}'`;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotStartsWith) {
return `description NOT STARTS WITH '${this.value.replace(/'/g, "''")}'`;
return `description NOT STARTS WITH '${escapedValue}'`;
} else if (this.operator === TransactionExplorerConditionOperatorType.EndsWith) {
return `description ENDS WITH '${this.value.replace(/'/g, "''")}'`;
return `description ENDS WITH '${escapedValue}'`;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotEndsWith) {
return `description NOT ENDS WITH '${this.value.replace(/'/g, "''")}'`;
return `description NOT ENDS WITH '${escapedValue}'`;
} else if (this.operator === TransactionExplorerConditionOperatorType.RegexMatch) {
return `description REGEXP LIKE '${escapedValue}'`;
} else if (this.operator === TransactionExplorerConditionOperatorType.NotRegexMatch) {
return `description NOT REGEXP LIKE '${escapedValue}'`;
}
return '';
}
private getCachedRegex(): RegExp | undefined {
if (this.operator !== TransactionExplorerConditionOperatorType.RegexMatch && this.operator !== TransactionExplorerConditionOperatorType.NotRegexMatch) {
return undefined;
}
if (TransactionExplorerDescriptionCondition.cachedRegexPattern !== this.value) {
try {
TransactionExplorerDescriptionCondition.cachedRegex = new RegExp(this.value);
TransactionExplorerDescriptionCondition.cachedRegexPattern = this.value;
} catch {
TransactionExplorerDescriptionCondition.cachedRegex = undefined;
TransactionExplorerDescriptionCondition.cachedRegexPattern = undefined;
}
}
return TransactionExplorerDescriptionCondition.cachedRegex;
}
}