@oneuptime/common 7.0.2972 → 7.0.2976

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 (40) hide show
  1. package/Models/DatabaseModels/StatusPage.ts +71 -0
  2. package/Models/DatabaseModels/StatusPageResource.ts +1 -7
  3. package/Server/API/StatusPageAPI.ts +2 -0
  4. package/Server/Infrastructure/Postgres/SchemaMigrations/1723825511054-MigrationName.ts +17 -0
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1723828588502-MigrationName.ts +17 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  7. package/Server/Services/StatusPageService.ts +11 -3
  8. package/Types/Domain.ts +1 -1
  9. package/Types/Monitor/MonitorSteps.ts +1 -1
  10. package/Types/StatusPage/UptimePrecision.ts +8 -0
  11. package/UI/Components/Alerts/Alert.tsx +18 -7
  12. package/UI/Components/Link/Link.tsx +14 -0
  13. package/Utils/Uptime/UptimeUtil.ts +119 -6
  14. package/build/dist/Models/DatabaseModels/StatusPage.js +75 -0
  15. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  16. package/build/dist/Models/DatabaseModels/StatusPageResource.js +1 -7
  17. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  18. package/build/dist/Server/API/StatusPageAPI.js +2 -0
  19. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  20. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1723825511054-MigrationName.js +12 -0
  21. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1723825511054-MigrationName.js.map +1 -0
  22. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1723828588502-MigrationName.js +12 -0
  23. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1723828588502-MigrationName.js.map +1 -0
  24. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  25. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  26. package/build/dist/Server/Services/StatusPageService.js +6 -1
  27. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  28. package/build/dist/Types/Domain.js +1 -1
  29. package/build/dist/Types/Domain.js.map +1 -1
  30. package/build/dist/Types/Monitor/MonitorSteps.js +1 -1
  31. package/build/dist/Types/Monitor/MonitorSteps.js.map +1 -1
  32. package/build/dist/Types/StatusPage/UptimePrecision.js +9 -0
  33. package/build/dist/Types/StatusPage/UptimePrecision.js.map +1 -0
  34. package/build/dist/UI/Components/Alerts/Alert.js +11 -8
  35. package/build/dist/UI/Components/Alerts/Alert.js.map +1 -1
  36. package/build/dist/UI/Components/Link/Link.js +13 -1
  37. package/build/dist/UI/Components/Link/Link.js.map +1 -1
  38. package/build/dist/Utils/Uptime/UptimeUtil.js +72 -5
  39. package/build/dist/Utils/Uptime/UptimeUtil.js.map +1 -1
  40. package/package.json +2 -2
@@ -39,6 +39,7 @@ import {
39
39
  ManyToMany,
40
40
  ManyToOne,
41
41
  } from "typeorm";
42
+ import UptimePrecision from "../../Types/StatusPage/UptimePrecision";
42
43
 
43
44
  @EnableDocumentation()
44
45
  @AccessControlColumn("labels")
@@ -1864,4 +1865,74 @@ export default class StatusPage extends BaseModel {
1864
1865
  create: PlanType.Free,
1865
1866
  })
1866
1867
  public reportDataInDays?: number = undefined;
1868
+
1869
+ @ColumnAccessControl({
1870
+ create: [
1871
+ Permission.ProjectOwner,
1872
+ Permission.ProjectAdmin,
1873
+ Permission.ProjectMember,
1874
+ Permission.CreateProjectStatusPage,
1875
+ ],
1876
+ read: [
1877
+ Permission.ProjectOwner,
1878
+ Permission.ProjectAdmin,
1879
+ Permission.ProjectMember,
1880
+ Permission.ReadProjectStatusPage,
1881
+ ],
1882
+ update: [
1883
+ Permission.ProjectOwner,
1884
+ Permission.ProjectAdmin,
1885
+ Permission.ProjectMember,
1886
+ Permission.EditProjectStatusPage,
1887
+ ],
1888
+ })
1889
+ @TableColumn({
1890
+ isDefaultValueColumn: true,
1891
+ type: TableColumnType.Boolean,
1892
+ title: "Show Overall Uptime Percent on Status Page",
1893
+ description: "Show Overall Uptime Percent on Status Page?",
1894
+ })
1895
+ @Column({
1896
+ type: ColumnType.Boolean,
1897
+ default: false,
1898
+ })
1899
+ @ColumnBillingAccessControl({
1900
+ read: PlanType.Free,
1901
+ update: PlanType.Scale,
1902
+ create: PlanType.Free,
1903
+ })
1904
+ public showOverallUptimePercentOnStatusPage?: boolean = undefined;
1905
+
1906
+ @ColumnAccessControl({
1907
+ create: [
1908
+ Permission.ProjectOwner,
1909
+ Permission.ProjectAdmin,
1910
+ Permission.ProjectMember,
1911
+ Permission.CreateProjectStatusPage,
1912
+ ],
1913
+ read: [
1914
+ Permission.ProjectOwner,
1915
+ Permission.ProjectAdmin,
1916
+ Permission.ProjectMember,
1917
+ Permission.ReadProjectStatusPage,
1918
+ ],
1919
+ update: [
1920
+ Permission.ProjectOwner,
1921
+ Permission.ProjectAdmin,
1922
+ Permission.ProjectMember,
1923
+ Permission.EditProjectStatusPage,
1924
+ ],
1925
+ })
1926
+ @TableColumn({
1927
+ type: TableColumnType.ShortText,
1928
+ title: "Overall Uptime Percent Precision",
1929
+ required: false,
1930
+ description: "Overall Precision of uptime percent for this status page.",
1931
+ })
1932
+ @Column({
1933
+ type: ColumnType.ShortText,
1934
+ nullable: true,
1935
+ default: UptimePrecision.TWO_DECIMAL,
1936
+ })
1937
+ public overallUptimePercentPrecision?: UptimePrecision = undefined;
1867
1938
  }
