@oneuptime/common 9.3.20 → 9.4.0

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 (139) hide show
  1. package/Models/DatabaseModels/IncomingCallLog.ts +521 -0
  2. package/Models/DatabaseModels/IncomingCallLogItem.ts +463 -0
  3. package/Models/DatabaseModels/IncomingCallPolicy.ts +811 -0
  4. package/Models/DatabaseModels/IncomingCallPolicyEscalationRule.ts +597 -0
  5. package/Models/DatabaseModels/Index.ts +18 -0
  6. package/Models/DatabaseModels/ProjectSCIMLog.ts +422 -0
  7. package/Models/DatabaseModels/StatusPageSCIMLog.ts +455 -0
  8. package/Models/DatabaseModels/User.ts +0 -15
  9. package/Models/DatabaseModels/UserIncomingCallNumber.ts +296 -0
  10. package/Server/API/UserIncomingCallNumberAPI.ts +128 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.ts +121 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.ts +22 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.ts +787 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.ts +29 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  16. package/Server/Services/IncomingCallLogItemService.ts +10 -0
  17. package/Server/Services/IncomingCallLogService.ts +10 -0
  18. package/Server/Services/IncomingCallPolicyEscalationRuleService.ts +267 -0
  19. package/Server/Services/IncomingCallPolicyService.ts +10 -0
  20. package/Server/Services/Index.ts +7 -0
  21. package/Server/Services/ProjectSCIMLogService.ts +11 -0
  22. package/Server/Services/StatusPageSCIMLogService.ts +11 -0
  23. package/Server/Services/UserCallService.ts +31 -0
  24. package/Server/Services/UserIncomingCallNumberService.ts +258 -0
  25. package/Server/Services/UserSmsService.ts +31 -0
  26. package/Server/Utils/AnalyticsDatabase/Statement.ts +2 -2
  27. package/Server/Utils/StartServer.ts +5 -0
  28. package/Tests/UI/Components/Input.test.tsx +33 -0
  29. package/Types/Call/CallProvider.ts +99 -0
  30. package/Types/Call/CallProviderType.ts +6 -0
  31. package/Types/Date.ts +18 -0
  32. package/Types/Icon/IconProp.ts +1 -0
  33. package/Types/IncomingCall/IncomingCallStatus.ts +13 -0
  34. package/Types/Permission.ts +126 -0
  35. package/Types/Phone.ts +53 -4
  36. package/Types/SCIM/SCIMLogStatus.ts +7 -0
  37. package/UI/Components/Date/StartAndEndDate.tsx +35 -11
  38. package/UI/Components/Diagram/ConceptCards.tsx +74 -0
  39. package/UI/Components/Diagram/HorizontalStepChain.tsx +92 -0
  40. package/UI/Components/Diagram/Index.ts +11 -0
  41. package/UI/Components/Diagram/NumberedSteps.tsx +77 -0
  42. package/UI/Components/Diagram/VerticalFlowSteps.tsx +59 -0
  43. package/UI/Components/Filters/FilterViewer.tsx +7 -0
  44. package/UI/Components/Icon/Icon.tsx +10 -0
  45. package/UI/Components/Input/Input.tsx +7 -0
  46. package/UI/Components/SimpleLogViewer/SimpleLogViewer.tsx +86 -2
  47. package/build/dist/Models/DatabaseModels/IncomingCallLog.js +565 -0
  48. package/build/dist/Models/DatabaseModels/IncomingCallLog.js.map +1 -0
  49. package/build/dist/Models/DatabaseModels/IncomingCallLogItem.js +497 -0
  50. package/build/dist/Models/DatabaseModels/IncomingCallLogItem.js.map +1 -0
  51. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js +840 -0
  52. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js.map +1 -0
  53. package/build/dist/Models/DatabaseModels/IncomingCallPolicyEscalationRule.js +619 -0
  54. package/build/dist/Models/DatabaseModels/IncomingCallPolicyEscalationRule.js.map +1 -0
  55. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  56. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  57. package/build/dist/Models/DatabaseModels/ProjectSCIMLog.js +455 -0
  58. package/build/dist/Models/DatabaseModels/ProjectSCIMLog.js.map +1 -0
  59. package/build/dist/Models/DatabaseModels/StatusPageSCIMLog.js +486 -0
  60. package/build/dist/Models/DatabaseModels/StatusPageSCIMLog.js.map +1 -0
  61. package/build/dist/Models/DatabaseModels/User.js +0 -16
  62. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  63. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +315 -0
  64. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -0
  65. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +72 -0
  66. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -0
  67. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.js +48 -0
  68. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768583966447-MigrationName.js.map +1 -0
  69. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.js +34 -0
  70. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768647802022-RemoveAlertPhoneNumberFromUser.js.map +1 -0
  71. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.js +270 -0
  72. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768649699509-MigrationName.js.map +1 -0
  73. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.js +16 -0
  74. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1768682071562-MigrationName.js.map +1 -0
  75. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  76. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  77. package/build/dist/Server/Services/IncomingCallLogItemService.js +9 -0
  78. package/build/dist/Server/Services/IncomingCallLogItemService.js.map +1 -0
  79. package/build/dist/Server/Services/IncomingCallLogService.js +9 -0
  80. package/build/dist/Server/Services/IncomingCallLogService.js.map +1 -0
  81. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js +197 -0
  82. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js.map +1 -0
  83. package/build/dist/Server/Services/IncomingCallPolicyService.js +9 -0
  84. package/build/dist/Server/Services/IncomingCallPolicyService.js.map +1 -0
  85. package/build/dist/Server/Services/Index.js +6 -0
  86. package/build/dist/Server/Services/Index.js.map +1 -1
  87. package/build/dist/Server/Services/ProjectSCIMLogService.js +10 -0
  88. package/build/dist/Server/Services/ProjectSCIMLogService.js.map +1 -0
  89. package/build/dist/Server/Services/StatusPageSCIMLogService.js +10 -0
  90. package/build/dist/Server/Services/StatusPageSCIMLogService.js.map +1 -0
  91. package/build/dist/Server/Services/UserCallService.js +21 -0
  92. package/build/dist/Server/Services/UserCallService.js.map +1 -1
  93. package/build/dist/Server/Services/UserIncomingCallNumberService.js +225 -0
  94. package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -0
  95. package/build/dist/Server/Services/UserSmsService.js +21 -0
  96. package/build/dist/Server/Services/UserSmsService.js.map +1 -1
  97. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +2 -2
  98. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  99. package/build/dist/Server/Utils/StartServer.js +5 -0
  100. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  101. package/build/dist/Tests/UI/Components/Input.test.js +10 -0
  102. package/build/dist/Tests/UI/Components/Input.test.js.map +1 -1
  103. package/build/dist/Types/Call/CallProvider.js +2 -0
  104. package/build/dist/Types/Call/CallProvider.js.map +1 -0
  105. package/build/dist/Types/Call/CallProviderType.js +7 -0
  106. package/build/dist/Types/Call/CallProviderType.js.map +1 -0
  107. package/build/dist/Types/Date.js +17 -3
  108. package/build/dist/Types/Date.js.map +1 -1
  109. package/build/dist/Types/Icon/IconProp.js +1 -0
  110. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  111. package/build/dist/Types/IncomingCall/IncomingCallStatus.js +14 -0
  112. package/build/dist/Types/IncomingCall/IncomingCallStatus.js.map +1 -0
  113. package/build/dist/Types/Permission.js +104 -0
  114. package/build/dist/Types/Permission.js.map +1 -1
  115. package/build/dist/Types/Phone.js +47 -3
  116. package/build/dist/Types/Phone.js.map +1 -1
  117. package/build/dist/Types/SCIM/SCIMLogStatus.js +8 -0
  118. package/build/dist/Types/SCIM/SCIMLogStatus.js.map +1 -0
  119. package/build/dist/UI/Components/Date/StartAndEndDate.js +13 -13
  120. package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
  121. package/build/dist/UI/Components/Diagram/ConceptCards.js +30 -0
  122. package/build/dist/UI/Components/Diagram/ConceptCards.js.map +1 -0
  123. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +30 -0
  124. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -0
  125. package/build/dist/UI/Components/Diagram/Index.js +5 -0
  126. package/build/dist/UI/Components/Diagram/Index.js.map +1 -0
  127. package/build/dist/UI/Components/Diagram/NumberedSteps.js +18 -0
  128. package/build/dist/UI/Components/Diagram/NumberedSteps.js.map +1 -0
  129. package/build/dist/UI/Components/Diagram/VerticalFlowSteps.js +16 -0
  130. package/build/dist/UI/Components/Diagram/VerticalFlowSteps.js.map +1 -0
  131. package/build/dist/UI/Components/Filters/FilterViewer.js +6 -5
  132. package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
  133. package/build/dist/UI/Components/Icon/Icon.js +4 -0
  134. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  135. package/build/dist/UI/Components/Input/Input.js +4 -1
  136. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  137. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js +30 -1
  138. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js.map +1 -1
  139. package/package.json +1 -1
