@oneuptime/common 12.0.9 → 12.0.11

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 (262) hide show
  1. package/Models/DatabaseModels/NetworkDevice.ts +44 -0
  2. package/Models/DatabaseModels/NetworkDeviceLink.ts +116 -0
  3. package/Models/DatabaseModels/RunnerJob.ts +17 -2
  4. package/Server/API/LlmProviderAPI.ts +8 -0
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts +52 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  7. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +240 -0
  8. package/Server/Services/NetworkDeviceLinkService.ts +338 -2
  9. package/Server/Services/NetworkDeviceService.ts +265 -12
  10. package/Server/Services/RunnerJobService.ts +24 -1
  11. package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +19 -5
  12. package/Server/Types/Database/JSONColumnQuery.ts +42 -4
  13. package/Server/Utils/LLM/LLMService.ts +108 -19
  14. package/Server/Utils/Monitor/MonitorAlert.ts +22 -115
  15. package/Server/Utils/Monitor/MonitorIncident.ts +7 -337
  16. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +27 -2
  17. package/Server/Utils/Monitor/SeriesResourceLabels.ts +32 -0
  18. package/Server/Utils/Monitor/SeriesResourceLinker.ts +469 -0
  19. package/Server/Utils/SSRFProtection.ts +5 -4
  20. package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +186 -38
  21. package/Tests/App/AdminDashboard/AdminUsersBulkAddToProject.test.tsx +955 -0
  22. package/Tests/App/AdminDashboard/BulkAddUsersToProject.test.ts +778 -0
  23. package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +1051 -0
  24. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +420 -112
  25. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +81 -6
  26. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +543 -0
  27. package/Tests/App/Dashboard/PayAsYouGoFreePlan.test.ts +125 -0
  28. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +612 -0
  29. package/Tests/App/Dashboard/SloWidgetChartRendering.test.tsx +536 -0
  30. package/Tests/App/Dashboard/UserElementEmail.test.tsx +447 -0
  31. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +284 -0
  32. package/Tests/Models/AnalyticsModels/CommonModel.test.ts +312 -0
  33. package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +250 -0
  34. package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +46 -18
  35. package/Tests/Server/Services/NetworkDeviceLabelRuleRun.test.ts +618 -0
  36. package/Tests/Server/Services/NetworkDeviceLinkParentValidation.test.ts +1043 -0
  37. package/Tests/Server/Services/NetworkSiteAssignmentRuleRun.test.ts +706 -0
  38. package/Tests/Server/Services/RunnerJobEnqueue.test.ts +412 -0
  39. package/Tests/Server/Types/Billing/PayAsYouGoMeteredPricing.test.ts +125 -0
  40. package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +508 -0
  41. package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +2 -2
  42. package/Tests/Server/Utils/AI/LLMServiceRetryPolicy.test.ts +450 -0
  43. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +556 -0
  44. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +547 -0
  45. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +30 -0
  46. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +699 -0
  47. package/Tests/Server/Utils/SeriesResourceLabels.test.ts +55 -0
  48. package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +668 -0
  49. package/Tests/Types/API/URLMalformedTolerance.test.ts +301 -0
  50. package/Tests/Types/API/URLTelScheme.test.ts +261 -0
  51. package/Tests/Types/API/URLUnsupportedScheme.test.ts +148 -0
  52. package/Tests/Types/Billing/PayAsYouGoPricing.test.ts +64 -0
  53. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +107 -0
  54. package/Tests/Types/Monitor/MonitorType.test.ts +62 -0
  55. package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +184 -0
  56. package/Tests/Types/Runbook/RunbookStepType.test.ts +124 -0
  57. package/Tests/Types/Workflow/BaseModelComponents.test.ts +17 -0
  58. package/Tests/UI/Components/Button.test.tsx +279 -0
  59. package/Tests/UI/Components/Charts/ChartXAxisDataKey.test.tsx +256 -0
  60. package/Tests/UI/Components/Charts/DataPointUtil.test.ts +323 -0
  61. package/Tests/UI/Components/DictionaryValuePlaceholderAndSuggestions.test.tsx +595 -0
  62. package/Tests/UI/Components/Icon.test.tsx +57 -0
  63. package/Tests/UI/Components/List.test.tsx +20 -3
  64. package/Tests/UI/Components/LogsSavedViewsDropdown.test.tsx +304 -0
  65. package/Tests/UI/Components/LogsViewerClearSavedView.test.tsx +179 -0
  66. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +349 -1
  67. package/Tests/UI/Components/Pagination.test.tsx +721 -146
  68. package/Tests/UI/Components/PaginationIntegration.test.tsx +386 -0
  69. package/Tests/UI/Components/PaginationUtil.test.ts +417 -0
  70. package/Tests/UI/Components/TelemetrySavedViewsDropdown.test.tsx +343 -0
  71. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnControl.test.ts +289 -0
  72. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnOperators.test.ts +271 -0
  73. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRow.test.ts +119 -0
  74. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.test.ts +968 -0
  75. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +766 -0
  76. package/Tests/UI/Utils/RunNetworkRule.test.ts +320 -0
  77. package/Tests/Utils/APIRetryPolicy.test.ts +823 -0
  78. package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +502 -0
  79. package/Tests/Utils/Monitor/NetworkTopologyDeclaredHierarchy.test.ts +759 -0
  80. package/Tests/Utils/NetworkAutomation/RuleRunSummary.test.ts +286 -0
  81. package/Tests/Utils/Schema/BaseSchema.test.ts +651 -0
  82. package/Types/API/Protocol.ts +9 -0
  83. package/Types/API/URL.ts +286 -20
  84. package/Types/Billing/PayAsYouGoPricing.ts +47 -0
  85. package/Types/CustomField/CustomFieldType.ts +28 -0
  86. package/Types/Monitor/MonitorType.ts +11 -0
  87. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
  88. package/Types/NetworkAutomation/RuleRunResult.ts +121 -0
  89. package/Types/Runbook/RunbookStepType.ts +23 -0
  90. package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -0
  91. package/UI/Components/Button/Button.tsx +14 -22
  92. package/UI/Components/Charts/Area/AreaChart.tsx +4 -2
  93. package/UI/Components/Charts/Bar/BarChart.tsx +4 -2
  94. package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +13 -0
  95. package/UI/Components/Charts/Line/LineChart.tsx +4 -2
  96. package/UI/Components/Charts/Types/XAxis/XAxis.ts +6 -0
  97. package/UI/Components/Charts/Utils/DataPoint.ts +15 -12
  98. package/UI/Components/Dictionary/Dictionary.tsx +4 -39
  99. package/UI/Components/Icon/Icon.tsx +1 -1
  100. package/UI/Components/LogsViewer/LogsViewer.tsx +5 -1
  101. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +8 -0
  102. package/UI/Components/LogsViewer/components/LogsPagination.tsx +29 -91
  103. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +2 -0
  104. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +66 -1
  105. package/UI/Components/ModelTable/CustomFieldColumns.tsx +55 -0
  106. package/UI/Components/Pagination/Pagination.tsx +373 -328
  107. package/UI/Components/Pagination/PaginationUtil.ts +263 -0
  108. package/UI/Components/Pagination/Screenshots/README.md +15 -0
  109. package/UI/Components/Pagination/Screenshots/pagination-before-after.png +0 -0
  110. package/UI/Components/Pagination/Screenshots/pagination-go-to-page-modal.png +0 -0
  111. package/UI/Components/Pagination/Screenshots/pagination-long-list.png +0 -0
  112. package/UI/Components/Pagination/Screenshots/pagination-mobile.png +0 -0
  113. package/UI/Components/Pagination/Screenshots/pagination-telemetry.png +0 -0
  114. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +66 -1
  115. package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +38 -92
  116. package/UI/Components/TextArea/TextArea.tsx +3 -0
  117. package/UI/Components/Workflow/ArgumentsForm.tsx +18 -1
  118. package/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.tsx +177 -0
  119. package/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.tsx +243 -0
  120. package/UI/Components/Workflow/ColumnEditor/ColumnControl.ts +255 -0
  121. package/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.tsx +178 -0
  122. package/UI/Components/Workflow/ColumnEditor/ColumnOperators.ts +206 -0
  123. package/UI/Components/Workflow/ColumnEditor/ColumnRow.ts +157 -0
  124. package/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.ts +517 -0
  125. package/UI/Components/Workflow/ColumnEditor/ColumnValueInput.tsx +482 -0
  126. package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +131 -0
  127. package/UI/Components/Workflow/ColumnEditor/ModelRecordForm.tsx +163 -0
  128. package/UI/Components/Workflow/ModelColumnEditor.tsx +284 -100
  129. package/UI/Utils/NetworkAutomation/RunNetworkRule.ts +122 -0
  130. package/Utils/API.ts +243 -36
  131. package/Utils/Monitor/NetworkDeviceRoleUtil.ts +45 -0
  132. package/Utils/Monitor/NetworkTopologyUtil.ts +42 -2
  133. package/Utils/NetworkAutomation/RuleRunSummary.ts +147 -0
  134. package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
  135. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  136. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +115 -0
  137. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -1
  138. package/build/dist/Models/DatabaseModels/RunnerJob.js +17 -2
  139. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  140. package/build/dist/Server/API/LlmProviderAPI.js +9 -1
  141. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  142. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js +33 -0
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js.map +1 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  146. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +202 -0
  147. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  148. package/build/dist/Server/Services/NetworkDeviceLinkService.js +253 -1
  149. package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -1
  150. package/build/dist/Server/Services/NetworkDeviceService.js +223 -12
  151. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  152. package/build/dist/Server/Services/RunnerJobService.js +20 -2
  153. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  154. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +12 -5
  155. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
  156. package/build/dist/Server/Types/Database/JSONColumnQuery.js +40 -4
  157. package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -1
  158. package/build/dist/Server/Utils/LLM/LLMService.js +78 -22
  159. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  160. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -98
  161. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  162. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +7 -254
  163. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  164. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +14 -2
  165. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  166. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +27 -0
  167. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  168. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +285 -0
  169. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -0
  170. package/build/dist/Server/Utils/SSRFProtection.js +5 -4
  171. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  172. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +128 -35
  173. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
  174. package/build/dist/Types/API/Protocol.js +9 -0
  175. package/build/dist/Types/API/Protocol.js.map +1 -1
  176. package/build/dist/Types/API/URL.js +241 -18
  177. package/build/dist/Types/API/URL.js.map +1 -1
  178. package/build/dist/Types/Billing/PayAsYouGoPricing.js +41 -0
  179. package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -0
  180. package/build/dist/Types/CustomField/CustomFieldType.js +26 -0
  181. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  182. package/build/dist/Types/Monitor/MonitorType.js +10 -0
  183. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  184. package/build/dist/Types/NetworkAutomation/RuleRunResult.js +39 -0
  185. package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -0
  186. package/build/dist/Types/Runbook/RunbookStepType.js +21 -0
  187. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  188. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
  189. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
  190. package/build/dist/UI/Components/Button/Button.js +10 -16
  191. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  192. package/build/dist/UI/Components/Charts/Area/AreaChart.js +2 -1
  193. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  194. package/build/dist/UI/Components/Charts/Bar/BarChart.js +2 -1
  195. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  196. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +12 -0
  197. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
  198. package/build/dist/UI/Components/Charts/Line/LineChart.js +2 -1
  199. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  200. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +17 -10
  201. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  202. package/build/dist/UI/Components/Dictionary/Dictionary.js +4 -18
  203. package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
  204. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  205. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  206. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +3 -3
  207. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  208. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +5 -1
  209. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  210. package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js +14 -44
  211. package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js.map +1 -1
  212. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
  213. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  214. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +20 -2
  215. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  216. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +42 -0
  217. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  218. package/build/dist/UI/Components/Pagination/Pagination.js +174 -199
  219. package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
  220. package/build/dist/UI/Components/Pagination/PaginationUtil.js +160 -0
  221. package/build/dist/UI/Components/Pagination/PaginationUtil.js.map +1 -0
  222. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +20 -2
  223. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
  224. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +23 -47
  225. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -1
  226. package/build/dist/UI/Components/TextArea/TextArea.js +1 -1
  227. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  228. package/build/dist/UI/Components/Workflow/ArgumentsForm.js +14 -2
  229. package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
  230. package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js +86 -0
  231. package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js.map +1 -0
  232. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js +119 -0
  233. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js.map +1 -0
  234. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js +206 -0
  235. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js.map +1 -0
  236. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js +57 -0
  237. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js.map +1 -0
  238. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js +150 -0
  239. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js.map +1 -0
  240. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js +67 -0
  241. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js.map +1 -0
  242. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js +309 -0
  243. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js.map +1 -0
  244. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js +204 -0
  245. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js.map +1 -0
  246. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +66 -0
  247. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -0
  248. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js +83 -0
  249. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js.map +1 -0
  250. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +187 -68
  251. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
  252. package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js +75 -0
  253. package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js.map +1 -0
  254. package/build/dist/Utils/API.js +175 -34
  255. package/build/dist/Utils/API.js.map +1 -1
  256. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +37 -0
  257. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
  258. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +25 -3
  259. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  260. package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js +78 -0
  261. package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js.map +1 -0
  262. package/package.json +1 -1
