@oneuptime/common 7.0.4220 → 7.0.4222

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 (121) hide show
  1. package/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.ts +4 -0
  2. package/Models/DatabaseModels/Index.ts +4 -0
  3. package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +498 -0
  4. package/Models/DatabaseModels/UserNotificationRule.ts +0 -2
  5. package/Models/DatabaseModels/WorkspaceNotificationRule.ts +2 -2
  6. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +0 -2
  7. package/Models/DatabaseModels/WorkspaceSetting.ts +0 -2
  8. package/Models/DatabaseModels/WorkspaceUserAuthToken.ts +0 -2
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/1747305098533-MigrationName.ts +69 -0
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  11. package/Server/Services/Index.ts +3 -0
  12. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +25 -0
  13. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +29 -0
  14. package/Server/Services/OnCallDutyPolicyScheduleService.ts +73 -0
  15. package/Server/Services/OnCallDutyPolicyTimeLogService.ts +175 -0
  16. package/Server/Services/TeamMemberService.ts +10 -0
  17. package/Server/Services/WorkspaceNotificationRuleService.ts +1 -1
  18. package/Server/Types/Database/QueryHelper.ts +15 -0
  19. package/Server/Types/Database/QueryUtil.ts +18 -0
  20. package/Server/Utils/AnalyticsDatabase/Statement.ts +5 -1
  21. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +16 -0
  22. package/Tests/Types/JSON.test.ts +2 -0
  23. package/Types/BaseDatabase/GreaterThan.ts +11 -0
  24. package/Types/BaseDatabase/GreaterThanOrEqual.ts +11 -0
  25. package/Types/BaseDatabase/GreaterThanOrNull.ts +39 -0
  26. package/Types/BaseDatabase/LessThan.ts +11 -0
  27. package/Types/BaseDatabase/LessThanOrEqual.ts +11 -0
  28. package/Types/BaseDatabase/LessThanOrNull.ts +39 -0
  29. package/Types/Date.ts +18 -0
  30. package/Types/JSON.ts +8 -0
  31. package/Types/Permission.ts +11 -0
  32. package/Types/SerializableObjectDictionary.ts +4 -0
  33. package/Types/Time/RangeStartAndEndDateTime.ts +98 -0
  34. package/Types/Time/TimeRange.ts +15 -0
  35. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +3 -3
  36. package/UI/Components/Date/RangeStartAndEndDateEdit.tsx +64 -0
  37. package/UI/Components/Date/RangeStartAndEndDateView.tsx +86 -0
  38. package/UI/Components/Filters/FilterViewer.tsx +5 -5
  39. package/UI/Components/Table/LocalTable.tsx +74 -0
  40. package/UI/Components/Table/Table.tsx +33 -24
  41. package/UI/Components/Table/TableBody.tsx +5 -1
  42. package/build/dist/Models/AnalyticsModels/AnalyticsBaseModel/CommonModel.js.map +1 -1
  43. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  44. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  45. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +522 -0
  46. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -0
  47. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +0 -2
  48. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  49. package/build/dist/Models/DatabaseModels/WorkspaceNotificationRule.js +2 -2
  50. package/build/dist/Models/DatabaseModels/WorkspaceNotificationRule.js.map +1 -1
  51. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js +0 -2
  52. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  53. package/build/dist/Models/DatabaseModels/WorkspaceSetting.js +0 -2
  54. package/build/dist/Models/DatabaseModels/WorkspaceSetting.js.map +1 -1
  55. package/build/dist/Models/DatabaseModels/WorkspaceUserAuthToken.js +0 -2
  56. package/build/dist/Models/DatabaseModels/WorkspaceUserAuthToken.js.map +1 -1
  57. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1747305098533-MigrationName.js +30 -0
  58. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1747305098533-MigrationName.js.map +1 -0
  59. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  60. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  61. package/build/dist/Server/Services/Index.js +2 -0
  62. package/build/dist/Server/Services/Index.js.map +1 -1
  63. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +20 -0
  64. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  65. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +24 -0
  66. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  67. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +58 -0
  68. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  69. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js +107 -0
  70. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js.map +1 -0
  71. package/build/dist/Server/Services/TeamMemberService.js +9 -0
  72. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  73. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +8 -8
  74. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  75. package/build/dist/Server/Types/Database/QueryHelper.js +21 -7
  76. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  77. package/build/dist/Server/Types/Database/QueryUtil.js +12 -0
  78. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  79. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +5 -1
  80. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  81. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +14 -0
  82. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  83. package/build/dist/Tests/Types/JSON.test.js +2 -0
  84. package/build/dist/Tests/Types/JSON.test.js.map +1 -1
  85. package/build/dist/Types/BaseDatabase/GreaterThan.js +8 -0
  86. package/build/dist/Types/BaseDatabase/GreaterThan.js.map +1 -1
  87. package/build/dist/Types/BaseDatabase/GreaterThanOrEqual.js +8 -0
  88. package/build/dist/Types/BaseDatabase/GreaterThanOrEqual.js.map +1 -1
  89. package/build/dist/Types/BaseDatabase/GreaterThanOrNull.js +29 -0
  90. package/build/dist/Types/BaseDatabase/GreaterThanOrNull.js.map +1 -0
  91. package/build/dist/Types/BaseDatabase/LessThan.js +8 -0
  92. package/build/dist/Types/BaseDatabase/LessThan.js.map +1 -1
  93. package/build/dist/Types/BaseDatabase/LessThanOrEqual.js +8 -0
  94. package/build/dist/Types/BaseDatabase/LessThanOrEqual.js.map +1 -1
  95. package/build/dist/Types/BaseDatabase/LessThanOrNull.js +29 -0
  96. package/build/dist/Types/BaseDatabase/LessThanOrNull.js.map +1 -0
  97. package/build/dist/Types/Date.js +12 -0
  98. package/build/dist/Types/Date.js.map +1 -1
  99. package/build/dist/Types/JSON.js +2 -0
  100. package/build/dist/Types/JSON.js.map +1 -1
  101. package/build/dist/Types/Permission.js +8 -0
  102. package/build/dist/Types/Permission.js.map +1 -1
  103. package/build/dist/Types/SerializableObjectDictionary.js +4 -0
  104. package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
  105. package/build/dist/Types/Time/RangeStartAndEndDateTime.js +48 -0
  106. package/build/dist/Types/Time/RangeStartAndEndDateTime.js.map +1 -0
  107. package/build/dist/Types/Time/TimeRange.js +16 -0
  108. package/build/dist/Types/Time/TimeRange.js.map +1 -0
  109. package/build/dist/UI/Components/Date/RangeStartAndEndDateEdit.js +32 -0
  110. package/build/dist/UI/Components/Date/RangeStartAndEndDateEdit.js.map +1 -0
  111. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +43 -0
  112. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -0
  113. package/build/dist/UI/Components/Filters/FilterViewer.js +3 -3
  114. package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
  115. package/build/dist/UI/Components/Table/LocalTable.js +32 -0
  116. package/build/dist/UI/Components/Table/LocalTable.js.map +1 -0
  117. package/build/dist/UI/Components/Table/Table.js +19 -8
  118. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  119. package/build/dist/UI/Components/Table/TableBody.js +3 -0
  120. package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
  121. package/package.json +2 -2
