@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
|
@@ -2,8 +2,15 @@ import Dropdown, { DropdownOption, DropdownValue } from "../Dropdown/Dropdown";
|
|
|
2
2
|
import FieldType from "../Types/FieldType";
|
|
3
3
|
import Filter from "./Types/Filter";
|
|
4
4
|
import FilterData from "./Types/FilterData";
|
|
5
|
+
import FilterOperator from "./Types/FilterOperator";
|
|
6
|
+
import OperatorSelector from "./OperatorSelector";
|
|
5
7
|
import GenericObject from "../../../Types/GenericObject";
|
|
6
|
-
import
|
|
8
|
+
import Includes from "../../../Types/BaseDatabase/Includes";
|
|
9
|
+
import IncludesAll from "../../../Types/BaseDatabase/IncludesAll";
|
|
10
|
+
import IncludesNone from "../../../Types/BaseDatabase/IncludesNone";
|
|
11
|
+
import IsNull from "../../../Types/BaseDatabase/IsNull";
|
|
12
|
+
import NotNull from "../../../Types/BaseDatabase/NotNull";
|
|
13
|
+
import React, { ReactElement, useEffect, useState } from "react";
|
|
7
14
|
|
|
8
15
|
export interface ComponentProps<T extends GenericObject> {
|
|
9
16
|
filter: Filter<T>;
|
|
@@ -15,56 +22,237 @@ type EntityFilterFunction = <T extends GenericObject>(
|
|
|
15
22
|
props: ComponentProps<T>,
|
|
16
23
|
) => ReactElement;
|
|
17
24
|
|
|
25
|
+
const ENTITY_ARRAY_OPERATORS: Array<FilterOperator> = [
|
|
26
|
+
FilterOperator.HasAnyOf,
|
|
27
|
+
FilterOperator.HasAllOf,
|
|
28
|
+
FilterOperator.HasNoneOf,
|
|
29
|
+
FilterOperator.IsEmpty,
|
|
30
|
+
FilterOperator.IsNotEmpty,
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const ENTITY_OPERATORS: Array<FilterOperator> = [
|
|
34
|
+
FilterOperator.Is,
|
|
35
|
+
FilterOperator.IsNot,
|
|
36
|
+
FilterOperator.IsEmpty,
|
|
37
|
+
FilterOperator.IsNotEmpty,
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
type EntityState = {
|
|
41
|
+
operator: FilterOperator;
|
|
42
|
+
values: Array<string>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
type DetectStateFunction = (rawValue: unknown) => EntityState;
|
|
46
|
+
|
|
47
|
+
const detectArrayState: DetectStateFunction = (
|
|
48
|
+
rawValue: unknown,
|
|
49
|
+
): EntityState => {
|
|
50
|
+
if (rawValue instanceof IncludesAll) {
|
|
51
|
+
return {
|
|
52
|
+
operator: FilterOperator.HasAllOf,
|
|
53
|
+
values: (rawValue.values as Array<string>).map((v: string) => {
|
|
54
|
+
return v.toString();
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (rawValue instanceof IncludesNone) {
|
|
59
|
+
return {
|
|
60
|
+
operator: FilterOperator.HasNoneOf,
|
|
61
|
+
values: (rawValue.values as Array<string>).map((v: string) => {
|
|
62
|
+
return v.toString();
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (rawValue instanceof Includes) {
|
|
67
|
+
return {
|
|
68
|
+
operator: FilterOperator.HasAnyOf,
|
|
69
|
+
values: (rawValue.values as Array<string>).map((v: string) => {
|
|
70
|
+
return v.toString();
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (Array.isArray(rawValue)) {
|
|
75
|
+
return {
|
|
76
|
+
operator: FilterOperator.HasAnyOf,
|
|
77
|
+
values: (rawValue as Array<string>).map((v: string) => {
|
|
78
|
+
return v.toString();
|
|
79
|
+
}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (rawValue instanceof IsNull) {
|
|
83
|
+
return { operator: FilterOperator.IsEmpty, values: [] };
|
|
84
|
+
}
|
|
85
|
+
if (rawValue instanceof NotNull) {
|
|
86
|
+
return { operator: FilterOperator.IsNotEmpty, values: [] };
|
|
87
|
+
}
|
|
88
|
+
return { operator: FilterOperator.HasAnyOf, values: [] };
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const detectSingleState: DetectStateFunction = (
|
|
92
|
+
rawValue: unknown,
|
|
93
|
+
): EntityState => {
|
|
94
|
+
if (rawValue instanceof IsNull) {
|
|
95
|
+
return { operator: FilterOperator.IsEmpty, values: [] };
|
|
96
|
+
}
|
|
97
|
+
if (rawValue instanceof NotNull) {
|
|
98
|
+
return { operator: FilterOperator.IsNotEmpty, values: [] };
|
|
99
|
+
}
|
|
100
|
+
if (typeof rawValue === "string" && rawValue) {
|
|
101
|
+
return { operator: FilterOperator.Is, values: [rawValue] };
|
|
102
|
+
}
|
|
103
|
+
return { operator: FilterOperator.Is, values: [] };
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
type BuildValueFunction = (state: EntityState) => unknown;
|
|
107
|
+
|
|
108
|
+
const buildArrayValue: BuildValueFunction = (state: EntityState): unknown => {
|
|
109
|
+
switch (state.operator) {
|
|
110
|
+
case FilterOperator.HasAllOf:
|
|
111
|
+
return state.values.length > 0
|
|
112
|
+
? new IncludesAll(state.values)
|
|
113
|
+
: undefined;
|
|
114
|
+
case FilterOperator.HasNoneOf:
|
|
115
|
+
return state.values.length > 0
|
|
116
|
+
? new IncludesNone(state.values)
|
|
117
|
+
: undefined;
|
|
118
|
+
case FilterOperator.HasAnyOf:
|
|
119
|
+
return state.values.length > 0 ? state.values : undefined;
|
|
120
|
+
case FilterOperator.IsEmpty:
|
|
121
|
+
return new IsNull();
|
|
122
|
+
case FilterOperator.IsNotEmpty:
|
|
123
|
+
return new NotNull();
|
|
124
|
+
default:
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const buildSingleValue: BuildValueFunction = (state: EntityState): unknown => {
|
|
130
|
+
switch (state.operator) {
|
|
131
|
+
case FilterOperator.Is:
|
|
132
|
+
return state.values[0] || undefined;
|
|
133
|
+
case FilterOperator.IsNot:
|
|
134
|
+
// Use IncludesNone with single-item array to represent "is not".
|
|
135
|
+
return state.values[0] ? new IncludesNone([state.values[0]]) : undefined;
|
|
136
|
+
case FilterOperator.IsEmpty:
|
|
137
|
+
return new IsNull();
|
|
138
|
+
case FilterOperator.IsNotEmpty:
|
|
139
|
+
return new NotNull();
|
|
140
|
+
default:
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
18
145
|
const EntityFilter: EntityFilterFunction = <T extends GenericObject>(
|
|
19
146
|
props: ComponentProps<T>,
|
|
20
147
|
): ReactElement => {
|
|
21
148
|
const filter: Filter<T> = props.filter;
|
|
22
|
-
|
|
149
|
+
|
|
150
|
+
if (
|
|
151
|
+
filter.type !== FieldType.Entity &&
|
|
152
|
+
filter.type !== FieldType.EntityArray
|
|
153
|
+
) {
|
|
154
|
+
return <></>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!filter.filterDropdownOptions) {
|
|
158
|
+
return <></>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const isArray: boolean = filter.type === FieldType.EntityArray;
|
|
162
|
+
const detectedState: EntityState = isArray
|
|
163
|
+
? detectArrayState(props.filterData[filter.key])
|
|
164
|
+
: detectSingleState(props.filterData[filter.key]);
|
|
165
|
+
|
|
166
|
+
/*
|
|
167
|
+
* Hold the operator locally so the user's choice persists even when no
|
|
168
|
+
* values are selected yet (otherwise `buildArrayValue` would return
|
|
169
|
+
* undefined, filterData wouldn't carry the operator, and the next render
|
|
170
|
+
* would reset back to the default).
|
|
171
|
+
*/
|
|
172
|
+
const [localOperator, setLocalOperator] = useState<FilterOperator>(
|
|
173
|
+
detectedState.operator,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
/*
|
|
177
|
+
* When the external filter data changes and can unambiguously tell us
|
|
178
|
+
* which operator it represents, sync local state.
|
|
179
|
+
*/
|
|
180
|
+
useEffect(() => {
|
|
181
|
+
const raw: unknown = props.filterData[filter.key];
|
|
182
|
+
if (raw !== undefined && raw !== null) {
|
|
183
|
+
setLocalOperator(detectedState.operator);
|
|
184
|
+
}
|
|
185
|
+
/*
|
|
186
|
+
* Intentionally only re-run when the underlying filter data reference
|
|
187
|
+
* changes — not on every detectedState re-computation.
|
|
188
|
+
*/
|
|
189
|
+
}, [props.filterData[filter.key]]);
|
|
190
|
+
|
|
191
|
+
const operator: FilterOperator = localOperator;
|
|
192
|
+
const state: EntityState = { ...detectedState, operator };
|
|
193
|
+
|
|
194
|
+
const valuelessOperator: boolean =
|
|
195
|
+
operator === FilterOperator.IsEmpty ||
|
|
196
|
+
operator === FilterOperator.IsNotEmpty;
|
|
23
197
|
|
|
24
198
|
const dropdownValues: Array<DropdownOption> =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return (filterData[filter.key] as Array<string>)
|
|
28
|
-
.map((value: string) => {
|
|
29
|
-
return value.toString();
|
|
30
|
-
})
|
|
31
|
-
.includes(option.value.toString());
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return option.value.toString() === filterData[filter.key]?.toString();
|
|
199
|
+
filter.filterDropdownOptions?.filter((option: DropdownOption) => {
|
|
200
|
+
return state.values.includes(option.value.toString());
|
|
35
201
|
}) || [];
|
|
36
202
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
filter.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
203
|
+
type ApplyFunction = (nextState: EntityState) => void;
|
|
204
|
+
|
|
205
|
+
const apply: ApplyFunction = (nextState: EntityState): void => {
|
|
206
|
+
if (!filter.key) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
setLocalOperator(nextState.operator);
|
|
210
|
+
const next: FilterData<T> = { ...props.filterData };
|
|
211
|
+
const built: unknown = isArray
|
|
212
|
+
? buildArrayValue(nextState)
|
|
213
|
+
: buildSingleValue(nextState);
|
|
214
|
+
if (built === undefined) {
|
|
215
|
+
delete next[filter.key];
|
|
216
|
+
} else {
|
|
217
|
+
next[filter.key] = built as any;
|
|
218
|
+
}
|
|
219
|
+
props.onFilterChanged?.(next);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
return (
|
|
223
|
+
<div className="flex gap-2 items-start">
|
|
224
|
+
<OperatorSelector
|
|
225
|
+
value={operator}
|
|
226
|
+
options={isArray ? ENTITY_ARRAY_OPERATORS : ENTITY_OPERATORS}
|
|
227
|
+
onChange={(nextOperator: FilterOperator) => {
|
|
228
|
+
apply({ ...state, operator: nextOperator });
|
|
59
229
|
}}
|
|
60
|
-
value={dropdownValues}
|
|
61
|
-
isMultiSelect={filter.type === FieldType.EntityArray}
|
|
62
|
-
placeholder={`Filter by ${filter.title}`}
|
|
63
230
|
/>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
231
|
+
{!valuelessOperator && (
|
|
232
|
+
<div className="flex-1 min-w-0">
|
|
233
|
+
<Dropdown
|
|
234
|
+
options={filter.filterDropdownOptions}
|
|
235
|
+
onChange={(value: DropdownValue | Array<DropdownValue> | null) => {
|
|
236
|
+
if (!value || (Array.isArray(value) && value.length === 0)) {
|
|
237
|
+
apply({ ...state, values: [] });
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const nextValues: Array<string> = Array.isArray(value)
|
|
241
|
+
? (value as Array<DropdownValue>).map((v: DropdownValue) => {
|
|
242
|
+
return v.toString();
|
|
243
|
+
})
|
|
244
|
+
: [value.toString()];
|
|
245
|
+
apply({ ...state, values: nextValues });
|
|
246
|
+
}}
|
|
247
|
+
value={dropdownValues}
|
|
248
|
+
isMultiSelect={isArray}
|
|
249
|
+
placeholder={`Filter by ${filter.title}`}
|
|
250
|
+
className="relative rounded-md w-full overflow-visible"
|
|
251
|
+
/>
|
|
252
|
+
</div>
|
|
253
|
+
)}
|
|
254
|
+
</div>
|
|
255
|
+
);
|
|
68
256
|
};
|
|
69
257
|
|
|
70
258
|
export default EntityFilter;
|