@oneuptime/common 10.5.31 → 10.5.33

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.
Files changed (82) hide show
  1. package/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.ts +45 -0
  2. package/Models/AnalyticsModels/AuditLog.ts +3 -0
  3. package/Models/AnalyticsModels/ExceptionInstance.ts +3 -0
  4. package/Models/AnalyticsModels/Index.ts +2 -0
  5. package/Models/AnalyticsModels/Log.ts +3 -0
  6. package/Models/AnalyticsModels/Metric.ts +3 -0
  7. package/Models/AnalyticsModels/Span.ts +3 -0
  8. package/Models/DatabaseModels/Index.ts +4 -0
  9. package/Models/DatabaseModels/KubernetesResource.ts +37 -0
  10. package/Models/DatabaseModels/MetricSavedView.ts +334 -0
  11. package/Models/DatabaseModels/TraceSavedView.ts +334 -0
  12. package/Server/API/KubernetesResourceAPI.ts +18 -9
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1780645560183-AddMetricAndTraceSavedView.ts +81 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1780651429467-AddKubernetesLatestMemoryPercent.ts +19 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  16. package/Server/Services/KubernetesResourceService.ts +37 -11
  17. package/Server/Services/MetricSavedViewService.ts +109 -0
  18. package/Server/Services/TraceSavedViewService.ts +109 -0
  19. package/Server/Utils/Monitor/MonitorAlert.ts +34 -0
  20. package/Server/Utils/Monitor/MonitorIncident.ts +60 -93
  21. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +229 -0
  22. package/Server/Utils/Monitor/MonitorResource.ts +18 -0
  23. package/Server/Utils/Monitor/SeriesResourceLabels.ts +156 -0
  24. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +211 -0
  25. package/Types/Telemetry/TelemetrySavedViewState.ts +26 -0
  26. package/UI/Components/Table/TableHeader.tsx +6 -2
  27. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +175 -0
  28. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js +32 -0
  29. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel.js.map +1 -1
  30. package/build/dist/Models/AnalyticsModels/AuditLog.js +2 -0
  31. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  32. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +2 -0
  33. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
  34. package/build/dist/Models/AnalyticsModels/Index.js +2 -0
  35. package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
  36. package/build/dist/Models/AnalyticsModels/Log.js +2 -0
  37. package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
  38. package/build/dist/Models/AnalyticsModels/Metric.js +2 -0
  39. package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
  40. package/build/dist/Models/AnalyticsModels/Span.js +2 -0
  41. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  42. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  43. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  44. package/build/dist/Models/DatabaseModels/KubernetesResource.js +38 -0
  45. package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -1
  46. package/build/dist/Models/DatabaseModels/MetricSavedView.js +356 -0
  47. package/build/dist/Models/DatabaseModels/MetricSavedView.js.map +1 -0
  48. package/build/dist/Models/DatabaseModels/TraceSavedView.js +356 -0
  49. package/build/dist/Models/DatabaseModels/TraceSavedView.js.map +1 -0
  50. package/build/dist/Server/API/KubernetesResourceAPI.js +6 -4
  51. package/build/dist/Server/API/KubernetesResourceAPI.js.map +1 -1
  52. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780645560183-AddMetricAndTraceSavedView.js +34 -0
  53. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780645560183-AddMetricAndTraceSavedView.js.map +1 -0
  54. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780651429467-AddKubernetesLatestMemoryPercent.js +12 -0
  55. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1780651429467-AddKubernetesLatestMemoryPercent.js.map +1 -0
  56. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  57. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  58. package/build/dist/Server/Services/KubernetesResourceService.js +13 -5
  59. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  60. package/build/dist/Server/Services/MetricSavedViewService.js +82 -0
  61. package/build/dist/Server/Services/MetricSavedViewService.js.map +1 -0
  62. package/build/dist/Server/Services/TraceSavedViewService.js +82 -0
  63. package/build/dist/Server/Services/TraceSavedViewService.js.map +1 -0
  64. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +36 -17
  65. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  66. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +60 -107
  67. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  68. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +165 -0
  69. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -0
  70. package/build/dist/Server/Utils/Monitor/MonitorResource.js +16 -0
  71. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  72. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +106 -0
  73. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -0
  74. package/build/dist/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.js +142 -0
  75. package/build/dist/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.js.map +1 -0
  76. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js +9 -0
  77. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js.map +1 -0
  78. package/build/dist/UI/Components/Table/TableHeader.js +2 -2
  79. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  80. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +58 -0
  81. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -0
  82. package/package.json +1 -1