@@ -0,0 +1,39 @@
1
+ import CompareBase, { CompareType } from "../Database/CompareBase";
2
+ import OneUptimeDate from "../Date";
3
+ import BadDataException from "../Exception/BadDataException";
4
+ import { JSONObject, ObjectType } from "../JSON";
5
+
6
+ export default class LessThanOrNull<
7
+ T extends CompareType,
8
+ > extends CompareBase<T> {
9
+ public constructor(value: T) {
10
+ super(value);
11
+ }
12
+
13
+ public override toJSON(): JSONObject {
14
+ return {
15
+ _type: ObjectType.LessThanOrNull,
16
+ value: (this as LessThanOrNull<T>).toString(),
17
+ };
18
+ }
19
+
20
+ public override toString(): string {
21
+ let value: T = this.value;
22
+
23
+ if (value instanceof Date) {
24
+ value = OneUptimeDate.asDateForDatabaseQuery(value) as T;
25
+ }
26
+
27
+ return value.toString();
28
+ }
29
+
30
+ public static override fromJSON<T extends CompareType>(
31
+ json: JSONObject,
32
+ ): LessThanOrNull<T> {
33
+ if (json["_type"] === ObjectType.LessThanOrNull) {
34
+ return new LessThanOrNull<T>(json["value"] as T);
35
+ }
36
+
37
+ throw new BadDataException("Invalid JSON: " + JSON.stringify(json));
38
+ }
39
+ }
package/Types/Date.ts CHANGED
@@ -10,6 +10,24 @@ export const Moment: typeof moment = moment;
10
10
 
