@oneuptime/common 10.5.2 → 10.5.4

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 (55) hide show
  1. package/Models/DatabaseModels/AlertGroupingRule.ts +76 -0
  2. package/Models/DatabaseModels/IncidentGroupingRule.ts +76 -0
  3. package/Models/DatabaseModels/StatusPageGroup.ts +212 -0
  4. package/Models/DatabaseModels/StatusPageResource.ts +86 -0
  5. package/Server/API/StatusPageAPI.ts +15 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/1779879993421-MigrationName.ts +61 -13
  7. package/Server/Infrastructure/Postgres/SchemaMigrations/1779882573463-MigrationName.ts +65 -0
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/1779971548393-AddLabelGroupByToGroupingRules.ts +37 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -3
  10. package/Server/Services/AlertGroupingEngineService.ts +83 -0
  11. package/Server/Services/IncidentGroupingEngineService.ts +99 -0
  12. package/Server/Services/StatusPageService.ts +5 -0
  13. package/Tests/Server/Services/AlertGroupingEngineService.test.ts +28 -0
  14. package/Tests/Server/Services/AlertGroupingRuleService.test.ts +14 -0
  15. package/Types/Monitor/MonitorStep.ts +85 -0
  16. package/Types/StatusPage/StatusPageGroupViewMode.ts +6 -0
  17. package/UI/Components/Accordion/Accordion.tsx +40 -26
  18. package/build/dist/Models/DatabaseModels/AlertGroupingRule.js +78 -0
  19. package/build/dist/Models/DatabaseModels/AlertGroupingRule.js.map +1 -1
  20. package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js +78 -0
  21. package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js.map +1 -1
  22. package/build/dist/Models/DatabaseModels/StatusPageGroup.js +217 -0
  23. package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
  24. package/build/dist/Models/DatabaseModels/StatusPageResource.js +88 -0
  25. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  26. package/build/dist/Server/API/StatusPageAPI.js +15 -0
  27. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  28. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779879993421-MigrationName.js +29 -5
  29. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779879993421-MigrationName.js.map +1 -1
  30. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779882573463-MigrationName.js +28 -0
  31. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779882573463-MigrationName.js.map +1 -0
  32. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779971548393-AddLabelGroupByToGroupingRules.js +18 -0
  33. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779971548393-AddLabelGroupByToGroupingRules.js.map +1 -0
  34. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +5 -3
  35. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  36. package/build/dist/Server/Services/AlertGroupingEngineService.js +85 -0
  37. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  38. package/build/dist/Server/Services/IncidentGroupingEngineService.js +95 -0
  39. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  40. package/build/dist/Server/Services/StatusPageService.js +5 -0
  41. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  42. package/build/dist/Tests/Server/Services/AlertGroupingEngineService.test.js +21 -0
  43. package/build/dist/Tests/Server/Services/AlertGroupingEngineService.test.js.map +1 -1
  44. package/build/dist/Tests/Server/Services/AlertGroupingRuleService.test.js +12 -0
  45. package/build/dist/Tests/Server/Services/AlertGroupingRuleService.test.js.map +1 -1
  46. package/build/dist/Types/Monitor/MonitorStep.js +59 -0
  47. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  48. package/build/dist/Types/StatusPage/StatusPageGroupViewMode.js +7 -0
  49. package/build/dist/Types/StatusPage/StatusPageGroupViewMode.js.map +1 -0
  50. package/build/dist/UI/Components/Accordion/Accordion.js +11 -11
  51. package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
  52. package/package.json +1 -1
  53. package/Server/Infrastructure/Postgres/SchemaMigrations/1779900000000-DedupeTelemetryExceptionsAndAddUniqueIndex.ts +0 -115
  54. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779900000000-DedupeTelemetryExceptionsAndAddUniqueIndex.js +0 -106
  55. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779900000000-DedupeTelemetryExceptionsAndAddUniqueIndex.js.map +0 -1
@@ -811,6 +811,82 @@ export default class AlertGroupingRule extends BaseModel {
811
811
  })
