@oneuptime/common 11.4.0 → 11.4.1

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 (178) hide show
  1. package/Server/API/AIAgentTaskAPI.ts +10 -24
  2. package/Server/API/TelemetryAPI.ts +4 -3
  3. package/Server/Services/AIAgentTaskService.ts +62 -0
  4. package/Server/Services/AnalyticsDatabaseService.ts +27 -0
  5. package/Server/Services/LogAggregationService.ts +29 -11
  6. package/Server/Services/MetricService.ts +603 -13
  7. package/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.ts +1 -1
  8. package/Server/Utils/AI/Sentinel/README.md +10 -0
  9. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +44 -0
  10. package/Server/Utils/Monitor/MonitorMetricUtil.ts +108 -2
  11. package/Tests/Server/Services/AIAgentTaskServiceClaim.test.ts +146 -0
  12. package/Tests/Server/Services/LogAggregationService.test.ts +22 -0
  13. package/Tests/Server/Services/MetricServiceAggregate.test.ts +194 -0
  14. package/Tests/Types/AI/AIAgentTaskStatus.test.ts +86 -0
  15. package/Tests/Types/BaseDatabase/AggregationIntervalUtil.test.ts +127 -0
  16. package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.test.ts +152 -0
  17. package/Tests/Types/Trace/TraceRecordingRuleDefinition.test.ts +308 -0
  18. package/Tests/UI/Components/Dropdown.test.tsx +17 -0
  19. package/Tests/UI/Components/EntityDropdown.test.tsx +130 -0
  20. package/Tests/UI/Components/Modal.test.tsx +144 -2
  21. package/Tests/UI/Components/TelemetrySearchBar.test.tsx +90 -0
  22. package/Tests/UI/Utils/Theme.test.ts +161 -0
  23. package/Types/BaseDatabase/AggregateBy.ts +12 -0
  24. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  25. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  26. package/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.ts +19 -0
  27. package/Types/Dashboard/DashboardTemplates.ts +9 -1
  28. package/Types/Monitor/CriteriaFilter.ts +4 -0
  29. package/Types/Monitor/HttpPhaseTimings.ts +16 -0
  30. package/Types/Monitor/MonitorMetricType.ts +17 -0
  31. package/Types/Monitor/PingMonitor/PingMonitorResponse.ts +20 -0
  32. package/Types/Probe/ProbeMonitorResponse.ts +14 -0
  33. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +8 -5
  34. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +4 -1
  35. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +6 -3
  36. package/UI/Components/CodeBlock/CodeBlock.tsx +2 -1
  37. package/UI/Components/CodeEditor/CodeEditor.tsx +3 -0
  38. package/UI/Components/Divider/Divider.tsx +1 -1
  39. package/UI/Components/Dropdown/Dropdown.tsx +13 -4
  40. package/UI/Components/EntityDropdown/EntityDropdown.tsx +110 -2
  41. package/UI/Components/ErrorBoundary.tsx +2 -1
  42. package/UI/Components/EventItem/EventItem.tsx +2 -2
  43. package/UI/Components/GanttChart/Bar/Index.tsx +1 -1
  44. package/UI/Components/Graphs/UptimeBarTooltip.tsx +30 -23
  45. package/UI/Components/Header/Header.tsx +7 -0
  46. package/UI/Components/Header/HeaderIconDropdownButton.tsx +2 -0
  47. package/UI/Components/Label/Label.tsx +2 -2
  48. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +22 -10
  49. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +9 -3
  50. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +8 -8
  51. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +44 -20
  52. package/UI/Components/Modal/ConfirmModal.tsx +1 -1
  53. package/UI/Components/Modal/Modal.tsx +213 -121
  54. package/UI/Components/Modal/ModalFooter.tsx +33 -22
  55. package/UI/Components/ModelTable/TableView.tsx +1 -1
  56. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +20 -12
  57. package/UI/Components/Pill/Pill.tsx +21 -13
  58. package/UI/Components/StatusBubble/StatusBubble.tsx +3 -3
  59. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +7 -1
  60. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +9 -3
  61. package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +62 -4
  62. package/UI/Components/Workflow/Component.tsx +53 -33
  63. package/UI/Components/Workflow/ComponentPortViewer.tsx +6 -6
  64. package/UI/Components/Workflow/ComponentReturnValueViewer.tsx +8 -8
  65. package/UI/Components/Workflow/ComponentsModal.tsx +16 -9
  66. package/UI/Components/Workflow/Workflow.tsx +13 -11
  67. package/UI/Utils/Theme.ts +140 -0
  68. package/Utils/Dashboard/Components/DashboardLogChartComponent.ts +104 -0
  69. package/Utils/Dashboard/Components/Index.ts +7 -0
  70. package/Utils/Monitor/MonitorMetricType.ts +70 -2
  71. package/build/dist/Server/API/AIAgentTaskAPI.js +8 -23
  72. package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -1
  73. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  74. package/build/dist/Server/Services/AIAgentTaskService.js +59 -0
  75. package/build/dist/Server/Services/AIAgentTaskService.js.map +1 -1
  76. package/build/dist/Server/Services/AnalyticsDatabaseService.js +19 -0
  77. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  78. package/build/dist/Server/Services/LogAggregationService.js +21 -7
  79. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  80. package/build/dist/Server/Services/MetricService.js +449 -7
  81. package/build/dist/Server/Services/MetricService.js.map +1 -1
  82. package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js +1 -1
  83. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +29 -0
  84. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  85. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +86 -2
  86. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  87. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  88. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  89. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  90. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  91. package/build/dist/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.js +2 -0
  92. package/build/dist/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.js.map +1 -0
  93. package/build/dist/Types/Dashboard/DashboardTemplates.js +9 -1
  94. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  95. package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
  96. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  97. package/build/dist/Types/Monitor/HttpPhaseTimings.js +2 -0
  98. package/build/dist/Types/Monitor/HttpPhaseTimings.js.map +1 -0
  99. package/build/dist/Types/Monitor/MonitorMetricType.js +15 -0
  100. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  101. package/build/dist/Types/Monitor/PingMonitor/PingMonitorResponse.js +2 -0
  102. package/build/dist/Types/Monitor/PingMonitor/PingMonitorResponse.js.map +1 -0
  103. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +7 -4
  104. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  105. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +4 -1
  106. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  107. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +6 -3
  108. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  109. package/build/dist/UI/Components/CodeBlock/CodeBlock.js +1 -1
  110. package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
  111. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +3 -1
  112. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  113. package/build/dist/UI/Components/Divider/Divider.js +1 -1
  114. package/build/dist/UI/Components/Divider/Divider.js.map +1 -1
  115. package/build/dist/UI/Components/Dropdown/Dropdown.js +10 -4
  116. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  117. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +76 -3
  118. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  119. package/build/dist/UI/Components/ErrorBoundary.js +2 -1
  120. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  121. package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
  122. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  123. package/build/dist/UI/Components/GanttChart/Bar/Index.js +1 -1
  124. package/build/dist/UI/Components/GanttChart/Bar/Index.js.map +1 -1
  125. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +29 -23
  126. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  127. package/build/dist/UI/Components/Header/Header.js +1 -0
  128. package/build/dist/UI/Components/Header/Header.js.map +1 -1
  129. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
  130. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  131. package/build/dist/UI/Components/Label/Label.js +2 -2
  132. package/build/dist/UI/Components/Label/Label.js.map +1 -1
  133. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +20 -8
  134. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  135. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +8 -2
  136. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  137. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +8 -8
  138. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +40 -20
  139. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  140. package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
  141. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  142. package/build/dist/UI/Components/Modal/Modal.js +109 -51
  143. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  144. package/build/dist/UI/Components/Modal/ModalFooter.js +13 -10
  145. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  146. package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
  147. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  148. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +17 -12
  149. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  150. package/build/dist/UI/Components/Pill/Pill.js +12 -13
  151. package/build/dist/UI/Components/Pill/Pill.js.map +1 -1
  152. package/build/dist/UI/Components/StatusBubble/StatusBubble.js +3 -3
  153. package/build/dist/UI/Components/StatusBubble/StatusBubble.js.map +1 -1
  154. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +1 -1
  155. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  156. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -2
  157. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  158. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +36 -6
  159. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
  160. package/build/dist/UI/Components/Workflow/Component.js +43 -33
  161. package/build/dist/UI/Components/Workflow/Component.js.map +1 -1
  162. package/build/dist/UI/Components/Workflow/ComponentPortViewer.js +6 -6
  163. package/build/dist/UI/Components/Workflow/ComponentPortViewer.js.map +1 -1
  164. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js +8 -8
  165. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js.map +1 -1
  166. package/build/dist/UI/Components/Workflow/ComponentsModal.js +15 -9
  167. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  168. package/build/dist/UI/Components/Workflow/Workflow.js +13 -11
  169. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  170. package/build/dist/UI/Utils/Theme.js +106 -0
  171. package/build/dist/UI/Utils/Theme.js.map +1 -0
  172. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js +92 -0
  173. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js.map +1 -0
  174. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  175. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  176. package/build/dist/Utils/Monitor/MonitorMetricType.js +70 -3
  177. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  178. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import Button, { ButtonStyleType } from "../Button/Button";