package/Types/Phone.ts CHANGED
@@ -13,7 +13,7 @@ export default class Phone extends DatabaseProperty {
13
13
  public static pickPhoneNumberToSendSMSOrCallFrom(data: {
14
14
  to: Phone | string;
15
15
  primaryPhoneNumberToPickFrom: Phone | string;
16
- seocndaryPhoneNumbersToPickFrom: Phone[] | string[];
16
+ secondaryPhoneNumbersToPickFrom: Phone[] | string[];
17
17
  }): Phone {
18
18
  /*
19
19
  * convert all to string, so that we can compare them
@@ -28,8 +28,8 @@ export default class Phone extends DatabaseProperty {
28
28
  ? data.primaryPhoneNumberToPickFrom
29
29
  : data.primaryPhoneNumberToPickFrom.toString();
30
30
 
31
- const seocndaryPhoneNumbersToPickFrom: string[] =
32
- data.seocndaryPhoneNumbersToPickFrom.map((phone: Phone | string) => {
31
+ const secondaryPhoneNumbersToPickFrom: string[] =
32
+ data.secondaryPhoneNumbersToPickFrom.map((phone: Phone | string) => {
33
33
  return typeof phone === "string" ? phone : phone.toString();
34
34
  });
35
35
 
@@ -51,7 +51,7 @@ export default class Phone extends DatabaseProperty {
51
51
  return new Phone(primaryPhoneNumberToPickFrom);
52
52
  }
53
53
 
54
- for (const secondaryPhoneNumber of seocndaryPhoneNumbersToPickFrom) {
54
+ for (const secondaryPhoneNumber of secondaryPhoneNumbersToPickFrom) {
55
55
  const secondaryPhoneNumberCountryCode: string = normalizePhoneNumber(
56
56
  secondaryPhoneNumber,
57
57
  ).substring(0, 2);
@@ -148,4 +148,53 @@ export default class Phone extends DatabaseProperty {
148
148
  example: { _type: ObjectType.Phone, value: "+1-555-123-4567" },
149
149
  });
150
150
  }
151
+
152
+ // Map of calling code prefixes to ISO country codes
153
+ private static readonly CALLING_CODE_TO_COUNTRY_MAP: Record<string, string> =
154
+ {
155
+ "+1": "US", // US and Canada
156
+ "+44": "GB", // United Kingdom
157
+ "+61": "AU", // Australia
158
+ "+49": "DE", // Germany
159
+ "+33": "FR", // France
160
+ "+91": "IN", // India
161
+ "+81": "JP", // Japan
162
+ "+86": "CN", // China
163
+ "+55": "BR", // Brazil
164
+ "+52": "MX", // Mexico
165
+ };
166
+
167
+ /**
168
+ * Extract ISO country code from a phone number
169
+ * @param phoneNumber - The phone number (e.g., "+15551234567")
170
+ * @returns ISO country code (e.g., "US") or "US" as default
171
+ */
172
+ public static getCountryCodeFromPhoneNumber(phoneNumber: string): string {
173
+ for (const [prefix, countryCode] of Object.entries(
174
+ Phone.CALLING_CODE_TO_COUNTRY_MAP,
175
+ )) {
176
+ if (phoneNumber.startsWith(prefix)) {
177
+ return countryCode;
178
+ }
179
+ }
180
+ return "US"; // Default to US if unknown
181
+ }
182
+
183
+ /**
184
+ * Extract area code from a phone number
185
+ * Currently only supports US/Canada (+1) numbers
186
+ * @param phoneNumber - The phone number (e.g., "+15551234567")
187
+ * @returns Area code (e.g., "555") or empty string for non-US/CA numbers
188
+ */
189
+ public static getAreaCodeFromPhoneNumber(phoneNumber: string): string {
190
+ // For US/Canada numbers (+1), extract the next 3 digits
191
+ if (phoneNumber.startsWith("+1")) {
192
+ const number: string = phoneNumber.substring(2);
193
+ if (number.length >= 3) {
194
+ return number.substring(0, 3);
195
+ }
196
+ }
197
+ // For other countries, area code extraction is more complex
198
+ return "";
199
+ }
151
200
  }
@@ -0,0 +1,7 @@
1
+ enum SCIMLogStatus {
2
+ Success = "Success",
3
+ Error = "Error",
4
+ Warning = "Warning",
5
+ }
6
+
7
+ export default SCIMLogStatus;
@@ -158,6 +158,9 @@ const StartAndEndDate: DateFilterFunction = (
158
158
  value={startDateTime || ""}
159
159
  placeholder={`Start Date`}
160
160
  type={inputType}
161
+ showSecondsForDateTime={
162
+ props.type === StartAndEndDateType.DateTime
163
+ }
161
164
  />
162
165
  </div>
163
166
  </div>
@@ -192,6 +195,9 @@ const StartAndEndDate: DateFilterFunction = (
192
195
  value={endDateTime || ""}
193
196
  placeholder={`End Date`}
194
197
  type={inputType}
198
+ showSecondsForDateTime={
199
+ props.type === StartAndEndDateType.DateTime
200
+ }
195
201
  />
196
202
  </div>
197
203
  </div>
@@ -207,7 +213,10 @@ const StartAndEndDate: DateFilterFunction = (
207
213
  buttonSize={ButtonSize.Small}
208
214
  onClick={() => {
209
215
  // set it to past 1 hour
210
- const endDate: Date = OneUptimeDate.getCurrentDate();
216
+ const endDate: Date =
217
+ OneUptimeDate.resetSecondsAndMilliseconds(
218
+ OneUptimeDate.getCurrentDate(),
219
+ );
211
220
  const startDate: Date = OneUptimeDate.addRemoveHours(
212
221
  endDate,
213
222
  -1,
@@ -229,7 +238,10 @@ const StartAndEndDate: DateFilterFunction = (
229
238
  buttonSize={ButtonSize.Small}
230
239
  onClick={() => {
231
240
  // set it to past 3 hour
232
- const endDate: Date = OneUptimeDate.getCurrentDate();
241
+ const endDate: Date =
242
+ OneUptimeDate.resetSecondsAndMilliseconds(
243
+ OneUptimeDate.getCurrentDate(),
244
+ );
233
245
  const startDate: Date = OneUptimeDate.addRemoveHours(
234
246
  endDate,
235
247
  -3,
@@ -251,7 +263,9 @@ const StartAndEndDate: DateFilterFunction = (
251
263
  buttonSize={ButtonSize.Small}
252
264
  onClick={() => {
253
265
  // set it to past 1 day
254
- const endDate: Date = OneUptimeDate.getCurrentDate();
266
+ const endDate: Date = OneUptimeDate.resetSecondsAndMilliseconds(
267
+ OneUptimeDate.getCurrentDate(),
268
+ );
255
269
  const startDate: Date = OneUptimeDate.addRemoveDays(
256
270
  endDate,
257
271
  -1,
@@ -269,7 +283,9 @@ const StartAndEndDate: DateFilterFunction = (
269
283
  buttonSize={ButtonSize.Small}
270
284
  onClick={() => {
271
285
  // set it to past 1 week
272
- const endDate: Date = OneUptimeDate.getCurrentDate();
286
+ const endDate: Date = OneUptimeDate.resetSecondsAndMilliseconds(
287
+ OneUptimeDate.getCurrentDate(),
288
+ );
273
289
  const startDate: Date = OneUptimeDate.addRemoveDays(
274
290
  endDate,
275
291
  -7,
@@ -286,8 +302,10 @@ const StartAndEndDate: DateFilterFunction = (
286
302
  }
287
303
  buttonSize={ButtonSize.Small}
288
304
  onClick={() => {
289
- // set it to past 1 week
290
- const endDate: Date = OneUptimeDate.getCurrentDate();
305
+ // set it to past 2 weeks
306
+ const endDate: Date = OneUptimeDate.resetSecondsAndMilliseconds(
307
+ OneUptimeDate.getCurrentDate(),
308
+ );
291
309
  const startDate: Date = OneUptimeDate.addRemoveDays(
292
310
  endDate,
293
311
  -14,
@@ -305,8 +323,10 @@ const StartAndEndDate: DateFilterFunction = (
305
323
  }
306
324
  buttonSize={ButtonSize.Small}
307
325
  onClick={() => {
308
- // set it to past 1 week
309
- const endDate: Date = OneUptimeDate.getCurrentDate();
326
+ // set it to past 3 weeks
327
+ const endDate: Date = OneUptimeDate.resetSecondsAndMilliseconds(
328
+ OneUptimeDate.getCurrentDate(),
329
+ );
310
330
  const startDate: Date = OneUptimeDate.addRemoveDays(
311
331
  endDate,
312
332
  -21,
@@ -325,7 +345,9 @@ const StartAndEndDate: DateFilterFunction = (
325
345
  buttonSize={ButtonSize.Small}
326
346
  onClick={() => {
327
347
  // set it to past 1 month
328
- const endDate: Date = OneUptimeDate.getCurrentDate();
348
+ const endDate: Date = OneUptimeDate.resetSecondsAndMilliseconds(
349
+ OneUptimeDate.getCurrentDate(),
350
+ );
329
351
  const startDate: Date = OneUptimeDate.addRemoveMonths(
330
352
  endDate,
331
353
  -1,
@@ -343,8 +365,10 @@ const StartAndEndDate: DateFilterFunction = (
343
365
  }
344
366
  buttonSize={ButtonSize.Small}
345
367
  onClick={() => {
346
- // set it to past 1 month
347
- const endDate: Date = OneUptimeDate.getCurrentDate();
368
+ // set it to past 3 months
369
+ const endDate: Date = OneUptimeDate.resetSecondsAndMilliseconds(
370
+ OneUptimeDate.getCurrentDate(),
371
+ );
348
372
  const startDate: Date = OneUptimeDate.addRemoveMonths(
349
373
  endDate,
350
374
  -3,
@@ -0,0 +1,74 @@
1
+ import React, { FunctionComponent, ReactElement } from "react";
2
+ import Icon from "../Icon/Icon";
3
+ import IconProp from "../../../Types/Icon/IconProp";
4
+ import Color from "../../../Types/Color";
5
+
6
+ export interface ConceptCard {
7
+ title: string;
8
+ description: string;
9
+ icon: IconProp;
10
+ iconColor: Color;
11
+ }
12
+
13
+ export interface ComponentProps {
14
+ cards: ConceptCard[];
15
+ /** Number of columns in the grid (1-4). Default is 2. */
16
+ columns?: 1 | 2 | 3 | 4 | undefined;
17
+ }
18
+
19
+ const ConceptCards: FunctionComponent<ComponentProps> = (
20
+ props: ComponentProps,
21
+ ): ReactElement => {
22
+ const columns: number = props.columns || 2;
23
+
24
+ const getGridClasses: () => string = (): string => {
25
+ switch (columns) {
26
+ case 1:
27
+ return "grid-cols-1";
28
+ case 2:
29
+ return "grid-cols-1 md:grid-cols-2";
30
+ case 3:
31
+ return "grid-cols-1 md:grid-cols-2 lg:grid-cols-3";
32
+ case 4:
33
+ return "grid-cols-1 md:grid-cols-2 lg:grid-cols-4";
34
+ default:
35
+ return "grid-cols-1 md:grid-cols-2";
36
+ }
37
+ };
38
+
39
+ return (
40
+ <div className={`grid ${getGridClasses()} gap-3`}>
41
+ {props.cards.map((card: ConceptCard, index: number) => {
42
+ return (
43
+ <div
44
+ key={index}
45
+ className="border border-gray-200 rounded-md p-3 bg-white hover:border-gray-300 transition-colors"
46
+ >
47
+ <div className="flex items-start space-x-3">
48
+ <div
49
+ className="flex-shrink-0 w-8 h-8 rounded flex items-center justify-center"
50
+ style={{ backgroundColor: `${card.iconColor.toString()}15` }}
51
+ >
52
+ <Icon
53
+ icon={card.icon}
54
+ className="h-4 w-4"
55
+ style={{ color: card.iconColor.toString() }}
56
+ />
57
+ </div>
58
+ <div className="flex-1 min-w-0">
59
+ <h4 className="text-sm font-medium text-gray-900">
60
+ {card.title}
61
+ </h4>
62
+ <p className="text-sm text-gray-500 mt-1 leading-relaxed">
63
+ {card.description}
64
+ </p>
65
+ </div>
66
+ </div>
67
+ </div>
68
+ );
69
+ })}
70
+ </div>
71
+ );
72
+ };
73
+
74
+ export default ConceptCards;
@@ -0,0 +1,92 @@
1
+ import React, { FunctionComponent, ReactElement } from "react";
2
+ import Icon from "../Icon/Icon";
3
+ import IconProp from "../../../Types/Icon/IconProp";
4
+ import Color from "../../../Types/Color";
5
+
6
+ export interface ChainStep {
7
+ stepNumber: number;
8
+ title: string;
9
+ description: string;
10
+ color: Color;
11
+ /** Optional label shown below the step number. Default is "Step" */
12
+ stepLabel?: string | undefined;
13
+ }
14
+
15
+ export interface ChainEndStep {
16
+ title: string;
17
+ description: string;
18
+ icon: IconProp;
19
+ color: Color;
20
+ }
21
+
22
+ export interface ComponentProps {
23
+ steps: ChainStep[];
24
+ endStep?: ChainEndStep | undefined;
25
+ /** Default label for steps. Default is "Step" */
26
+ defaultStepLabel?: string | undefined;
27
+ }
28
+
29
+ const HorizontalStepChain: FunctionComponent<ComponentProps> = (
30
+ props: ComponentProps,
31
+ ): ReactElement => {
32
+ const defaultLabel: string = props.defaultStepLabel || "Step";
33
+
34
+ return (
35
+ <div className="flex items-center flex-wrap gap-3">
36
+ {props.steps.map((step: ChainStep, index: number) => {
37
+ return (
38
+ <React.Fragment key={index}>
39
+ {/* Step */}
40
+ <div className="flex items-center space-x-3">
41
+ <div
42
+ className="w-10 h-10 rounded-full flex items-center justify-center text-white text-sm font-medium"
43
+ style={{ backgroundColor: step.color.toString() }}
44
+ >
45
+ {step.stepNumber}
46
+ </div>
47
+ <div>
48
+ <p className="text-sm font-medium text-gray-900">
49
+ {step.title}
50
+ </p>
51
+ <p className="text-xs text-gray-500">
52
+ {step.stepLabel || defaultLabel} {step.stepNumber} ·{" "}
53
+ {step.description}
54
+ </p>
55
+ </div>
56
+ </div>
57
+
58
+ {/* Arrow */}
59
+ <Icon
60
+ icon={IconProp.ChevronRight}
61
+ className="h-4 w-4 text-gray-300 hidden sm:block"
62
+ />
63
+ </React.Fragment>
64
+ );
65
+ })}
66
+
67
+ {/* End Step */}
68
+ {props.endStep && (
69
+ <div className="flex items-center space-x-3">
70
+ <div
71
+ className="w-10 h-10 rounded-full flex items-center justify-center"
72
+ style={{ backgroundColor: `${props.endStep.color.toString()}15` }}
73
+ >
74
+ <Icon
75
+ icon={props.endStep.icon}
76
+ className="h-4 w-4"
77
+ style={{ color: props.endStep.color.toString() }}
78
+ />
79
+ </div>
80
+ <div>
81
+ <p className="text-sm font-medium text-gray-900">
82
+ {props.endStep.title}
83
+ </p>
84
+ <p className="text-xs text-gray-500">{props.endStep.description}</p>
85
+ </div>
86
+ </div>
87
+ )}
88
+ </div>
89
+ );
90
+ };
91
+
92
+ export default HorizontalStepChain;
@@ -0,0 +1,11 @@
1
+ export { default as VerticalFlowSteps } from "./VerticalFlowSteps";
2
+ export type { FlowStep } from "./VerticalFlowSteps";
3
+
4
+ export { default as HorizontalStepChain } from "./HorizontalStepChain";
5
+ export type { ChainStep, ChainEndStep } from "./HorizontalStepChain";
6
+
7
+ export { default as NumberedSteps } from "./NumberedSteps";
8
+ export type { NumberedStep } from "./NumberedSteps";
9
+
10
+ export { default as ConceptCards } from "./ConceptCards";
11
+ export type { ConceptCard } from "./ConceptCards";
@@ -0,0 +1,77 @@
1
+ import React, { FunctionComponent, ReactElement } from "react";
2
+ import Icon from "../Icon/Icon";
3
+ import IconProp from "../../../Types/Icon/IconProp";
4
+ import Color from "../../../Types/Color";
5
+
6
+ export interface NumberedStep {
7
+ title: string;
8
+ description: string;
9
+ /** If provided, shows an icon instead of number */
10
+ icon?: IconProp | undefined;
11
+ /** Color for the step indicator */
12
+ color?: Color | undefined;
13
+ }
14
+
15
+ export interface ComponentProps {
16
+ steps: NumberedStep[];
17
+ /** Default color for steps */
18
+ defaultColor?: Color | undefined;
19
+ }
20
+
21
+ const NumberedSteps: FunctionComponent<ComponentProps> = (
22
+ props: ComponentProps,
23
+ ): ReactElement => {
24
+ const defaultColor: Color = props.defaultColor || new Color("#6b7280"); // gray-500
25
+
26
+ return (
27
+ <div className="relative">
28
+ {props.steps.map((step: NumberedStep, index: number) => {
29
+ const color: Color = step.color || defaultColor;
30
+ const isLast: boolean = index === props.steps.length - 1;
31
+
32
+ return (
33
+ <div key={index} className="relative flex items-start pb-5 last:pb-0">
34
+ {/* Vertical line connecting steps */}
35
+ {!isLast && (
36
+ <div
37
+ className="absolute left-4 top-10 w-px bg-gray-200"
38
+ style={{ height: "calc(100% - 1.5rem)" }}
39
+ />
40
+ )}
41
+
42
+ {/* Number/Icon indicator */}
43
+ <div
44
+ className="relative flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center border-2 bg-white"
45
+ style={{ borderColor: color.toString() }}
46
+ >
47
+ {step.icon ? (
48
+ <Icon
49
+ icon={step.icon}
50
+ className="h-4 w-4"
51
+ style={{ color: color.toString() }}
52
+ />
53
+ ) : (
54
+ <span
55
+ className="text-sm font-medium"
56
+ style={{ color: color.toString() }}
57
+ >
58
+ {index + 1}
59
+ </span>
60
+ )}
61
+ </div>
62
+
63
+ {/* Content */}
64
+ <div className="ml-4 flex-1 pt-0.5">
65
+ <h4 className="text-sm font-medium text-gray-900">
66
+ {step.title}
67
+ </h4>
68
+ <p className="text-sm text-gray-500 mt-0.5">{step.description}</p>
69
+ </div>
70
+ </div>
71
+ );
72
+ })}
73
+ </div>
74
+ );
75
+ };
76
+
77
+ export default NumberedSteps;
@@ -0,0 +1,59 @@
1
+ import React, { FunctionComponent, ReactElement } from "react";
2
+ import Icon from "../Icon/Icon";
3
+ import IconProp from "../../../Types/Icon/IconProp";
4
+ import Color from "../../../Types/Color";
5
+
6
+ export interface FlowStep {
7
+ title: string;
8
+ description: string;
9
+ icon: IconProp;
10
+ iconColor: Color;
11
+ }
12
+
13
+ export interface ComponentProps {
14
+ steps: FlowStep[];
15
+ }
16
+
17
+ const VerticalFlowSteps: FunctionComponent<ComponentProps> = (
18
+ props: ComponentProps,
19
+ ): ReactElement => {
20
+ return (
21
+ <div className="relative">
22
+ {props.steps.map((step: FlowStep, index: number) => {
23
+ const isLast: boolean = index === props.steps.length - 1;
24
+
25
+ return (
26
+ <div key={index} className="relative flex items-start pb-6 last:pb-0">
27
+ {/* Vertical line connecting steps */}
28
+ {!isLast && (
29
+ <div
30
+ className="absolute left-4 top-10 w-px bg-gray-200"
31
+ style={{ height: "calc(100% - 1rem)" }}
32
+ />
33
+ )}
34
+
35
+ {/* Icon */}
36
+ <div
37
+ className="relative flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center border border-gray-200 bg-white"
38
+ style={{ borderColor: `${step.iconColor.toString()}40` }}
39
+ >
40
+ <Icon
41
+ icon={step.icon}
42
+ className="h-4 w-4"
43
+ style={{ color: step.iconColor.toString() }}
44
+ />
45
+ </div>
46
+
47
+ {/* Content */}
48
+ <div className="ml-4 flex-1">
49
+ <p className="text-sm font-medium text-gray-900">{step.title}</p>
50
+ <p className="text-sm text-gray-500 mt-0.5">{step.description}</p>
51
+ </div>
52
+ </div>
53
+ );
54
+ })}
55
+ </div>
56
+ );
57
+ };
58
+
59
+ export default VerticalFlowSteps;
@@ -209,15 +209,19 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
209
209
  ] as InBetween<Date>;
210
210
 
211
211
  const shouldOnlyShowDate: boolean = data.filter.type === FieldType.Date;
212
+ const shouldShowSeconds: boolean =
213
+ data.filter.type === FieldType.DateTime;
212
214
 
213
215
  if (
214
216
  OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
215
217
  startAndEndDates.startValue as Date,
216
218
  shouldOnlyShowDate,
219
+ shouldShowSeconds,
217
220
  ) ===
218
221
  OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
219
222
  startAndEndDates.endValue as Date,
220
223
  shouldOnlyShowDate,
224
+ shouldShowSeconds,
221
225
  )
222
226
  ) {
223
227
  return (
@@ -228,6 +232,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
228
232
  {OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
229
233
  startAndEndDates.startValue as Date,
230
234
  data.filter.type === FieldType.Date,
235
+ shouldShowSeconds,
231
236
  )}
232
237
  </span>{" "}
233
238
  </div>
@@ -241,6 +246,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
241
246
  {OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
242
247
  startAndEndDates.startValue as Date,
243
248
  shouldOnlyShowDate,
249
+ shouldShowSeconds,
244
250
  )}
245
251
  </span>{" "}
246
252
  and{" "}
@@ -248,6 +254,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
248
254
  {OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
249
255
  startAndEndDates.endValue as Date,
250
256
  shouldOnlyShowDate,
257
+ shouldShowSeconds,
251
258
  )}
252
259
  </span>{" "}
253
260
  </div>
@@ -978,6 +978,16 @@ const Icon: FunctionComponent<ComponentProps> = ({
978
978
  d="M2.25 6.75c0 8.284 6.716 15 15 15h2.25a2.25 2.25 0 002.25-2.25v-1.372c0-.516-.351-.966-.852-1.091l-4.423-1.106c-.44-.11-.902.055-1.173.417l-.97 1.293c-.282.376-.769.542-1.21.38a12.035 12.035 0 01-7.143-7.143c-.162-.441.004-.928.38-1.21l1.293-.97c.363-.271.527-.734.417-1.173L6.963 3.102a1.125 1.125 0 00-1.091-.852H4.5A2.25 2.25 0 002.25 4.5v2.25z"
979
979
  />,
980
980
  );
981
+ } else if (icon === IconProp.IncomingCall) {
982
+ return getSvgWrapper(
983
+ <>
984
+ <path
985
+ strokeLinecap="round"
986
+ strokeLinejoin="round"
987
+ d="M14.25 9.75v-4.5m0 4.5h4.5m-4.5 0l6-6m-3 18c-8.284 0-15-6.716-15-15V4.5A2.25 2.25 0 014.5 2.25h1.372c.516 0 .966.351 1.091.852l1.106 4.423c.11.44-.054.902-.417 1.173l-1.293.97a1.062 1.062 0 00-.38 1.21 12.035 12.035 0 007.143 7.143c.441.162.928-.004 1.21-.38l.97-1.293a1.125 1.125 0 011.173-.417l4.423 1.106c.5.125.852.575.852 1.091V19.5a2.25 2.25 0 01-2.25 2.25h-2.25z"
988
+ />
989
+ </>,
990
+ );
981
991
  } else if (icon === IconProp.More) {
982
992
  return getSvgWrapper(
983
993
  <path
@@ -39,6 +39,7 @@ export interface ComponentProps {
39
39
  outerDivClassName?: string | undefined;
40
40
  autoFocus?: boolean | undefined;
41
41
  disableSpellCheck?: boolean | undefined;
42
+ showSecondsForDateTime?: boolean | undefined;
42
43
  }
43
44
 
44
45
  const Input: FunctionComponent<ComponentProps> = (
@@ -188,6 +189,12 @@ const Input: FunctionComponent<ComponentProps> = (
188
189
  }
189
190
  readOnly={props.readOnly || props.disabled || false}
190
191
  type={props.type || "text"}
192
+ step={
193
+ props.type === InputType.DATETIME_LOCAL &&
194
+ props.showSecondsForDateTime
195
+ ? "1"
196
+ : undefined
197
+ }
191
198
  placeholder={props.placeholder}
192
199
  className={className}
193
200
  onBlur={() => {