@@ -23,13 +23,7 @@ import IconProp from "../../Types/Icon/IconProp";
23
23
  import ObjectID from "../../Types/ObjectID";
24
24
  import Permission from "../../Types/Permission";
25
25
  import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
26
-
27
- export enum UptimePrecision {
28
- NO_DECIMAL = "99% (No Decimal)",
29
- ONE_DECIMAL = "99.9% (One Decimal)",
30
- TWO_DECIMAL = "99.99% (Two Decimal)",
31
- THREE_DECIMAL = "99.999% (Three Decimal)",
32
- }
26
+ import UptimePrecision from "../../Types/StatusPage/UptimePrecision";
33
27
 
34
28
  @EnableDocumentation()
35
29
  @CanAccessIfCanReadOn("statusPage")
@@ -494,6 +494,8 @@ export default class StatusPageAPI extends BaseAPI<
494
494
  _id: true,
495
495
  },
496
496
  defaultBarColor: true,
497
+ showOverallUptimePercentOnStatusPage: true,
498
+ overallUptimePercentPrecision: true,
497
499
  },
498
500
  props: {
499
501
  isRoot: true,
@@ -0,0 +1,17 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class MigrationName1723825511054 implements MigrationInterface {
4
+ public name = "MigrationName1723825511054";
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(
8
+ `ALTER TABLE "StatusPage" ADD "showOverallUptimePercentOnStatusPage" boolean NOT NULL DEFAULT false`,
9
+ );
10
+ }
11
+
12
+ public async down(queryRunner: QueryRunner): Promise<void> {
13
+ await queryRunner.query(
14
+ `ALTER TABLE "StatusPage" DROP COLUMN "showOverallUptimePercentOnStatusPage"`,
15
+ );
16
+ }
17
+ }
@@ -0,0 +1,17 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class MigrationName1723828588502 implements MigrationInterface {
4
+ public name = "MigrationName1723828588502";
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(
8
+ `ALTER TABLE "StatusPage" ADD "overallUptimePercentPrecision" character varying DEFAULT '99.99% (Two Decimal)'`,
9
+ );
10
+ }
11
+
12
+ public async down(queryRunner: QueryRunner): Promise<void> {
13
+ await queryRunner.query(
14
+ `ALTER TABLE "StatusPage" DROP COLUMN "overallUptimePercentPrecision"`,
15
+ );
16
+ }
17
+ }
@@ -38,6 +38,8 @@ import { MigrationName1721779190475 } from "./1721779190475-MigrationName";
38
38
  import { MigrationName1722031205897 } from "./1722031205897-MigrationName";
39
39
  import { MigrationName1722543640526 } from "./1722543640526-MigrationName";
40
40
  import { MigrationName1722892318363 } from "./1722892318363-MigrationName";
41
+ import { MigrationName1723825511054 } from "./1723825511054-MigrationName";
42
+ import { MigrationName1723828588502 } from "./1723828588502-MigrationName";
41
43
 