11
11
  export default class OneUptimeDate {
12
12
  // get date time from unix timestamp
13
+
14
+ public static getHoursAndMinutesFromMinutes(minutes: number): string {
15
+ const hours: number = Math.floor(minutes / 60);
16
+ const mins: number = minutes % 60;
17
+
18
+ let formattedString: string = "";
19
+
20
+ if (hours > 0) {
21
+ formattedString += hours + " hours ";
22
+ }
23
+
24
+ if (mins > 0) {
25
+ formattedString += mins + " minutes";
26
+ }
27
+
28
+ return formattedString.trim() || "0 minutes";
29
+ }
30
+
13
31
  public static fromUnixTimestamp(timestamp: number): Date {
14
32
  return new Date(timestamp * 1000);
15
33
  }
package/Types/JSON.ts CHANGED
@@ -28,6 +28,8 @@ import StartAndEndTime from "./Time/StartAndEndTime";
28
28
  import Version from "./Version";
29
29
  import { BaseEntity } from "typeorm";
30
30
  import DashboardViewConfig from "./Dashboard/DashboardViewConfig";
31
+ import LessThanOrNull from "./BaseDatabase/LessThanOrNull";
32
+ import GreaterThanOrNull from "./BaseDatabase/GreaterThanOrNull";
31
33
 
32
34
  export enum ObjectType {
33
35
  ObjectID = "ObjectID",
@@ -54,6 +56,8 @@ export enum ObjectType {
54
56
  Search = "Search",
55
57
  GreaterThan = "GreaterThan",
56
58
  GreaterThanOrEqual = "GreaterThanOrEqual",
59
+ GreaterThanOrNull = "GreaterThanOrNull",
60
+ LessThanOrNull = "LessThanOrNull",
57
61
  LessThan = "LessThan",
58
62
  LessThanOrEqual = "LessThanOrEqual",
59
63
  Port = "Port",
@@ -119,6 +123,10 @@ export type JSONValue =
119
123
  | Array<GreaterThan<CompareType>>
120
124
  | GreaterThanOrEqual<CompareType>
121
125
  | Array<GreaterThanOrEqual<CompareType>>
126
+ | LessThanOrNull<CompareType>
127
+ | Array<LessThanOrNull<CompareType>>
128
+ | GreaterThanOrNull<CompareType>
129
+ | Array<GreaterThanOrNull<CompareType>>
122
130
  | PositiveNumber
123
131
  | Array<PositiveNumber>
124
132
  | LessThan<CompareType>
@@ -532,6 +532,8 @@ enum Permission {
532
532
  DeleteOnCallDutyPolicyUserOverride = "DeleteOnCallDutyPolicyUserOverride",
533
533
  ReadOnCallDutyPolicyUserOverride = "ReadOnCallDutyPolicyUserOverride",
534
534
 
535
+ ReadOnCallDutyPolicyTimeLog = "ReadOnCallDutyPolicyTimeLog",
536
+
535
537
  // Resource Permissions (Team Permission)
536
538
  CreateProjectOnCallDutyPolicyEscalationRuleUser = "CreateProjectOnCallDutyPolicyEscalationRuleUser",
537
539
  EditProjectOnCallDutyPolicyEscalationRuleUser = "EditProjectOnCallDutyPolicyEscalationRuleUser",
@@ -2424,6 +2426,15 @@ export class PermissionHelper {
2424
2426
  isAccessControlPermission: false,
2425
2427
  },
2426
2428
 
2429
+ {
2430
+ permission: Permission.ReadOnCallDutyPolicyTimeLog,
2431
+ title: "Create On-Call Policy Time Log",
2432
+ description:
2433
+ "This permission can read on-call policy time log this project.",
2434
+ isAssignableToTenant: true,
2435
+ isAccessControlPermission: false,
2436
+ },
2437
+
2427
2438
  {
2428
2439
  permission: Permission.CreateOnCallDutyPolicyUserOverride,
2429
2440
  title: "Create On-Call Duty Policy User Override",
@@ -9,6 +9,8 @@ import Includes from "./BaseDatabase/Includes";
9
9
  import IsNull from "./BaseDatabase/IsNull";
10
10
  import LessThan from "./BaseDatabase/LessThan";
11
11
  import LessThanOrEqual from "./BaseDatabase/LessThanOrEqual";
12
+ import LessThanOrNull from "./BaseDatabase/LessThanOrNull";
13
+ import GreaterThanOrNull from "./BaseDatabase/GreaterThanOrNull";
12
14
  import NotEqual from "./BaseDatabase/NotEqual";
13
15
  import NotNull from "./BaseDatabase/NotNull";
14
16
  import Search from "./BaseDatabase/Search";
@@ -54,6 +56,8 @@ const SerializableObjectDictionary: Dictionary<any> = {
54
56
  [ObjectType.GreaterThanOrEqual]: GreaterThanOrEqual,
55
57
  [ObjectType.LessThan]: LessThan,
56
58
  [ObjectType.LessThanOrEqual]: LessThanOrEqual,
59
+ [ObjectType.LessThanOrNull]: LessThanOrNull,
60
+ [ObjectType.GreaterThanOrNull]: GreaterThanOrNull,
57
61
  [ObjectType.Port]: Port,
58
62
  [ObjectType.Hostname]: Hostname,
59
63
  [ObjectType.HashedString]: HashedString,
@@ -0,0 +1,98 @@
1
+ import InBetween from "Common/Types/BaseDatabase/InBetween";
2
+ import TimeRange from "./TimeRange";
3
+ import OneUptimeDate from "Common/Types/Date";
4
+
5
+ export default interface RangeStartAndEndDateTime {
6
+ startAndEndDate?: InBetween<Date> | undefined;
7
+ range: TimeRange;
8
+ }
9
+
10
+ export class RangeStartAndEndDateTimeUtil {
11
+ public static getStartAndEndDate(
12
+ dashboardStartAndEndDate: RangeStartAndEndDateTime,
13
+ ): InBetween<Date> {
14
+ const currentDate: Date = OneUptimeDate.getCurrentDate();
15
+
16
+ // 30 mins.
17
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_THIRTY_MINS) {
18
+ return new InBetween<Date>(
19
+ OneUptimeDate.addRemoveMinutes(currentDate, -30),
20
+ currentDate,
21
+ );
22
+ }
23
+
24
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_ONE_HOUR) {
25
+ return new InBetween<Date>(
26
+ OneUptimeDate.addRemoveHours(currentDate, -1),
27
+ currentDate,
28
+ );
29
+ }
30
+
31
+ // two hours.
32
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_TWO_HOURS) {
33
+ return new InBetween<Date>(
34
+ OneUptimeDate.addRemoveHours(currentDate, -2),
35
+ currentDate,
36
+ );
37
+ }
38
+
39
+ // three hours
40
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_THREE_HOURS) {
41
+ return new InBetween<Date>(
42
+ OneUptimeDate.addRemoveHours(currentDate, -3),
43
+ currentDate,
44
+ );
45
+ }
46
+
47
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_ONE_DAY) {
48
+ return new InBetween<Date>(
49
+ OneUptimeDate.addRemoveDays(currentDate, -1),
50
+ currentDate,
51
+ );
52
+ }
53
+
54
+ // two days .
55
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_TWO_DAYS) {
56
+ return new InBetween<Date>(
57
+ OneUptimeDate.addRemoveDays(currentDate, -2),
58
+ currentDate,
59
+ );
60
+ }
61
+
62
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_ONE_WEEK) {
63
+ return new InBetween<Date>(
64
+ OneUptimeDate.addRemoveDays(currentDate, -7),
65
+ currentDate,
66
+ );
67
+ }
68
+
69
+ // two weeks.
70
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_TWO_WEEKS) {
71
+ return new InBetween<Date>(
72
+ OneUptimeDate.addRemoveDays(currentDate, -14),
73
+ currentDate,
74
+ );
75
+ }
76
+
77
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_ONE_MONTH) {
78
+ return new InBetween<Date>(
79
+ OneUptimeDate.addRemoveMonths(currentDate, -1),
80
+ currentDate,
81
+ );
82
+ }
83
+
84
+ // three months.
85
+ if (dashboardStartAndEndDate.range === TimeRange.PAST_THREE_MONTHS) {
86
+ return new InBetween<Date>(
87
+ OneUptimeDate.addRemoveMonths(currentDate, -3),
88
+ currentDate,
89
+ );
90
+ }
91
+
92
+ // custom
93
+ return (
94
+ dashboardStartAndEndDate.startAndEndDate ||
95
+ new InBetween<Date>(currentDate, currentDate)
96
+ );
97
+ }
98
+ }
@@ -0,0 +1,15 @@
1
+ enum Range {
2
+ PAST_THIRTY_MINS = "Past 30 Mins",
3
+ PAST_ONE_HOUR = "Past 1 Hour",
4
+ PAST_TWO_HOURS = "Past 2 Hours",
5
+ PAST_THREE_HOURS = "Past 3 Hours",
6
+ PAST_ONE_DAY = "Past 1 Day",
7
+ PAST_TWO_DAYS = "Past 2 Days",
8
+ PAST_ONE_WEEK = "Past 1 Week",
9
+ PAST_TWO_WEEKS = "Past 2 Weeks",
10
+ PAST_ONE_MONTH = "Past 1 Month",
11
+ PAST_THREE_MONTHS = "Past 3 Months",
12
+ CUSTOM = "Custom",
13
+ }
14
+
15
+ export default Range;
@@ -62,9 +62,9 @@ export interface ComponentProps<T extends GenericObject> {
62
62
  pluralLabel: string;
63
63
  onClearSelectionClick: () => void;
64
64
  buttons: Array<BulkActionButtonSchema<T>>;
65
- onActionStart?: () => void;
66
- onActionEnd?: () => void;
67
- itemToString?: (item: T) => string;
65
+ onActionStart?: (() => void) | undefined;
66
+ onActionEnd?: (() => void) | undefined;
67
+ itemToString?: ((item: T) => string) | undefined;
68
68
  }