1
+ import { ButtonStyleType } from "../Button/Button";
2
2
  import ButtonType from "../Button/ButtonTypes";
3
3
  import Icon, { IconType, SizeProp, ThickProp } from "../Icon/Icon";
4
4
  import Loader, { LoaderType } from "../Loader/Loader";
@@ -11,6 +11,7 @@ import React, {
11
11
  FunctionComponent,
12
12
  ReactElement,
13
13
  useEffect,
14
+ useId,
14
15
  useRef,
15
16
  } from "react";
16
17
 
@@ -56,162 +57,253 @@ const Modal: FunctionComponent<ComponentProps> = (
56
57
  const translatedCloseButtonText: string | undefined = translateString(
57
58
  props.closeButtonText,
58
59
  );
60
+ const translatedCloseLabel: string = translateString("Close") || "Close";
59
61
  const modalRef: React.RefObject<HTMLDivElement> =
60
62
  useRef<HTMLDivElement>(null);
63
+ const previouslyFocusedElementRef: React.MutableRefObject<HTMLElement | null> =
64
+ useRef<HTMLElement | null>(
65
+ typeof document !== "undefined" &&
66
+ document.activeElement instanceof HTMLElement
67
+ ? document.activeElement
68
+ : null,
69
+ );
70
+ const onCloseRef: React.MutableRefObject<(() => void) | undefined> = useRef<
71
+ (() => void) | undefined
72
+ >(props.onClose);
73
+ const titleId: string = useId();
74
+ const descriptionId: string = useId();
61
75
 
62
- // Handle Escape key to close modal
63
76
  useEffect(() => {
64
- const handleEscapeKey: (event: KeyboardEvent) => void = (
77
+ onCloseRef.current = props.onClose;
78
+ }, [props.onClose]);
79
+
80
+ useEffect(() => {
81
+ const modal: HTMLDivElement | null = modalRef.current;
82
+ if (!modal) {
83
+ return;
84
+ }
85
+
86
+ const getFocusableElements: () => Array<HTMLElement> =
87
+ (): Array<HTMLElement> => {
88
+ return Array.from(
89
+ modal.querySelectorAll<HTMLElement>(
90
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
91
+ ),
92
+ ).filter((element: HTMLElement) => {
93
+ return (
94
+ !element.hasAttribute("disabled") &&
95
+ element.getAttribute("aria-hidden") !== "true"
96
+ );
97
+ });
98
+ };
99
+
100
+ const isTopmostDialog: () => boolean = (): boolean => {
101
+ const openDialogs: Array<Element> = Array.from(
102
+ document.querySelectorAll('[role="dialog"][aria-modal="true"]'),
103
+ );
104
+
105
+ return openDialogs[openDialogs.length - 1] === modal;
106
+ };
107
+
108
+ const initialFocusElement: HTMLElement | undefined =
109
+ getFocusableElements().find((element: HTMLElement) => {
110
+ return element.getAttribute("data-testid") !== "close-button";
111
+ });
112
+
113
+ if (isTopmostDialog()) {
114
+ (initialFocusElement || modal).focus();
115
+ }
116
+
117
+ const handleKeyDown: (event: KeyboardEvent) => void = (
65
118
  event: KeyboardEvent,
66
119
  ): void => {
67
- if (event.key === "Escape" && props.onClose) {
68
- props.onClose();
120
+ if (event.defaultPrevented || !isTopmostDialog()) {
121
+ return;
122
+ }
123
+
124
+ if (event.key === "Escape" && onCloseRef.current) {
125
+ event.preventDefault();
126
+ onCloseRef.current();
127
+ return;
128
+ }
129
+
130
+ if (event.key !== "Tab") {
131
+ return;
132
+ }
133
+
134
+ const focusableElements: Array<HTMLElement> = getFocusableElements();
135
+
136
+ if (focusableElements.length === 0) {
137
+ event.preventDefault();
138
+ modal.focus();
139
+ return;
140
+ }
141
+
142
+ const firstFocusableElement: HTMLElement = focusableElements[0]!;
143
+ const lastFocusableElement: HTMLElement =
144
+ focusableElements[focusableElements.length - 1]!;
145
+ const activeElement: Element | null = document.activeElement;
146
+
147
+ if (
148
+ event.shiftKey &&
149
+ (activeElement === firstFocusableElement ||
150
+ !modal.contains(activeElement))
151
+ ) {
152
+ event.preventDefault();
153
+ lastFocusableElement.focus();
154
+ } else if (
155
+ !event.shiftKey &&
156
+ (activeElement === lastFocusableElement ||
157
+ !modal.contains(activeElement))
158
+ ) {
159
+ event.preventDefault();
160
+ firstFocusableElement.focus();
69
161
  }
70
162
  };
71
163
 
72
- document.addEventListener("keydown", handleEscapeKey);
164
+ document.addEventListener("keydown", handleKeyDown);
165
+
73
166
  return () => {
74
- document.removeEventListener("keydown", handleEscapeKey);
75
- };
76
- }, [props.onClose]);
167
+ document.removeEventListener("keydown", handleKeyDown);
77
168
 
78
- // Focus trap and initial focus
79
- useEffect(() => {
80
- const modal: HTMLDivElement | null = modalRef.current;
81
- if (modal) {
82
- // Focus the first focusable element in the modal, excluding the close button
83
- const focusableElements: NodeListOf<Element> = modal.querySelectorAll(
84
- 'button:not([data-testid="close-button"]), [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
85
- );
86
- const firstFocusable: HTMLElement | undefined = focusableElements[0] as
87
- | HTMLElement
88
- | undefined;
89
- if (firstFocusable) {
90
- firstFocusable.focus();
169
+ if (previouslyFocusedElementRef.current?.isConnected) {
170
+ previouslyFocusedElementRef.current.focus();
91
171
  }
92
- }
172
+ };
93
173
  }, []);
94
174
 
95
- let iconBgColor: string = "bg-indigo-100";
175
+ let iconBgColor: string = "bg-indigo-50";
96
176
  let iconColor: string = "text-indigo-600";
177
+ let iconRingColor: string = "ring-indigo-100";
97
178
 
98
179
  if (props.iconType === IconType.Info) {
99
- iconBgColor = "bg-indigo-100";
180
+ iconBgColor = "bg-indigo-50";
100
181
  iconColor = "text-indigo-600";
182
+ iconRingColor = "ring-indigo-100";
101
183
  } else if (props.iconType === IconType.Warning) {
102
- iconBgColor = "bg-yellow-100";
103
- iconColor = "text-yellow-600";
184
+ iconBgColor = "bg-yellow-50";
185
+ iconColor = "text-yellow-700";
186
+ iconRingColor = "ring-yellow-100";
104
187
  } else if (props.iconType === IconType.Success) {
105
- iconBgColor = "bg-green-100";
188
+ iconBgColor = "bg-green-50";
106
189
  iconColor = "text-green-600";
190
+ iconRingColor = "ring-green-100";
107
191
  } else if (props.iconType === IconType.Danger) {
108
- iconBgColor = "bg-red-100";
192
+ iconBgColor = "bg-red-50";
109
193
  iconColor = "text-red-600";
194
+ iconRingColor = "ring-red-100";
195
+ }
196
+
197
+ let modalWidthClassName: string = "sm:max-w-lg md:max-w-lg";
198
+
199
+ if (props.modalWidth === ModalWidth.Medium) {
200
+ modalWidthClassName = "sm:max-w-3xl md:max-w-3xl";
201
+ } else if (props.modalWidth === ModalWidth.Large) {
202
+ modalWidthClassName = "sm:max-w-7xl md:max-w-7xl";
110
203
  }
111
204
 
112
205
  return (
113
- <div
114
- ref={modalRef}
115
- className="relative z-20"
116
- aria-labelledby="modal-title"
117
- aria-describedby={props.description ? "modal-description" : undefined}
118
- role="dialog"
119
- aria-modal="true"
120
- >
121
- <div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"></div>
206
+ <div className="relative z-50">
207
+ <div
208
+ className="fixed inset-0 bg-gray-950/45 backdrop-blur-[2px]"
209
+ data-testid="modal-backdrop"
210
+ aria-hidden="true"
211
+ />
122
212
 
123
- <div className="fixed inset-0 z-20 overflow-y-auto">
124
- <div className="flex min-h-screen items-end justify-center p-0 text-center md:items-center md:p-4">
213
+ <div className="fixed inset-0 z-50 overflow-y-auto">
214
+ <div className="flex min-h-full items-end justify-center p-0 text-center sm:items-center sm:p-6">
125
215
  <div
126
- className={`relative transform bg-white text-left shadow-xl transition-all w-full h-full md:rounded-lg md:my-8 ${
127
- props.modalWidth && props.modalWidth === ModalWidth.Large
128
- ? "md:max-w-7xl"
129
- : ""
130
- } ${
131
- props.modalWidth && props.modalWidth === ModalWidth.Medium
132
- ? "md:max-w-3xl"
133
- : ""
134
- } ${!props.modalWidth ? "md:max-w-lg" : ""} `}
216
+ ref={modalRef}
217
+ className={`relative flex max-h-[calc(100vh-1rem)] w-full flex-col rounded-t-2xl border border-gray-200/80 bg-white text-left shadow-2xl ring-1 ring-black/5 sm:my-8 sm:max-h-[calc(100vh-3rem)] sm:rounded-xl ${modalWidthClassName}`}
135
218
  data-testid="modal"
219
+ aria-labelledby={titleId}
220
+ aria-describedby={translatedDescription ? descriptionId : undefined}
221
+ role="dialog"
222
+ aria-modal="true"
223
+ tabIndex={-1}
136
224
  >
137
- {props.onClose && (
138
- <div className="absolute top-0 right-0 z-10 pt-4 pr-4 md:hidden lg:block">
139
- <Button
140
- buttonStyle={ButtonStyleType.ICON}
141
- icon={IconProp.Close}
142
- iconSize={SizeProp.Large}
143
- title="Close"
144
- dataTestId="close-button"
145
- onClick={props.onClose}
146
- />
225
+ <div className="relative flex shrink-0 flex-col gap-4 rounded-t-2xl border-b border-gray-100 bg-white px-5 py-4 sm:flex-row sm:items-start sm:justify-between sm:gap-6 sm:rounded-t-xl sm:px-6">
226
+ <div
227
+ className={`flex min-w-0 flex-1 items-start gap-3 ${
228
+ props.onClose ? "pr-9 sm:pr-0" : ""
229
+ }`}
230
+ >
231
+ {props.icon && (
232
+ <div
233
+ className={`flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg ${iconBgColor} ring-1 ring-inset ${iconRingColor}`}
234
+ data-testid="icon"
235
+ >
236
+ <Icon
237
+ thick={ThickProp.Thick}
238
+ type={
239
+ props.iconType === undefined
240
+ ? IconType.Info
241
+ : props.iconType
242
+ }
243
+ className={`${iconColor} h-5 w-5`}
244
+ icon={props.icon}
245
+ size={SizeProp.Five}
246
+ />
247
+ </div>
248
+ )}
249
+ <div className="min-w-0 flex-1">
250
+ <h3
251
+ data-testid="modal-title"
252
+ className="text-base font-semibold leading-6 tracking-tight text-gray-900"
253
+ id={titleId}
254
+ >
255
+ {translatedTitle}
256
+ </h3>
257
+ {translatedDescription && (
258
+ <p
259
+ id={descriptionId}
260
+ data-testid="modal-description"
261
+ className="mt-0.5 text-sm leading-5 text-gray-500"
262
+ >
263
+ {translatedDescription}
264
+ </p>
265
+ )}
266
+ </div>
147
267
  </div>
148
- )}
149
- <div className="p-4 md:p-6">
150
- {props.icon && (
268
+ {props.rightElement && (
151
269
  <div
152
- className={`mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full ${iconBgColor} md:mx-0 md:h-10 md:w-10`}
153
- data-testid="icon"
270
+ data-testid="right-element"
271
+ className={`flex-shrink-0 ${props.onClose ? "pr-9" : ""}`}
154
272
  >
155
- <Icon
156
- thick={ThickProp.Thick}
157
- type={
158
- props.iconType === undefined
159
- ? IconType.Info
160
- : props.iconType
161
- }
162
- className={`${iconColor} h-6 w-6 stroke-2`}
163
- icon={props.icon}
164
- size={SizeProp.Large}
165
- />
273
+ {props.rightElement}
166
274
  </div>
167
275
  )}
168
- <div className="text-left md:mt-0 md:ml-4 md:mr-4">
169
- <div className="flex flex-col md:flex-row md:justify-between">
170
- <div className="flex-1">
171
- <h3
172
- data-testid="modal-title"
173
- className={`text-lg font-medium leading-6 text-gray-900 ${
174
- props.icon ? "mt-4 md:ml-10 md:-mt-8 md:mb-5" : ""
175
- }`}
176
- id="modal-title"
177
- >
178
- {translatedTitle}
179
- </h3>
180
- {translatedDescription && (
181
- <p
182
- id="modal-description"
183
- data-testid="modal-description"
184
- className="text-sm leading-6 text-gray-500 mt-2"
185
- >
186
- {translatedDescription}
187
- </p>
188
- )}
276
+ {props.onClose && (
277
+ <button
278
+ type="button"
279
+ title={translatedCloseLabel}
280
+ aria-label={translatedCloseLabel}
281
+ data-testid="close-button"
282
+ onClick={props.onClose}
283
+ className="absolute right-4 top-4 inline-flex h-8 w-8 items-center justify-center rounded-md text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2"
284
+ >
285
+ <Icon icon={IconProp.Close} className="h-4 w-4" />
286
+ </button>
287
+ )}
288
+ </div>
289
+
290
+ <div
291
+ className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-5 py-5 sm:px-6"
292
+ data-testid="modal-content"
293
+ >
294
+ <ModalBody error={props.error}>
295
+ {!props.isBodyLoading ? (
296
+ props.children
297
+ ) : (
298
+ <div className="modal-body flex justify-center py-16">
299
+ <Loader
300
+ loaderType={LoaderType.Bar}
301
+ color={VeryLightGray}
302
+ size={200}
303
+ />
189
304
  </div>
190
- {props.rightElement && (
191
- <div
192
- data-testid="right-element"
193
- className="mt-4 md:mt-0 lg:mr-4"
194
- >
195
- {props.rightElement}
196
- </div>
197
- )}
198
- </div>
199
- <div className="mt-2">
200
- <ModalBody error={props.error}>
201
- {!props.isBodyLoading ? (
202
- props.children
203
- ) : (
204
- <div className="modal-body mt-20 mb-20 flex justify-center">
205
- <Loader
206
- loaderType={LoaderType.Bar}
207
- color={VeryLightGray}
208
- size={200}
209
- />
210
- </div>
211
- )}
212
- </ModalBody>
213
- </div>
214
- </div>
305
+ )}
306
+ </ModalBody>
215
307
  </div>
216
308
  <ModalFooter
217
309
  submitButtonType={
@@ -18,14 +18,42 @@ export interface ComponentProps {
18
18
  const ModalFooter: FunctionComponent<ComponentProps> = (
19
19
  props: ComponentProps,
20
20
  ): ReactElement => {
21
+ if (!props.onClose && !props.onSubmit && !props.leftFooterElement) {
22
+ return <></>;
23
+ }
24
+
21
25
  return (
22
- <div className="bg-gray-50 px-4 py-3 flex flex-row gap-3 md:px-6 md:justify-between">
26
+ <div
27
+ className="flex shrink-0 flex-col gap-3 rounded-b-2xl border-t border-gray-100 bg-gray-50/70 px-5 py-3 sm:flex-row sm:items-center sm:justify-between sm:rounded-b-xl sm:px-6"
28
+ data-testid="modal-footer"
29
+ >
23
30
  {props.leftFooterElement ? (
24
- <div className="flex flex-row gap-3">{props.leftFooterElement}</div>
31
+ <div className="flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:flex-wrap sm:items-center [&>div]:w-full [&>div]:flex-col [&_button]:!w-full sm:[&>div]:w-auto sm:[&>div]:flex-row sm:[&_button]:!ml-0 sm:[&_button]:!w-auto">
32
+ {props.leftFooterElement}
33
+ </div>
25
34
  ) : (
26
- <div />
35
+ <div className="hidden sm:block" />
27
36
  )}
28
- <div className="flex flex-row gap-3 md:flex-row-reverse">
37
+ <div className="flex w-full flex-col gap-2 sm:w-auto sm:flex-row sm:items-center">
38
+ {props.onClose ? (
39
+ <Button
40
+ buttonStyle={
41
+ props.closeButtonStyleType
42
+ ? props.closeButtonStyleType
43
+ : ButtonStyleType.NORMAL
44
+ }
45
+ title={props.closeButtonText ? props.closeButtonText : "Cancel"}
46
+ data-dismiss="modal"
47
+ onClick={() => {
48
+ props.onClose?.();
49
+ }}
50
+ dataTestId="modal-footer-close-button"
51
+ className="sm:!w-auto md:!ml-0"
52
+ />
53
+ ) : (
54
+ <></>
55
+ )}
56
+
29
57
  {props.onSubmit ? (
30
58
  <Button
31
59
  buttonStyle={
@@ -47,24 +75,7 @@ const ModalFooter: FunctionComponent<ComponentProps> = (
47
75
  : ButtonType.Button
48
76
  }
49
77
  dataTestId="modal-footer-submit-button"
50
- />
51
- ) : (
52
- <></>
53
- )}
54
-
55
- {props.onClose ? (
56
- <Button
57
- buttonStyle={
58
- props.closeButtonStyleType
59
- ? props.closeButtonStyleType
60
- : ButtonStyleType.NORMAL
61
- }
62
- title={props.closeButtonText ? props.closeButtonText : "Cancel"}
63
- data-dismiss="modal"
64
- onClick={() => {
65
- props.onClose?.();
66
- }}
67
- dataTestId="modal-footer-close-button"
78
+ className="sm:!w-auto md:!ml-0"
68
79
  />
69
80
  ) : (
70
81
  <></>
@@ -226,7 +226,7 @@ const TableViewElement: <T extends DatabaseBaseModel | AnalyticsBaseModel>(
226
226
  const getMenuContents: GetReactElementArrayFunction =
227
227
  (): Array<ReactElement> => {
228
228
  if (isLoading) {
229
- return [<BarLoader key={-1} />];
229
+ return [<BarLoader key={-1} color="var(--ou-link, #4f46e5)" />];
230
230
  }
231
231
 
232
232
  const elements: Array<ReactElement> = [];
@@ -41,7 +41,8 @@ const UptimeBarDayModal: FunctionComponent<ComponentProps> = (
41
41
  width: "48px",
42
42
  height: "48px",
43
43
  borderRadius: "50%",
44
- backgroundColor: "#f0fdf4",
44
+ backgroundColor:
45
+ "color-mix(in srgb, #22c55e 14%, var(--ou-surface-primary, #ffffff))",
45
46
  display: "flex",
46
47
  alignItems: "center",
47
48
  justifyContent: "center",
@@ -65,13 +66,18 @@ const UptimeBarDayModal: FunctionComponent<ComponentProps> = (
65
66
  style={{
66
67
  fontSize: "14px",
67
68
  fontWeight: 600,
68
- color: "#111827",
69
+ color: "var(--ou-text-primary, #111827)",
69
70
  marginBottom: "4px",
70
71
  }}
71
72
  >
72
73
  No incidents
73
74
  </div>
74
- <div style={{ fontSize: "13px", color: "#6b7280" }}>
75
+ <div
76
+ style={{
77
+ fontSize: "13px",
78
+ color: "var(--ou-text-muted, #6b7280)",
79
+ }}
80
+ >
75
81
  No incidents were reported on this day.
76
82
  </div>
77
83
  </div>
@@ -91,20 +97,20 @@ const UptimeBarDayModal: FunctionComponent<ComponentProps> = (
91
97
  : undefined
92
98
  }
93
99
  style={{
94
- border: "1px solid #e5e7eb",
100
+ border: "1px solid var(--ou-border-default, #e5e7eb)",
95
101
  borderRadius: "10px",
96
102
  padding: "14px 16px",
97
103
  marginBottom: "10px",
98
104
  cursor: isClickable ? "pointer" : "default",
99
105
  transition: "all 0.15s ease",
100
- backgroundColor: "#ffffff",
106
+ backgroundColor: "var(--ou-surface-primary, #ffffff)",
101
107
  }}
102
108
  onMouseEnter={(e: React.MouseEvent<HTMLDivElement>) => {
103
109
  if (isClickable) {
104
110
  (e.currentTarget as HTMLDivElement).style.backgroundColor =
105
- "#f9fafb";
111
+ "var(--ou-surface-secondary, #f9fafb)";
106
112
  (e.currentTarget as HTMLDivElement).style.borderColor =
107
- "#d1d5db";
113
+ "var(--ou-border-strong, #d1d5db)";
108
114
  (e.currentTarget as HTMLDivElement).style.boxShadow =
109
115
  "0 1px 3px rgba(0,0,0,0.06)";
110
116
  }
@@ -112,9 +118,9 @@ const UptimeBarDayModal: FunctionComponent<ComponentProps> = (
112
118
  onMouseLeave={(e: React.MouseEvent<HTMLDivElement>) => {
113
119
  if (isClickable) {
114
120
  (e.currentTarget as HTMLDivElement).style.backgroundColor =
115
- "#ffffff";
121
+ "var(--ou-surface-primary, #ffffff)";
116
122
  (e.currentTarget as HTMLDivElement).style.borderColor =
117
- "#e5e7eb";
123
+ "var(--ou-border-default, #e5e7eb)";
118
124
  (e.currentTarget as HTMLDivElement).style.boxShadow = "none";
119
125
  }
120
126
  }}
@@ -132,7 +138,9 @@ const UptimeBarDayModal: FunctionComponent<ComponentProps> = (
132
138
  style={{
133
139
  fontSize: "14px",
134
140
  fontWeight: 600,
135
- color: isClickable ? "#2563eb" : "#111827",
141
+ color: isClickable
142
+ ? "var(--ou-link, #2563eb)"
143
+ : "var(--ou-text-primary, #111827)",
136
144
  lineHeight: "1.4",
137
145
  marginBottom: "4px",
138
146
  }}
@@ -142,7 +150,7 @@ const UptimeBarDayModal: FunctionComponent<ComponentProps> = (
142
150
  <div
143
151
  style={{
144
152
  fontSize: "12px",
145
- color: "#6b7280",
153
+ color: "var(--ou-text-muted, #6b7280)",
146
154
  }}
147
155
  >
148
156
  Declared{" "}
@@ -162,7 +170,7 @@ const UptimeBarDayModal: FunctionComponent<ComponentProps> = (
162
170
  >
163
171
  <path
164
172
  d="M6 3l5 5-5 5"
165
- stroke="#9ca3af"
173
+ stroke="var(--ou-text-subtle, #9ca3af)"
166
174
  strokeWidth="1.5"
167
175
  strokeLinecap="round"
168
176
  strokeLinejoin="round"
@@ -1,4 +1,4 @@
1
- import { Black } from "../../../Types/BrandColors";
1
+ import { Gray500 } from "../../../Types/BrandColors";
2
2
  import Color from "../../../Types/Color";
3
3
  import Icon, { SizeProp, ThickProp } from "../Icon/Icon";
4
4
  import IconProp from "../../../Types/Icon/IconProp";
@@ -26,22 +26,32 @@ export interface ComponentProps {
26
26
  const Pill: FunctionComponent<ComponentProps> = (
27
27
  props: ComponentProps,
28
28
  ): ReactElement => {
29
+ const color: Color = props.color || Gray500;
30
+ const backgroundColor: string = color.toString();
31
+
29
32
  if (props.isMinimal) {
30
33
  return (
31
- <span className="relative inline-flex items-center rounded-full border border-gray-300 px-3 py-0.5 text-sm">
34
+ <span
35
+ className="relative inline-flex items-center rounded-full border px-3 py-0.5 text-sm"
36
+ style={{
37
+ borderColor: "var(--ou-border-strong, #d1d5db)",
38
+ }}
39
+ >
32
40
  <span className="absolute flex flex-shrink-0 items-center justify-center">
33
41
  <span
34
42
  className="h-1.5 w-1.5 rounded-full bg-rose-500"
35
43
  style={{
36
- backgroundColor:
37
- props.style?.backgroundColor || props.color
38
- ? props.color.toString()
39
- : Black.toString(),
44
+ backgroundColor: backgroundColor,
40
45
  }}
41
46
  aria-hidden="true"
42
47
  ></span>
43
48
  </span>
44
- <span className="ml-3.5 font-medium text-gray-900">{props.text}</span>
49
+ <span
50
+ className="ml-3.5 font-medium"
51
+ style={{ color: "var(--ou-text-primary, #111827)" }}
52
+ >
53
+ {props.text}
54
+ </span>
45
55
  </span>
46
56
  );
47
57
  }
@@ -50,18 +60,16 @@ const Pill: FunctionComponent<ComponentProps> = (
50
60
  return (
51
61
  <span
52
62
  data-testid="pill"
53
- className="inline-flex items-center rounded-full p-1 pl-3 pr-3"
63
+ className="inline-flex items-center rounded-full border p-1 pl-3 pr-3"
54
64
  style={{
55
65
  // https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color
56
66
 
57
67
  color:
58
- props.style?.color || Color.shouldUseDarkText(props.color || Black)
68
+ props.style?.color || Color.shouldUseDarkText(color)
59
69
  ? "#000000"
60
70
  : "#ffffff",
61
- backgroundColor:
62
- props.style?.backgroundColor || props.color
63
- ? props.color.toString()
64
- : Black.toString(),
71
+ backgroundColor: backgroundColor,
72
+ borderColor: "var(--ou-border-strong, #d1d5db)",
65
73
  fontSize: props.size ? props.size.toString() : PillSize.Normal,
66
74
  ...props.style,
67
75
  }}
@@ -1,4 +1,3 @@
1
- import { Black } from "../../../Types/BrandColors";
2
1
  import Color from "../../../Types/Color";
3
2
  import React, { CSSProperties, FunctionComponent, ReactElement } from "react";
4
3
 
@@ -14,7 +13,7 @@ const Statusbubble: FunctionComponent<ComponentProps> = (
14
13
  ): ReactElement => {
15
14
  const backgroundColor: string = props.color
16
15
  ? props.color.toString()
17
- : Black.toString();
16
+ : "var(--ou-text-subtle, #9ca3af)";
18
17
 
19
18
  return (
20
19
  <div
@@ -37,6 +36,7 @@ const Statusbubble: FunctionComponent<ComponentProps> = (
37
36
  className="relative inline-flex rounded-full h-3.5 w-3.5"
38
37
  style={{
39
38
  backgroundColor: backgroundColor,
39
+ boxShadow: "0 0 0 1px var(--ou-border-strong, #d1d5db)",
40
40
  }}
41
41
  ></span>
42
42
  </span>
@@ -44,7 +44,7 @@ const Statusbubble: FunctionComponent<ComponentProps> = (
44
44
  <div
45
45
  className="text-sm font-medium"
46
46
  style={{
47
- color: props.color ? props.color.toString() : Black.toString(),
47
+ color: "var(--ou-text-secondary, #4b5563)",
48
48
  }}
49
49
  >
50
50
  {props.text}