42
44
  export default [
43
45
  InitialMigration,
@@ -80,4 +82,6 @@ export default [
80
82
  MigrationName1722031205897,
81
83
  MigrationName1722543640526,
82
84
  MigrationName1722892318363,
85
+ MigrationName1723825511054,
86
+ MigrationName1723828588502,
83
87
  ];
@@ -43,9 +43,7 @@ import MailService from "./MailService";
43
43
  import EmailTemplateType from "../../Types/Email/EmailTemplateType";
44
44
  import { FileRoute } from "Common/ServiceRoute";
45
45
  import ProjectSMTPConfigService from "./ProjectSmtpConfigService";
46
- import StatusPageResource, {
47
- UptimePrecision,
48
- } from "Common/Models/DatabaseModels/StatusPageResource";
46
+ import StatusPageResource from "Common/Models/DatabaseModels/StatusPageResource";
49
47
  import StatusPageResourceService from "./StatusPageResourceService";
50
48
  import Dictionary from "../../Types/Dictionary";
51
49
  import MonitorGroupResource from "Common/Models/DatabaseModels/MonitorGroupResource";
@@ -57,6 +55,7 @@ import MonitorStatusTimeline from "Common/Models/DatabaseModels/MonitorStatusTim
57
55
  import MonitorStatusTimelineService from "./MonitorStatusTimelineService";
58
56
  import SortOrder from "../../Types/BaseDatabase/SortOrder";
59
57
  import UptimeUtil from "Common/Utils/Uptime/UptimeUtil";
58
+ import UptimePrecision from "../../Types/StatusPage/UptimePrecision";
60
59
 
61
60
  export interface StatusPageReportItem {
62
61
  resourceName: string;
@@ -67,6 +66,7 @@ export interface StatusPageReportItem {
67
66
  }
68
67
 
69
68
  export interface StatusPageReport {
69
+ reportDates: string; // start date and end date in string. e.g. "01 July 2021 - 14 July 2021"
70
70
  totalResources: number;
71
71
  totalIncidents: number;
72
72
  averageUptimePercent: string;
@@ -755,8 +755,15 @@ export class Service extends DatabaseService<StatusPage> {
755
755
  statusPageId: data.statusPageId,
756
756
  });
757
757
 
758
+ const currentDate: Date = OneUptimeDate.getCurrentDate();
759
+ const startDate: Date = OneUptimeDate.getSomeDaysAgo(
760
+ data.historyDays || 14,
761
+ );
762
+ const startAndEndDate: string = `${OneUptimeDate.getDateAsLocalFormattedString(startDate, true)} - ${OneUptimeDate.getDateAsLocalFormattedString(currentDate, true)}`;
763
+
758
764
  if (statusPageResources.length === 0) {
759
765
  return {
766
+ reportDates: startAndEndDate,
760
767
  totalResources: 0,
761
768
  totalIncidents: 0,
762
769
  averageUptimePercent: "0%",
@@ -854,6 +861,7 @@ export class Service extends DatabaseService<StatusPage> {
854
861
  );
855
862
 
856
863
  return {
864
+ reportDates: startAndEndDate,
857
865
  totalResources: statusPageResources.length,
858
866
  totalIncidents: incidentCount,
859
867
  averageUptimePercent: avgUptimePercentString,
package/Types/Domain.ts CHANGED
@@ -26,7 +26,7 @@ export default class Domain extends DatabaseProperty {
26
26
  "|",
27
27
  );
28
28
  const secondTLDs: Array<string> =
29
- "ac|academy|accountant|accountants|actor|adult|aero|ag|agency|ai|airforce|am|amsterdam|apartments|app|archi|army|art|asia|associates|at|attorney|au|auction|auto|autos|baby|band|bar|barcelona|bargains|basketball|bayern|be|beauty|beer|berlin|best|bet|bid|bike|bingo|bio|biz|biz.pl|black|blog|blue|boats|boston|boutique|broker|build|builders|business|buzz|bz|ca|cab|cafe|camera|camp|capital|car|cards|care|careers|cars|casa|cash|casino|catering|cc|center|ceo|ch|charity|chat|cheap|church|city|cl|claims|cleaning|clinic|clothing|cloud|club|cn|co|co.in|co.jp|co.kr|co.nz|co.uk|co.za|coach|codes|coffee|college|com|com.ag|com.au|com.br|com.bz|com.cn|com.co|com.es|com.ky|com.mx|com.pe|com.ph|com.pl|com.ru|com.tw|community|company|computer|condos|construction|consulting|contact|contractors|cooking|cool|country|coupons|courses|credit|creditcard|cricket|cruises|cymru|cz|dance|date|dating|de|deals|degree|delivery|democrat|dental|dentist|design|dev|diamonds|digital|direct|directory|discount|dk|doctor|dog|domains|download|earth|education|email|energy|engineer|engineering|enterprises|equipment|es|estate|eu|events|exchange|expert|exposed|express|fail|faith|family|fan|fans|farm|fashion|film|finance|financial|firm.in|fish|fishing|fit|fitness|flights|florist|fm|football|forsale|foundation|fr|fun|fund|furniture|futbol|fyi|gallery|games|garden|gay|gen.in|gg|gifts|gives|giving|glass|global|gmbh|gold|golf|graphics|gratis|green|gripe|group|gs|guide|guru|hair|haus|health|healthcare|hockey|holdings|holiday|homes|horse|hospital|host|house|idv.tw|immo|immobilien|in|inc|ind.in|industries|info|info.pl|ink|institute|insure|international|investments|io|irish|ist|istanbul|it|jetzt|jewelry|jobs|jp|kaufen|kids|kim|kitchen|kiwi|kr|ky|la|land|lat|law|lawyer|lease|legal|lgbt|life|lighting|limited|limo|live|llc|llp|loan|loans|london|love|ltd|ltda|luxury|maison|makeup|management|market|marketing|mba|me|me.uk|media|melbourne|memorial|men|menu|miami|mobi|moda|moe|money|monster|mortgage|motorcycles|movie|ms|music|mx|nagoya|name|navy|ne.kr|net|net.ag|net.au|net.br|net.bz|net.cn|net.co|net.in|net.ky|net.nz|net.pe|net.ph|net.pl|net.ru|network|news|ninja|nl|no|nom.co|nom.es|nom.pe|nrw|nyc|okinawa|one|onl|online|org|org.ag|org.au|org.cn|org.es|org.in|org.ky|org.nz|org.pe|org.ph|org.pl|org.ru|org.uk|organic|page|paris|partners|parts|party|pe|pet|ph|photography|photos|pictures|pink|pizza|pl|place|plumbing|plus|poker|porn|press|pro|productions|promo|properties|protection|pub|pw|quebec|quest|racing|re.kr|realestate|recipes|red|rehab|reise|reisen|rent|rentals|repair|report|republican|rest|restaurant|review|reviews|rich|rip|rocks|rodeo|rugby|run|ryukyu|sale|salon|sarl|school|schule|science|se|security|services|sex|sg|sh|shiksha|shoes|shop|shopping|show|singles|site|ski|skin|soccer|social|software|solar|solutions|space|storage|store|stream|studio|study|style|supplies|supply|support|surf|surgery|sydney|systems|tax|taxi|team|tech|technology|tel|tennis|theater|theatre|tickets|tienda|tips|tires|today|tokyo|tools|tours|town|toys|trade|trading|training|travel|tube|tv|tw|uk|university|uno|us|vacations|vc|vegas|ventures|vet|viajes|video|villas|vin|vip|vision|vodka|vote|voto|voyage|wales|watch|web|webcam|website|wedding|wiki|win|wine|work|works|world|ws|wtf|xxx|xyz|yachts|yoga|yokohama|zone|移动|dev|com|edu|gov|net|mil|org|nom|sch|sbs|caa|res|off|gob|int|tur|ip6|uri|urn|asn|act|nsw|qld|tas|vic|pro|biz|adm|adv|agr|arq|art|ato|bio|bmd|cim|cng|cnt|ecn|eco|emp|eng|esp|etc|eti|far|fnd|fot|fst|g12|ggf|imb|ind|inf|jor|jus|leg|lel|mat|med|mus|not|ntr|odo|ppg|psc|psi|qsl|rec|slg|srv|teo|tmp|trd|vet|zlg|web|ltd|sld|pol|fin|k12|lib|pri|aip|fie|eun|sci|prd|cci|pvt|mod|idv|rel|sex|gen|nic|abr|bas|cal|cam|emr|fvg|laz|lig|lom|mar|mol|pmn|pug|sar|sic|taa|tos|umb|vao|vda|ven|mie|北海道|和歌山|神奈川|鹿児島|ass|rep|tra|per|ngo|soc|grp|plc|its|air|and|bus|can|ddr|jfk|mad|nrw|nyc|ski|spy|tcm|ulm|usa|war|fhs|vgs|dep|eid|fet|fla|flå|gol|hof|hol|sel|vik|cri|iwi|ing|abo|fam|gok|gon|gop|gos|aid|atm|gsm|sos|elk|waw|est|aca|bar|cpa|jur|law|sec|plo|www|bir|cbg|jar|khv|msk|nov|nsk|ptz|rnd|spb|stv|tom|tsk|udm|vrn|cmw|kms|nkz|snz|pub|fhv|red|ens|nat|rns|rnu|bbs|tel|bel|kep|nhs|dni|fed|isa|nsn|gub|e12|tec|орг|обр|упр|alt|nis|jpn|mex|ath|iki|nid|gda|inc|za|ovh".split(
29
+ "ac|academy|accountant|accountants|actor|adult|aero|ag|agency|ai|airforce|am|amsterdam|apartments|app|archi|army|art|asia|associates|at|attorney|au|auction|auto|autos|baby|band|bar|barcelona|bargains|basketball|bayern|be|beauty|beer|berlin|best|bet|bid|bike|bingo|bio|biz|biz.pl|black|blog|blue|boats|boston|boutique|broker|build|builders|business|buzz|bz|ca|cab|cafe|camera|camp|capital|car|cards|care|careers|cars|casa|cash|casino|catering|cc|center|ceo|ch|charity|chat|cheap|church|city|cl|claims|cleaning|clinic|clothing|cloud|club|cn|co|co.in|co.jp|co.kr|co.nz|co.uk|co.za|coach|codes|coffee|college|com|com.ag|com.au|com.br|com.bz|com.cn|com.co|com.es|com.ky|com.mx|com.pe|com.ph|com.pl|com.ru|com.tw|community|company|computer|condos|construction|consulting|contact|contractors|cooking|cool|country|coupons|courses|credit|creditcard|cricket|cruises|cymru|cz|dance|date|dating|de|deals|degree|delivery|democrat|dental|dentist|design|dev|diamonds|digital|direct|directory|discount|dk|doctor|dog|domains|download|earth|education|email|energy|engineer|engineering|enterprises|equipment|es|estate|eu|events|exchange|expert|exposed|express|fail|faith|family|fan|fans|farm|fashion|film|finance|financial|firm.in|fish|fishing|fit|fitness|flights|florist|fm|football|forsale|foundation|fr|fun|fund|furniture|futbol|fyi|gallery|games|garden|gay|gen.in|gg|gifts|gives|giving|glass|global|gmbh|gold|golf|graphics|gratis|green|gripe|group|gs|guide|guru|hair|haus|health|healthcare|hockey|holdings|holiday|homes|horse|hospital|host|house|idv.tw|immo|immobilien|in|inc|ind.in|industries|info|info.pl|ink|institute|insure|international|investments|io|irish|ist|istanbul|it|jetzt|jewelry|jobs|jp|kaufen|kids|kim|kitchen|kiwi|kr|ky|la|land|lat|law|lawyer|lease|legal|lgbt|life|lighting|limited|limo|live|llc|llp|loan|loans|london|love|ltd|ltda|luxury|maison|makeup|management|market|marketing|mba|me|me.uk|media|melbourne|memorial|men|menu|miami|mobi|moda|moe|money|monster|mortgage|motorcycles|movie|ms|music|mx|nagoya|name|navy|ne.kr|net|net.ag|net.au|net.br|net.bz|net.cn|net.co|net.in|net.ky|net.nz|net.pe|net.ph|net.pl|net.ru|network|news|ninja|nl|no|nom.co|nom.es|nom.pe|nrw|nyc|okinawa|one|onl|online|org|org.ag|org.au|org.cn|org.es|org.in|org.ky|org.nz|org.pe|org.ph|org.pl|org.ru|org.uk|organic|page|paris|partners|parts|party|pe|pet|ph|photography|photos|pictures|pink|pizza|pl|place|plumbing|plus|poker|porn|press|pro|productions|promo|properties|protection|pub|pw|quebec|quest|racing|re.kr|realestate|recipes|red|rehab|reise|reisen|rent|rentals|repair|report|republican|rest|restaurant|review|reviews|rich|rip|rocks|rodeo|rugby|run|ryukyu|sale|salon|sarl|school|schule|science|se|security|services|sex|sg|sh|shiksha|shoes|shop|shopping|show|singles|site|ski|skin|soccer|social|software|solar|solutions|space|storage|store|stream|studio|study|style|supplies|supply|support|surf|surgery|sydney|systems|tax|taxi|team|tech|technology|tel|tennis|theater|theatre|tickets|tienda|tips|tires|today|tokyo|tools|tours|town|toys|trade|trading|training|travel|tube|tv|tw|uk|university|uno|us|vacations|vc|vegas|ventures|vet|viajes|video|villas|vin|vip|vision|vodka|vote|voto|voyage|wales|watch|web|webcam|website|wedding|wiki|win|wine|work|works|world|ws|wtf|xxx|xyz|yachts|yoga|yokohama|zone|移动|dev|com|edu|gov|net|mil|org|nom|sch|sbs|caa|res|off|gob|int|tur|ip6|uri|urn|asn|act|nsw|qld|tas|vic|pro|biz|adm|adv|agr|arq|art|ato|bio|bmd|cim|cng|cnt|ecn|eco|emp|eng|esp|etc|eti|far|fnd|fot|fst|g12|ggf|imb|ind|inf|jor|jus|leg|lel|mat|med|mus|not|ntr|odo|ppg|psc|psi|qsl|rec|slg|srv|teo|tmp|trd|vet|zlg|web|ltd|sld|pol|fin|k12|lib|pri|aip|fie|eun|sci|prd|cci|pvt|mod|idv|rel|sex|gen|nic|abr|bas|cal|cam|emr|fvg|laz|lig|lom|mar|mol|pmn|pug|sar|sic|taa|tos|umb|vao|vda|ven|mie|北海道|和歌山|神奈川|鹿児島|ass|rep|tra|per|ngo|soc|grp|plc|its|air|and|bus|can|ddr|jfk|mad|nrw|nyc|ski|spy|tcm|ulm|usa|war|fhs|vgs|dep|eid|fet|fla|flå|gol|hof|hol|sel|vik|cri|iwi|ing|abo|fam|gok|gon|gop|gos|aid|atm|gsm|sos|elk|waw|est|aca|bar|cpa|jur|law|sec|plo|www|bir|cbg|jar|khv|msk|nov|nsk|ptz|rnd|spb|stv|tom|tsk|udm|vrn|cmw|kms|nkz|snz|pub|fhv|red|ens|nat|rns|rnu|bbs|tel|bel|kep|nhs|dni|fed|isa|nsn|gub|e12|tec|орг|обр|упр|alt|nis|jpn|mex|ath|iki|nid|gda|inc|za|ovh|lol".split(
30
30
  "|",
31
31
  );
32
32
 
@@ -93,7 +93,7 @@ export default class MonitorSteps extends DatabaseProperty {
93
93
  public static override fromJSON(
94
94
  json: JSONObject | MonitorSteps | undefined,
95
95
  ): MonitorSteps {
96
- if (json === undefined) {
96
+ if (!json) {
97
97
  return new MonitorSteps();
98
98
  }
99
99
 
@@ -0,0 +1,8 @@
1
+ enum UptimePrecision {
2
+ NO_DECIMAL = "99% (No Decimal)",
3
+ ONE_DECIMAL = "99.9% (One Decimal)",
4
+ TWO_DECIMAL = "99.99% (Two Decimal)",
5
+ THREE_DECIMAL = "99.999% (Three Decimal)",
6
+ }
7
+
8
+ export default UptimePrecision;
@@ -27,6 +27,7 @@ export interface ComponentProps {
27
27
  className?: string | undefined;
28
28
  color?: Color | undefined;
29
29
  id?: string | undefined;
30
+ textOnRight?: string | undefined;
30
31
  }
31
32
 
32
33
  const Alert: FunctionComponent<ComponentProps> = (
@@ -93,14 +94,24 @@ const Alert: FunctionComponent<ComponentProps> = (
93
94
  </div>
94
95
  )}
95
96
  <div
96
- className={`ml-3 flex-1 md:flex md:justify-between ${props.className}`}
97
+ className={`ml-3 mr-3 flex-1 md:flex md:justify-between ${props.className}`}
97
98
  >
98
- <p className={props.textClassName || `text-sm ${className}-200`}>
99
- <span className="font-medium">
100
- {props.strongTitle} {props.title && props.strongTitle ? "-" : ""}{" "}
101
- </span>
102
- {props.title}
103
- </p>
99
+ <div
100
+ className={
101
+ props.textClassName ||
102
+ `text-sm flex justify-between ${className}-200`
103
+ }
104
+ >
105
+ <div>
106
+ <span className="font-medium">
107
+ {props.strongTitle}{" "}
108
+ {props.title && props.strongTitle ? "-" : ""}{" "}
109
+ </span>
110
+ {props.title}
111
+ </div>
112
+ {props.textOnRight && <div>{props.textOnRight}</div>}
113
+ </div>
114
+
104
115
  {props.onClose && (
105
116
  <p className="mt-3 text-sm md:mt-0 md:ml-6">
106
117
  <button
@@ -48,6 +48,20 @@ const Link: FunctionComponent<ComponentProps> = (
48
48
  onMouseOut={props.onMouseOut}
49
49
  onMouseLeave={props.onMouseLeave}
50
50
  style={props.style}
51
+ onAuxClick={(event: React.MouseEvent<HTMLAnchorElement>) => {
52
+ // middle click
53
+ if (event.button === 1) {
54
+ if (props.to) {
55
+ Navigation.navigate(props.to, {
56
+ openInNewTab: true,
57
+ });
58
+
59
+ if (props.onNavigateComplete) {
60
+ props.onNavigateComplete();
61
+ }
62
+ }
63
+ }
64
+ }}
51
65
  onClick={() => {
52
66
  if (props.onClick) {
53
67
  props.onClick();
@@ -5,7 +5,9 @@ import OneUptimeDate from "../../Types/Date";
5
5
  import ObjectID from "../../Types/ObjectID";
6
6
  import MonitorStatus from "../../Models/DatabaseModels/MonitorStatus";
7
7
  import MonitorStatusTimeline from "../../Models/DatabaseModels/MonitorStatusTimeline";
8
- import { UptimePrecision } from "../../Models/DatabaseModels/StatusPageResource";
8
+ import StatusPageResource from "../../Models/DatabaseModels/StatusPageResource";
9
+ import Dictionary from "../../Types/Dictionary";
10
+ import UptimePrecision from "../../Types/StatusPage/UptimePrecision";
9
11
 
10
12
  export default class UptimeUtil {
11
13
  /**
@@ -221,14 +223,15 @@ export default class UptimeUtil {
221
223
  }
222
224
 
223
225
  public static getTotalDowntimeInSeconds(
224
- items: Array<MonitorStatusTimeline>,
226
+ monitorStatusTimelines: Array<MonitorStatusTimeline>,
225
227
  downtimeMonitorStatuses: Array<MonitorStatus>,
226
228
  ): {
227
229
  totalDowntimeInSeconds: number;
228
230
  totalSecondsInTimePeriod: number;
229
231
  } {
230
- const monitorEvents: Array<Event> =
231
- this.getNonOverlappingMonitorEvents(items);
232
+ const monitorEvents: Array<Event> = this.getNonOverlappingMonitorEvents(
233
+ monitorStatusTimelines,
234
+ );
232
235
 
233
236
  // sort these by start date,
234
237
  monitorEvents.sort((a: Event, b: Event) => {
@@ -298,15 +301,125 @@ export default class UptimeUtil {
298
301
  };
299
302
  }
300
303
 
304
+ public static calculateAvgUptimePercentageOfAllResources(data: {
305
+ monitorStatusTimelines: Array<MonitorStatusTimeline>;
306
+ precision: UptimePrecision;
307
+ downtimeMonitorStatuses: Array<MonitorStatus>;
308
+ statusPageResources: Array<StatusPageResource>;
309
+ monitorsInGroup: Dictionary<Array<ObjectID>>;
310
+ }): number | null {
311
+ const showUptimePercentage: boolean = Boolean(
312
+ data.statusPageResources.find((item: StatusPageResource) => {
313
+ return item.showUptimePercent || item.showStatusHistoryChart;
314
+ }),
315
+ );
316
+
317
+ if (!showUptimePercentage) {
318
+ return null;
319
+ }
320
+
321
+ const uptimePercentPerResource: Array<number> = [];
322
+
323
+ for (const resource of data.statusPageResources) {
324
+ if (!resource.showUptimePercent && !resource.showStatusHistoryChart) {
325
+ continue;
326
+ }
327
+
328
+ let timelinesForThisResource: Array<MonitorStatusTimeline> = [];
329
+
330
+ if (resource.monitorGroupId) {
331
+ timelinesForThisResource = [...data.monitorStatusTimelines].filter(
332
+ (timeline: MonitorStatusTimeline) => {
333
+ const monitorsInThisGroup: Array<ObjectID> | undefined =
334
+ data.monitorsInGroup[resource.monitorGroupId?.toString() || ""];
335
+
336
+ if (!monitorsInThisGroup) {
337
+ return false;
338
+ }
339
+
340
+ return monitorsInThisGroup.find((monitorId: ObjectID) => {
341
+ return monitorId.toString() === timeline.monitorId?.toString();
342
+ });
343
+ },
344
+ );
345
+ }
346
+
347
+ if (resource.monitorId || resource.monitor?.id) {
348
+ const monitorId: ObjectID | null | undefined =
349
+ resource.monitorId || resource.monitor?.id;
350
+
351
+ if (!monitorId) {
352
+ // this should never happen.
353
+ continue;
354
+ }
355
+
356
+ timelinesForThisResource = [...data.monitorStatusTimelines].filter(
357
+ (timeline: MonitorStatusTimeline) => {
358
+ return (
359
+ timeline.monitorId?.toString() === resource.monitorId?.toString()
360
+ );
361
+ },
362
+ );
363
+ }
364
+
365
+ const uptimePercent: number = this.calculateUptimePercentage(
366
+ timelinesForThisResource,
367
+ data.precision,
368
+ data.downtimeMonitorStatuses,
369
+ );
370
+
371
+ uptimePercentPerResource.push(uptimePercent);
372
+ }
373
+
374
+ // calculate avg
375
+
376
+ if (uptimePercentPerResource.length === 0) {
377
+ return null;
378
+ }
379
+
380
+ const averageUptimePercentage: number =
381
+ uptimePercentPerResource.reduce((a: number, b: number) => {
382
+ return a + b;
383
+ }) / uptimePercentPerResource.length;
384
+
385
+ //round this to precision.
386
+
387
+ if (data.precision === UptimePrecision.NO_DECIMAL) {
388
+ const percent: number = Math.round(averageUptimePercentage);
389
+
390
+ return percent;
391
+ }
392
+
393
+ if (data.precision === UptimePrecision.ONE_DECIMAL) {
394
+ const percent: number = Math.round(averageUptimePercentage * 10) / 10;
395
+ return percent;
396
+ }
397
+
398
+ if (data.precision === UptimePrecision.TWO_DECIMAL) {
399
+ const percent: number = Math.round(averageUptimePercentage * 100) / 100;
400
+ return percent;
401
+ }
402
+
403
+ if (data.precision === UptimePrecision.THREE_DECIMAL) {
404
+ const percent: number = Math.round(averageUptimePercentage * 1000) / 1000;
405
+ return percent;
406
+ }
407
+
408
+ return averageUptimePercentage;
409
+ }
410
+
301
411
  public static calculateUptimePercentage(
302
- items: Array<MonitorStatusTimeline>,
412
+ monitorStatusTimelines: Array<MonitorStatusTimeline>,
303
413
  precision: UptimePrecision,
304
414
  downtimeMonitorStatuses: Array<MonitorStatus>,
305
415
  ): number {
306
416
  // calculate percentage.
307
417
 
308
418
  const { totalDowntimeInSeconds, totalSecondsInTimePeriod } =
309
- this.getTotalDowntimeInSeconds(items, downtimeMonitorStatuses);
419
+ this.getTotalDowntimeInSeconds(
420
+ monitorStatusTimelines,
421
+ downtimeMonitorStatuses,
422
+ );
310
423
 
311
424
  if (totalSecondsInTimePeriod === 0) {
312
425
  return 100;
@@ -38,6 +38,7 @@ import IconProp from "../../Types/Icon/IconProp";
38
38
  import ObjectID from "../../Types/ObjectID";
39
39
  import Permission from "../../Types/Permission";
40
40
  import { Column, Entity, Index, JoinColumn, JoinTable, ManyToMany, ManyToOne, } from "typeorm";
41
+ import UptimePrecision from "../../Types/StatusPage/UptimePrecision";
41
42
  let StatusPage = class StatusPage extends BaseModel {
42
43
  constructor() {
43
44
  super(...arguments);
@@ -94,6 +95,8 @@ let StatusPage = class StatusPage extends BaseModel {
94
95
  this.reportRecurringInterval = undefined;
95
96
  this.sendNextReportBy = undefined;
96
97
  this.reportDataInDays = undefined;
98
+ this.showOverallUptimePercentOnStatusPage = undefined;
99
+ this.overallUptimePercentPrecision = undefined;
97
100
  }
98
101
  };
99
102
  __decorate([
@@ -1874,6 +1877,78 @@ __decorate([
1874
1877
  }),
1875
1878
  __metadata("design:type", Number)
1876
1879
  ], StatusPage.prototype, "reportDataInDays", void 0);
1880
+ __decorate([
1881
+ ColumnAccessControl({
1882
+ create: [
1883
+ Permission.ProjectOwner,
1884
+ Permission.ProjectAdmin,
1885
+ Permission.ProjectMember,
1886
+ Permission.CreateProjectStatusPage,
1887
+ ],
1888
+ read: [
1889
+ Permission.ProjectOwner,
1890
+ Permission.ProjectAdmin,
1891
+ Permission.ProjectMember,
1892
+ Permission.ReadProjectStatusPage,
1893
+ ],
1894
+ update: [
1895
+ Permission.ProjectOwner,
1896
+ Permission.ProjectAdmin,
1897
+ Permission.ProjectMember,
1898
+ Permission.EditProjectStatusPage,
1899
+ ],
1900
+ }),
1901
+ TableColumn({
1902
+ isDefaultValueColumn: true,
1903
+ type: TableColumnType.Boolean,
1904
+ title: "Show Overall Uptime Percent on Status Page",
1905
+ description: "Show Overall Uptime Percent on Status Page?",
1906
+ }),
1907
+ Column({
1908
+ type: ColumnType.Boolean,
1909
+ default: false,
1910
+ }),
1911
+ ColumnBillingAccessControl({
1912
+ read: PlanType.Free,
1913
+ update: PlanType.Scale,
1914
+ create: PlanType.Free,
1915
+ }),
1916
+ __metadata("design:type", Boolean)
1917
+ ], StatusPage.prototype, "showOverallUptimePercentOnStatusPage", void 0);
1918
+ __decorate([
1919
+ ColumnAccessControl({
1920
+ create: [
1921
+ Permission.ProjectOwner,
1922
+ Permission.ProjectAdmin,
1923
+ Permission.ProjectMember,
1924
+ Permission.CreateProjectStatusPage,
1925
+ ],
1926
+ read: [
1927
+ Permission.ProjectOwner,
1928
+ Permission.ProjectAdmin,
1929
+ Permission.ProjectMember,
1930
+ Permission.ReadProjectStatusPage,
1931
+ ],
1932
+ update: [
1933
+ Permission.ProjectOwner,
1934
+ Permission.ProjectAdmin,
1935
+ Permission.ProjectMember,
1936
+ Permission.EditProjectStatusPage,
1937
+ ],
1938
+ }),
1939
+ TableColumn({
1940
+ type: TableColumnType.ShortText,
1941
+ title: "Overall Uptime Percent Precision",
1942
+ required: false,
1943
+ description: "Overall Precision of uptime percent for this status page.",
1944
+ }),
1945
+ Column({
1946
+ type: ColumnType.ShortText,
1947
+ nullable: true,
1948
+ default: UptimePrecision.TWO_DECIMAL,
1949
+ }),
1950
+ __metadata("design:type", String)
1951
+ ], StatusPage.prototype, "overallUptimePercentPrecision", void 0);
1877
1952
  StatusPage = __decorate([
1878
1953
  EnableDocumentation(),
1879
1954
  AccessControlColumn("labels"),