@oneuptime/common 11.7.3 → 11.7.4
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.
- package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
- package/Models/DatabaseModels/Index.ts +5 -0
- package/Models/DatabaseModels/LogDropFilter.ts +89 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +13 -3
- package/Models/DatabaseModels/RecommendationDismissal.ts +463 -0
- package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
- package/Models/DatabaseModels/StatusPageGroup.ts +95 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +89 -0
- package/Models/DatabaseModels/WorkflowVariable.ts +5 -1
- package/Server/API/AlertAPI.ts +32 -17
- package/Server/API/BaseAPI.ts +31 -2
- package/Server/API/BaseAnalyticsAPI.ts +36 -2
- package/Server/API/CommonAPI.ts +57 -0
- package/Server/API/IncidentAPI.ts +60 -33
- package/Server/API/IncidentEpisodeAPI.ts +31 -16
- package/Server/API/MonitorAPI.ts +30 -0
- package/Server/API/MonitorTemplateAPI.ts +8 -0
- package/Server/API/ProbeAPI.ts +196 -15
- package/Server/API/ProjectAPI.ts +79 -1
- package/Server/API/ScheduledMaintenanceAPI.ts +33 -18
- package/Server/API/StatusPageAPI.ts +74 -37
- package/Server/API/WorkspaceNotificationRuleAPI.ts +34 -4
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.ts +527 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.ts +55 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.ts +53 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Services/AlertEpisodeService.ts +47 -0
- package/Server/Services/AlertService.ts +125 -0
- package/Server/Services/BillingService.ts +98 -0
- package/Server/Services/DatabaseService.ts +184 -20
- package/Server/Services/IncidentEpisodeService.ts +47 -0
- package/Server/Services/IncidentService.ts +123 -0
- package/Server/Services/IncidentTemplateService.ts +123 -1
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/LogDropFilterService.ts +133 -0
- package/Server/Services/MonitorProbeService.ts +94 -4
- package/Server/Services/MonitorService.ts +48 -43
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +70 -0
- package/Server/Services/ProbeService.ts +66 -0
- package/Server/Services/ProjectService.ts +131 -7
- package/Server/Services/RecommendationDismissalService.ts +52 -0
- package/Server/Services/RunbookAgentJobService.ts +68 -7
- package/Server/Services/ScheduledMaintenanceService.ts +103 -0
- package/Server/Services/ScheduledMaintenanceTemplateService.ts +90 -0
- package/Server/Services/StatusPageGroupService.ts +186 -0
- package/Server/Services/TraceDropFilterService.ts +133 -0
- package/Server/Types/Workflow/Components/API/Delete.ts +12 -0
- package/Server/Types/Workflow/Components/API/Get.ts +12 -0
- package/Server/Types/Workflow/Components/API/Patch.ts +12 -0
- package/Server/Types/Workflow/Components/API/Post.ts +12 -0
- package/Server/Types/Workflow/Components/API/Put.ts +13 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +212 -0
- package/Server/Utils/DropFilterValidation.ts +127 -0
- package/Server/Utils/Errors.ts +5 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
- package/Server/Utils/Monitor/MonitorIncident.ts +31 -2
- package/Server/Utils/Telemetry/AppMetrics.ts +31 -0
- package/Tests/Models/DatabaseModels/MonitorProbeColumnAccessControl.test.ts +196 -0
- package/Tests/Models/RecommendationDismissalModel.test.ts +269 -0
- package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +320 -0
- package/Tests/Server/API/BaseAnalyticsAPIUpdatePayloadValidation.test.ts +293 -0
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +164 -0
- package/Tests/Server/API/ProbeAPI.test.ts +422 -53
- package/Tests/Server/API/ProjectAPI.test.ts +180 -0
- package/Tests/Server/API/ProjectAPIExtendTrialBillingDisabled.test.ts +138 -0
- package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +458 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +359 -0
- package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +427 -0
- package/Tests/Server/Services/BillingServiceExtendTrial.test.ts +439 -0
- package/Tests/Server/Services/CrossProjectReferenceWriteGuard.test.ts +810 -0
- package/Tests/Server/Services/DatabaseServiceAtomicAddToColumns.test.ts +269 -0
- package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +277 -0
- package/Tests/Server/Services/DatabaseServiceSortColumnSelect.test.ts +201 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +81 -23
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +398 -0
- package/Tests/Server/Services/MonitorProbeDeleteHooks.test.ts +280 -0
- package/Tests/Server/Services/MonitorProbeServiceProbeTenancy.test.ts +304 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +262 -0
- package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +614 -0
- package/Tests/Server/Services/RecommendationDismissalService.test.ts +306 -0
- package/Tests/Server/Services/RepairCrossProjectIncidentReferencesMigration.test.ts +528 -0
- package/Tests/Server/Services/StatusPageGroupNesting.test.ts +395 -0
- package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +26 -21
- package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +227 -0
- package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +285 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +463 -0
- package/Tests/Server/Utils/DropFilterValidation.test.ts +269 -0
- package/Tests/Server/Utils/Telemetry/SpanUtil.test.ts +94 -0
- package/Tests/Types/DateUserTimezone.test.ts +52 -0
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +177 -9
- package/Tests/Types/Monitor/MonitorStepDnsMonitor.test.ts +105 -0
- package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +131 -0
- package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +60 -0
- package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +82 -0
- package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +268 -0
- package/Tests/Types/Monitor/MonitorStepMetricMonitor.test.ts +386 -0
- package/Tests/Types/Monitor/MonitorStepProfileMonitor.test.ts +185 -0
- package/Tests/Types/Monitor/MonitorStepSnmpMonitor.test.ts +156 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +371 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +901 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +607 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +754 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +960 -0
- package/Tests/Types/RollingTime/RollingTimeUtil.test.ts +186 -0
- package/Tests/Types/Runbook/RunbookStepTimeout.test.ts +410 -0
- package/Tests/Types/Telemetry/DropFilterSampling.test.ts +241 -0
- package/Tests/Types/Workspace/NotificationRuleConditionUtil.test.ts +353 -0
- package/Tests/Types/Workspace/NotificationRuleUtil.test.ts +566 -0
- package/Tests/UI/Components/CodeEditor.test.tsx +174 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +555 -24
- package/Tests/UI/Components/InfoCard.test.tsx +358 -0
- package/Tests/UI/Components/LogTimeRangePicker.test.tsx +138 -0
- package/Tests/UI/Components/Modal.test.tsx +43 -5
- package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +397 -0
- package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +427 -0
- package/Tests/UI/Components/Runbook/StepTimeoutInput.test.tsx +386 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +671 -0
- package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +404 -0
- package/Tests/UI/Utils/DropdownAlignment.test.ts +306 -0
- package/Tests/UI/Utils/TableFilterUrlState.test.ts +292 -0
- package/Tests/Utils/Monitor/MonitorSummaryProbeUtil.test.ts +263 -0
- package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +583 -0
- package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +1072 -0
- package/Tests/Utils/StatusPage/GroupTree.test.ts +583 -0
- package/Tests/Utils/StatusPage/ResourceUptime.test.ts +411 -0
- package/Types/Date.ts +15 -6
- package/Types/Monitor/KubernetesAlertTemplates.ts +205 -0
- package/Types/Monitor/MonitorStep.ts +10 -1
- package/Types/Monitor/MonitorStepMetricMonitor.ts +46 -1
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +413 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +168 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +175 -0
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +743 -0
- package/Types/Permission.ts +45 -0
- package/Types/Recommendation/RecommendationType.ts +20 -0
- package/Types/Runbook/RunbookExecutionDeadline.ts +129 -0
- package/Types/Runbook/RunbookStepTimeout.ts +202 -0
- package/Types/Telemetry/DropFilterSampling.ts +92 -0
- package/UI/Components/AI/GenerateFromAIModal.tsx +0 -2
- package/UI/Components/Accordion/Accordion.tsx +10 -2
- package/UI/Components/BulkUpdate/BulkLabelActions.tsx +0 -1
- package/UI/Components/CodeEditor/CodeEditor.tsx +34 -20
- package/UI/Components/Date/RangeStartAndEndDateView.tsx +0 -1
- package/UI/Components/EditionLabel/EditionLabel.tsx +1 -27
- package/UI/Components/Error/PageError.tsx +0 -4
- package/UI/Components/ErrorBoundary.tsx +252 -15
- package/UI/Components/InfoCard/InfoCard.tsx +58 -1
- package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +34 -1
- package/UI/Components/Modal/Modal.tsx +16 -60
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +0 -8
- package/UI/Components/ModelTable/BaseModelTable.tsx +116 -67
- package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +150 -47
- package/UI/Components/Runbook/StepTimeoutInput.tsx +173 -0
- package/UI/Components/StatusPage/ResourceGroupSection.tsx +231 -0
- package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +34 -1
- package/UI/Utils/DropdownAlignment.ts +162 -0
- package/UI/Utils/TableFilterUrlState.ts +59 -20
- package/Utils/API.ts +106 -2
- package/Utils/Monitor/MonitorSummaryProbeUtil.ts +130 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +434 -0
- package/Utils/StatusPage/GroupNestingLayout.ts +343 -0
- package/Utils/StatusPage/GroupTree.ts +307 -0
- package/Utils/StatusPage/ResourceUptime.ts +90 -17
- package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +91 -0
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +14 -4
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RecommendationDismissal.js +484 -0
- package/build/dist/Models/DatabaseModels/RecommendationDismissal.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageGroup.js +94 -0
- package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +91 -0
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js +5 -1
- package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
- package/build/dist/Server/API/AlertAPI.js +22 -13
- package/build/dist/Server/API/AlertAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +22 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js +24 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +42 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +43 -26
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/IncidentEpisodeAPI.js +21 -12
- package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
- package/build/dist/Server/API/MonitorAPI.js +23 -0
- package/build/dist/Server/API/MonitorAPI.js.map +1 -1
- package/build/dist/Server/API/MonitorTemplateAPI.js +4 -0
- package/build/dist/Server/API/MonitorTemplateAPI.js.map +1 -1
- package/build/dist/Server/API/ProbeAPI.js +131 -15
- package/build/dist/Server/API/ProbeAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectAPI.js +62 -3
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js +23 -14
- package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +61 -33
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js +26 -2
- package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js +397 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js +30 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertEpisodeService.js +39 -0
- package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +95 -0
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/BillingService.js +71 -0
- package/build/dist/Server/Services/BillingService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +140 -17
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +39 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +100 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +97 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LogDropFilterService.js +93 -0
- package/build/dist/Server/Services/LogDropFilterService.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +73 -5
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +34 -39
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +71 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +64 -0
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +103 -7
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RecommendationDismissalService.js +50 -0
- package/build/dist/Server/Services/RecommendationDismissalService.js.map +1 -0
- package/build/dist/Server/Services/RunbookAgentJobService.js +63 -5
- package/build/dist/Server/Services/RunbookAgentJobService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +83 -0
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +65 -0
- package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageGroupService.js +136 -0
- package/build/dist/Server/Services/StatusPageGroupService.js.map +1 -1
- package/build/dist/Server/Services/TraceDropFilterService.js +93 -0
- package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js +11 -0
- package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js +12 -0
- package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +132 -0
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -0
- package/build/dist/Server/Utils/DropFilterValidation.js +80 -0
- package/build/dist/Server/Utils/DropFilterValidation.js.map +1 -0
- package/build/dist/Server/Utils/Errors.js +3 -0
- package/build/dist/Server/Utils/Errors.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +30 -12
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +38 -18
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js +26 -0
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
- package/build/dist/Types/Date.js +14 -4
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +192 -0
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +6 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +32 -1
- package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +294 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +110 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +58 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +451 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -0
- package/build/dist/Types/Permission.js +40 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Recommendation/RecommendationType.js +21 -0
- package/build/dist/Types/Recommendation/RecommendationType.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookExecutionDeadline.js +93 -0
- package/build/dist/Types/Runbook/RunbookExecutionDeadline.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepTimeout.js +142 -0
- package/build/dist/Types/Runbook/RunbookStepTimeout.js.map +1 -0
- package/build/dist/Types/Telemetry/DropFilterSampling.js +75 -0
- package/build/dist/Types/Telemetry/DropFilterSampling.js.map +1 -0
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -2
- package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
- package/build/dist/UI/Components/Accordion/Accordion.js +9 -2
- package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +27 -14
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +1 -1
- package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +2 -20
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Error/PageError.js +1 -3
- package/build/dist/UI/Components/Error/PageError.js.map +1 -1
- package/build/dist/UI/Components/ErrorBoundary.js +145 -11
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js +28 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +13 -2
- package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +4 -32
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +69 -33
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +73 -32
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
- package/build/dist/UI/Components/Runbook/StepTimeoutInput.js +101 -0
- package/build/dist/UI/Components/Runbook/StepTimeoutInput.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +73 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +13 -2
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
- package/build/dist/UI/Utils/DropdownAlignment.js +98 -0
- package/build/dist/UI/Utils/DropdownAlignment.js.map +1 -0
- package/build/dist/UI/Utils/TableFilterUrlState.js +48 -15
- package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
- package/build/dist/Utils/API.js +39 -2
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js +97 -0
- package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +330 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js +280 -0
- package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -0
- package/build/dist/Utils/StatusPage/GroupTree.js +214 -0
- package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceUptime.js +60 -16
- package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
FunctionComponent,
|
|
3
|
+
ReactElement,
|
|
4
|
+
ReactNode,
|
|
5
|
+
useEffect,
|
|
6
|
+
useId,
|
|
7
|
+
useState,
|
|
8
|
+
} from "react";
|
|
9
|
+
import {
|
|
10
|
+
NON_NUMERIC_TIMEOUT_MESSAGE,
|
|
11
|
+
TimeoutBounds,
|
|
12
|
+
getTimeoutValidationError,
|
|
13
|
+
secondsInputValueToTimeoutInMs,
|
|
14
|
+
timeoutInMsToSecondsInputValue,
|
|
15
|
+
willTimeoutBeClamped,
|
|
16
|
+
} from "../../../Types/Runbook/RunbookStepTimeout";
|
|
17
|
+
|
|
18
|
+
export interface ComponentProps {
|
|
19
|
+
label: string;
|
|
20
|
+
// Stored value, in milliseconds. Undefined means "use the default".
|
|
21
|
+
value: number | undefined;
|
|
22
|
+
bounds: TimeoutBounds;
|
|
23
|
+
onChange: (timeoutInMs: number | undefined) => void;
|
|
24
|
+
description?: ReactNode | undefined;
|
|
25
|
+
dataTestId?: string | undefined;
|
|
26
|
+
disabled?: boolean | undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* Seconds-in, milliseconds-out editor for a per-step timeout.
|
|
31
|
+
*
|
|
32
|
+
* The typed text is held locally rather than derived from the stored value on
|
|
33
|
+
* every keystroke: deriving it would fight the author mid-edit, because a
|
|
34
|
+
* partially typed "0" or an emptied field both resolve to "unset" and would
|
|
35
|
+
* erase what they were typing. The stored value only moves when the text
|
|
36
|
+
* parses to something usable.
|
|
37
|
+
*/
|
|
38
|
+
const StepTimeoutInput: FunctionComponent<ComponentProps> = (
|
|
39
|
+
props: ComponentProps,
|
|
40
|
+
): ReactElement => {
|
|
41
|
+
const uniqueId: string = useId();
|
|
42
|
+
const inputId: string = `step-timeout-${uniqueId}`;
|
|
43
|
+
const describedById: string = `step-timeout-help-${uniqueId}`;
|
|
44
|
+
const errorId: string = `step-timeout-error-${uniqueId}`;
|
|
45
|
+
|
|
46
|
+
const [text, setText] = useState<string>(
|
|
47
|
+
timeoutInMsToSecondsInputValue(props.value),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
/*
|
|
51
|
+
* A number input reports an empty string for text it cannot parse — a
|
|
52
|
+
* dangling exponent ("1e"), a lone "-" — while still showing that text to
|
|
53
|
+
* the author. Tracked separately from `text` so an unparseable keystroke
|
|
54
|
+
* does not read as "the author cleared the field".
|
|
55
|
+
*/
|
|
56
|
+
const [hasUnparseableInput, setHasUnparseableInput] =
|
|
57
|
+
useState<boolean>(false);
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
* Re-sync when the step being edited changes underneath us (collapse /
|
|
61
|
+
* reorder / reload). Skipped while the text still represents the stored
|
|
62
|
+
* value so the author's in-progress typing survives re-renders.
|
|
63
|
+
*/
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const storedAsText: string = timeoutInMsToSecondsInputValue(props.value);
|
|
66
|
+
setText((currentText: string) => {
|
|
67
|
+
return secondsInputValueToTimeoutInMs(currentText) === props.value
|
|
68
|
+
? currentText
|
|
69
|
+
: storedAsText;
|
|
70
|
+
});
|
|
71
|
+
}, [props.value]);
|
|
72
|
+
|
|
73
|
+
const validationError: string | null = hasUnparseableInput
|
|
74
|
+
? NON_NUMERIC_TIMEOUT_MESSAGE
|
|
75
|
+
: getTimeoutValidationError(text, props.bounds);
|
|
76
|
+
|
|
77
|
+
const defaultInSeconds: number = props.bounds.defaultInMs / 1000;
|
|
78
|
+
|
|
79
|
+
const handleChange: (value: string, isUnparseable: boolean) => void = (
|
|
80
|
+
value: string,
|
|
81
|
+
isUnparseable: boolean,
|
|
82
|
+
): void => {
|
|
83
|
+
if (isUnparseable) {
|
|
84
|
+
/*
|
|
85
|
+
* Hold the stored value. Reporting undefined here would discard a
|
|
86
|
+
* timeout the author had already saved, without them touching a digit —
|
|
87
|
+
* the field would look edited, save cleanly, and the step would silently
|
|
88
|
+
* drop back to the default.
|
|
89
|
+
*/
|
|
90
|
+
setHasUnparseableInput(true);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
setHasUnparseableInput(false);
|
|
95
|
+
setText(value);
|
|
96
|
+
props.onChange(secondsInputValueToTimeoutInMs(value));
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/*
|
|
100
|
+
* Only a usable-but-out-of-range value gets clamped at run time. Anything
|
|
101
|
+
* unusable falls back to the default instead, so the two cases need
|
|
102
|
+
* different copy.
|
|
103
|
+
*/
|
|
104
|
+
const consequence: string = hasUnparseableInput
|
|
105
|
+
? "The saved value is unchanged."
|
|
106
|
+
: willTimeoutBeClamped(text, props.bounds)
|
|
107
|
+
? "Values outside the range are clamped when the step runs."
|
|
108
|
+
: "Leave the field blank to use the default.";
|
|
109
|
+
|
|
110
|
+
let inputClassName: string =
|
|
111
|
+
"block w-full rounded-md border border-gray-300 bg-white py-2 pl-3 pr-3 text-sm placeholder-gray-500 focus:border-indigo-500 focus:text-gray-900 focus:placeholder-gray-400 focus:outline-none focus:ring-1 focus:ring-indigo-500 sm:text-sm";
|
|
112
|
+
|
|
113
|
+
if (validationError) {
|
|
114
|
+
inputClassName +=
|
|
115
|
+
" border-red-300 text-red-900 placeholder-red-300 focus:border-red-500 focus:ring-red-500";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (props.disabled) {
|
|
119
|
+
inputClassName += " bg-gray-100 text-gray-500 cursor-not-allowed";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div>
|
|
124
|
+
<label
|
|
125
|
+
htmlFor={inputId}
|
|
126
|
+
className="block text-xs font-medium text-gray-700 mb-1.5"
|
|
127
|
+
>
|
|
128
|
+
{props.label}
|
|
129
|
+
<span className="ml-2 text-[10px] font-normal text-gray-400">
|
|
130
|
+
seconds
|
|
131
|
+
</span>
|
|
132
|
+
</label>
|
|
133
|
+
<input
|
|
134
|
+
id={inputId}
|
|
135
|
+
type="number"
|
|
136
|
+
inputMode="decimal"
|
|
137
|
+
min={props.bounds.minInMs / 1000}
|
|
138
|
+
max={props.bounds.maxInMs / 1000}
|
|
139
|
+
step="any"
|
|
140
|
+
disabled={props.disabled}
|
|
141
|
+
className={inputClassName}
|
|
142
|
+
value={text}
|
|
143
|
+
placeholder={`${defaultInSeconds}`}
|
|
144
|
+
/*
|
|
145
|
+
* The error is part of the field's description, not only a live region:
|
|
146
|
+
* a screen reader that reaches an already-invalid field on focus still
|
|
147
|
+
* hears why.
|
|
148
|
+
*/
|
|
149
|
+
aria-describedby={
|
|
150
|
+
validationError ? `${describedById} ${errorId}` : describedById
|
|
151
|
+
}
|
|
152
|
+
aria-invalid={validationError ? true : undefined}
|
|
153
|
+
data-testid={props.dataTestId}
|
|
154
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
155
|
+
handleChange(e.target.value, e.target.validity?.badInput === true);
|
|
156
|
+
}}
|
|
157
|
+
/>
|
|
158
|
+
<p id={describedById} className="text-xs text-gray-500 mt-1.5">
|
|
159
|
+
{props.description ? <>{props.description} </> : null}
|
|
160
|
+
Leave blank to use the default of {defaultInSeconds} seconds. Allowed
|
|
161
|
+
range: {props.bounds.minInMs / 1000}–{props.bounds.maxInMs / 1000}{" "}
|
|
162
|
+
seconds.
|
|
163
|
+
</p>
|
|
164
|
+
{validationError ? (
|
|
165
|
+
<p id={errorId} role="alert" className="text-xs text-red-600 mt-1">
|
|
166
|
+
{validationError} {consequence}
|
|
167
|
+
</p>
|
|
168
|
+
) : null}
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export default StepTimeoutInput;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import Icon, { ThickProp } from "../Icon/Icon";
|
|
2
|
+
import MarkdownViewer from "../Markdown.tsx/LazyMarkdownViewer";
|
|
3
|
+
import IconProp from "../../../Types/Icon/IconProp";
|
|
4
|
+
import StatusPageGroupNestingLayoutUtil from "../../../Utils/StatusPage/GroupNestingLayout";
|
|
5
|
+
import React, {
|
|
6
|
+
FunctionComponent,
|
|
7
|
+
ReactElement,
|
|
8
|
+
useEffect,
|
|
9
|
+
useState,
|
|
10
|
+
} from "react";
|
|
11
|
+
|
|
12
|
+
export interface ComponentProps {
|
|
13
|
+
/*
|
|
14
|
+
* 0 for a top level group, 1 for its children, and so on. Everything about
|
|
15
|
+
* how this section is drawn comes from it - see GroupNestingLayout.
|
|
16
|
+
*/
|
|
17
|
+
depth: number;
|
|
18
|
+
name: string;
|
|
19
|
+
/*
|
|
20
|
+
* Markdown. Rendered below the header rather than inside it - a description
|
|
21
|
+
* may contain links, and a link inside a button is not something a browser or
|
|
22
|
+
* a screen reader can make sense of.
|
|
23
|
+
*/
|
|
24
|
+
description?: string | undefined;
|
|
25
|
+
/*
|
|
26
|
+
* Rendered next to the name when the group has sub groups. Pre-translated by
|
|
27
|
+
* the caller: this component has no i18n of its own.
|
|
28
|
+
*/
|
|
29
|
+
subGroupCountLabel?: string | undefined;
|
|
30
|
+
/*
|
|
31
|
+
* The group's rolled up status or uptime, already formatted and translated by
|
|
32
|
+
* the caller ("99.9% uptime", "Operational"). Drawn with a status dot so it
|
|
33
|
+
* reads as a rollup of everything below rather than as one more resource
|
|
34
|
+
* reading, and it stays visible while the section is open - the point of the
|
|
35
|
+
* hierarchy is that every level always shows what it rolls up, and a number
|
|
36
|
+
* that disappears on expand is a number you cannot compare against the level
|
|
37
|
+
* below it.
|
|
38
|
+
*/
|
|
39
|
+
rollupLabel?: string | undefined;
|
|
40
|
+
/* Hex or css colour for the rollup, from the rolled up status. */
|
|
41
|
+
rollupColor?: string | undefined;
|
|
42
|
+
isInitiallyExpanded?: boolean | undefined;
|
|
43
|
+
/* The group's own resources. */
|
|
44
|
+
resourcesElement?: ReactElement | undefined;
|
|
45
|
+
/* Nested sections, normally one per sub group. */
|
|
46
|
+
subGroupsElement?: ReactElement | undefined;
|
|
47
|
+
hasOwnResources?: boolean | undefined;
|
|
48
|
+
subGroupCount?: number | undefined;
|
|
49
|
+
testId?: string | undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/*
|
|
53
|
+
* One level of the status page resource group hierarchy.
|
|
54
|
+
*
|
|
55
|
+
* A top level group is a card. Everything under it is a row on a tree rail -
|
|
56
|
+
* no card, no second border, no background tint stacked on the last one - so
|
|
57
|
+
* the hierarchy stays readable however deep it goes and the uptime bars keep
|
|
58
|
+
* the width they need.
|
|
59
|
+
*/
|
|
60
|
+
const ResourceGroupSection: FunctionComponent<ComponentProps> = (
|
|
61
|
+
props: ComponentProps,
|
|
62
|
+
): ReactElement => {
|
|
63
|
+
const [isOpen, setIsOpen] = useState<boolean>(
|
|
64
|
+
Boolean(props.isInitiallyExpanded),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* Groups arrive with the page payload, so isInitiallyExpanded can flip after
|
|
69
|
+
* the first render. Keyed on the *boolean*, not on the prop: the column is an
|
|
70
|
+
* optional boolean, so it routinely arrives as undefined and settles to false,
|
|
71
|
+
* and keying on the prop would fire on that and slam shut a section the
|
|
72
|
+
* visitor had just opened.
|
|
73
|
+
*/
|
|
74
|
+
const initiallyExpanded: boolean = Boolean(props.isInitiallyExpanded);
|
|
75
|
+
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
setIsOpen(initiallyExpanded);
|
|
78
|
+
}, [initiallyExpanded]);
|
|
79
|
+
|
|
80
|
+
const generatedId: string = React.useId();
|
|
81
|
+
const bodyId: string = `status-page-group-body-${generatedId}`;
|
|
82
|
+
const descriptionId: string = `status-page-group-description-${generatedId}`;
|
|
83
|
+
|
|
84
|
+
const isRootLevel: boolean = StatusPageGroupNestingLayoutUtil.isRootLevel({
|
|
85
|
+
depth: props.depth,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const subGroupCount: number = props.subGroupCount || 0;
|
|
89
|
+
|
|
90
|
+
const showSubGroupDivider: boolean =
|
|
91
|
+
StatusPageGroupNestingLayoutUtil.shouldShowSubGroupDivider({
|
|
92
|
+
hasOwnResources: Boolean(props.hasOwnResources),
|
|
93
|
+
subGroupCount: subGroupCount,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<div
|
|
98
|
+
className={StatusPageGroupNestingLayoutUtil.getContainerClassName({
|
|
99
|
+
depth: props.depth,
|
|
100
|
+
})}
|
|
101
|
+
data-testid={
|
|
102
|
+
props.testId ||
|
|
103
|
+
(isRootLevel ? "status-page-group" : "status-page-nested-group")
|
|
104
|
+
}
|
|
105
|
+
data-depth={props.depth}
|
|
106
|
+
>
|
|
107
|
+
<button
|
|
108
|
+
type="button"
|
|
109
|
+
className={StatusPageGroupNestingLayoutUtil.getHeaderClassName({
|
|
110
|
+
depth: props.depth,
|
|
111
|
+
})}
|
|
112
|
+
aria-expanded={isOpen}
|
|
113
|
+
aria-controls={isOpen ? bodyId : undefined}
|
|
114
|
+
aria-describedby={props.description ? descriptionId : undefined}
|
|
115
|
+
data-testid="status-page-group-header"
|
|
116
|
+
onClick={() => {
|
|
117
|
+
setIsOpen(!isOpen);
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
<span
|
|
121
|
+
className={StatusPageGroupNestingLayoutUtil.getHeaderRowClassName()}
|
|
122
|
+
>
|
|
123
|
+
<span
|
|
124
|
+
className={`${StatusPageGroupNestingLayoutUtil.getChevronBoxClassName()} ${
|
|
125
|
+
isOpen ? "bg-gray-900/5 text-gray-700" : "text-gray-400"
|
|
126
|
+
}`}
|
|
127
|
+
data-testid="status-page-group-chevron"
|
|
128
|
+
aria-hidden="true"
|
|
129
|
+
>
|
|
130
|
+
<Icon
|
|
131
|
+
className={`h-3.5 w-3.5 transition-transform duration-200 ease-out ${
|
|
132
|
+
isOpen ? "rotate-90" : ""
|
|
133
|
+
}`}
|
|
134
|
+
icon={IconProp.ChevronRight}
|
|
135
|
+
thick={ThickProp.Thick}
|
|
136
|
+
/>
|
|
137
|
+
</span>
|
|
138
|
+
<span
|
|
139
|
+
className={StatusPageGroupNestingLayoutUtil.getTitleClassName({
|
|
140
|
+
depth: props.depth,
|
|
141
|
+
})}
|
|
142
|
+
title={props.name}
|
|
143
|
+
>
|
|
144
|
+
{props.name}
|
|
145
|
+
</span>
|
|
146
|
+
{props.subGroupCountLabel ? (
|
|
147
|
+
<span
|
|
148
|
+
className={StatusPageGroupNestingLayoutUtil.getSubGroupCountBadgeClassName()}
|
|
149
|
+
data-testid="status-page-group-sub-group-count"
|
|
150
|
+
>
|
|
151
|
+
{props.subGroupCountLabel}
|
|
152
|
+
</span>
|
|
153
|
+
) : (
|
|
154
|
+
<></>
|
|
155
|
+
)}
|
|
156
|
+
</span>
|
|
157
|
+
{props.rollupLabel ? (
|
|
158
|
+
<span
|
|
159
|
+
className={StatusPageGroupNestingLayoutUtil.getRollupClassName()}
|
|
160
|
+
data-testid="status-page-group-rollup"
|
|
161
|
+
>
|
|
162
|
+
<span className="inline-flex items-center gap-1.5">
|
|
163
|
+
<span
|
|
164
|
+
className={StatusPageGroupNestingLayoutUtil.getRollupDotClassName()}
|
|
165
|
+
style={
|
|
166
|
+
props.rollupColor
|
|
167
|
+
? { backgroundColor: props.rollupColor }
|
|
168
|
+
: undefined
|
|
169
|
+
}
|
|
170
|
+
data-testid="status-page-group-rollup-dot"
|
|
171
|
+
aria-hidden="true"
|
|
172
|
+
/>
|
|
173
|
+
<span
|
|
174
|
+
className={StatusPageGroupNestingLayoutUtil.getRollupLabelClassName()}
|
|
175
|
+
style={
|
|
176
|
+
props.rollupColor ? { color: props.rollupColor } : undefined
|
|
177
|
+
}
|
|
178
|
+
>
|
|
179
|
+
{props.rollupLabel}
|
|
180
|
+
</span>
|
|
181
|
+
</span>
|
|
182
|
+
</span>
|
|
183
|
+
) : (
|
|
184
|
+
<></>
|
|
185
|
+
)}
|
|
186
|
+
</button>
|
|
187
|
+
{props.description ? (
|
|
188
|
+
<div
|
|
189
|
+
id={descriptionId}
|
|
190
|
+
className={StatusPageGroupNestingLayoutUtil.getDescriptionClassName()}
|
|
191
|
+
data-testid="status-page-group-description"
|
|
192
|
+
>
|
|
193
|
+
<MarkdownViewer text={props.description} />
|
|
194
|
+
</div>
|
|
195
|
+
) : (
|
|
196
|
+
<></>
|
|
197
|
+
)}
|
|
198
|
+
{isOpen ? (
|
|
199
|
+
<div
|
|
200
|
+
id={bodyId}
|
|
201
|
+
className={StatusPageGroupNestingLayoutUtil.getBodyClassName({
|
|
202
|
+
depth: props.depth,
|
|
203
|
+
})}
|
|
204
|
+
data-testid="status-page-group-body"
|
|
205
|
+
>
|
|
206
|
+
{props.resourcesElement || <></>}
|
|
207
|
+
{props.subGroupsElement ? (
|
|
208
|
+
<div
|
|
209
|
+
className={`${
|
|
210
|
+
showSubGroupDivider
|
|
211
|
+
? StatusPageGroupNestingLayoutUtil.getSubGroupDividerClassName()
|
|
212
|
+
: ""
|
|
213
|
+
} ${StatusPageGroupNestingLayoutUtil.getSubGroupListClassName({
|
|
214
|
+
depth: props.depth,
|
|
215
|
+
})}`.trim()}
|
|
216
|
+
data-testid="status-page-sub-group-list"
|
|
217
|
+
>
|
|
218
|
+
{props.subGroupsElement}
|
|
219
|
+
</div>
|
|
220
|
+
) : (
|
|
221
|
+
<></>
|
|
222
|
+
)}
|
|
223
|
+
</div>
|
|
224
|
+
) : (
|
|
225
|
+
<></>
|
|
226
|
+
)}
|
|
227
|
+
</div>
|
|
228
|
+
);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
export default ResourceGroupSection;
|
|
@@ -14,12 +14,20 @@ import InBetween from "../../../../Types/BaseDatabase/InBetween";
|
|
|
14
14
|
import StartAndEndDate, {
|
|
15
15
|
StartAndEndDateType,
|
|
16
16
|
} from "../../Date/StartAndEndDate";
|
|
17
|
+
import {
|
|
18
|
+
DropdownHorizontalAlignment,
|
|
19
|
+
getDropdownAlignmentClassName,
|
|
20
|
+
useDropdownHorizontalAlignment,
|
|
21
|
+
} from "../../../Utils/DropdownAlignment";
|
|
17
22
|
|
|
18
23
|
export interface TelemetryTimeRangePickerProps {
|
|
19
24
|
value: RangeStartAndEndDateTime;
|
|
20
25
|
onChange: (value: RangeStartAndEndDateTime) => void;
|
|
21
26
|
}
|
|
22
27
|
|
|
28
|
+
// Matches the Tailwind `w-72` on the dropdown below (18rem).
|
|
29
|
+
export const TIME_RANGE_DROPDOWN_WIDTH_IN_PX: number = 288;
|
|
30
|
+
|
|
23
31
|
const PRESET_OPTIONS: Array<{ range: TimeRange; label: string }> = [
|
|
24
32
|
{ range: TimeRange.PAST_FIVE_MINS, label: "Past 5 Minutes" },
|
|
25
33
|
{ range: TimeRange.PAST_FIFTEEN_MINS, label: "Past 15 Minutes" },
|
|
@@ -67,6 +75,20 @@ const TelemetryTimeRangePicker: FunctionComponent<
|
|
|
67
75
|
const containerRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
|
68
76
|
null!,
|
|
69
77
|
);
|
|
78
|
+
const buttonRef: React.RefObject<HTMLButtonElement> =
|
|
79
|
+
useRef<HTMLButtonElement>(null!);
|
|
80
|
+
const dropdownRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
|
81
|
+
null!,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const alignment: DropdownHorizontalAlignment = useDropdownHorizontalAlignment(
|
|
85
|
+
{
|
|
86
|
+
isOpen: isOpen,
|
|
87
|
+
anchorRef: buttonRef,
|
|
88
|
+
dropdownRef: dropdownRef,
|
|
89
|
+
dropdownWidthInPx: TIME_RANGE_DROPDOWN_WIDTH_IN_PX,
|
|
90
|
+
},
|
|
91
|
+
);
|
|
70
92
|
|
|
71
93
|
useEffect(() => {
|
|
72
94
|
const handleClickOutside: (e: MouseEvent) => void = (
|
|
@@ -117,7 +139,11 @@ const TelemetryTimeRangePicker: FunctionComponent<
|
|
|
117
139
|
return (
|
|
118
140
|
<div ref={containerRef} className="relative">
|
|
119
141
|
<button
|
|
142
|
+
ref={buttonRef}
|
|
120
143
|
type="button"
|
|
144
|
+
data-testid="telemetry-time-range-picker-button"
|
|
145
|
+
aria-haspopup="true"
|
|
146
|
+
aria-expanded={isOpen}
|
|
121
147
|
className={`inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs font-medium shadow-sm transition-colors ${
|
|
122
148
|
isOpen
|
|
123
149
|
? "border-indigo-300 bg-indigo-50 text-indigo-700"
|
|
@@ -136,7 +162,14 @@ const TelemetryTimeRangePicker: FunctionComponent<
|
|
|
136
162
|
</button>
|
|
137
163
|
|
|
138
164
|
{isOpen && (
|
|
139
|
-
<div
|
|
165
|
+
<div
|
|
166
|
+
ref={dropdownRef}
|
|
167
|
+
data-testid="telemetry-time-range-picker-dropdown"
|
|
168
|
+
data-align={alignment}
|
|
169
|
+
className={`absolute ${getDropdownAlignmentClassName(
|
|
170
|
+
alignment,
|
|
171
|
+
)} top-full z-50 mt-1 w-72 max-w-[calc(100vw-1rem)] rounded-lg border border-gray-200 bg-white shadow-lg`}
|
|
172
|
+
>
|
|
140
173
|
<div className="max-h-64 overflow-y-auto py-1">
|
|
141
174
|
{PRESET_OPTIONS.map(
|
|
142
175
|
(option: { range: TimeRange; label: string }) => {
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Horizontal edge of the trigger that a popup pins itself to.
|
|
5
|
+
* "Left" means the popup grows rightwards from the trigger's left edge
|
|
6
|
+
* (Tailwind `left-0`), "Right" means it grows leftwards from the trigger's
|
|
7
|
+
* right edge (Tailwind `right-0`).
|
|
8
|
+
*/
|
|
9
|
+
export enum DropdownHorizontalAlignment {
|
|
10
|
+
Left = "left",
|
|
11
|
+
Right = "right",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Breathing room we keep between a popup and the edge of the viewport.
|
|
15
|
+
export const DEFAULT_DROPDOWN_VIEWPORT_MARGIN_IN_PX: number = 8;
|
|
16
|
+
|
|
17
|
+
export interface DropdownAlignmentInput {
|
|
18
|
+
// Viewport-relative left edge of the trigger, as reported by getBoundingClientRect().
|
|
19
|
+
anchorLeft: number;
|
|
20
|
+
// Viewport-relative right edge of the trigger.
|
|
21
|
+
anchorRight: number;
|
|
22
|
+
// Rendered width of the popup in pixels.
|
|
23
|
+
dropdownWidth: number;
|
|
24
|
+
// Width of the viewport in pixels.
|
|
25
|
+
viewportWidth: number;
|
|
26
|
+
// Optional override for the viewport gutter.
|
|
27
|
+
viewportMargin?: number | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* Picks the edge a popup should align to so that it stays inside the viewport.
|
|
32
|
+
*
|
|
33
|
+
* Left alignment is preferred because it reads naturally next to the trigger.
|
|
34
|
+
* We only flip to the right edge when left alignment would spill past the right
|
|
35
|
+
* side of the viewport, and we never flip if doing so would spill past the left
|
|
36
|
+
* side by even more (which is what produced the off-screen popup on the metric
|
|
37
|
+
* explorer toolbar, where the trigger sits at the far left of the page).
|
|
38
|
+
*/
|
|
39
|
+
export function getDropdownHorizontalAlignment(
|
|
40
|
+
input: DropdownAlignmentInput,
|
|
41
|
+
): DropdownHorizontalAlignment {
|
|
42
|
+
const margin: number =
|
|
43
|
+
input.viewportMargin === undefined
|
|
44
|
+
? DEFAULT_DROPDOWN_VIEWPORT_MARGIN_IN_PX
|
|
45
|
+
: input.viewportMargin;
|
|
46
|
+
|
|
47
|
+
/*
|
|
48
|
+
* Before the popup is laid out (or in a non-visual environment) measurements
|
|
49
|
+
* come back as zero. There is nothing to solve for, so keep the default.
|
|
50
|
+
*/
|
|
51
|
+
if (
|
|
52
|
+
!Number.isFinite(input.dropdownWidth) ||
|
|
53
|
+
!Number.isFinite(input.viewportWidth) ||
|
|
54
|
+
input.dropdownWidth <= 0 ||
|
|
55
|
+
input.viewportWidth <= 0
|
|
56
|
+
) {
|
|
57
|
+
return DropdownHorizontalAlignment.Left;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// How far a left-aligned popup would poke past the right gutter.
|
|
61
|
+
const leftAlignedOverflow: number =
|
|
62
|
+
input.anchorLeft + input.dropdownWidth - (input.viewportWidth - margin);
|
|
63
|
+
|
|
64
|
+
// How far a right-aligned popup would poke past the left gutter.
|
|
65
|
+
const rightAlignedOverflow: number =
|
|
66
|
+
margin - (input.anchorRight - input.dropdownWidth);
|
|
67
|
+
|
|
68
|
+
if (leftAlignedOverflow <= 0) {
|
|
69
|
+
return DropdownHorizontalAlignment.Left;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (rightAlignedOverflow <= 0) {
|
|
73
|
+
return DropdownHorizontalAlignment.Right;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Neither edge fits. Pick whichever clips the least, preferring left on a tie.
|
|
77
|
+
return leftAlignedOverflow <= rightAlignedOverflow
|
|
78
|
+
? DropdownHorizontalAlignment.Left
|
|
79
|
+
: DropdownHorizontalAlignment.Right;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* Tailwind positioning class for an alignment. Kept next to the resolver so
|
|
84
|
+
* callers cannot drift out of sync with the enum.
|
|
85
|
+
*/
|
|
86
|
+
export function getDropdownAlignmentClassName(
|
|
87
|
+
alignment: DropdownHorizontalAlignment,
|
|
88
|
+
): string {
|
|
89
|
+
return alignment === DropdownHorizontalAlignment.Right ? "right-0" : "left-0";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface UseDropdownHorizontalAlignmentOptions {
|
|
93
|
+
// Only measure while the popup is actually on screen.
|
|
94
|
+
isOpen: boolean;
|
|
95
|
+
// The trigger the popup hangs off.
|
|
96
|
+
anchorRef: React.RefObject<HTMLElement>;
|
|
97
|
+
// The popup itself. When it has not been laid out we fall back to the declared width.
|
|
98
|
+
dropdownRef?: React.RefObject<HTMLElement> | undefined;
|
|
99
|
+
// Width the popup is styled to (e.g. 288 for Tailwind `w-72`).
|
|
100
|
+
dropdownWidthInPx: number;
|
|
101
|
+
viewportMargin?: number | undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
* Keeps a popup's horizontal alignment in sync with the space available around
|
|
106
|
+
* its trigger. Re-measures when the popup opens and whenever the viewport
|
|
107
|
+
* changes size or scrolls the trigger somewhere new.
|
|
108
|
+
*/
|
|
109
|
+
export function useDropdownHorizontalAlignment(
|
|
110
|
+
options: UseDropdownHorizontalAlignmentOptions,
|
|
111
|
+
): DropdownHorizontalAlignment {
|
|
112
|
+
const [alignment, setAlignment] = useState<DropdownHorizontalAlignment>(
|
|
113
|
+
DropdownHorizontalAlignment.Left,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const {
|
|
117
|
+
isOpen,
|
|
118
|
+
anchorRef,
|
|
119
|
+
dropdownRef,
|
|
120
|
+
dropdownWidthInPx,
|
|
121
|
+
viewportMargin,
|
|
122
|
+
}: UseDropdownHorizontalAlignmentOptions = options;
|
|
123
|
+
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (!isOpen) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const measure: () => void = (): void => {
|
|
130
|
+
const anchor: HTMLElement | null = anchorRef.current;
|
|
131
|
+
|
|
132
|
+
if (!anchor || typeof anchor.getBoundingClientRect !== "function") {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const anchorRect: DOMRect = anchor.getBoundingClientRect();
|
|
137
|
+
const measuredWidth: number = dropdownRef?.current?.offsetWidth || 0;
|
|
138
|
+
|
|
139
|
+
setAlignment(
|
|
140
|
+
getDropdownHorizontalAlignment({
|
|
141
|
+
anchorLeft: anchorRect.left,
|
|
142
|
+
anchorRight: anchorRect.right,
|
|
143
|
+
dropdownWidth: measuredWidth > 0 ? measuredWidth : dropdownWidthInPx,
|
|
144
|
+
viewportWidth: window.innerWidth,
|
|
145
|
+
viewportMargin: viewportMargin,
|
|
146
|
+
}),
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
measure();
|
|
151
|
+
|
|
152
|
+
window.addEventListener("resize", measure);
|
|
153
|
+
window.addEventListener("scroll", measure, true);
|
|
154
|
+
|
|
155
|
+
return () => {
|
|
156
|
+
window.removeEventListener("resize", measure);
|
|
157
|
+
window.removeEventListener("scroll", measure, true);
|
|
158
|
+
};
|
|
159
|
+
}, [isOpen, anchorRef, dropdownRef, dropdownWidthInPx, viewportMargin]);
|
|
160
|
+
|
|
161
|
+
return alignment;
|
|
162
|
+
}
|