69
69
 
70
70
  const BulkUpdateForm: <T extends GenericObject>(
@@ -0,0 +1,64 @@
1
+ import React, { FunctionComponent, ReactElement } from "react";
2
+ import RangeStartAndEndDateTime from "Common/Types/Time/RangeStartAndEndDateTime";
3
+ import StartAndEndDate, {
4
+ StartAndEndDateType,
5
+ } from "Common/UI/Components/Date/StartAndEndDate";
6
+ import InBetween from "Common/Types/BaseDatabase/InBetween";
7
+ import TimeRange from "Common/Types/Time/TimeRange";
8
+ import Dropdown, {
9
+ DropdownOption,
10
+ DropdownValue,
11
+ } from "Common/UI/Components/Dropdown/Dropdown";
12
+ import DropdownUtil from "Common/UI/Utils/Dropdown";
13
+
14
+ export interface ComponentProps {
15
+ value?: RangeStartAndEndDateTime | undefined;
16
+ onChange: (startAndEndDate: RangeStartAndEndDateTime) => void;
17
+ }
18
+
19
+ const DashboardStartAndEndDateEditElement: FunctionComponent<ComponentProps> = (
20
+ props: ComponentProps,
21
+ ): ReactElement => {
22
+ const dropdownOptions: DropdownOption[] =
23
+ DropdownUtil.getDropdownOptionsFromEnum(TimeRange);
24
+ const defaultDropdownOption: DropdownOption =
25
+ dropdownOptions.find((option: DropdownOption) => {
26
+ return option.value === TimeRange.PAST_ONE_HOUR;
27
+ }) || dropdownOptions[0]!;
28
+ const selectedDropdownnOption: DropdownOption =
29
+ dropdownOptions.find((option: DropdownOption) => {
30
+ return option.value === props.value?.range;
31
+ }) || defaultDropdownOption;
32
+
33
+ return (
34
+ <div>
35
+ <Dropdown
36
+ value={selectedDropdownnOption}
37
+ onChange={(range: DropdownValue | Array<DropdownValue> | null) => {
38
+ props.onChange({
39
+ range: range as TimeRange,
40
+ });
41
+ }}
42
+ options={dropdownOptions}
43
+ />
44
+ {/* Start and End Date */}
45
+ {props.value?.range === TimeRange.CUSTOM && (
46
+ <StartAndEndDate
47
+ type={StartAndEndDateType.DateTime}
48
+ value={props.value?.startAndEndDate || undefined}
49
+ hideTimeButtons={true}
50
+ onValueChanged={(startAndEndDate: InBetween<Date> | null) => {
51
+ if (startAndEndDate) {
52
+ props.onChange({
53
+ range: TimeRange.CUSTOM,
54
+ startAndEndDate,
55
+ });
56
+ }
57
+ }}
58
+ />
59
+ )}
60
+ </div>
61
+ );
62
+ };
63
+
64
+ export default DashboardStartAndEndDateEditElement;
@@ -0,0 +1,86 @@
1
+ import React, { FunctionComponent, ReactElement, useState } from "react";
2
+ import RangeStartAndEndDateTime from "Common/Types/Time/RangeStartAndEndDateTime";
3
+ import TimeRange from "Common/Types/Time/TimeRange";
4
+ import OneUptimeDate from "Common/Types/Date";
5
+ import IconProp from "Common/Types/Icon/IconProp";
6
+ import { GetReactElementFunction } from "Common/UI/Types/FunctionTypes";
7
+ import HeaderAlert, {
8
+ HeaderAlertType,
9
+ } from "Common/UI/Components/HeaderAlert/HeaderAlert";
10
+ import ColorSwatch from "Common/Types/ColorSwatch";
11
+ import RangeStartAndEndDateEdit from "./RangeStartAndEndDateEdit";
12
+ import Modal from "../Modal/Modal";
13
+
14
+ export interface ComponentProps {
15
+ dashboardStartAndEndDate: RangeStartAndEndDateTime;
16
+ onChange: (startAndEndDate: RangeStartAndEndDateTime) => void;
17
+ }
18
+
19
+ const DashboardStartAndEndDateView: FunctionComponent<ComponentProps> = (
20
+ props: ComponentProps,
21
+ ): ReactElement => {
22
+ const [tempStartAndEndDate, setTempStartAndEndDate] =
23
+ useState<RangeStartAndEndDateTime | null>(null);
24
+ const [showTimeSelectModal, setShowTimeSelectModal] =
25
+ useState<boolean>(false);
26
+
27
+ const isCustomRange: boolean =
28
+ props.dashboardStartAndEndDate.range === TimeRange.CUSTOM;
29
+
30
+ const getContent: GetReactElementFunction = (): ReactElement => {
31
+ const title: string = isCustomRange
32
+ ? `${OneUptimeDate.getDateAsLocalFormattedString(
33
+ props.dashboardStartAndEndDate.startAndEndDate?.startValue ||
34
+ OneUptimeDate.getCurrentDate(),
35
+ )} - ${OneUptimeDate.getDateAsLocalFormattedString(
36
+ props.dashboardStartAndEndDate.startAndEndDate?.endValue ||
37
+ OneUptimeDate.getCurrentDate(),
38
+ )}`
39
+ : props.dashboardStartAndEndDate.range;
40
+
41
+ return (
42
+ <div>
43
+ <HeaderAlert
44
+ icon={IconProp.Clock}
45
+ onClick={() => {
46
+ setTempStartAndEndDate(props.dashboardStartAndEndDate);
47
+ setShowTimeSelectModal(true);
48
+ }}
49
+ title={title}
50
+ alertType={HeaderAlertType.INFO}
51
+ colorSwatch={ColorSwatch.Blue}
52
+ tooltip="Click to change the date and time range of data on this dashboard."
53
+ />
54
+ {showTimeSelectModal && (
55
+ <Modal
56
+ title="Select Start and End Time"
57
+ onClose={() => {
58
+ setTempStartAndEndDate(null);
59
+ setShowTimeSelectModal(false);
60
+ }}
61
+ onSubmit={() => {
62
+ if (tempStartAndEndDate) {
63
+ props.onChange(tempStartAndEndDate);
64
+ }
65
+ setShowTimeSelectModal(false);
66
+ setTempStartAndEndDate(null);
67
+ }}
68
+ >
69
+ <div className="mt-5">
70
+ <RangeStartAndEndDateEdit
71
+ value={tempStartAndEndDate || undefined}
72
+ onChange={(startAndEndDate: RangeStartAndEndDateTime) => {
73
+ setTempStartAndEndDate(startAndEndDate);
74
+ }}
75
+ />
76
+ </div>
77
+ </Modal>
78
+ )}
79
+ </div>
80
+ );
81
+ };
82
+
83
+ return <div>{getContent()}</div>;
84
+ };
85
+
86
+ export default DashboardStartAndEndDateView;
@@ -25,8 +25,8 @@ export interface ComponentProps<T extends GenericObject> {
25
25
  showFilterModal: boolean;
26
26
  onFilterChanged?: undefined | ((filterData: FilterData<T>) => void);
27
27
  filterError?: string | undefined;
28
- onFilterModalClose: () => void;
29
- onFilterModalOpen: () => void;
28
+ onFilterModalClose?: (() => void) | undefined;
29
+ onFilterModalOpen?: (() => void) | undefined;
30
30
  isModalLoading?: boolean;
31
31
  onFilterRefreshClick?: undefined | (() => void);
32
32
  filterData?: FilterData<T> | undefined;
@@ -399,7 +399,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
399
399
  <Button
400
400
  onClick={() => {
401
401
  changeFilterData({});
402
- props.onFilterModalClose();
402
+ props.onFilterModalClose && props.onFilterModalClose();
403
403
  }}
404
404
  className="font-medium text-gray-900"
405
405
  icon={IconProp.Close}
@@ -421,7 +421,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
421
421
  } by the following criteria:`}
422
422
  submitButtonText={`Apply Filters`}
423
423
  onClose={() => {
424
- props.onFilterModalClose();
424
+ props.onFilterModalClose && props.onFilterModalClose();
425
425
  }}
426
426
  onSubmit={() => {
427
427
  setTempFilterDataForModal({});
@@ -430,7 +430,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
430
430
  ...tempFilterDataForModal,
431
431
  });
432
432
  }
433
- props.onFilterModalClose();
433
+ props.onFilterModalClose && props.onFilterModalClose();
434
434
  }}
435
435
  >
436
436
  <FiltersForm
@@ -0,0 +1,74 @@
1
+ import React, { ReactElement } from "react";
2
+ import GenericObject from "../../../Types/GenericObject";
3
+ import Columns from "./Types/Columns";
4
+ import Table from "./Table";
5
+ import SortOrder from "../../../Types/BaseDatabase/SortOrder";
6
+
7
+ export interface ComponentProps<T extends GenericObject> {
8
+ data: Array<T>;
9
+ columns: Columns<T>;
10
+ id: string;
11
+ singularLabel: string;
12
+ pluralLabel: string;
13
+ }
14
+
15
+ type TableFunction = <T extends GenericObject>(
16
+ props: ComponentProps<T>,
17
+ ) => ReactElement;
18
+
19
+ const LocalTable: TableFunction = <T extends GenericObject>(
20
+ props: ComponentProps<T>,
21
+ ): ReactElement => {
22
+ const [currentPage, setCurrentPage] = React.useState<number>(1);
23
+ const [itemsPerPage, setItemsPerPage] = React.useState<number>(10);
24
+ const [sortOrder, setSortOrder] = React.useState<SortOrder>(
25
+ SortOrder.Ascending,
26
+ );
27
+ const [sortBy, setSortBy] = React.useState<keyof T | null>(null);
28
+
29
+ const [dataSlice, setDataSlice] = React.useState<Array<T>>(
30
+ props.data.slice(0, itemsPerPage),
31
+ );
32
+
33
+ React.useEffect(() => {
34
+ const startIndex: number = (currentPage - 1) * itemsPerPage;
35
+ const endIndex: number = startIndex + itemsPerPage;
36
+ setDataSlice(props.data.slice(startIndex, endIndex));
37
+ }, [currentPage, itemsPerPage, props.data]);
38
+
39
+ return (
40
+ <Table
41
+ data={dataSlice}
42
+ columns={props.columns}
43
+ totalItemsCount={props.data.length}
44
+ currentPageNumber={currentPage}
45
+ error={""}
46
+ isLoading={false}
47
+ itemsOnPage={itemsPerPage}
48
+ onNavigateToPage={(pageNumber: number, itemsPerPage: number) => {
49
+ setCurrentPage(pageNumber);
50
+ setItemsPerPage(itemsPerPage);
51
+ }}
52
+ id={props.id}
53
+ disablePagination={false}
54
+ singularLabel={props.singularLabel}
55
+ pluralLabel={props.pluralLabel}
56
+ sortOrder={sortOrder}
57
+ sortBy={sortBy}
58
+ onSortChanged={(sortBy: keyof T | null, sortOrder: SortOrder) => {
59
+ setSortOrder(sortOrder);
60
+ setSortBy(sortBy);
61
+ const sortedData: T[] = [...props.data].sort((a: T, b: T) => {
62
+ if (sortOrder === SortOrder.Ascending) {
63
+ return a[sortBy as keyof T] > b[sortBy as keyof T] ? 1 : -1;
64
+ }
65
+ return a[sortBy as keyof T] < b[sortBy as keyof T] ? 1 : -1;
66
+ });
67
+ setDataSlice(sortedData.slice(0, itemsPerPage));
68
+ setCurrentPage(1);
69
+ }}
70
+ />
71
+ );
72
+ };
73
+
74
+ export default LocalTable;
@@ -51,8 +51,8 @@ export interface ComponentProps<T extends GenericObject> {
51
51
  filterError?: string | undefined;
52
52
  onFilterChanged?: undefined | ((filterData: FilterData<T>) => void);
53
53
  onFilterRefreshClick?: undefined | (() => void);
54
- onFilterModalClose: () => void;
55
- onFilterModalOpen: () => void;
54
+ onFilterModalClose?: (() => void) | undefined;
55
+ onFilterModalOpen?: (() => void) | undefined;
56
56
  filterData?: undefined | FilterData<T>;
57
57
 
58
58
  enableDragAndDrop?: boolean | undefined;
@@ -61,17 +61,17 @@ export interface ComponentProps<T extends GenericObject> {
61
61
  onDragDrop?: ((id: string, newIndex: number) => void) | undefined;
62
62
 
63
63
  // bulk actions
64
- bulkActions: BulkActionProps<T>;
65
- bulkSelectedItems: Array<T>;
66
- onBulkSelectedItemAdded: (item: T) => void;
67
- onBulkSelectedItemRemoved: (item: T) => void;
68
- onBulkSelectAllItems: () => void;
69
- onBulkSelectItemsOnCurrentPage: () => void;
70
- onBulkClearAllItems: () => void;
71
- matchBulkSelectedItemByField: keyof T; // which field to use to match selected items. For exmaple this could be '_id'
72
- onBulkActionEnd: () => void;
73
- onBulkActionStart: () => void;
74
- bulkItemToString: (item: T) => string;
64
+ bulkActions?: BulkActionProps<T> | undefined;
65
+ bulkSelectedItems?: Array<T> | undefined;
66
+ onBulkSelectedItemAdded?: ((item: T) => void) | undefined;
67
+ onBulkSelectedItemRemoved?: ((item: T) => void) | undefined;
68
+ onBulkSelectAllItems?: (() => void) | undefined;
69
+ onBulkSelectItemsOnCurrentPage?: (() => void) | undefined;
70
+ onBulkClearAllItems?: (() => void) | undefined;
71
+ matchBulkSelectedItemByField?: keyof T | undefined; // which field to use to match selected items. For exmaple this could be '_id'
72
+ onBulkActionEnd?: (() => void) | undefined;
73
+ onBulkActionStart?: (() => void) | undefined;
74
+ bulkItemToString?: ((item: T) => string) | undefined;
75
75
  }
76
76
 
77
77
  type TableFunction = <T extends GenericObject>(
@@ -81,7 +81,7 @@ type TableFunction = <T extends GenericObject>(
81
81
  const Table: TableFunction = <T extends GenericObject>(
82
82
  props: ComponentProps<T>,
83
83
  ): ReactElement => {
84
- const isBulkActionsEnabled: boolean =
84
+ const isBulkActionsEnabled: boolean | undefined =
85
85
  props.bulkActions &&
86
86
  props.bulkActions.buttons &&
87
87
  props.bulkActions.buttons.length > 0;
@@ -90,7 +90,9 @@ const Table: TableFunction = <T extends GenericObject>(
90
90
  const [bulkSelectedItems, setBulkSelectedItems] = useState<Array<T>>([]);
91
91
 
92
92
  useEffect(() => {
93
- setBulkSelectedItems(props.bulkSelectedItems);
93
+ if (props.bulkSelectedItems) {
94
+ setBulkSelectedItems(props.bulkSelectedItems);
95
+ }
94
96
  }, [props.bulkSelectedItems]);
95
97
 
96
98
  let colspan: number = props.columns.length || 0;
@@ -165,14 +167,17 @@ const Table: TableFunction = <T extends GenericObject>(
165
167
  onItemSelected={(item: T) => {
166
168
  // set bulk selected items.
167
169
  setBulkSelectedItems([...bulkSelectedItems, item]);
168
- props.onBulkSelectedItemAdded(item);
170
+ props.onBulkSelectedItemAdded?.(item);
169
171
  }}
170
172
  onItemDeselected={(item: T) => {
171
173
  // set bulk selected items.
174
+ if (props.matchBulkSelectedItemByField === undefined) {
175
+ return;
176
+ }
172
177
  const index: number = bulkSelectedItems.findIndex((x: T) => {
173
178
  return (
174
- x[props.matchBulkSelectedItemByField]?.toString() ===
175
- item[props.matchBulkSelectedItemByField]?.toString()
179
+ x[props.matchBulkSelectedItemByField!]?.toString() ===
180
+ item[props.matchBulkSelectedItemByField!]?.toString()
176
181
  );
177
182
  });
178
183
 
@@ -180,7 +185,7 @@ const Table: TableFunction = <T extends GenericObject>(
180
185
  bulkSelectedItems.splice(index, 1);
181
186
  }
182
187
 
183
- props.onBulkSelectedItemRemoved(item);
188
+ props.onBulkSelectedItemRemoved?.(item);
184
189
  }}
185
190
  selectedItems={bulkSelectedItems}
186
191
  matchBulkSelectedItemByField={props.matchBulkSelectedItemByField}
@@ -193,6 +198,9 @@ const Table: TableFunction = <T extends GenericObject>(
193
198
 
194
199
  props.data.forEach((item: T) => {
195
200
  const index: number = bulkSelectedItems.findIndex((x: T) => {
201
+ if (props.matchBulkSelectedItemByField === undefined) {
202
+ return false;
203
+ }
196
204
  return (
197
205
  x[props.matchBulkSelectedItemByField]?.toString() ===
198
206
  item[props.matchBulkSelectedItemByField]?.toString()
@@ -224,11 +232,11 @@ const Table: TableFunction = <T extends GenericObject>(
224
232
  <BulkUpdateForm
225
233
  buttons={props.bulkActions.buttons}
226
234
  onClearSelectionClick={() => {
227
- props.onBulkClearAllItems();
235
+ props.onBulkClearAllItems && props.onBulkClearAllItems();
228
236
  setIsAllItemsSelected(false);
229
237
  }}
230
238
  onSelectAllClick={() => {
231
- props.onBulkSelectAllItems();
239
+ props.onBulkSelectAllItems && props.onBulkSelectAllItems();
232
240
  setIsAllItemsSelected(true);
233
241
  }}
234
242
  selectedItems={bulkSelectedItems}
@@ -239,7 +247,7 @@ const Table: TableFunction = <T extends GenericObject>(
239
247
  onActionEnd={() => {
240
248
  setIsAllItemsSelected(false);
241
249
  setBulkSelectedItems([]);
242
- props.onBulkActionEnd();
250
+ props.onBulkActionEnd && props.onBulkActionEnd();
243
251
  }}
244
252
  itemToString={props.bulkItemToString}
245
253
  />
@@ -271,10 +279,11 @@ const Table: TableFunction = <T extends GenericObject>(
271
279
  isBulkActionsEnabled={isBulkActionsEnabled}
272
280
  onAllItemsDeselected={() => {
273
281
  setIsAllItemsSelected(false);
274
- props.onBulkClearAllItems();
282
+ props.onBulkClearAllItems && props.onBulkClearAllItems();
275
283
  }}
276
284
  onAllItemsOnThePageSelected={() => {
277
- props.onBulkSelectItemsOnCurrentPage();
285
+ props.onBulkSelectItemsOnCurrentPage &&
286
+ props.onBulkSelectItemsOnCurrentPage();
278
287
  }}
279
288
  isAllItemsOnThePageSelected={isAllItemsOnThePageSelected}
280
289
  hasTableItems={props.data.length > 0}