812
812
  public groupByAlertTitle?: boolean = undefined;
813
813
 
814
+ @ColumnAccessControl({
815
+ create: [
816
+ Permission.ProjectOwner,
817
+ Permission.ProjectAdmin,
818
+ Permission.CreateAlertGroupingRule,
819
+ ],
820
+ read: [
821
+ Permission.ProjectOwner,
822
+ Permission.ProjectAdmin,
823
+ Permission.ProjectMember,
824
+ Permission.Viewer,
825
+ Permission.AlertAdmin,
826
+ Permission.AlertMember,
827
+ Permission.AlertViewer,
828
+ Permission.ReadAlertGroupingRule,
829
+ ],
830
+ update: [
831
+ Permission.ProjectOwner,
832
+ Permission.ProjectAdmin,
833
+ Permission.EditAlertGroupingRule,
834
+ ],
835
+ })
836
+ @TableColumn({
837
+ required: false,
838
+ type: TableColumnType.Boolean,
839
+ title: "Group By Alert Labels",
840
+ description:
841
+ "When enabled, alerts with different sets of labels will be grouped into separate episodes (exact set match). When disabled, alert labels are ignored for grouping.",
842
+ defaultValue: false,
843
+ isDefaultValueColumn: true,
844
+ })
845
+ @Column({
846
+ type: ColumnType.Boolean,
847
+ nullable: false,
848
+ default: false,
849
+ })
850
+ public groupByAlertLabels?: boolean = undefined;
851
+
852
+ @ColumnAccessControl({
853
+ create: [
854
+ Permission.ProjectOwner,
855
+ Permission.ProjectAdmin,
856
+ Permission.CreateAlertGroupingRule,
857
+ ],
858
+ read: [
859
+ Permission.ProjectOwner,
860
+ Permission.ProjectAdmin,
861
+ Permission.ProjectMember,
862
+ Permission.Viewer,
863
+ Permission.AlertAdmin,
864
+ Permission.AlertMember,
865
+ Permission.AlertViewer,
866
+ Permission.ReadAlertGroupingRule,
867
+ ],
868
+ update: [
869
+ Permission.ProjectOwner,
870
+ Permission.ProjectAdmin,
871
+ Permission.EditAlertGroupingRule,
872
+ ],
873
+ })
874
+ @TableColumn({
875
+ required: false,
876
+ type: TableColumnType.Boolean,
877
+ title: "Group By Monitor Labels",
878
+ description:
879
+ "When enabled, alerts whose monitors have different sets of labels will be grouped into separate episodes (exact set match). When disabled, monitor labels are ignored for grouping.",
880
+ defaultValue: false,
881
+ isDefaultValueColumn: true,
882
+ })
883
+ @Column({
884
+ type: ColumnType.Boolean,
885
+ nullable: false,
886
+ default: false,
887
+ })
888
+ public groupByMonitorLabels?: boolean = undefined;
889
+
814
890
  @ColumnAccessControl({
815
891
  create: [
816
892
  Permission.ProjectOwner,
@@ -815,6 +815,82 @@ export default class IncidentGroupingRule extends BaseModel {
815
815
  })
816
816
  public groupByIncidentTitle?: boolean = undefined;
817
817
 
818
+ @ColumnAccessControl({
819
+ create: [
820
+ Permission.ProjectOwner,
821
+ Permission.ProjectAdmin,
822
+ Permission.CreateIncidentGroupingRule,
823
+ ],
824
+ read: [
825
+ Permission.ProjectOwner,
826
+ Permission.ProjectAdmin,
827
+ Permission.ProjectMember,
828
+ Permission.Viewer,
829
+ Permission.IncidentAdmin,
830
+ Permission.IncidentMember,
831
+ Permission.IncidentViewer,
832
+ Permission.ReadIncidentGroupingRule,
833
+ ],
834
+ update: [
835
+ Permission.ProjectOwner,
836
+ Permission.ProjectAdmin,
837
+ Permission.EditIncidentGroupingRule,
838
+ ],
839
+ })
840
+ @TableColumn({
841
+ required: false,
842
+ type: TableColumnType.Boolean,
843
+ title: "Group By Incident Labels",
844
+ description:
845
+ "When enabled, incidents with different sets of labels will be grouped into separate episodes (exact set match). When disabled, incident labels are ignored for grouping.",
846
+ defaultValue: false,
847
+ isDefaultValueColumn: true,
848
+ })
849
+ @Column({
850
+ type: ColumnType.Boolean,
851
+ nullable: false,
852
+ default: false,
853
+ })
854
+ public groupByIncidentLabels?: boolean = undefined;
855
+
856
+ @ColumnAccessControl({
857
+ create: [
858
+ Permission.ProjectOwner,
859
+ Permission.ProjectAdmin,
860
+ Permission.CreateIncidentGroupingRule,
861
+ ],
862
+ read: [
863
+ Permission.ProjectOwner,
864
+ Permission.ProjectAdmin,
865
+ Permission.ProjectMember,
866
+ Permission.Viewer,
867
+ Permission.IncidentAdmin,
868
+ Permission.IncidentMember,
869
+ Permission.IncidentViewer,
870
+ Permission.ReadIncidentGroupingRule,
871
+ ],
872
+ update: [
873
+ Permission.ProjectOwner,
874
+ Permission.ProjectAdmin,
875
+ Permission.EditIncidentGroupingRule,
876
+ ],
877
+ })
878
+ @TableColumn({
879
+ required: false,
880
+ type: TableColumnType.Boolean,
881
+ title: "Group By Monitor Labels",
882
+ description:
883
+ "When enabled, incidents whose monitors have different sets of labels will be grouped into separate episodes (exact set match). When disabled, monitor labels are ignored for grouping.",
884
+ defaultValue: false,
885
+ isDefaultValueColumn: true,
886
+ })
887
+ @Column({
888
+ type: ColumnType.Boolean,
889
+ nullable: false,
890
+ default: false,
891
+ })
892
+ public groupByMonitorLabels?: boolean = undefined;
893
+
818
894
  @ColumnAccessControl({
819
895
  create: [
820
896
  Permission.ProjectOwner,
@@ -25,6 +25,7 @@ import ObjectID from "../../Types/ObjectID";
25
25
  import Permission from "../../Types/Permission";
26
26
  import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
27
27
  import UptimePrecision from "../../Types/StatusPage/UptimePrecision";
28
+ import StatusPageGroupViewMode from "../../Types/StatusPage/StatusPageGroupViewMode";
28
29
 
29
30
  @EnableDocumentation()
30
31
  @TableBillingAccessControl({
@@ -695,4 +696,215 @@ export default class StatusPageGroup extends BaseModel {
695
696
  nullable: true,
696
697
  })
697
698
  public uptimePercentPrecision?: UptimePrecision = undefined;
699
+
700
+ @ColumnAccessControl({
701
+ create: [
702
+ Permission.ProjectOwner,
703
+ Permission.ProjectAdmin,
704
+ Permission.ProjectMember,
705
+ Permission.StatusPageAdmin,
706
+ Permission.StatusPageMember,
707
+ Permission.CreateStatusPageGroup,
708
+ ],
709
+ read: [
710
+ Permission.ProjectOwner,
711
+ Permission.ProjectAdmin,
712
+ Permission.ProjectMember,
713
+ Permission.Viewer,
714
+ Permission.StatusPageAdmin,
715
+ Permission.StatusPageMember,
716
+ Permission.StatusPageViewer,
717
+ Permission.ReadStatusPageGroup,
718
+ ],
719
+ update: [
720
+ Permission.ProjectOwner,
721
+ Permission.ProjectAdmin,
722
+ Permission.ProjectMember,
723
+ Permission.StatusPageAdmin,
724
+ Permission.StatusPageMember,
725
+ Permission.EditStatusPageGroup,
726
+ ],
727
+ })
728
+ @TableColumn({
729
+ type: TableColumnType.ShortText,
730
+ title: "View Mode",
731
+ required: false,
732
+ description:
733
+ "Layout of this group on the status page. 'List' renders resources stacked vertically (default). 'Grid' renders resources as a matrix using row and column axes.",
734
+ defaultValue: StatusPageGroupViewMode.List,
735
+ })
736
+ @Column({
737
+ type: ColumnType.ShortText,
738
+ nullable: true,
739
+ default: StatusPageGroupViewMode.List,
740
+ })
741
+ public viewMode?: StatusPageGroupViewMode = undefined;
742
+
743
+ @ColumnAccessControl({
744
+ create: [
745
+ Permission.ProjectOwner,
746
+ Permission.ProjectAdmin,
747
+ Permission.ProjectMember,
748
+ Permission.StatusPageAdmin,
749
+ Permission.StatusPageMember,
750
+ Permission.CreateStatusPageGroup,
751
+ ],
752
+ read: [
753
+ Permission.ProjectOwner,
754
+ Permission.ProjectAdmin,
755
+ Permission.ProjectMember,
756
+ Permission.Viewer,
757
+ Permission.StatusPageAdmin,
758
+ Permission.StatusPageMember,
759
+ Permission.StatusPageViewer,
760
+ Permission.ReadStatusPageGroup,
761
+ ],
762
+ update: [
763
+ Permission.ProjectOwner,
764
+ Permission.ProjectAdmin,
765
+ Permission.ProjectMember,
766
+ Permission.StatusPageAdmin,
767
+ Permission.StatusPageMember,
768
+ Permission.EditStatusPageGroup,
769
+ ],
770
+ })
771
+ @TableColumn({
772
+ type: TableColumnType.ShortText,
773
+ title: "Row Axis Label",
774
+ required: false,
775
+ description:
776
+ "Label shown above the row axis when the group is rendered as a grid (e.g. 'Service', 'Tenant'). Free-form so you can use any dimension you like.",
777
+ })
778
+ @Column({
779
+ nullable: true,
780
+ type: ColumnType.ShortText,
781
+ length: ColumnLength.ShortText,
782
+ })
783
+ public rowAxisLabel?: string = undefined;
784
+
785
+ @ColumnAccessControl({
786
+ create: [
787
+ Permission.ProjectOwner,
788
+ Permission.ProjectAdmin,
789
+ Permission.ProjectMember,
790
+ Permission.StatusPageAdmin,
791
+ Permission.StatusPageMember,
792
+ Permission.CreateStatusPageGroup,
793
+ ],
794
+ read: [
795
+ Permission.ProjectOwner,
796
+ Permission.ProjectAdmin,
797
+ Permission.ProjectMember,
798
+ Permission.Viewer,
799
+ Permission.StatusPageAdmin,
800
+ Permission.StatusPageMember,
801
+ Permission.StatusPageViewer,
802
+ Permission.ReadStatusPageGroup,
803
+ ],
804
+ update: [
805
+ Permission.ProjectOwner,
806
+ Permission.ProjectAdmin,
807
+ Permission.ProjectMember,
808
+ Permission.StatusPageAdmin,
809
+ Permission.StatusPageMember,
810
+ Permission.EditStatusPageGroup,
811
+ ],
812
+ })
813
+ @TableColumn({
814
+ type: TableColumnType.ShortText,
815
+ title: "Column Axis Label",
816
+ required: false,
817
+ description:
818
+ "Label shown above the column axis when the group is rendered as a grid (e.g. 'Region', 'Environment'). Free-form so you can use any dimension you like.",
819
+ })
820
+ @Column({
821
+ nullable: true,
822
+ type: ColumnType.ShortText,
823
+ length: ColumnLength.ShortText,
824
+ })
825
+ public columnAxisLabel?: string = undefined;
826
+
827
+ @ColumnAccessControl({
828
+ create: [
829
+ Permission.ProjectOwner,
830
+ Permission.ProjectAdmin,
831
+ Permission.ProjectMember,
832
+ Permission.StatusPageAdmin,
833
+ Permission.StatusPageMember,
834
+ Permission.CreateStatusPageGroup,
835
+ ],
836
+ read: [
837
+ Permission.ProjectOwner,
838
+ Permission.ProjectAdmin,
839
+ Permission.ProjectMember,
840
+ Permission.Viewer,
841
+ Permission.StatusPageAdmin,
842
+ Permission.StatusPageMember,
843
+ Permission.StatusPageViewer,
844
+ Permission.ReadStatusPageGroup,
845
+ ],
846
+ update: [
847
+ Permission.ProjectOwner,
848
+ Permission.ProjectAdmin,
849
+ Permission.ProjectMember,
850
+ Permission.StatusPageAdmin,
851
+ Permission.StatusPageMember,
852
+ Permission.EditStatusPageGroup,
853
+ ],
854
+ })
855
+ @TableColumn({
856
+ required: false,
857
+ type: TableColumnType.LongText,
858
+ title: "Row Axis Values",
859
+ description:
860
+ "Comma-separated list of row labels for the grid (e.g. 'Auth, API, Database'). Determines row order in the grid layout.",
861
+ })
862
+ @Column({
863
+ nullable: true,
864
+ type: ColumnType.LongText,
865
+ length: ColumnLength.LongText,
866
+ })
867
+ public rowAxisValues?: string = undefined;
868
+
869
+ @ColumnAccessControl({
870
+ create: [
871
+ Permission.ProjectOwner,
872
+ Permission.ProjectAdmin,
873
+ Permission.ProjectMember,
874
+ Permission.StatusPageAdmin,
875
+ Permission.StatusPageMember,
876
+ Permission.CreateStatusPageGroup,
877
+ ],
878
+ read: [
879
+ Permission.ProjectOwner,
880
+ Permission.ProjectAdmin,
881
+ Permission.ProjectMember,
882
+ Permission.Viewer,
883
+ Permission.StatusPageAdmin,
884
+ Permission.StatusPageMember,
885
+ Permission.StatusPageViewer,
886
+ Permission.ReadStatusPageGroup,
887
+ ],
888
+ update: [
889
+ Permission.ProjectOwner,
890
+ Permission.ProjectAdmin,
891
+ Permission.ProjectMember,
892
+ Permission.StatusPageAdmin,
893
+ Permission.StatusPageMember,
894
+ Permission.EditStatusPageGroup,
895
+ ],
896
+ })
897
+ @TableColumn({
898
+ required: false,
899
+ type: TableColumnType.LongText,
900
+ title: "Column Axis Values",
901
+ description:
902
+ "Comma-separated list of column labels for the grid (e.g. 'US-East, EU-West, Asia'). Determines column order in the grid layout.",
903
+ })
904
+ @Column({
905
+ nullable: true,
906
+ type: ColumnType.LongText,
907
+ length: ColumnLength.LongText,
908
+ })
909
+ public columnAxisValues?: string = undefined;
698
910
  }
@@ -926,6 +926,92 @@ export default class StatusPageResource extends BaseModel {
926
926
  })
927
927
  public order?: number = undefined;
928
928
 
929
+ @ColumnAccessControl({
930
+ create: [
931
+ Permission.ProjectOwner,
932
+ Permission.ProjectAdmin,
933
+ Permission.ProjectMember,
934
+ Permission.StatusPageAdmin,
935
+ Permission.StatusPageMember,
936
+ Permission.CreateStatusPageResource,
937
+ ],
938
+ read: [
939
+ Permission.ProjectOwner,
940
+ Permission.ProjectAdmin,
941
+ Permission.ProjectMember,
942
+ Permission.Viewer,
943
+ Permission.StatusPageAdmin,
944
+ Permission.StatusPageMember,
945
+ Permission.StatusPageViewer,
946
+ Permission.ReadStatusPageResource,
947
+ ],
948
+ update: [
949
+ Permission.ProjectOwner,
950
+ Permission.ProjectAdmin,
951
+ Permission.ProjectMember,
952
+ Permission.StatusPageAdmin,
953
+ Permission.StatusPageMember,
954
+ Permission.EditStatusPageResource,
955
+ ],
956
+ })
957
+ @TableColumn({
958
+ type: TableColumnType.ShortText,
959
+ required: false,
960
+ title: "Row Axis Value",
961
+ description:
962
+ "Row this resource belongs to when its status page group is rendered as a grid. Should match one of the row axis values defined on the group.",
963
+ example: "API",
964
+ })
965
+ @Column({
966
+ nullable: true,
967
+ type: ColumnType.ShortText,
968
+ length: ColumnLength.ShortText,
969
+ })
970
+ public rowAxisValue?: string = undefined;
971
+
972
+ @ColumnAccessControl({
973
+ create: [
974
+ Permission.ProjectOwner,
975
+ Permission.ProjectAdmin,
976
+ Permission.ProjectMember,
977
+ Permission.StatusPageAdmin,
978
+ Permission.StatusPageMember,
979
+ Permission.CreateStatusPageResource,
980
+ ],
981
+ read: [
982
+ Permission.ProjectOwner,
983
+ Permission.ProjectAdmin,
984
+ Permission.ProjectMember,
985
+ Permission.Viewer,
986
+ Permission.StatusPageAdmin,
987
+ Permission.StatusPageMember,
988
+ Permission.StatusPageViewer,
989
+ Permission.ReadStatusPageResource,
990
+ ],
991
+ update: [
992
+ Permission.ProjectOwner,
993
+ Permission.ProjectAdmin,
994
+ Permission.ProjectMember,
995
+ Permission.StatusPageAdmin,
996
+ Permission.StatusPageMember,
997
+ Permission.EditStatusPageResource,
998
+ ],
999
+ })
1000
+ @TableColumn({
1001
+ type: TableColumnType.ShortText,
1002
+ required: false,
1003
+ title: "Column Axis Value",
1004
+ description:
1005
+ "Column this resource belongs to when its status page group is rendered as a grid. Should match one of the column axis values defined on the group.",
1006
+ example: "US-East",
1007
+ })
1008
+ @Column({
1009
+ nullable: true,
1010
+ type: ColumnType.ShortText,
1011
+ length: ColumnLength.ShortText,
1012
+ })
1013
+ public columnAxisValue?: string = undefined;
1014
+
929
1015
  @ColumnAccessControl({
930
1016
  create: [],
931
1017
  read: [],
@@ -3070,11 +3070,16 @@ export default class StatusPageAPI extends BaseAPI<
3070
3070
  statusPageGroupId: true,
3071
3071
  statusPageGroup: {
3072
3072
  name: true,
3073
+ viewMode: true,
3074
+ rowAxisLabel: true,
3075
+ columnAxisLabel: true,
3073
3076
  },
3074
3077
  monitorId: true,
3075
3078
  displayTooltip: true,
3076
3079
  displayDescription: true,
3077
3080
  displayName: true,
3081
+ rowAxisValue: true,
3082
+ columnAxisValue: true,
3078
3083
  monitorGroupId: true,
3079
3084
  monitor: {
3080
3085
  _id: true,
@@ -4837,6 +4842,11 @@ export default class StatusPageAPI extends BaseAPI<
4837
4842
  showCurrentStatus: true,
4838
4843
  showUptimePercent: true,
4839
4844
  uptimePercentPrecision: true,
4845
+ viewMode: true,
4846
+ rowAxisLabel: true,
4847
+ columnAxisLabel: true,
4848
+ rowAxisValues: true,
4849
+ columnAxisValues: true,
4840
4850
  },
4841
4851
  sort: {
4842
4852
  order: SortOrder.Ascending,
@@ -4858,6 +4868,9 @@ export default class StatusPageAPI extends BaseAPI<
4858
4868
  statusPageGroupId: true,
4859
4869
  statusPageGroup: {
4860
4870
  name: true,
4871
+ viewMode: true,
4872
+ rowAxisLabel: true,
4873
+ columnAxisLabel: true,
4861
4874
  },
4862
4875
  monitorId: true,
4863
4876
  displayTooltip: true,
@@ -4873,6 +4886,8 @@ export default class StatusPageAPI extends BaseAPI<
4873
4886
  monitorGroupId: true,
4874
4887
  showUptimePercent: true,
4875
4888
  uptimePercentPrecision: true,
4889
+ rowAxisValue: true,
4890
+ columnAxisValue: true,
4876
4891
  },
4877
4892
  sort: {
4878
4893
  order: SortOrder.Ascending,
@@ -1,20 +1,68 @@
1
1
  import { MigrationInterface, QueryRunner } from "typeorm";
2
2
 
3
3
  export class MigrationName1779879993421 implements MigrationInterface {
4
- public name = 'MigrationName1779879993421'
4
+ public name = "MigrationName1779879993421";
5
5
 
6
- public async up(queryRunner: QueryRunner): Promise<void> {
7
- await queryRunner.query(`DROP INDEX "public"."IDX_telemetry_exception_project_service_fingerprint"`);
8
- await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`);
9
- await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`);
10
- await queryRunner.query(`CREATE UNIQUE INDEX "IDX_1f55d43a0b73e883bb226158c7" ON "TelemetryException" ("projectId", "serviceId", "fingerprint") `);
11
- }
12
-
13
- public async down(queryRunner: QueryRunner): Promise<void> {
14
- await queryRunner.query(`DROP INDEX "public"."IDX_1f55d43a0b73e883bb226158c7"`);
15
- await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`);
16
- await queryRunner.query(`ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`);
17
- await queryRunner.query(`CREATE UNIQUE INDEX "IDX_telemetry_exception_project_service_fingerprint" ON "TelemetryException" ("projectId", "serviceId", "fingerprint") `);
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(
8
+ `DROP INDEX IF EXISTS "public"."IDX_telemetry_exception_project_service_fingerprint"`,
9
+ );
10
+ await queryRunner.query(
11
+ `ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
12
+ );
13
+ await queryRunner.query(
14
+ `ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
15
+ );
16
+ /*
17
+ * Remove pre-existing duplicates so the unique index below can be created.
18
+ * Done as: one cheap GROUP BY to find duplicate keys, then a small DELETE
19
+ * per key — keeps every individual statement well under the 30s
20
+ * statement/query timeout that applies to the migration connection.
21
+ */
22
+ const duplicateKeys: Array<{
23
+ projectId: string;
24
+ serviceId: string;
25
+ fingerprint: string;
26
+ }> = await queryRunner.query(
27
+ `SELECT "projectId", "serviceId", "fingerprint"
28
+ FROM "TelemetryException"
29
+ GROUP BY "projectId", "serviceId", "fingerprint"
30
+ HAVING COUNT(*) > 1`,
31
+ );
32
+ for (const key of duplicateKeys) {
33
+ await queryRunner.query(
34
+ `DELETE FROM "TelemetryException"
35
+ WHERE "projectId" = $1
36
+ AND "serviceId" = $2
37
+ AND "fingerprint" = $3
38
+ AND "_id" <> (
39
+ SELECT "_id" FROM "TelemetryException"
40
+ WHERE "projectId" = $1
41
+ AND "serviceId" = $2
42
+ AND "fingerprint" = $3
43
+ ORDER BY "lastSeenAt" DESC NULLS LAST, "_id" DESC
44
+ LIMIT 1
45
+ )`,
46
+ [key.projectId, key.serviceId, key.fingerprint],
47
+ );
18
48
  }
49
+ await queryRunner.query(
50
+ `CREATE UNIQUE INDEX IF NOT EXISTS "IDX_1f55d43a0b73e883bb226158c7" ON "TelemetryException" ("projectId", "serviceId", "fingerprint") `,
51
+ );
52
+ }
19
53
 
54
+ public async down(queryRunner: QueryRunner): Promise<void> {
55
+ await queryRunner.query(
56
+ `DROP INDEX IF EXISTS "public"."IDX_1f55d43a0b73e883bb226158c7"`,
57
+ );
58
+ await queryRunner.query(
59
+ `ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
60
+ );
61
+ await queryRunner.query(
62
+ `ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
63
+ );
64
+ await queryRunner.query(
65
+ `CREATE UNIQUE INDEX IF NOT EXISTS "IDX_telemetry_exception_project_service_fingerprint" ON "TelemetryException" ("projectId", "serviceId", "fingerprint") `,
66
+ );
67
+ }
20
68
  }
@@ -0,0 +1,65 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class MigrationName1779882573463 implements MigrationInterface {
4
+ public name = "MigrationName1779882573463";
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(
8
+ `ALTER TABLE "StatusPageGroup" ADD "viewMode" character varying DEFAULT 'List'`,
9
+ );
10
+ await queryRunner.query(
11
+ `ALTER TABLE "StatusPageGroup" ADD "rowAxisLabel" character varying(100)`,
12
+ );
13
+ await queryRunner.query(
14
+ `ALTER TABLE "StatusPageGroup" ADD "columnAxisLabel" character varying(100)`,
15
+ );
16
+ await queryRunner.query(
17
+ `ALTER TABLE "StatusPageGroup" ADD "rowAxisValues" character varying(500)`,
18
+ );
19
+ await queryRunner.query(
20
+ `ALTER TABLE "StatusPageGroup" ADD "columnAxisValues" character varying(500)`,
21
+ );
22
+ await queryRunner.query(
23
+ `ALTER TABLE "StatusPageResource" ADD "rowAxisValue" character varying(100)`,
24
+ );
25
+ await queryRunner.query(
26
+ `ALTER TABLE "StatusPageResource" ADD "columnAxisValue" character varying(100)`,
27
+ );
28
+ await queryRunner.query(
29
+ `ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type":"Recurring","value":{"intervalType":"Day","intervalCount":{"_type":"PositiveNumber","value":1}}}'`,
30
+ );
31
+ await queryRunner.query(
32
+ `ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type":"RestrictionTimes","value":{"restictionType":"None","dayRestrictionTimes":null,"weeklyRestrictionTimes":[]}}'`,
33
+ );
34
+ }
35
+
36
+ public async down(queryRunner: QueryRunner): Promise<void> {
37
+ await queryRunner.query(
38
+ `ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "restrictionTimes" SET DEFAULT '{"_type": "RestrictionTimes", "value": {"restictionType": "None", "dayRestrictionTimes": null, "weeklyRestrictionTimes": []}}'`,
39
+ );
40
+ await queryRunner.query(
41
+ `ALTER TABLE "OnCallDutyPolicyScheduleLayer" ALTER COLUMN "rotation" SET DEFAULT '{"_type": "Recurring", "value": {"intervalType": "Day", "intervalCount": {"_type": "PositiveNumber", "value": 1}}}'`,
42
+ );
43
+ await queryRunner.query(
44
+ `ALTER TABLE "StatusPageResource" DROP COLUMN "columnAxisValue"`,
45
+ );
46
+ await queryRunner.query(
47
+ `ALTER TABLE "StatusPageResource" DROP COLUMN "rowAxisValue"`,
48
+ );
49
+ await queryRunner.query(
50
+ `ALTER TABLE "StatusPageGroup" DROP COLUMN "columnAxisValues"`,
51
+ );
52
+ await queryRunner.query(
53
+ `ALTER TABLE "StatusPageGroup" DROP COLUMN "rowAxisValues"`,
54
+ );
55
+ await queryRunner.query(
56
+ `ALTER TABLE "StatusPageGroup" DROP COLUMN "columnAxisLabel"`,
57
+ );
58
+ await queryRunner.query(
59
+ `ALTER TABLE "StatusPageGroup" DROP COLUMN "rowAxisLabel"`,
60
+ );
61
+ await queryRunner.query(
62
+ `ALTER TABLE "StatusPageGroup" DROP COLUMN "viewMode"`,
63
+ );
64
+ }
65
+ }