@@ -27,6 +27,12 @@ export interface ComponentProps {
27
27
  isLoadingSuggestions?: boolean | undefined;
28
28
  loadingMessage?: string | undefined;
29
29
  noSuggestionsMessage?: string | undefined;
30
+ /*
31
+ * The id of the element that names this input. Without it a picker that draws
32
+ * its own label - the workflow record editor, where the field's name sits in
33
+ * the column beside the box - leaves the input unnamed to a screen reader.
34
+ */
35
+ ariaLabelledby?: string | undefined;
30
36
  }
31
37
 
32
38
  const BASE_INPUT_CLASS: string =
@@ -458,6 +464,7 @@ const AutocompleteTextInput: FunctionComponent<ComponentProps> = (
458
464
  className={getInputClassName()}
459
465
  data-testid={props.dataTestId}
460
466
  disabled={props.disabled}
467
+ aria-labelledby={props.ariaLabelledby}
461
468
  aria-autocomplete="list"
462
469
  aria-controls={listboxIdRef.current}
463
470
  aria-expanded={showMenu}
@@ -158,47 +158,39 @@ const Button: FunctionComponent<ComponentProps> = ({
158
158
 
159
159
  if (buttonStyle === ButtonStyleType.DANGER) {
160
160
  buttonStyleCssClass = `inline-flex w-full justify-center rounded-md border border-transparent bg-red-600 text-base font-medium text-white shadow-sm ${
161
- disabled ? "hover:bg-red-700" : ""
161
+ disabled ? "" : "hover:bg-red-700"
162
162
  } focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 md:ml-3 md:w-auto md:text-sm`;
163
163
  }
164
164
 
165
165
  if (buttonStyle === ButtonStyleType.DANGER_OUTLINE) {
166
166
  buttonStyleCssClass = `inline-flex w-full justify-center rounded-md border border-red-700 bg-white text-base font-medium text-red-700 shadow-sm ${
167
- disabled ? "hover:bg-red-50" : ""
167
+ disabled ? "" : "hover:bg-red-50"
168
168
  } focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm`;
169
169
  }
170
170
 
171
171
  if (buttonStyle === ButtonStyleType.PRIMARY) {
172
172
  loadingIconClassName += ` text-indigo-100`;
173
- buttonStyleCssClass = `inline-flex w-full justify-center rounded-md border border-transparent bg-indigo-600 text-base font-medium text-white shadow-sm ${
174
- disabled ? "hover:bg-indigo-700" : ""
175
- } focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 md:ml-3 md:w-auto md:text-sm`;
176
-
177
- if (disabled) {
178
- buttonStyleCssClass += ` bg-indigo-300`;
179
- }
173
+ buttonStyleCssClass = `inline-flex w-full justify-center rounded-md border border-transparent ${
174
+ disabled ? "bg-indigo-300" : "bg-indigo-600 hover:bg-indigo-700"
175
+ } text-base font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 md:ml-3 md:w-auto md:text-sm`;
180
176
  }
181
177
 
182
178
  if (buttonStyle === ButtonStyleType.SECONDARY) {
183
179
  loadingIconClassName += ` text-indigo-500`;
184
- buttonStyleCssClass = `inline-flex items-center rounded-md border border-transparent bg-indigo-100 text-sm font-medium text-indigo-700 ${
185
- disabled ? "hover:bg-indigo-200" : ""
186
- } focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2`;
187
-
188
- if (disabled) {
189
- buttonStyleCssClass += ` bg-indigo-300`;
190
- }
180
+ buttonStyleCssClass = `inline-flex items-center rounded-md border border-transparent ${
181
+ disabled ? "bg-indigo-300" : "bg-indigo-100 hover:bg-indigo-200"
182
+ } text-sm font-medium text-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2`;
191
183
  }
192
184
 
193
185
  if (buttonStyle === ButtonStyleType.ICON_LIGHT) {
194
186
  buttonStyleCssClass = `rounded-md bg-white text-gray-400 ${
195
- disabled ? "hover:text-gray-500" : ""
187
+ disabled ? "" : "hover:text-gray-500"
196
188
  } focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2`;
197
189
  }
198
190
 
199
191
  if (buttonStyle === ButtonStyleType.ICON) {
200
192
  buttonStyleCssClass = `rounded-md bg-transparent text-gray-600 ${
201
- disabled ? "hover:text-gray-900" : ""
193
+ disabled ? "" : "hover:text-gray-900"
202
194
  } focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2`;
203
195
  }
204
196
 
@@ -225,25 +217,25 @@ const Button: FunctionComponent<ComponentProps> = ({
225
217
 
226
218
  if (buttonStyle === ButtonStyleType.SUCCESS) {
227
219
  buttonStyleCssClass = `inline-flex w-full justify-center rounded-md border border-transparent bg-green-600 text-base font-medium text-white shadow-sm ${
228
- disabled ? "hover:bg-green-700" : ""
220
+ disabled ? "" : "hover:bg-green-700"
229
221
  } focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 md:ml-3 md:w-auto md:text-sm`;
230
222
  }
231
223
 
232
224
  if (buttonStyle === ButtonStyleType.SUCCESS_OUTLINE) {
233
225
  buttonStyleCssClass = `inline-flex w-full justify-center rounded-md border border-green-700 bg-white text-base font-medium text-green-700 shadow-sm ${
234
- disabled ? "hover:bg-green-50" : ""
226
+ disabled ? "" : "hover:bg-green-50"
235
227
  } focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm`;
236
228
  }
237
229
 
238
230
  if (buttonStyle === ButtonStyleType.WARNING) {
239
231
  buttonStyleCssClass = `inline-flex w-full justify-center rounded-md border border-transparent bg-yellow-600 text-base font-medium text-white shadow-sm ${
240
- disabled ? "hover:bg-yellow-700" : ""
232
+ disabled ? "" : "hover:bg-yellow-700"
241
233
  } focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:ring-offset-2 md:ml-3 md:w-auto md:text-sm`;
242
234
  }
243
235
 
244
236
  if (buttonStyle === ButtonStyleType.WARNING_OUTLINE) {
245
237
  buttonStyleCssClass = `inline-flex w-full justify-center rounded-md border border-yellow-700 bg-white text-base font-medium text-yellow-700 shadow-sm ${
246
- disabled ? "hover:bg-yellow-50" : ""
238
+ disabled ? "" : "hover:bg-yellow-50"
247
239
  } focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:ring-offset-2 md:mt-0 md:ml-3 md:w-auto md:text-sm`;
248
240
  }
249
241
 
@@ -13,7 +13,9 @@ import SeriesPoint from "../Types/SeriesPoints";
13
13
  import { XAxis } from "../Types/XAxis/XAxis";
14
14
  import YAxis from "../Types/YAxis/YAxis";
15
15
  import ChartCurve from "../Types/ChartCurve";
16
- import ChartDataPoint from "../ChartLibrary/Types/ChartDataPoint";
16
+ import ChartDataPoint, {
17
+ CHART_DATA_POINT_X_AXIS_KEY,
18
+ } from "../ChartLibrary/Types/ChartDataPoint";
17
19
  import FormattedExemplarPoint from "../ChartLibrary/Types/FormattedExemplarPoint";
18
20
  import FormattedReferenceRegion from "../ChartLibrary/Types/FormattedReferenceRegion";
19
21
  import FormattedTimeReferenceLine from "../ChartLibrary/Types/FormattedTimeReferenceLine";
@@ -185,7 +187,7 @@ const AreaChartElement: FunctionComponent<AreaInternalProps> = (
185
187
  <AreaChart
186
188
  data={records}
187
189
  tickGap={30}
188
- index={"Time"}
190
+ index={CHART_DATA_POINT_X_AXIS_KEY}
189
191
  categories={categories}
190
192
  colors={
191
193
  props.colors && props.colors.length > 0
@@ -12,7 +12,9 @@ import React, {
12
12
  import SeriesPoint from "../Types/SeriesPoints";
13
13
  import { XAxis } from "../Types/XAxis/XAxis";
14
14
  import YAxis from "../Types/YAxis/YAxis";
15
- import ChartDataPoint from "../ChartLibrary/Types/ChartDataPoint";
15
+ import ChartDataPoint, {
16
+ CHART_DATA_POINT_X_AXIS_KEY,
17
+ } from "../ChartLibrary/Types/ChartDataPoint";
16
18
  import FormattedReferenceRegion from "../ChartLibrary/Types/FormattedReferenceRegion";
17
19
  import FormattedTimeReferenceLine from "../ChartLibrary/Types/FormattedTimeReferenceLine";
18
20
  import DataPointUtil from "../Utils/DataPoint";
@@ -119,7 +121,7 @@ const BarChartElement: FunctionComponent<BarInternalProps> = (
119
121
  <BarChart
120
122
  data={records}
121
123
  tickGap={30}
122
- index={"Time"}
124
+ index={CHART_DATA_POINT_X_AXIS_KEY}
123
125
  categories={categories}
124
126
  colors={
125
127
  props.colors && props.colors.length > 0
@@ -5,6 +5,19 @@
5
5
  */
6
6
  export const CHART_DATA_POINT_DATE_KEY: string = "__date";
7
7
 
8
+ /**
9
+ * Per-row field carrying the FORMATTED x-axis label.
10
+ *
11
+ * This is the recharts `XAxis` dataKey — the Line / Bar / Area wrappers all
12
+ * pass it down as their `index` prop. `DataPointUtil` must therefore write
13
+ * the label under exactly this key: a row keyed anything else leaves every
14
+ * point with an undefined category, and recharts then draws no line, bar or
15
+ * area at all (the axes and grid still render, so the chart looks alive but
16
+ * empty). Keeping the single constant on both sides is what stops that from
17
+ * being an invisible coupling between two distant files.
18
+ */
19
+ export const CHART_DATA_POINT_X_AXIS_KEY: string = "Time";
20
+
8
21
  export default interface ChartDataPoint {
9
22
  [x: string]: number | string;
10
23
  }
@@ -13,7 +13,9 @@ import SeriesPoint from "../Types/SeriesPoints";
13
13
  import { XAxis } from "../Types/XAxis/XAxis";
14
14
  import YAxis from "../Types/YAxis/YAxis";
15
15
  import ChartCurve from "../Types/ChartCurve";
16
- import ChartDataPoint from "../ChartLibrary/Types/ChartDataPoint";
16
+ import ChartDataPoint, {
17
+ CHART_DATA_POINT_X_AXIS_KEY,
18
+ } from "../ChartLibrary/Types/ChartDataPoint";
17
19
  import FormattedExemplarPoint from "../ChartLibrary/Types/FormattedExemplarPoint";
18
20
  import FormattedReferenceRegion from "../ChartLibrary/Types/FormattedReferenceRegion";
19
21
  import FormattedTimeReferenceLine from "../ChartLibrary/Types/FormattedTimeReferenceLine";
@@ -165,7 +167,7 @@ const LineChartElement: FunctionComponent<LineInternalProps> = (
165
167
  <LineChart
166
168
  data={records}
167
169
  tickGap={30}
168
- index={"Time"}
170
+ index={CHART_DATA_POINT_X_AXIS_KEY}
169
171
  categories={categories}
170
172
  colors={
171
173
  props.colors && props.colors.length > 0
@@ -16,6 +16,12 @@ export interface XAxisOptions {
16
16
  }
17
17
 
18
18
  export interface XAxis {
19
+ /*
20
+ * Human-readable name for the axis. Purely descriptive: the per-row key
21
+ * the charts read is CHART_DATA_POINT_X_AXIS_KEY, never this string. It
22
+ * used to double as that key, which meant a caller passing anything but
23
+ * "Time" got a chart with axes and no series drawn on them.
24
+ */
19
25
  legend: string;
20
26
  options: XAxisOptions;
21
27
  }
@@ -10,6 +10,7 @@
10
10
  import BadDataException from "../../../../Types/Exception/BadDataException";
11
11
  import ChartDataPoint, {
12
12
  CHART_DATA_POINT_DATE_KEY,
13
+ CHART_DATA_POINT_X_AXIS_KEY,
13
14
  } from "../ChartLibrary/Types/ChartDataPoint";
14
15
  import SeriesPoints from "../Types/SeriesPoints";
15
16
  import { XAxis, XAxisAggregateType } from "../Types/XAxis/XAxis";
@@ -30,18 +31,14 @@ export default class DataPointUtil {
30
31
  xAxis: XAxis;
31
32
  yAxis: YAxis;
32
33
  }): Array<ChartDataPoint> {
33
- const { xAxisLegend, intervals, formatter } = this.initializeXAxisData(
34
- data.xAxis,
35
- );
34
+ const { intervals, formatter } = this.initializeXAxisData(data.xAxis);
36
35
  const arrayOfData: ChartDataPoint[] = this.initializeArrayOfData(
37
36
  intervals,
38
- xAxisLegend,
39
37
  formatter,
40
38
  );
41
39
  this.processSeriesData(
42
40
  data.seriesPoints,
43
41
  arrayOfData,
44
- xAxisLegend,
45
42
  formatter,
46
43
  data.xAxis.options.aggregateType,
47
44
  );
@@ -51,13 +48,11 @@ export default class DataPointUtil {
51
48
  private static initializeXAxisData(xAxis: XAxis): {
52
49
  xAxisMax: XAxisMaxMin;
53
50
  xAxisMin: XAxisMaxMin;
54
- xAxisLegend: string;
55
51
  intervals: Array<Date>;
56
52
  formatter: (value: Date) => string;
57
53
  } {
58
54
  const xAxisMax: XAxisMaxMin = xAxis.options.max;
59
55
  const xAxisMin: XAxisMaxMin = xAxis.options.min;
60
- const xAxisLegend: string = xAxis.legend;
61
56
  const intervals: Array<Date> = XAxisUtil.getPrecisionIntervals({
62
57
  xAxisMax,
63
58
  xAxisMin,
@@ -66,18 +61,25 @@ export default class DataPointUtil {
66
61
  xAxisMax,
67
62
  xAxisMin,
68
63
  });
69
- return { xAxisMax, xAxisMin, xAxisLegend, intervals, formatter };
64
+ return { xAxisMax, xAxisMin, intervals, formatter };
70
65
  }
71
66
 
72
67
  private static initializeArrayOfData(
73
68
  intervals: Array<Date>,
74
- xAxisLegend: string,
75
69
  formatter: (value: Date) => string,
76
70
  ): Array<ChartDataPoint> {
77
71
  const arrayOfData: Array<ChartDataPoint> = [];
78
72
  for (const interval of intervals) {
79
73
  const dataPoint: ChartDataPoint = {};
80
- dataPoint[xAxisLegend] = formatter(interval);
74
+ /*
75
+ * Always the canonical key, NEVER `xAxis.legend`. The wrappers hand
76
+ * recharts this exact key as the XAxis dataKey, so keying rows off a
77
+ * caller-supplied string meant one caller passing anything else
78
+ * (the SLO dashboard widget passed "") produced rows recharts could
79
+ * not read — every point landed on an undefined category and the
80
+ * line silently vanished while the axes still drew.
81
+ */
82
+ dataPoint[CHART_DATA_POINT_X_AXIS_KEY] = formatter(interval);
81
83
  /*
82
84
  * The formatted label is not round-trippable back to a Date, so
83
85
  * keep the raw bucket start on the row — charts use it to recover
@@ -92,7 +94,6 @@ export default class DataPointUtil {
92
94
  private static processSeriesData(
93
95
  seriesPoints: Array<SeriesPoints>,
94
96
  arrayOfData: Array<ChartDataPoint>,
95
- xAxisLegend: string,
96
97
  formatter: (value: Date) => string,
97
98
  aggregateType: XAxisAggregateType,
98
99
  ): { [key: string]: SeriesData } {
@@ -123,7 +124,9 @@ export default class DataPointUtil {
123
124
 
124
125
  const target: ChartDataPoint | undefined = arrayOfData.find(
125
126
  (chartDataPoint: ChartDataPoint) => {
126
- return chartDataPoint[xAxisLegend] === formattedDate;
127
+ return (
128
+ chartDataPoint[CHART_DATA_POINT_X_AXIS_KEY] === formattedDate
129
+ );
127
130
  },
128
131
  );
129
132
  if (!target) {
@@ -36,20 +36,6 @@ export interface ComponentProps {
36
36
  valueTypes?: Array<ValueType>; // by default it'll be Text
37
37
  keys?: Array<string> | undefined;
38
38
  valueSuggestions?: Record<string, Array<string>> | undefined;
39
- /*
40
- * Per-key placeholder for the value input, falling back to valuePlaceholder
41
- * for any key not listed. The record editor uses this to show the model's own
42
- * example value against the column it belongs to, which is a far better
43
- * answer to "what goes in this box" than one generic word repeated down the
44
- * column.
45
- */
46
- valuePlaceholders?: Record<string, string> | undefined;
47
- /*
48
- * Suggestions offered on a row whose key has no entry in valueSuggestions.
49
- * Used for suggestions that are about the form rather than the column - the
50
- * workflow's {{...}} references, which are equally valid in any row.
51
- */
52
- defaultValueSuggestions?: Array<string> | undefined;
53
39
  onKeySelected?: ((key: string) => void) | undefined;
54
40
  isLoadingKeys?: boolean | undefined;
55
41
  loadingValueKeys?: Array<string> | undefined;
@@ -245,33 +231,12 @@ const DictionaryForm: FunctionComponent<ComponentProps> = (
245
231
  return "";
246
232
  };
247
233
 
248
- type ValuePlaceholderForFunction = (key: string) => string | undefined;
249
-
250
- const valuePlaceholderFor: ValuePlaceholderForFunction = (
251
- key: string,
252
- ): string | undefined => {
253
- return (
254
- (key ? props.valuePlaceholders?.[key] : undefined) ||
255
- props.valuePlaceholder
256
- );
257
- };
258
-
259
234
  type ValueSuggestionsForFunction = (key: string) => Array<string> | undefined;
260
235
 
261
236
  const valueSuggestionsFor: ValueSuggestionsForFunction = (
262
237
  key: string,
263
238
  ): Array<string> | undefined => {
264
- const forKey: Array<string> | undefined = key
265
- ? props.valueSuggestions?.[key]
266
- : undefined;
267
-
268
- /*
269
- * Column-specific suggestions win outright rather than merging: a column
270
- * with a known set of values should not have workflow references mixed into
271
- * that set, and a row with no such set is exactly where a reference is the
272
- * likely thing to type.
273
- */
274
- return forKey && forKey.length > 0 ? forKey : props.defaultValueSuggestions;
239
+ return key ? props.valueSuggestions?.[key] : undefined;
275
240
  };
276
241
 
277
242
  const operatorDropdownOptions: Array<DropdownOption> =
@@ -452,7 +417,7 @@ const DictionaryForm: FunctionComponent<ComponentProps> = (
452
417
  operatorOption.expectsMultiValue && (
453
418
  <Dropdown
454
419
  isMultiSelect={true}
455
- placeholder={valuePlaceholderFor(item.key)}
420
+ placeholder={props.valuePlaceholder}
456
421
  value={(Array.isArray(item.value) ? item.value : []).map(
457
422
  (selectedValue: string) => {
458
423
  return { label: selectedValue, value: selectedValue };
@@ -499,7 +464,7 @@ const DictionaryForm: FunctionComponent<ComponentProps> = (
499
464
  placeholder={
500
465
  operatorOption.expectsNumericValue
501
466
  ? "Number"
502
- : valuePlaceholderFor(item.key)
467
+ : props.valuePlaceholder
503
468
  }
504
469
  suggestions={
505
470
  operatorOption.expectsNumericValue
@@ -540,7 +505,7 @@ const DictionaryForm: FunctionComponent<ComponentProps> = (
540
505
  {!hideValueInput && item.type === ValueType.Number && (
541
506
  <Input
542
507
  value={item.value.toString()}
543
- placeholder={valuePlaceholderFor(item.key)}
508
+ placeholder={props.valuePlaceholder}
544
509
  onChange={(value: string) => {
545
510
  const newData: Array<Item> = [...data];
546
511
  const parsedValue: number = parseInt(value);
@@ -932,7 +932,7 @@ const Icon: FunctionComponent<ComponentProps> = ({
932
932
  <path
933
933
  strokeLinecap="round"
934
934
  strokeLinejoin="round"
935
- d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
935
+ d="M15.75 19.5L8.25 12l7.5-7.5"
936
936
  />,
937
937
  );
938
938
  } else if (icon === IconProp.Window) {
@@ -134,6 +134,8 @@ export interface ComponentProps {
134
134
  savedViews?: Array<LogsSavedViewOption> | undefined;
135
135
  selectedSavedViewId?: string | null;
136
136
  onSavedViewSelect?: ((viewId: string) => void) | undefined;
137
+ // Deselect the active saved view and reset the explorer to its default.
138
+ onClearSavedView?: (() => void) | undefined;
137
139
  onCreateSavedView?: (() => void) | undefined;
138
140
  onEditSavedView?: ((viewId: string) => void) | undefined;
139
141
  onDeleteSavedView?: ((viewId: string) => void) | undefined;
@@ -1044,6 +1046,7 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
1044
1046
  savedViews: props.savedViews,
1045
1047
  selectedSavedViewId: props.selectedSavedViewId,
1046
1048
  onSavedViewSelect: props.onSavedViewSelect,
1049
+ onClearSavedView: props.onClearSavedView,
1047
1050
  onCreateSavedView: props.onCreateSavedView,
1048
1051
  onEditSavedView: props.onEditSavedView,
1049
1052
  onDeleteSavedView: props.onDeleteSavedView,
@@ -1157,6 +1160,7 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
1157
1160
  savedViews={props.savedViews}
1158
1161
  selectedSavedViewId={props.selectedSavedViewId}
1159
1162
  onSavedViewSelect={props.onSavedViewSelect}
1163
+ onClearSavedView={props.onClearSavedView}
1160
1164
  onFacetSearchChange={props.onFacetSearchChange}
1161
1165
  />
1162
1166
  )}
@@ -1226,7 +1230,7 @@ const LogsViewer: FunctionComponent<ComponentProps> = (
1226
1230
  pageSizeOptions={PAGE_SIZE_OPTIONS}
1227
1231
  onPageChange={handlePageChange}
1228
1232
  onPageSizeChange={handlePageSizeChange}
1229
- isDisabled={props.isLoading || totalItems === 0}
1233
+ isDisabled={props.isLoading}
1230
1234
  />
1231
1235
  </div>
1232
1236
  </div>
@@ -30,6 +30,8 @@ export interface LogsFacetSidebarProps {
30
30
  savedViews?: Array<LogsSavedViewOption> | undefined;
31
31
  selectedSavedViewId?: string | null | undefined;
32
32
  onSavedViewSelect?: ((viewId: string) => void) | undefined;
33
+ // Toggling the applied view off here has to clear it, not re-apply it.
34
+ onClearSavedView?: (() => void) | undefined;
33
35
  /*
34
36
  * Called (debounced) when typing in a resource facet's search box. Lets
35
37
  * the parent re-issue the facets request with the typed text scoped to
@@ -283,7 +285,13 @@ const LogsFacetSidebar: FunctionComponent<LogsFacetSidebarProps> = (
283
285
  ? "bg-indigo-50 text-indigo-700"
284
286
  : "text-gray-600 hover:bg-gray-50 hover:text-gray-800"
285
287
  }`}
288
+ aria-pressed={isSelected}
286
289
  onClick={() => {
290
+ if (isSelected && props.onClearSavedView) {
291
+ props.onClearSavedView();
292
+ return;
293
+ }
294
+
287
295
  props.onSavedViewSelect?.(view.id);
288
296
  }}
289
297
  >
@@ -1,3 +1,4 @@
1
+ import Pagination from "../../Pagination/Pagination";
1
2
  import React, { FunctionComponent, ReactElement } from "react";
2
3
 
3
4
  export interface LogsPaginationProps {
@@ -10,101 +11,38 @@ export interface LogsPaginationProps {
10
11
  isDisabled?: boolean;
11
12
  }
12
13
 
14
+ /**
15
+ * The logs footer is the shared pagination control in its compact skin, so
16
+ * "rows per page" and jump-to-page behave the same here as they do under
17
+ * every table in the product.
18
+ */
13
19
  const LogsPagination: FunctionComponent<LogsPaginationProps> = (
14
20
  props: LogsPaginationProps,
15
21
  ): ReactElement => {
16
- const totalPages: number = Math.max(
17
- 1,
18
- Math.ceil(
19
- props.totalItems === 0
20
- ? 1
21
- : props.totalItems / Math.max(props.pageSize, 1),
22
- ),
23
- );
24
-
25
- const safeCurrentPage: number = Math.min(props.currentPage, totalPages);
26
-
27
- const firstItemIndex: number =
28
- props.totalItems === 0 ? 0 : (safeCurrentPage - 1) * props.pageSize + 1;
29
- const lastItemIndex: number =
30
- props.totalItems === 0
31
- ? 0
32
- : Math.min(props.totalItems, safeCurrentPage * props.pageSize);
33
-
34
- const disablePrev: boolean =
35
- props.isDisabled || props.totalItems === 0 || safeCurrentPage <= 1;
36
- const disableNext: boolean =
37
- props.isDisabled || props.totalItems === 0 || safeCurrentPage >= totalPages;
38
-
39
22
  return (
40
- <div className="flex flex-col gap-3 border-t border-gray-200 bg-gray-50/50 px-4 py-2.5 text-xs text-gray-500 md:flex-row md:items-center md:justify-between">
41
- <div>
42
- {props.totalItems === 0 ? (
43
- <span className="text-gray-500">No results to display.</span>
44
- ) : (
45
- <span className="text-gray-500">
46
- Showing {firstItemIndex.toLocaleString()}-
47
- {lastItemIndex.toLocaleString()} of{" "}
48
- {props.totalItems.toLocaleString()}
49
- </span>
50
- )}
51
- </div>
52
-
53
- <div className="flex flex-wrap items-center gap-3">
54
- <label className="flex items-center gap-2">
55
- <span className="text-[10px] uppercase tracking-wide text-gray-400">
56
- Rows
57
- </span>
58
- <select
59
- className="rounded-md border border-gray-200 bg-white px-2 py-1 text-xs text-gray-700 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-200"
60
- value={props.pageSize}
61
- onChange={(event: React.ChangeEvent<HTMLSelectElement>) => {
62
- const size: number = Number(event.target.value) || props.pageSize;
63
- props.onPageSizeChange(size);
64
- }}
65
- disabled={props.isDisabled}
66
- >
67
- {props.pageSizeOptions.map((option: number) => {
68
- return (
69
- <option key={option} value={option}>
70
- {option}
71
- </option>
72
- );
73
- })}
74
- </select>
75
- </label>
76
-
77
- <div className="inline-flex items-center gap-1 rounded-lg border border-gray-200 bg-white p-0.5">
78
- <button
79
- type="button"
80
- className="rounded-md px-3 py-1 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-300 disabled:cursor-not-allowed disabled:opacity-40"
81
- onClick={() => {
82
- if (!disablePrev) {
83
- props.onPageChange(Math.max(1, safeCurrentPage - 1));
84
- }
85
- }}
86
- disabled={disablePrev}
87
- >
88
- Previous
89
- </button>
90
- <span className="px-3 text-[11px] text-gray-400">
91
- Page {safeCurrentPage} / {totalPages}
92
- </span>
93
- <button
94
- type="button"
95
- className="rounded-md px-3 py-1 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-300 disabled:cursor-not-allowed disabled:opacity-40"
96
- onClick={() => {
97
- if (!disableNext) {
98
- props.onPageChange(Math.min(totalPages, safeCurrentPage + 1));
99
- }
100
- }}
101
- disabled={disableNext}
102
- >
103
- Next
104
- </button>
105
- </div>
106
- </div>
107
- </div>
23
+ <Pagination
24
+ dataTestId="logs-pagination"
25
+ singularLabel="log"
26
+ pluralLabel="logs"
27
+ currentPageNumber={props.currentPage}
28
+ totalItemsCount={props.totalItems}
29
+ itemsOnPage={props.pageSize}
30
+ itemsOnPageOptions={props.pageSizeOptions}
31
+ isCompact={true}
32
+ className="bg-gray-50/50"
33
+ isLoading={false}
34
+ isError={false}
35
+ isDisabled={Boolean(props.isDisabled)}
36
+ onNavigateToPage={(pageNumber: number, itemsOnPage: number) => {
37
+ if (itemsOnPage !== props.pageSize) {
38
+ props.onPageSizeChange(itemsOnPage);
39
+ }
40
+
41
+ if (pageNumber !== props.currentPage) {
42
+ props.onPageChange(pageNumber);
43
+ }
44
+ }}
45
+ />
108
46
  );
109
47
  };
110
48
 
@@ -28,6 +28,7 @@ export interface LogsViewerToolbarProps {
28
28
  savedViews?: Array<LogsSavedViewOption> | undefined;
29
29
  selectedSavedViewId?: string | null | undefined;
30
30
  onSavedViewSelect?: ((viewId: string) => void) | undefined;
31
+ onClearSavedView?: (() => void) | undefined;
31
32
  onEditSavedView?: ((viewId: string) => void) | undefined;
32
33
  onDeleteSavedView?: ((viewId: string) => void) | undefined;
33
34
  onUpdateCurrentSavedView?: (() => void) | undefined;
@@ -153,6 +154,7 @@ const LogsViewerToolbar: FunctionComponent<LogsViewerToolbarProps> = (
153
154
  savedViews={props.savedViews}
154
155
  selectedSavedViewId={props.selectedSavedViewId}
155
156
  onSelect={props.onSavedViewSelect}
157
+ onClear={props.onClearSavedView}
156
158
  onCreate={props.onCreateSavedView}
157
159
  onEdit={props.onEditSavedView}
158
160
  onDelete={props.onDeleteSavedView}