@@ -40,6 +40,16 @@ export default class AnalyticsBaseModel extends CommonModel {
40
40
  * tool generators.
41
41
  */
42
42
  crudApiPath?: Route | undefined;
43
+ /*
44
+ * When true, this model is published in the public REST API Reference
45
+ * (/reference). Mirrors @EnableDocumentation() on Postgres models —
46
+ * having a crudApiPath alone is not enough; documentation is an
47
+ * explicit opt-in so internal-only tables stay private.
48
+ */
49
+ enableDocumentation?: boolean | undefined;
50
+ // Human-readable summary shown on the model's API Reference page.
51
+ tableDescription?: string | undefined;
52
+ isMasterAdminApiDocs?: boolean | undefined;
43
53
  allowAccessIfSubscriptionIsUnpaid?: boolean | undefined;
44
54
  tableBillingAccessControl?: TableBillingAccessControl | undefined;
45
55
  accessControl?: TableAccessControl | undefined;
@@ -160,6 +170,9 @@ export default class AnalyticsBaseModel extends CommonModel {
160
170
  this.accessControl = data.accessControl;
161
171
  this.enableWorkflowOn = data.enableWorkflowOn;
162
172
  this.crudApiPath = data.crudApiPath;
173
+ this.enableDocumentation = data.enableDocumentation || false;
174
+ this.tableDescription = data.tableDescription || "";
175
+ this.isMasterAdminApiDocs = data.isMasterAdminApiDocs || false;
163
176
  this.enableRealtimeEventsOn = data.enableRealtimeEventsOn;
164
177
  this.partitionKey = data.partitionKey;
165
178
  this.projections = data.projections || [];
@@ -315,6 +328,30 @@ export default class AnalyticsBaseModel extends CommonModel {
315
328
  this._crudApiPath = v;
316
329
  }
317
330
 
331
+ private _enableDocumentation: boolean = false;
332
+ public get enableDocumentation(): boolean {
333
+ return this._enableDocumentation;
334
+ }
335
+ public set enableDocumentation(v: boolean) {
336
+ this._enableDocumentation = v;
337
+ }
338
+
339
+ private _tableDescription: string = "";
340
+ public get tableDescription(): string {
341
+ return this._tableDescription;
342
+ }
343
+ public set tableDescription(v: string) {
344
+ this._tableDescription = v;
345
+ }
346
+
347
+ private _isMasterAdminApiDocs: boolean = false;
348
+ public get isMasterAdminApiDocs(): boolean {
349
+ return this._isMasterAdminApiDocs;
350
+ }
351
+ public set isMasterAdminApiDocs(v: boolean) {
352
+ this._isMasterAdminApiDocs = v;
353
+ }
354
+
318
355
  private _projections: Array<Projection> = [];
319
356
  public get projections(): Array<Projection> {
320
357
  return this._projections;
@@ -440,6 +477,14 @@ export default class AnalyticsBaseModel extends CommonModel {
440
477
  }
441
478
 
442
479
  public getAPIDocumentationPath(): string {
480
+ /*
481
+ * Prefer the public CRUD API slug (e.g. "/logs" -> "logs") so the
482
+ * docs URL and the in-app "API Docs" link mirror the real endpoint,
483
+ * rather than the internal ClickHouse table name (e.g. "LogItemV2").
484
+ */
485
+ if (this.crudApiPath) {
486
+ return this.crudApiPath.toString().replace(/^\/+/, "");
487
+ }
443
488
  return Text.pascalCaseToDashes(this.tableName);
444
489
  }
445
490
 
@@ -267,6 +267,9 @@ export default class AuditLog extends AnalyticsBaseModel {
267
267
  delete: PlanType.Enterprise,
268
268
  },
269
269
  crudApiPath: new Route("/audit-log"),
270
+ enableDocumentation: true,
271
+ tableDescription:
272
+ "Immutable audit-trail records of actions taken within your project.",
270
273
  tableColumns: [
271
274
  projectIdColumn,
272
275
  resourceTypeColumn,
@@ -659,6 +659,9 @@ export default class ExceptionInstance extends AnalyticsBaseModel {
659
659
  ],
660
660
  },
661
661
  crudApiPath: new Route("/exceptions"),
662
+ enableDocumentation: true,
663
+ tableDescription:
664
+ "Individual exception occurrences captured from your telemetry. Query application errors and their attributes over time.",
662
665
  tableColumns: [
663
666
  projectIdColumn,
664
667
  serviceIdColumn,
@@ -9,6 +9,7 @@ import ExceptionInstance from "./ExceptionInstance";
9
9
  import MonitorLog from "./MonitorLog";
10
10
  import Profile from "./Profile";
11
11
  import ProfileSample from "./ProfileSample";
12
+ import AuditLog from "./AuditLog";
12
13
 
13
14
  const AnalyticsModels: Array<{ new (): AnalyticsBaseModel }> = [
14
15
  Log,
@@ -25,6 +26,7 @@ const AnalyticsModels: Array<{ new (): AnalyticsBaseModel }> = [
25
26
  MonitorLog,
26
27
  Profile,
27
28
  ProfileSample,
29
+ AuditLog,
28
30
  ];
29
31
 
30
32
  const modelTypeMap: { [key: string]: { new (): AnalyticsBaseModel } } = {};
@@ -556,6 +556,9 @@ export default class Log extends AnalyticsBaseModel {
556
556
  },
557
557
  pluralName: "Logs",
558
558
  crudApiPath: new Route("/logs"),
559
+ enableDocumentation: true,
560
+ tableDescription:
561
+ "OpenTelemetry log records ingested from your services. Query, filter, and aggregate structured logs across your project.",
559
562
  tableColumns: [
560
563
  projectIdColumn,
561
564
  serviceIdColumn,
@@ -1003,6 +1003,9 @@ export default class Metric extends AnalyticsBaseModel {
1003
1003
  singularName: "Metric",
1004
1004
  pluralName: "Metrics",
1005
1005
  crudApiPath: new Route("/metrics"),
1006
+ enableDocumentation: true,
1007
+ tableDescription:
1008
+ "OpenTelemetry metric data points. Query and aggregate time-series telemetry for dashboards, alerts, and analysis.",
1006
1009
  accessControl: {
1007
1010
  read: [
1008
1011
  Permission.ProjectOwner,
@@ -787,6 +787,9 @@ export default class Span extends AnalyticsBaseModel {
787
787
  singularName: "Span",
788
788
  pluralName: "Spans",
789
789
  crudApiPath: new Route("/span"),
790
+ enableDocumentation: true,
791
+ tableDescription:
792
+ "OpenTelemetry distributed-tracing spans. Each span is one operation within a trace; query and aggregate them to analyze latency and errors.",
790
793
  accessControl: {
791
794
  read: [
792
795
  Permission.ProjectOwner,
@@ -49,6 +49,8 @@ import IncidentTemplateOwnerUser from "./IncidentTemplateOwnerUser";
49
49
  //Labels.
50
50
  import Label from "./Label";
51
51
  import LogSavedView from "./LogSavedView";
52
+ import MetricSavedView from "./MetricSavedView";
53
+ import TraceSavedView from "./TraceSavedView";
52
54
  import LogPipeline from "./LogPipeline";
53
55
  import LogPipelineProcessor from "./LogPipelineProcessor";
54
56
  import LogDropFilter from "./LogDropFilter";
@@ -349,6 +351,8 @@ const AllModelTypes: Array<{
349
351
  ApiKey,
350
352
  Label,
351
353
  LogSavedView,
354
+ MetricSavedView,
355
+ TraceSavedView,
352
356
  LogPipeline,
353
357
  LogPipelineProcessor,
354
358
  LogDropFilter,
@@ -553,6 +553,43 @@ export default class KubernetesResource extends BaseModel {
553
553
  })
554
554
  public latestMemoryBytes?: number = undefined;
555
555
 
556
+ @ColumnAccessControl({
557
+ create: [],
558
+ read: READ_PERMISSIONS,
559
+ update: [],
560
+ })
561
+ @TableColumn({
562
+ required: false,
563
+ type: TableColumnType.Number,
564
+ canReadOnRelationQuery: true,
565
+ title: "Latest Memory Percent",
566
+ description:
567
+ "Most recent memory usage as a percent of the resource's node allocatable memory (Pod or Node). Stored as decimal — mirrors latestCpuPercent — so the workload/namespace list views can SUM a per-pod percentage. Null until the first metric arrives or while the node's allocatable memory is still unknown.",
568
+ })
569
+ @Column({
570
+ nullable: true,
571
+ type: ColumnType.Decimal,
572
+ transformer: {
573
+ to: (value: number | null | undefined): number | null => {
574
+ if (value === null || value === undefined) {
575
+ return null;
576
+ }
577
+ return value;
578
+ },
579
+ from: (value: string | number | null | undefined): number | null => {
580
+ if (value === null || value === undefined) {
581
+ return null;
582
+ }
583
+ if (typeof value === "number") {
584
+ return value;
585
+ }
586
+ const parsed: number = parseFloat(value);
587
+ return isNaN(parsed) ? null : parsed;
588
+ },
589
+ },
590
+ })
591
+ public latestMemoryPercent?: number = undefined;
592
+
556
593
  @ColumnAccessControl({
557
594
  create: [],
558
595
  read: READ_PERMISSIONS,
@@ -0,0 +1,334 @@
1
+ import Project from "./Project";
2
+ import User from "./User";
3
+ import BaseModel from "./DatabaseBaseModel/DatabaseBaseModel";
4
+ import Route from "../../Types/API/Route";
5
+ import TelemetrySavedViewState from "../../Types/Telemetry/TelemetrySavedViewState";
6
+ import ColumnAccessControl from "../../Types/Database/AccessControl/ColumnAccessControl";
7
+ import TableAccessControl from "../../Types/Database/AccessControl/TableAccessControl";
8
+ import TableBillingAccessControl from "../../Types/Database/AccessControl/TableBillingAccessControl";
9
+ import ColumnLength from "../../Types/Database/ColumnLength";
10
+ import ColumnType from "../../Types/Database/ColumnType";
11
+ import CrudApiEndpoint from "../../Types/Database/CrudApiEndpoint";
12
+ import EnableDocumentation from "../../Types/Database/EnableDocumentation";
13
+ import TableColumn from "../../Types/Database/TableColumn";
14
+ import TableColumnType from "../../Types/Database/TableColumnType";
15
+ import TableMetadata from "../../Types/Database/TableMetadata";
16
+ import TenantColumn from "../../Types/Database/TenantColumn";
17
+ import IconProp from "../../Types/Icon/IconProp";
18
+ import ObjectID from "../../Types/ObjectID";
19
+ import Permission from "../../Types/Permission";
20
+ import { PlanType } from "../../Types/Billing/SubscriptionPlan";
21
+ import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
22
+
23
+ @EnableDocumentation()
24
+ @TableBillingAccessControl({
25
+ create: PlanType.Free,
26
+ read: PlanType.Free,
27
+ update: PlanType.Free,
28
+ delete: PlanType.Free,
29
+ })
30
+ @TenantColumn("projectId")
31
+ @CrudApiEndpoint(new Route("/metric-saved-view"))
32
+ @Entity({
33
+ name: "MetricSavedView",
34
+ })
35
+ @TableMetadata({
36
+ tableName: "MetricSavedView",
37
+ singularName: "Metric Saved View",
38
+ pluralName: "Metric Saved Views",
39
+ icon: IconProp.Window,
40
+ tableDescription:
41
+ "Save and reuse metrics explorer views, including the current search, filters, time range, and page size.",
42
+ })
43
+ @TableAccessControl({
44
+ create: [
45
+ Permission.ProjectOwner,
46
+ Permission.ProjectAdmin,
47
+ Permission.ProjectMember,
48
+ ],
49
+ read: [
50
+ Permission.ProjectOwner,
51
+ Permission.ProjectAdmin,
52
+ Permission.ProjectMember,
53
+ Permission.Viewer,
54
+ ],
55
+ delete: [
56
+ Permission.ProjectOwner,
57
+ Permission.ProjectAdmin,
58
+ Permission.ProjectMember,
59
+ ],
60
+ update: [
61
+ Permission.ProjectOwner,
62
+ Permission.ProjectAdmin,
63
+ Permission.ProjectMember,
64
+ ],
65
+ })
66
+ export default class MetricSavedView extends BaseModel {
67
+ @ColumnAccessControl({
68
+ create: [
69
+ Permission.ProjectOwner,
70
+ Permission.ProjectAdmin,
71
+ Permission.ProjectMember,
72
+ ],
73
+ read: [
74
+ Permission.ProjectOwner,
75
+ Permission.ProjectAdmin,
76
+ Permission.ProjectMember,
77
+ Permission.Viewer,
78
+ ],
79
+ update: [],
80
+ })
81
+ @TableColumn({
82
+ manyToOneRelationColumn: "projectId",
83
+ type: TableColumnType.Entity,
84
+ modelType: Project,
85
+ title: "Project",
86
+ description: "Relation to the project this saved metric view belongs to.",
87
+ })
88
+ @ManyToOne(
89
+ () => {
90
+ return Project;
91
+ },
92
+ {
93
+ eager: false,
94
+ nullable: true,
95
+ onDelete: "CASCADE",
96
+ orphanedRowAction: "nullify",
97
+ },
98
+ )
99
+ @JoinColumn({ name: "projectId" })
100
+ public project?: Project = undefined;
101
+
102
+ @ColumnAccessControl({
103
+ create: [
104
+ Permission.ProjectOwner,
105
+ Permission.ProjectAdmin,
106
+ Permission.ProjectMember,
107
+ ],
108
+ read: [
109
+ Permission.ProjectOwner,
110
+ Permission.ProjectAdmin,
111
+ Permission.ProjectMember,
112
+ Permission.Viewer,
113
+ ],
114
+ update: [],
115
+ })
116
+ @Index()
117
+ @TableColumn({
118
+ type: TableColumnType.ObjectID,
119
+ required: true,
120
+ canReadOnRelationQuery: true,
121
+ title: "Project ID",
122
+ description: "ID of the project this saved metric view belongs to.",
123
+ })
124
+ @Column({
125
+ type: ColumnType.ObjectID,
126
+ nullable: false,
127
+ transformer: ObjectID.getDatabaseTransformer(),
128
+ })
129
+ public projectId?: ObjectID = undefined;
130
+
131
+ @ColumnAccessControl({
132
+ create: [
133
+ Permission.ProjectOwner,
134
+ Permission.ProjectAdmin,
135
+ Permission.ProjectMember,
136
+ ],
137
+ read: [
138
+ Permission.ProjectOwner,
139
+ Permission.ProjectAdmin,
140
+ Permission.ProjectMember,
141
+ Permission.Viewer,
142
+ ],
143
+ update: [
144
+ Permission.ProjectOwner,
145
+ Permission.ProjectAdmin,
146
+ Permission.ProjectMember,
147
+ ],
148
+ })
149
+ @TableColumn({
150
+ required: true,
151
+ type: TableColumnType.Name,
152
+ canReadOnRelationQuery: true,
153
+ title: "Name",
154
+ description: "Friendly name for this saved metric view.",
155
+ })
156
+ @Column({
157
+ nullable: false,
158
+ type: ColumnType.Name,
159
+ length: ColumnLength.Name,
160
+ })
161
+ public name?: string = undefined;
162
+
163
+ @ColumnAccessControl({
164
+ create: [],
165
+ read: [
166
+ Permission.ProjectOwner,
167
+ Permission.ProjectAdmin,
168
+ Permission.ProjectMember,
169
+ Permission.Viewer,
170
+ ],
171
+ update: [],
172
+ })
173
+ @TableColumn({
174
+ manyToOneRelationColumn: "createdByUserId",
175
+ type: TableColumnType.Entity,
176
+ modelType: User,
177
+ title: "Created By User",
178
+ description: "Relation to the user who created this saved metric view.",
179
+ })
180
+ @ManyToOne(
181
+ () => {
182
+ return User;
183
+ },
184
+ {
185
+ eager: false,
186
+ nullable: true,
187
+ onDelete: "SET NULL",
188
+ orphanedRowAction: "nullify",
189
+ },
190
+ )
191
+ @JoinColumn({ name: "createdByUserId" })
192
+ public createdByUser?: User = undefined;
193
+
194
+ @ColumnAccessControl({
195
+ create: [],
196
+ read: [
197
+ Permission.ProjectOwner,
198
+ Permission.ProjectAdmin,
199
+ Permission.ProjectMember,
200
+ Permission.Viewer,
201
+ ],
202
+ update: [],
203
+ })
204
+ @TableColumn({
205
+ type: TableColumnType.ObjectID,
206
+ title: "Created By User ID",
207
+ description: "ID of the user who created this saved metric view.",
208
+ })
209
+ @Column({
210
+ type: ColumnType.ObjectID,
211
+ nullable: true,
212
+ transformer: ObjectID.getDatabaseTransformer(),
213
+ })
214
+ public createdByUserId?: ObjectID = undefined;
215
+
216
+ @ColumnAccessControl({
217
+ create: [],
218
+ read: [
219
+ Permission.ProjectOwner,
220
+ Permission.ProjectAdmin,
221
+ Permission.ProjectMember,
222
+ Permission.Viewer,
223
+ ],
224
+ update: [],
225
+ })
226
+ @TableColumn({
227
+ manyToOneRelationColumn: "deletedByUserId",
228
+ type: TableColumnType.Entity,
229
+ modelType: User,
230
+ title: "Deleted By User",
231
+ description: "Relation to the user who deleted this saved metric view.",
232
+ })
233
+ @ManyToOne(
234
+ () => {
235
+ return User;
236
+ },
237
+ {
238
+ eager: false,
239
+ nullable: true,
240
+ onDelete: "SET NULL",
241
+ orphanedRowAction: "nullify",
242
+ },
243
+ )
244
+ @JoinColumn({ name: "deletedByUserId" })
245
+ public deletedByUser?: User = undefined;
246
+
247
+ @ColumnAccessControl({
248
+ create: [],
249
+ read: [
250
+ Permission.ProjectOwner,
251
+ Permission.ProjectAdmin,
252
+ Permission.ProjectMember,
253
+ Permission.Viewer,
254
+ ],
255
+ update: [],
256
+ })
257
+ @TableColumn({
258
+ type: TableColumnType.ObjectID,
259
+ title: "Deleted By User ID",
260
+ description: "ID of the user who deleted this saved metric view.",
261
+ })
262
+ @Column({
263
+ type: ColumnType.ObjectID,
264
+ nullable: true,
265
+ transformer: ObjectID.getDatabaseTransformer(),
266
+ })
267
+ public deletedByUserId?: ObjectID = undefined;
268
+
269
+ @ColumnAccessControl({
270
+ create: [
271
+ Permission.ProjectOwner,
272
+ Permission.ProjectAdmin,
273
+ Permission.ProjectMember,
274
+ ],
275
+ read: [
276
+ Permission.ProjectOwner,
277
+ Permission.ProjectAdmin,
278
+ Permission.ProjectMember,
279
+ Permission.Viewer,
280
+ ],
281
+ update: [
282
+ Permission.ProjectOwner,
283
+ Permission.ProjectAdmin,
284
+ Permission.ProjectMember,
285
+ ],
286
+ })
287
+ @TableColumn({
288
+ title: "Query",
289
+ required: true,
290
+ type: TableColumnType.JSON,
291
+ canReadOnRelationQuery: true,
292
+ description:
293
+ "Serialized metrics explorer view state (search, filters, time range, page size) for this saved view.",
294
+ })
295
+ @Column({
296
+ type: ColumnType.JSON,
297
+ nullable: false,
298
+ })
299
+ public query?: TelemetrySavedViewState = undefined;
300
+
301
+ @ColumnAccessControl({
302
+ create: [
303
+ Permission.ProjectOwner,
304
+ Permission.ProjectAdmin,
305
+ Permission.ProjectMember,
306
+ ],
307
+ read: [
308
+ Permission.ProjectOwner,
309
+ Permission.ProjectAdmin,
310
+ Permission.ProjectMember,
311
+ Permission.Viewer,
312
+ ],
313
+ update: [
314
+ Permission.ProjectOwner,
315
+ Permission.ProjectAdmin,
316
+ Permission.ProjectMember,
317
+ ],
318
+ })
319
+ @Index()
320
+ @TableColumn({
321
+ required: true,
322
+ type: TableColumnType.Boolean,
323
+ canReadOnRelationQuery: true,
324
+ title: "Is Default",
325
+ description: "Whether this saved metric view should be applied by default.",
326
+ defaultValue: false,
327
+ })
328
+ @Column({
329
+ nullable: false,
330
+ type: ColumnType.Boolean,
331
+ default: false,
332
+ })
333
+ public isDefault?: boolean = undefined;
334
+ }