@oneuptime/common 10.0.69 → 10.0.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/KubernetesCluster.ts +7 -0
- package/Models/DatabaseModels/Project.ts +5 -5
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776865086264-MigrationName.ts +11 -8
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776881254913-DedupeKubernetesClustersAndAddUniqueIndex.ts +137 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/AIBillingService.ts +2 -2
- package/Server/Services/BillingService.ts +116 -48
- package/Server/Services/DatabaseService.ts +10 -27
- package/Server/Services/KubernetesResourceService.ts +33 -10
- package/Server/Services/NotificationService.ts +2 -2
- package/Server/Types/Database/QueryHelper.ts +127 -0
- package/Server/Types/Database/QueryUtil.ts +250 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +79 -0
- package/Server/Utils/Monitor/MonitorIncident.ts +79 -0
- package/Types/BaseDatabase/EndsWith.ts +41 -0
- package/Types/BaseDatabase/IncludesAll.ts +45 -0
- package/Types/BaseDatabase/IncludesNone.ts +45 -0
- package/Types/BaseDatabase/NotContains.ts +41 -0
- package/Types/BaseDatabase/StartsWith.ts +41 -0
- package/Types/Email.ts +50 -0
- package/Types/JSON.ts +20 -0
- package/Types/SerializableObjectDictionary.ts +10 -0
- package/UI/Components/Filters/BooleanFilter.tsx +1 -0
- package/UI/Components/Filters/DateFilter.tsx +220 -25
- package/UI/Components/Filters/DropdownFilter.tsx +1 -0
- package/UI/Components/Filters/EntityFilter.tsx +229 -41
- package/UI/Components/Filters/FilterViewer.tsx +231 -147
- package/UI/Components/Filters/FilterViewerItem.tsx +1 -11
- package/UI/Components/Filters/FiltersForm.tsx +146 -97
- package/UI/Components/Filters/NumberFilter.tsx +220 -34
- package/UI/Components/Filters/OperatorSelector.tsx +91 -0
- package/UI/Components/Filters/TextFilter.tsx +183 -71
- package/UI/Components/Filters/Types/FilterOperator.ts +73 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +10 -0
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +9 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +5 -5
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776865086264-MigrationName.js +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776865086264-MigrationName.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776881254913-DedupeKubernetesClustersAndAddUniqueIndex.js +125 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776881254913-DedupeKubernetesClustersAndAddUniqueIndex.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AIBillingService.js +2 -2
- package/build/dist/Server/Services/AIBillingService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +99 -39
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +9 -6
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesResourceService.js +4 -2
- package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
- package/build/dist/Server/Services/NotificationService.js +2 -2
- package/build/dist/Server/Services/NotificationService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +110 -0
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryUtil.js +186 -0
- package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +68 -0
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +68 -0
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Types/BaseDatabase/EndsWith.js +31 -0
- package/build/dist/Types/BaseDatabase/EndsWith.js.map +1 -0
- package/build/dist/Types/BaseDatabase/IncludesAll.js +34 -0
- package/build/dist/Types/BaseDatabase/IncludesAll.js.map +1 -0
- package/build/dist/Types/BaseDatabase/IncludesNone.js +34 -0
- package/build/dist/Types/BaseDatabase/IncludesNone.js.map +1 -0
- package/build/dist/Types/BaseDatabase/NotContains.js +31 -0
- package/build/dist/Types/BaseDatabase/NotContains.js.map +1 -0
- package/build/dist/Types/BaseDatabase/StartsWith.js +31 -0
- package/build/dist/Types/BaseDatabase/StartsWith.js.map +1 -0
- package/build/dist/Types/Email.js +42 -0
- package/build/dist/Types/Email.js.map +1 -1
- package/build/dist/Types/JSON.js +5 -0
- package/build/dist/Types/JSON.js.map +1 -1
- package/build/dist/Types/SerializableObjectDictionary.js +10 -0
- package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
- package/build/dist/UI/Components/Filters/BooleanFilter.js +1 -1
- package/build/dist/UI/Components/Filters/BooleanFilter.js.map +1 -1
- package/build/dist/UI/Components/Filters/DateFilter.js +155 -14
- package/build/dist/UI/Components/Filters/DateFilter.js.map +1 -1
- package/build/dist/UI/Components/Filters/DropdownFilter.js +1 -1
- package/build/dist/UI/Components/Filters/DropdownFilter.js.map +1 -1
- package/build/dist/UI/Components/Filters/EntityFilter.js +181 -30
- package/build/dist/UI/Components/Filters/EntityFilter.js.map +1 -1
- package/build/dist/UI/Components/Filters/FilterViewer.js +188 -98
- package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
- package/build/dist/UI/Components/Filters/FilterViewerItem.js +1 -6
- package/build/dist/UI/Components/Filters/FilterViewerItem.js.map +1 -1
- package/build/dist/UI/Components/Filters/FiltersForm.js +46 -38
- package/build/dist/UI/Components/Filters/FiltersForm.js.map +1 -1
- package/build/dist/UI/Components/Filters/NumberFilter.js +164 -23
- package/build/dist/UI/Components/Filters/NumberFilter.js.map +1 -1
- package/build/dist/UI/Components/Filters/OperatorSelector.js +41 -0
- package/build/dist/UI/Components/Filters/OperatorSelector.js.map +1 -0
- package/build/dist/UI/Components/Filters/TextFilter.js +131 -53
- package/build/dist/UI/Components/Filters/TextFilter.js.map +1 -1
- package/build/dist/UI/Components/Filters/Types/FilterOperator.js +63 -0
- package/build/dist/UI/Components/Filters/Types/FilterOperator.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +9 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import BadDataException from "../Exception/BadDataException";
|
|
2
|
+
import { JSONObject, ObjectType } from "../JSON";
|
|
3
|
+
import JSONFunctions from "../JSONFunctions";
|
|
4
|
+
import ObjectID from "../ObjectID";
|
|
5
|
+
import QueryOperator from "./QueryOperator";
|
|
6
|
+
|
|
7
|
+
export type IncludesAllType = Array<string> | Array<ObjectID> | Array<number>;
|
|
8
|
+
|
|
9
|
+
export default class IncludesAll extends QueryOperator<IncludesAllType> {
|
|
10
|
+
private _values: IncludesAllType = [];
|
|
11
|
+
|
|
12
|
+
public get values(): IncludesAllType {
|
|
13
|
+
return this._values;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public set values(v: IncludesAllType) {
|
|
17
|
+
this._values = v;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public constructor(values: IncludesAllType) {
|
|
21
|
+
super();
|
|
22
|
+
this.values = values;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public override toJSON(): JSONObject {
|
|
26
|
+
return {
|
|
27
|
+
_type: ObjectType.IncludesAll,
|
|
28
|
+
value: (this as IncludesAll)._values,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public static override fromJSON(json: JSONObject): IncludesAll {
|
|
33
|
+
if (json["_type"] === ObjectType.IncludesAll) {
|
|
34
|
+
const valuesArray: Array<string> = [];
|
|
35
|
+
|
|
36
|
+
for (const value of (json["value"] as Array<string>) || []) {
|
|
37
|
+
valuesArray.push(JSONFunctions.deserializeValue(value) as string);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return new IncludesAll(valuesArray);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
throw new BadDataException("Invalid JSON: " + JSON.stringify(json));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import BadDataException from "../Exception/BadDataException";
|
|
2
|
+
import { JSONObject, ObjectType } from "../JSON";
|
|
3
|
+
import JSONFunctions from "../JSONFunctions";
|
|
4
|
+
import ObjectID from "../ObjectID";
|
|
5
|
+
import QueryOperator from "./QueryOperator";
|
|
6
|
+
|
|
7
|
+
export type IncludesNoneType = Array<string> | Array<ObjectID> | Array<number>;
|
|
8
|
+
|
|
9
|
+
export default class IncludesNone extends QueryOperator<IncludesNoneType> {
|
|
10
|
+
private _values: IncludesNoneType = [];
|
|
11
|
+
|
|
12
|
+
public get values(): IncludesNoneType {
|
|
13
|
+
return this._values;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public set values(v: IncludesNoneType) {
|
|
17
|
+
this._values = v;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public constructor(values: IncludesNoneType) {
|
|
21
|
+
super();
|
|
22
|
+
this.values = values;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public override toJSON(): JSONObject {
|
|
26
|
+
return {
|
|
27
|
+
_type: ObjectType.IncludesNone,
|
|
28
|
+
value: (this as IncludesNone)._values,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public static override fromJSON(json: JSONObject): IncludesNone {
|
|
33
|
+
if (json["_type"] === ObjectType.IncludesNone) {
|
|
34
|
+
const valuesArray: Array<string> = [];
|
|
35
|
+
|
|
36
|
+
for (const value of (json["value"] as Array<string>) || []) {
|
|
37
|
+
valuesArray.push(JSONFunctions.deserializeValue(value) as string);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return new IncludesNone(valuesArray);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
throw new BadDataException("Invalid JSON: " + JSON.stringify(json));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import BadDataException from "../Exception/BadDataException";
|
|
2
|
+
import { JSONObject, ObjectType } from "../JSON";
|
|
3
|
+
import QueryOperator from "./QueryOperator";
|
|
4
|
+
|
|
5
|
+
export default class NotContains<T extends string> extends QueryOperator<T> {
|
|
6
|
+
private _value!: T;
|
|
7
|
+
|
|
8
|
+
public get value(): T {
|
|
9
|
+
return this._value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public set value(v: T) {
|
|
13
|
+
this._value = v;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public constructor(value: T) {
|
|
17
|
+
super();
|
|
18
|
+
this.value = value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public override toString(): T {
|
|
22
|
+
return this.value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public override toJSON(): JSONObject {
|
|
26
|
+
return {
|
|
27
|
+
_type: ObjectType.NotContains,
|
|
28
|
+
value: (this as NotContains<T>).toString(),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public static override fromJSON<T extends string>(
|
|
33
|
+
json: JSONObject,
|
|
34
|
+
): NotContains<T> {
|
|
35
|
+
if (json["_type"] === ObjectType.NotContains) {
|
|
36
|
+
return new NotContains<T>((json["value"] as T) || ("" as T));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
throw new BadDataException("Invalid JSON: " + JSON.stringify(json));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import BadDataException from "../Exception/BadDataException";
|
|
2
|
+
import { JSONObject, ObjectType } from "../JSON";
|
|
3
|
+
import QueryOperator from "./QueryOperator";
|
|
4
|
+
|
|
5
|
+
export default class StartsWith<T extends string> extends QueryOperator<T> {
|
|
6
|
+
private _value!: T;
|
|
7
|
+
|
|
8
|
+
public get value(): T {
|
|
9
|
+
return this._value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public set value(v: T) {
|
|
13
|
+
this._value = v;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public constructor(value: T) {
|
|
17
|
+
super();
|
|
18
|
+
this.value = value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public override toString(): T {
|
|
22
|
+
return this.value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public override toJSON(): JSONObject {
|
|
26
|
+
return {
|
|
27
|
+
_type: ObjectType.StartsWith,
|
|
28
|
+
value: (this as StartsWith<T>).toString(),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public static override fromJSON<T extends string>(
|
|
33
|
+
json: JSONObject,
|
|
34
|
+
): StartsWith<T> {
|
|
35
|
+
if (json["_type"] === ObjectType.StartsWith) {
|
|
36
|
+
return new StartsWith<T>((json["value"] as T) || ("" as T));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
throw new BadDataException("Invalid JSON: " + JSON.stringify(json));
|
|
40
|
+
}
|
|
41
|
+
}
|
package/Types/Email.ts
CHANGED
|
@@ -75,6 +75,56 @@ export default class Email extends DatabaseProperty {
|
|
|
75
75
|
return new Email(value);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
public static parseList(value: string | null | undefined): Array<Email> {
|
|
79
|
+
if (!value) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const seen: Set<string> = new Set<string>();
|
|
84
|
+
const emails: Array<Email> = [];
|
|
85
|
+
|
|
86
|
+
for (const part of value.split(/[,;\s]+/)) {
|
|
87
|
+
const trimmed: string = part.trim();
|
|
88
|
+
if (!trimmed) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const email: Email = new Email(trimmed);
|
|
92
|
+
const key: string = email.toString();
|
|
93
|
+
if (!seen.has(key)) {
|
|
94
|
+
seen.add(key);
|
|
95
|
+
emails.push(email);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return emails;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public static isValidList(value: string | null | undefined): boolean {
|
|
103
|
+
if (!value) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const parts: Array<string> = value
|
|
108
|
+
.split(/[,;\s]+/)
|
|
109
|
+
.map((p: string): string => {
|
|
110
|
+
return p.trim();
|
|
111
|
+
})
|
|
112
|
+
.filter((p: string): boolean => {
|
|
113
|
+
return p.length > 0;
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (parts.length === 0) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
for (const part of parts) {
|
|
121
|
+
if (!Email.isValid(part)) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
78
128
|
public static override fromJSON(json: JSONObject): Email {
|
|
79
129
|
if (json["_type"] === ObjectType.Email) {
|
|
80
130
|
return new Email((json["value"] as string) || "");
|
package/Types/JSON.ts
CHANGED
|
@@ -7,6 +7,11 @@ import GreaterThan from "./BaseDatabase/GreaterThan";
|
|
|
7
7
|
import GreaterThanOrEqual from "./BaseDatabase/GreaterThanOrEqual";
|
|
8
8
|
import InBetween from "./BaseDatabase/InBetween";
|
|
9
9
|
import Includes from "./BaseDatabase/Includes";
|
|
10
|
+
import IncludesAll from "./BaseDatabase/IncludesAll";
|
|
11
|
+
import IncludesNone from "./BaseDatabase/IncludesNone";
|
|
12
|
+
import StartsWith from "./BaseDatabase/StartsWith";
|
|
13
|
+
import EndsWith from "./BaseDatabase/EndsWith";
|
|
14
|
+
import NotContains from "./BaseDatabase/NotContains";
|
|
10
15
|
import LessThan from "./BaseDatabase/LessThan";
|
|
11
16
|
import LessThanOrEqual from "./BaseDatabase/LessThanOrEqual";
|
|
12
17
|
import NotEqual from "./BaseDatabase/NotEqual";
|
|
@@ -71,6 +76,11 @@ export enum ObjectType {
|
|
|
71
76
|
NotNull = "NotNull",
|
|
72
77
|
IsNull = "IsNull",
|
|
73
78
|
Includes = "Includes",
|
|
79
|
+
IncludesAll = "IncludesAll",
|
|
80
|
+
IncludesNone = "IncludesNone",
|
|
81
|
+
StartsWith = "StartsWith",
|
|
82
|
+
EndsWith = "EndsWith",
|
|
83
|
+
NotContains = "NotContains",
|
|
74
84
|
DashboardComponent = "DashboardComponent",
|
|
75
85
|
DashboardViewConfig = "DashboardViewConfig",
|
|
76
86
|
}
|
|
@@ -157,6 +167,16 @@ export type JSONValue =
|
|
|
157
167
|
| Array<StartAndEndTime>
|
|
158
168
|
| Includes
|
|
159
169
|
| Array<Includes>
|
|
170
|
+
| IncludesAll
|
|
171
|
+
| Array<IncludesAll>
|
|
172
|
+
| IncludesNone
|
|
173
|
+
| Array<IncludesNone>
|
|
174
|
+
| StartsWith<string>
|
|
175
|
+
| Array<StartsWith<string>>
|
|
176
|
+
| EndsWith<string>
|
|
177
|
+
| Array<EndsWith<string>>
|
|
178
|
+
| NotContains<string>
|
|
179
|
+
| Array<NotContains<string>>
|
|
160
180
|
| DashboardViewConfig;
|
|
161
181
|
|
|
162
182
|
export interface JSONObject {
|
|
@@ -7,6 +7,11 @@ import GreaterThan from "./BaseDatabase/GreaterThan";
|
|
|
7
7
|
import GreaterThanOrEqual from "./BaseDatabase/GreaterThanOrEqual";
|
|
8
8
|
import InBetween from "./BaseDatabase/InBetween";
|
|
9
9
|
import Includes from "./BaseDatabase/Includes";
|
|
10
|
+
import IncludesAll from "./BaseDatabase/IncludesAll";
|
|
11
|
+
import IncludesNone from "./BaseDatabase/IncludesNone";
|
|
12
|
+
import StartsWith from "./BaseDatabase/StartsWith";
|
|
13
|
+
import EndsWith from "./BaseDatabase/EndsWith";
|
|
14
|
+
import NotContains from "./BaseDatabase/NotContains";
|
|
10
15
|
import IsNull from "./BaseDatabase/IsNull";
|
|
11
16
|
import LessThan from "./BaseDatabase/LessThan";
|
|
12
17
|
import LessThanOrEqual from "./BaseDatabase/LessThanOrEqual";
|
|
@@ -65,6 +70,11 @@ const SerializableObjectDictionary: Dictionary<any> = {
|
|
|
65
70
|
[ObjectType.HashedString]: HashedString,
|
|
66
71
|
[ObjectType.InBetween]: InBetween,
|
|
67
72
|
[ObjectType.Includes]: Includes,
|
|
73
|
+
[ObjectType.IncludesAll]: IncludesAll,
|
|
74
|
+
[ObjectType.IncludesNone]: IncludesNone,
|
|
75
|
+
[ObjectType.StartsWith]: StartsWith,
|
|
76
|
+
[ObjectType.EndsWith]: EndsWith,
|
|
77
|
+
[ObjectType.NotContains]: NotContains,
|
|
68
78
|
[ObjectType.NotNull]: NotNull,
|
|
69
79
|
[ObjectType.IsNull]: IsNull,
|
|
70
80
|
[ObjectType.Recurring]: Recurring,
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import StartAndEndDate, { StartAndEndDateType } from "../Date/StartAndEndDate";
|
|
1
|
+
import Input, { InputType } from "../Input/Input";
|
|
3
2
|
import FieldType from "../Types/FieldType";
|
|
4
3
|
import Filter from "./Types/Filter";
|
|
5
4
|
import FilterData from "./Types/FilterData";
|
|
5
|
+
import FilterOperator from "./Types/FilterOperator";
|
|
6
|
+
import OperatorSelector from "./OperatorSelector";
|
|
6
7
|
import InBetween from "../../../Types/BaseDatabase/InBetween";
|
|
8
|
+
import GreaterThan from "../../../Types/BaseDatabase/GreaterThan";
|
|
9
|
+
import LessThan from "../../../Types/BaseDatabase/LessThan";
|
|
10
|
+
import EqualTo from "../../../Types/BaseDatabase/EqualTo";
|
|
11
|
+
import IsNull from "../../../Types/BaseDatabase/IsNull";
|
|
12
|
+
import NotNull from "../../../Types/BaseDatabase/NotNull";
|
|
13
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
7
14
|
import GenericObject from "../../../Types/GenericObject";
|
|
8
|
-
import React, { ReactElement } from "react";
|
|
15
|
+
import React, { ReactElement, useEffect, useState } from "react";
|
|
9
16
|
|
|
10
17
|
export interface ComponentProps<T extends GenericObject> {
|
|
11
18
|
filter: Filter<T>;
|
|
@@ -17,38 +24,226 @@ type DateFilterFunction = <T extends GenericObject>(
|
|
|
17
24
|
props: ComponentProps<T>,
|
|
18
25
|
) => ReactElement;
|
|
19
26
|
|
|
27
|
+
const DATE_OPERATORS: Array<FilterOperator> = [
|
|
28
|
+
FilterOperator.Is,
|
|
29
|
+
FilterOperator.Before,
|
|
30
|
+
FilterOperator.After,
|
|
31
|
+
FilterOperator.Between,
|
|
32
|
+
FilterOperator.IsEmpty,
|
|
33
|
+
FilterOperator.IsNotEmpty,
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
type DateState = {
|
|
37
|
+
operator: FilterOperator;
|
|
38
|
+
start: Date | null;
|
|
39
|
+
end: Date | null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type ToDateFunction = (value: unknown) => Date | null;
|
|
43
|
+
|
|
44
|
+
const toDate: ToDateFunction = (value: unknown): Date | null => {
|
|
45
|
+
if (!value) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
if (value instanceof Date) {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
return OneUptimeDate.fromString(value as string);
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type DetectStateFunction = (rawValue: unknown) => DateState;
|
|
59
|
+
|
|
60
|
+
const detectState: DetectStateFunction = (rawValue: unknown): DateState => {
|
|
61
|
+
if (rawValue instanceof InBetween) {
|
|
62
|
+
const start: Date | null = toDate(rawValue.startValue as unknown);
|
|
63
|
+
const end: Date | null = toDate(rawValue.endValue as unknown);
|
|
64
|
+
|
|
65
|
+
// If start/end match the bounds of a single day, treat as "Is".
|
|
66
|
+
if (start && end) {
|
|
67
|
+
const startOfDay: Date = OneUptimeDate.getStartOfDay(start);
|
|
68
|
+
const endOfDay: Date = OneUptimeDate.getEndOfDay(start);
|
|
69
|
+
if (
|
|
70
|
+
start.getTime() === startOfDay.getTime() &&
|
|
71
|
+
end.getTime() === endOfDay.getTime()
|
|
72
|
+
) {
|
|
73
|
+
return { operator: FilterOperator.Is, start, end: null };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { operator: FilterOperator.Between, start, end };
|
|
78
|
+
}
|
|
79
|
+
if (rawValue instanceof GreaterThan) {
|
|
80
|
+
return {
|
|
81
|
+
operator: FilterOperator.After,
|
|
82
|
+
start: toDate(rawValue.value as unknown),
|
|
83
|
+
end: null,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (rawValue instanceof LessThan) {
|
|
87
|
+
return {
|
|
88
|
+
operator: FilterOperator.Before,
|
|
89
|
+
start: toDate(rawValue.value as unknown),
|
|
90
|
+
end: null,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (rawValue instanceof EqualTo) {
|
|
94
|
+
return {
|
|
95
|
+
operator: FilterOperator.Is,
|
|
96
|
+
start: toDate(rawValue.value as unknown),
|
|
97
|
+
end: null,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (rawValue instanceof IsNull) {
|
|
101
|
+
return { operator: FilterOperator.IsEmpty, start: null, end: null };
|
|
102
|
+
}
|
|
103
|
+
if (rawValue instanceof NotNull) {
|
|
104
|
+
return { operator: FilterOperator.IsNotEmpty, start: null, end: null };
|
|
105
|
+
}
|
|
106
|
+
return { operator: FilterOperator.Is, start: null, end: null };
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
type BuildValueFunction = (state: DateState, isDateTime: boolean) => unknown;
|
|
110
|
+
|
|
111
|
+
const buildValue: BuildValueFunction = (
|
|
112
|
+
state: DateState,
|
|
113
|
+
isDateTime: boolean,
|
|
114
|
+
): unknown => {
|
|
115
|
+
switch (state.operator) {
|
|
116
|
+
case FilterOperator.Is: {
|
|
117
|
+
if (!state.start) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
if (isDateTime) {
|
|
121
|
+
return new EqualTo(state.start as any);
|
|
122
|
+
}
|
|
123
|
+
return new InBetween(
|
|
124
|
+
OneUptimeDate.getStartOfDay(state.start) as any,
|
|
125
|
+
OneUptimeDate.getEndOfDay(state.start) as any,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
case FilterOperator.Before:
|
|
129
|
+
return state.start ? new LessThan(state.start) : undefined;
|
|
130
|
+
case FilterOperator.After:
|
|
131
|
+
return state.start ? new GreaterThan(state.start) : undefined;
|
|
132
|
+
case FilterOperator.Between: {
|
|
133
|
+
if (!state.start || !state.end) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
return new InBetween(
|
|
137
|
+
(isDateTime
|
|
138
|
+
? state.start
|
|
139
|
+
: OneUptimeDate.getStartOfDay(state.start)) as any,
|
|
140
|
+
(isDateTime ? state.end : OneUptimeDate.getEndOfDay(state.end)) as any,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
case FilterOperator.IsEmpty:
|
|
144
|
+
return new IsNull();
|
|
145
|
+
case FilterOperator.IsNotEmpty:
|
|
146
|
+
return new NotNull();
|
|
147
|
+
default:
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
20
152
|
const DateFilter: DateFilterFunction = <T extends GenericObject>(
|
|
21
153
|
props: ComponentProps<T>,
|
|
22
154
|
): ReactElement => {
|
|
23
155
|
const filter: Filter<T> = props.filter;
|
|
24
|
-
const filterData: FilterData<T> = { ...props.filterData };
|
|
25
156
|
|
|
26
157
|
if (filter.type !== FieldType.Date && filter.type !== FieldType.DateTime) {
|
|
27
158
|
return <></>;
|
|
28
159
|
}
|
|
29
160
|
|
|
161
|
+
const isDateTime: boolean = filter.type === FieldType.DateTime;
|
|
162
|
+
const detected: DateState = detectState(props.filterData[filter.key]);
|
|
163
|
+
|
|
164
|
+
const [localOperator, setLocalOperator] = useState<FilterOperator>(
|
|
165
|
+
detected.operator,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
const raw: unknown = props.filterData[filter.key];
|
|
170
|
+
if (raw !== undefined && raw !== null) {
|
|
171
|
+
setLocalOperator(detected.operator);
|
|
172
|
+
}
|
|
173
|
+
}, [props.filterData[filter.key]]);
|
|
174
|
+
|
|
175
|
+
const state: DateState = { ...detected, operator: localOperator };
|
|
176
|
+
|
|
177
|
+
const valuelessOperator: boolean =
|
|
178
|
+
state.operator === FilterOperator.IsEmpty ||
|
|
179
|
+
state.operator === FilterOperator.IsNotEmpty;
|
|
180
|
+
const isBetween: boolean = state.operator === FilterOperator.Between;
|
|
181
|
+
|
|
182
|
+
type ApplyFunction = (nextState: DateState) => void;
|
|
183
|
+
|
|
184
|
+
const apply: ApplyFunction = (nextState: DateState): void => {
|
|
185
|
+
if (!filter.key) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
setLocalOperator(nextState.operator);
|
|
189
|
+
const next: FilterData<T> = { ...props.filterData };
|
|
190
|
+
const built: unknown = buildValue(nextState, isDateTime);
|
|
191
|
+
if (built === undefined) {
|
|
192
|
+
delete next[filter.key];
|
|
193
|
+
} else {
|
|
194
|
+
next[filter.key] = built as any;
|
|
195
|
+
}
|
|
196
|
+
props.onFilterChanged?.(next);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const inputType: InputType = isDateTime
|
|
200
|
+
? InputType.DATETIME_LOCAL
|
|
201
|
+
: InputType.DATE;
|
|
202
|
+
|
|
30
203
|
return (
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
204
|
+
<div className="flex gap-2 items-start">
|
|
205
|
+
<OperatorSelector
|
|
206
|
+
value={state.operator}
|
|
207
|
+
options={DATE_OPERATORS}
|
|
208
|
+
onChange={(nextOperator: FilterOperator) => {
|
|
209
|
+
apply({ ...state, operator: nextOperator });
|
|
210
|
+
}}
|
|
211
|
+
/>
|
|
212
|
+
{!valuelessOperator && (
|
|
213
|
+
<div
|
|
214
|
+
className={isBetween ? "flex-1 flex gap-2 min-w-0" : "flex-1 min-w-0"}
|
|
215
|
+
>
|
|
216
|
+
<div className="flex-1 min-w-0">
|
|
217
|
+
<Input
|
|
218
|
+
key={`${filter.key as string}-start-${state.operator}`}
|
|
219
|
+
onChange={(changed: string | Date) => {
|
|
220
|
+
const parsed: Date | null = toDate(changed);
|
|
221
|
+
apply({ ...state, start: parsed });
|
|
222
|
+
}}
|
|
223
|
+
value={state.start || ""}
|
|
224
|
+
placeholder={isBetween ? "From" : `Filter by ${filter.title}`}
|
|
225
|
+
type={inputType}
|
|
226
|
+
outerDivClassName="relative rounded-md w-full"
|
|
227
|
+
/>
|
|
228
|
+
</div>
|
|
229
|
+
{isBetween && (
|
|
230
|
+
<div className="flex-1 min-w-0">
|
|
231
|
+
<Input
|
|
232
|
+
key={`${filter.key as string}-end-${state.operator}`}
|
|
233
|
+
onChange={(changed: string | Date) => {
|
|
234
|
+
const parsed: Date | null = toDate(changed);
|
|
235
|
+
apply({ ...state, end: parsed });
|
|
236
|
+
}}
|
|
237
|
+
value={state.end || ""}
|
|
238
|
+
placeholder="To"
|
|
239
|
+
type={inputType}
|
|
240
|
+
outerDivClassName="relative rounded-md w-full"
|
|
241
|
+
/>
|
|
242
|
+
</div>
|
|
243
|
+
)}
|
|
244
|
+
</div>
|
|
245
|
+
)}
|
|
246
|
+
</div>
|
|
52
247
|
);
|
|
53
248
|
};
|
|
54
249
|
|
|
@@ -61,6 +61,7 @@ const DropdownFilter: DropdownFilterFunction = <T extends GenericObject>(
|
|
|
61
61
|
value={dropdownValues}
|
|
62
62
|
isMultiSelect={props.isMultiSelect || false}
|
|
63
63
|
placeholder={`Filter by ${filter.title}`}
|
|
64
|
+
className="relative rounded-md w-full overflow-visible"
|
|
64
65
|
/>
|
|
65
66
|
);
|
|
66
67
|
}
|