@oneuptime/common 12.0.23 → 12.0.25
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/AnalyticsModels/Span.ts +101 -0
- package/Models/DatabaseModels/DetectionRule.ts +55 -0
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +27 -7
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +67 -0
- package/Models/DatabaseModels/Project.ts +68 -0
- package/Models/DatabaseModels/User.ts +68 -0
- package/Server/API/BaseAPI.ts +0 -24
- package/Server/API/SlackAPI.ts +0 -2
- package/Server/API/TelemetryAPI.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/GzipRequestBody.ts +311 -0
- package/Server/Middleware/MultipartFormData.ts +87 -3
- package/Server/Middleware/SlackAuthorization.ts +96 -18
- package/Server/Services/DetectionRuleService.ts +73 -6
- package/Server/Services/Index.ts +205 -0
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
- package/Server/Services/NetworkDeviceService.ts +148 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
- package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
- package/Server/Services/ProjectService.ts +29 -19
- package/Server/Services/SecurityEventService.ts +90 -13
- package/Server/Services/StatusPageResourceService.ts +223 -0
- package/Server/Services/TelemetryAttributeService.ts +17 -0
- package/Server/Services/UserService.ts +4 -6
- package/Server/Types/Markdown.ts +161 -67
- package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
- package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
- package/Server/Utils/Attribution.ts +4 -0
- package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
- package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
- package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
- package/Server/Utils/StartServer.ts +12 -32
- package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
- package/Server/Utils/Telemetry/LlmMetricSpend.ts +181 -0
- package/Server/Utils/Telemetry/LlmSpan.ts +46 -0
- package/Server/Utils/Workspace/Slack/Actions/Auth.ts +0 -12
- package/Server/Views/Partials/AnalyticsConsent.ejs +159 -102
- package/Server/Views/Partials/Head.ejs +2 -1
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +776 -38
- package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +359 -0
- package/Tests/App/Dashboard/CorrelateGraph.test.tsx +865 -0
- package/Tests/App/Dashboard/CorrelationGraph.test.ts +346 -0
- package/Tests/App/Dashboard/CriteriaFilterConditionDropdown.test.tsx +256 -0
- package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +738 -0
- package/Tests/App/Dashboard/CriteriaFilterMonitorTypeChange.test.ts +1122 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +283 -0
- package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +407 -0
- package/Tests/App/Dashboard/LlmCallsTableIdentity.test.tsx +322 -0
- package/Tests/App/Dashboard/LlmOverview.test.tsx +335 -0
- package/Tests/App/Dashboard/LlmSpanDisplay.test.ts +391 -0
- package/Tests/App/Dashboard/LlmUsageBreakdown.test.tsx +1007 -0
- package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +5 -14
- package/Tests/App/Dashboard/MonitorCriteriaActionToggles.test.tsx +426 -0
- package/Tests/App/Dashboard/MonitorStepsCriteriaAlignmentWiring.test.tsx +352 -0
- package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +278 -0
- package/Tests/App/Dashboard/OnCallLayerShiftPreviewOverrides.test.ts +237 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +2 -2
- package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +460 -0
- package/Tests/App/Dashboard/SecurityEventAttributeUtil.test.ts +171 -0
- package/Tests/App/Dashboard/SecurityEventCorrelation.test.ts +857 -0
- package/Tests/App/Dashboard/SecurityEventDetailObservables.test.tsx +194 -0
- package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +124 -0
- package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +79 -19
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +382 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +216 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +590 -11
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +757 -0
- package/Tests/Models/DiscoveryScanNameColumn.test.ts +293 -0
- package/Tests/Server/API/BaseAPI.test.ts +41 -0
- package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +9 -16
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +564 -0
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +120 -4
- package/Tests/Server/Middleware/GzipRequestBody.test.ts +725 -0
- package/Tests/Server/Middleware/MultipartFormData.test.ts +298 -0
- package/Tests/Server/Middleware/SlackAuthorization.test.ts +262 -5
- package/Tests/Server/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
- package/Tests/Server/Services/DetectionRuleService.test.ts +134 -2
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
- package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
- package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
- package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
- package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
- package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
- package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
- package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
- package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
- package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
- package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
- package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
- package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +387 -4
- package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +386 -0
- package/Tests/Server/Utils/Telemetry/LlmSpan.test.ts +804 -0
- package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +48 -5
- package/Tests/Types/Code/YamlSyntax.test.ts +396 -0
- package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +957 -0
- package/Tests/Types/Monitor/MonitorCriteriaActionValidation.test.ts +598 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +49 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +6 -6
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +4 -4
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +4 -3
- package/Tests/Types/Telemetry/LlmMetricConventions.test.ts +584 -0
- package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +0 -12
- package/Tests/UI/Components/CardModelDetailEdit.test.tsx +1 -17
- package/Tests/UI/Components/CodeEditor.test.tsx +474 -10
- package/Tests/UI/Components/Detail/YamlField.test.tsx +105 -0
- package/Tests/UI/Components/EntityDropdownLabelsBulkAdd.test.tsx +319 -0
- package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +231 -0
- package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +1 -0
- package/Tests/UI/Components/Forms/ValidationYAML.test.ts +234 -0
- package/Tests/UI/Components/ModelTable/AttributeColumns.test.tsx +573 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableAttributeColumns.test.tsx +824 -0
- package/Tests/UI/Components/ModelTable/ColumnCustomizationModalAddableColumns.test.tsx +707 -0
- package/Tests/UI/Components/SideOver.test.tsx +1 -1
- package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +294 -0
- package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +436 -0
- package/Tests/UI/Components/TableBulkCsvExport.test.tsx +6 -2
- package/Tests/UI/Components/Toggle.test.tsx +25 -0
- package/Tests/UI/Components/YamlEditor.test.tsx +847 -0
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +252 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
- package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
- package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +770 -0
- package/Types/Code/YamlSyntax.ts +396 -0
- package/Types/Exception/ExceptionCode.ts +1 -0
- package/Types/Exception/PayloadTooLargeException.ts +8 -0
- package/Types/Marketing/Attribution.ts +10 -0
- package/Types/Marketing/MarketingEvent.ts +4 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +116 -56
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +2 -1
- package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
- package/Types/Telemetry/LlmConventions.ts +255 -0
- package/Types/Telemetry/LlmMetricConventions.ts +329 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +3 -0
- package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +10 -1
- package/UI/Components/CodeEditor/CodeEditor.tsx +241 -79
- package/UI/Components/CodeEditor/YamlEditor.tsx +369 -0
- package/UI/Components/Detail/Detail.tsx +10 -0
- package/UI/Components/EntityDropdown/EntityDropdown.tsx +33 -0
- package/UI/Components/Forms/Fields/FormField.tsx +31 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/Forms/Types/FormFieldSchemaType.ts +1 -0
- package/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.ts +2 -0
- package/UI/Components/Forms/Validation.ts +46 -0
- package/UI/Components/Input/Input.tsx +3 -0
- package/UI/Components/ModelTable/AttributeColumns.tsx +321 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +263 -14
- package/UI/Components/ModelTable/Column.ts +8 -0
- package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +310 -0
- package/UI/Components/ModelTable/ColumnPreference.ts +13 -1
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.tsx +2 -2
- package/UI/Components/SideOver/SideOver.tsx +5 -5
- package/UI/Components/StatusPage/ResourceGrid.tsx +82 -2
- package/UI/Components/StatusPage/ResourceList.tsx +197 -38
- package/UI/Components/Toggle/Toggle.tsx +9 -1
- package/UI/Components/Types/FieldType.ts +1 -0
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +73 -1
- package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
- package/Utils/StatusPage/ResourceExplorer.ts +258 -0
- package/Utils/Telemetry/LlmMetricQuery.ts +287 -0
- package/build/dist/Models/AnalyticsModels/Span.js +89 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +27 -7
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +69 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +76 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +76 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +3 -19
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +0 -2
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +17 -0
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
- package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
- package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Middleware/SlackAuthorization.js +58 -7
- package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
- package/build/dist/Server/Services/DetectionRuleService.js +49 -4
- package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +204 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +25 -45
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/SecurityEventService.js +57 -5
- package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
- package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
- package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +2 -12
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +147 -61
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Attribution.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +12 -21
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +151 -0
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/LlmSpan.js +24 -1
- package/build/dist/Server/Utils/Telemetry/LlmSpan.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +0 -10
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
- package/build/dist/Types/Code/YamlSyntax.js +212 -0
- package/build/dist/Types/Code/YamlSyntax.js.map +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
- package/build/dist/Types/Exception/PayloadTooLargeException.js +8 -0
- package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -0
- package/build/dist/Types/Marketing/Attribution.js +10 -0
- package/build/dist/Types/Marketing/Attribution.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +112 -51
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +2 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +9 -0
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
- package/build/dist/Types/Telemetry/LlmConventions.js +236 -0
- package/build/dist/Types/Telemetry/LlmConventions.js.map +1 -1
- package/build/dist/Types/Telemetry/LlmMetricConventions.js +290 -0
- package/build/dist/Types/Telemetry/LlmMetricConventions.js.map +1 -0
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +5 -2
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +206 -76
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js +201 -0
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -0
- package/build/dist/UI/Components/Detail/Detail.js +9 -0
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +16 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +14 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
- package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js +1 -0
- package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js.map +1 -1
- package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js +2 -0
- package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +27 -0
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +1 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/AttributeColumns.js +159 -0
- package/build/dist/UI/Components/ModelTable/AttributeColumns.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +179 -17
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +133 -2
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js +7 -1
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.js +2 -2
- package/build/dist/UI/Components/SideOver/SideOver.js +5 -5
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +28 -2
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceList.js +87 -20
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
- package/build/dist/UI/Components/Toggle/Toggle.js +9 -1
- package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
- package/build/dist/UI/Components/Types/FieldType.js +1 -0
- package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +37 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
- package/build/dist/Utils/Telemetry/LlmMetricQuery.js +175 -0
- package/build/dist/Utils/Telemetry/LlmMetricQuery.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/tsconfig.json +2 -1
- package/Tests/UI/Components/Toast.test.tsx +0 -197
- package/Tests/UI/Components/ToastStacking.test.tsx +0 -198
- package/UI/Components/Toast/Toast.tsx +0 -189
- package/UI/Components/Toast/ToastInit.tsx +0 -110
- package/build/dist/UI/Components/Toast/Toast.js +0 -123
- package/build/dist/UI/Components/Toast/Toast.js.map +0 -1
- package/build/dist/UI/Components/Toast/ToastInit.js +0 -53
- package/build/dist/UI/Components/Toast/ToastInit.js.map +0 -1
|
@@ -17,6 +17,82 @@ import Model from "../../Models/DatabaseModels/StatusPageResource";
|
|
|
17
17
|
import Monitor from "../../Models/DatabaseModels/Monitor";
|
|
18
18
|
import MonitorGroupResource from "../../Models/DatabaseModels/MonitorGroupResource";
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* The ways a create or update can name the resource's target. Everything
|
|
22
|
+
* server side sets the foreign key column, but the dashboard's resource form
|
|
23
|
+
* posts the relation - and the relation does NOT arrive in the same shape on
|
|
24
|
+
* both write paths:
|
|
25
|
+
*
|
|
26
|
+
* - create goes through BaseAPI.createItem, which revives the body with
|
|
27
|
+
* BaseModel.fromJSON, so `monitor` is a real Monitor and `monitor.id` is
|
|
28
|
+
* an ObjectID;
|
|
29
|
+
* - update goes through BaseAPI.updateItem, which only runs
|
|
30
|
+
* JSONFunctions.deserialize. That revives ObjectID/DateTime values, but
|
|
31
|
+
* never nested models, so `monitor` stays the plain `{ _id: "<uuid>" }`
|
|
32
|
+
* the browser sent and has no `id` at all.
|
|
33
|
+
*
|
|
34
|
+
* Reading only `.id` therefore silently saw nothing on every edit-form save,
|
|
35
|
+
* which is the whole path the update guard exists for - so this accepts the
|
|
36
|
+
* id however it arrives.
|
|
37
|
+
*/
|
|
38
|
+
type StatusPageResourceTargetValue =
|
|
39
|
+
| ObjectID
|
|
40
|
+
| string
|
|
41
|
+
| { id?: unknown; _id?: unknown }
|
|
42
|
+
| null
|
|
43
|
+
| undefined;
|
|
44
|
+
|
|
45
|
+
interface StatusPageResourceTargetInput {
|
|
46
|
+
monitorId?: StatusPageResourceTargetValue;
|
|
47
|
+
monitor?: StatusPageResourceTargetValue;
|
|
48
|
+
monitorGroupId?: StatusPageResourceTargetValue;
|
|
49
|
+
monitorGroup?: StatusPageResourceTargetValue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function toTargetObjectID(
|
|
53
|
+
value: StatusPageResourceTargetValue,
|
|
54
|
+
): ObjectID | null {
|
|
55
|
+
if (!value) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (value instanceof ObjectID) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (typeof value === "string") {
|
|
64
|
+
return new ObjectID(value);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (typeof value === "object") {
|
|
68
|
+
return (
|
|
69
|
+
toTargetObjectID(value.id as StatusPageResourceTargetValue) ||
|
|
70
|
+
toTargetObjectID(value._id as StatusPageResourceTargetValue)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface StatusPageResourceTarget {
|
|
78
|
+
monitorId: ObjectID | null;
|
|
79
|
+
monitorGroupId: ObjectID | null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Named after what the operator sees rather than what the column is, because
|
|
84
|
+
* this reads back to them on the resource form.
|
|
85
|
+
*/
|
|
86
|
+
function duplicateResourceException(
|
|
87
|
+
target: StatusPageResourceTarget,
|
|
88
|
+
): BadDataException {
|
|
89
|
+
const thing: string = target.monitorId ? "monitor" : "monitor group";
|
|
90
|
+
|
|
91
|
+
return new BadDataException(
|
|
92
|
+
`This ${thing} is already added to this status page. A ${thing} can only be added once so it is not shown twice to your customers.`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
20
96
|
export class Service extends DatabaseService<Model> {
|
|
21
97
|
public constructor() {
|
|
22
98
|
super(Model);
|
|
@@ -115,6 +191,76 @@ export class Service extends DatabaseService<Model> {
|
|
|
115
191
|
return statusPageResources;
|
|
116
192
|
}
|
|
117
193
|
|
|
194
|
+
/**
|
|
195
|
+
* The id of the thing a resource points at, whichever way the caller
|
|
196
|
+
* expressed it. The dashboard's resource form posts the relation
|
|
197
|
+
* (`monitor: { _id }`) while everything server side sets the foreign key
|
|
198
|
+
* column, and both mean the same resource.
|
|
199
|
+
*/
|
|
200
|
+
private getResourceMonitorTarget(
|
|
201
|
+
data: StatusPageResourceTargetInput,
|
|
202
|
+
): StatusPageResourceTarget {
|
|
203
|
+
return {
|
|
204
|
+
monitorId:
|
|
205
|
+
toTargetObjectID(data.monitorId) || toTargetObjectID(data.monitor),
|
|
206
|
+
monitorGroupId:
|
|
207
|
+
toTargetObjectID(data.monitorGroupId) ||
|
|
208
|
+
toTargetObjectID(data.monitorGroup),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* A status page lists a monitor once.
|
|
214
|
+
*
|
|
215
|
+
* Nothing stopped the same monitor being added twice, so re-adding a label's
|
|
216
|
+
* monitors after a new one joined that label created a second resource for
|
|
217
|
+
* every monitor already there, and the public page listed each of them twice
|
|
218
|
+
* (issue #3420). The rule engine has always refused to add a monitor that is
|
|
219
|
+
* already on the page for exactly this reason; this makes the same promise
|
|
220
|
+
* hold for every other way a resource is created - the resource form, the
|
|
221
|
+
* bulk add modal, and the API.
|
|
222
|
+
*
|
|
223
|
+
* The check is status-page-wide rather than per group: a monitor in two
|
|
224
|
+
* groups is still a monitor a visitor sees twice.
|
|
225
|
+
*/
|
|
226
|
+
@CaptureSpan()
|
|
227
|
+
public async isResourceAlreadyOnStatusPage(data: {
|
|
228
|
+
statusPageId: ObjectID;
|
|
229
|
+
monitorId?: ObjectID | null | undefined;
|
|
230
|
+
monitorGroupId?: ObjectID | null | undefined;
|
|
231
|
+
excludeResourceId?: ObjectID | null | undefined;
|
|
232
|
+
}): Promise<boolean> {
|
|
233
|
+
if (!data.monitorId && !data.monitorGroupId) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const query: Query<Model> = {
|
|
238
|
+
statusPageId: data.statusPageId,
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
if (data.monitorId) {
|
|
242
|
+
query.monitorId = data.monitorId;
|
|
243
|
+
} else {
|
|
244
|
+
query.monitorGroupId = data.monitorGroupId!;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (data.excludeResourceId) {
|
|
248
|
+
query._id = QueryHelper.notEquals(data.excludeResourceId.toString());
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const existingResource: Model | null = await this.findOneBy({
|
|
252
|
+
query: query,
|
|
253
|
+
select: {
|
|
254
|
+
_id: true,
|
|
255
|
+
},
|
|
256
|
+
props: {
|
|
257
|
+
isRoot: true,
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
return Boolean(existingResource);
|
|
262
|
+
}
|
|
263
|
+
|
|
118
264
|
@CaptureSpan()
|
|
119
265
|
protected override async onBeforeCreate(
|
|
120
266
|
createBy: CreateBy<Model>,
|
|
@@ -125,6 +271,20 @@ export class Service extends DatabaseService<Model> {
|
|
|
125
271
|
);
|
|
126
272
|
}
|
|
127
273
|
|
|
274
|
+
const target: StatusPageResourceTarget = this.getResourceMonitorTarget(
|
|
275
|
+
createBy.data as unknown as StatusPageResourceTargetInput,
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
if (
|
|
279
|
+
await this.isResourceAlreadyOnStatusPage({
|
|
280
|
+
statusPageId: createBy.data.statusPageId,
|
|
281
|
+
monitorId: target.monitorId,
|
|
282
|
+
monitorGroupId: target.monitorGroupId,
|
|
283
|
+
})
|
|
284
|
+
) {
|
|
285
|
+
throw duplicateResourceException(target);
|
|
286
|
+
}
|
|
287
|
+
|
|
128
288
|
if (!createBy.data.order) {
|
|
129
289
|
const query: Query<Model> = {
|
|
130
290
|
statusPageId: createBy.data.statusPageId,
|
|
@@ -222,6 +382,69 @@ export class Service extends DatabaseService<Model> {
|
|
|
222
382
|
protected override async onBeforeUpdate(
|
|
223
383
|
updateBy: UpdateBy<Model>,
|
|
224
384
|
): Promise<OnUpdate<Model>> {
|
|
385
|
+
/*
|
|
386
|
+
* Pointing an existing resource at a monitor the page already lists is the
|
|
387
|
+
* same duplicate onBeforeCreate refuses, just reached from the edit form.
|
|
388
|
+
*/
|
|
389
|
+
const updatedTarget: StatusPageResourceTarget =
|
|
390
|
+
this.getResourceMonitorTarget(
|
|
391
|
+
updateBy.data as unknown as StatusPageResourceTargetInput,
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
if (
|
|
395
|
+
(updatedTarget.monitorId || updatedTarget.monitorGroupId) &&
|
|
396
|
+
updateBy.query._id
|
|
397
|
+
) {
|
|
398
|
+
const resourceBeingUpdated: Model | null = await this.findOneBy({
|
|
399
|
+
query: {
|
|
400
|
+
_id: updateBy.query._id!,
|
|
401
|
+
},
|
|
402
|
+
props: {
|
|
403
|
+
isRoot: true,
|
|
404
|
+
},
|
|
405
|
+
select: {
|
|
406
|
+
_id: true,
|
|
407
|
+
statusPageId: true,
|
|
408
|
+
monitorId: true,
|
|
409
|
+
monitorGroupId: true,
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
const currentTarget: StatusPageResourceTarget =
|
|
414
|
+
this.getResourceMonitorTarget(
|
|
415
|
+
(resourceBeingUpdated ||
|
|
416
|
+
{}) as unknown as StatusPageResourceTargetInput,
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
/*
|
|
420
|
+
* The edit form is a ModelForm, so it posts every field it collects -
|
|
421
|
+
* the monitor included - even when all the operator changed was the
|
|
422
|
+
* display name. Checking an unchanged target would refuse those saves
|
|
423
|
+
* on a status page that already carries a duplicate from before this
|
|
424
|
+
* rule existed, which would leave both of its rows uneditable.
|
|
425
|
+
*/
|
|
426
|
+
const isTargetUnchanged: boolean =
|
|
427
|
+
(!updatedTarget.monitorId ||
|
|
428
|
+
updatedTarget.monitorId.toString() ===
|
|
429
|
+
currentTarget.monitorId?.toString()) &&
|
|
430
|
+
(!updatedTarget.monitorGroupId ||
|
|
431
|
+
updatedTarget.monitorGroupId.toString() ===
|
|
432
|
+
currentTarget.monitorGroupId?.toString());
|
|
433
|
+
|
|
434
|
+
if (
|
|
435
|
+
resourceBeingUpdated?.statusPageId &&
|
|
436
|
+
!isTargetUnchanged &&
|
|
437
|
+
(await this.isResourceAlreadyOnStatusPage({
|
|
438
|
+
statusPageId: resourceBeingUpdated.statusPageId,
|
|
439
|
+
monitorId: updatedTarget.monitorId,
|
|
440
|
+
monitorGroupId: updatedTarget.monitorGroupId,
|
|
441
|
+
excludeResourceId: resourceBeingUpdated.id,
|
|
442
|
+
}))
|
|
443
|
+
) {
|
|
444
|
+
throw duplicateResourceException(updatedTarget);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
225
448
|
if (updateBy.data.order && !updateBy.props.isRoot && updateBy.query._id) {
|
|
226
449
|
const resource: Model | null = await this.findOneBy({
|
|
227
450
|
query: {
|
|
@@ -4,6 +4,7 @@ import LogDatabaseService from "./LogService";
|
|
|
4
4
|
import MetricDatabaseService from "./MetricService";
|
|
5
5
|
import SpanDatabaseService from "./SpanService";
|
|
6
6
|
import ExceptionInstanceService from "./ExceptionInstanceService";
|
|
7
|
+
import SecurityEventService from "./SecurityEventService";
|
|
7
8
|
import MutableMetricDatabaseService, {
|
|
8
9
|
MutableMetricService as MutableMetricServiceClass,
|
|
9
10
|
} from "./MutableMetricService";
|
|
@@ -101,6 +102,22 @@ export class TelemetryAttributeService {
|
|
|
101
102
|
attributeKeysColumn: "attributeKeys",
|
|
102
103
|
timeColumn: "time",
|
|
103
104
|
};
|
|
105
|
+
/*
|
|
106
|
+
* Security events carry the whole source payload flattened into
|
|
107
|
+
* `attributes`, which is where every field the OCSF schema does not
|
|
108
|
+
* have a typed column for ends up (device.hostname,
|
|
109
|
+
* finding_info.title, metadata.product.name, ...). The security
|
|
110
|
+
* events table offers those as optional columns, and this is the
|
|
111
|
+
* list it offers.
|
|
112
|
+
*/
|
|
113
|
+
case TelemetryType.SecurityEvent:
|
|
114
|
+
return {
|
|
115
|
+
service: SecurityEventService,
|
|
116
|
+
tableName: SecurityEventService.model.tableName,
|
|
117
|
+
attributesColumn: "attributes",
|
|
118
|
+
attributeKeysColumn: "attributeKeys",
|
|
119
|
+
timeColumn: "time",
|
|
120
|
+
};
|
|
104
121
|
default:
|
|
105
122
|
return null;
|
|
106
123
|
}
|
|
@@ -42,7 +42,9 @@ import TeamMember from "../../Models/DatabaseModels/TeamMember";
|
|
|
42
42
|
import Model from "../../Models/DatabaseModels/User";
|
|
43
43
|
import SlackUtil from "../Utils/Workspace/Slack/Slack";
|
|
44
44
|
import ProductAnalytics from "../Utils/ProductAnalytics";
|
|
45
|
-
import MarketingEventUtil
|
|
45
|
+
import MarketingEventUtil, {
|
|
46
|
+
utmAnalyticsProperties,
|
|
47
|
+
} from "../Utils/Marketing/MarketingEventUtil";
|
|
46
48
|
import { MarketingEventType } from "../../Types/Marketing/MarketingEvent";
|
|
47
49
|
import UserTotpAuthService from "./UserTotpAuthService";
|
|
48
50
|
import UserTwoFactorBackupCodeService from "./UserTwoFactorBackupCodeService";
|
|
@@ -242,11 +244,7 @@ export class Service extends DatabaseService<Model> {
|
|
|
242
244
|
distinctId: createdItem.email.toString(),
|
|
243
245
|
properties: {
|
|
244
246
|
has_password: Boolean(createdItem.password),
|
|
245
|
-
|
|
246
|
-
utm_medium: createdItem.utmMedium || "",
|
|
247
|
-
utm_campaign: createdItem.utmCampaign || "",
|
|
248
|
-
utm_term: createdItem.utmTerm || "",
|
|
249
|
-
utm_content: createdItem.utmContent || "",
|
|
247
|
+
...utmAnalyticsProperties(createdItem as unknown as JSONObject),
|
|
250
248
|
utm_url: createdItem.utmUrl || "",
|
|
251
249
|
click_ids: createdItem.clickIds || {},
|
|
252
250
|
first_touch: createdItem.firstTouchAttribution || {},
|
package/Server/Types/Markdown.ts
CHANGED
|
@@ -246,6 +246,68 @@ export default class Markdown {
|
|
|
246
246
|
return markdownSlugify(text);
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
+
/*
|
|
250
|
+
* Human-readable names for the languages a docs code fence can declare.
|
|
251
|
+
* Rendered into the code block's header bar. A fence with no language, or
|
|
252
|
+
* one that is not listed here, gets no label rather than a guess — the
|
|
253
|
+
* label used to come from highlight.js auto-detection, which cheerfully
|
|
254
|
+
* announced shell snippets as "PHP".
|
|
255
|
+
*/
|
|
256
|
+
private static readonly codeLanguageNames: Record<string, string> = {
|
|
257
|
+
apache: "Apache",
|
|
258
|
+
bash: "Bash",
|
|
259
|
+
c: "C",
|
|
260
|
+
cpp: "C++",
|
|
261
|
+
csharp: "C#",
|
|
262
|
+
css: "CSS",
|
|
263
|
+
diff: "Diff",
|
|
264
|
+
dns: "DNS Zone",
|
|
265
|
+
docker: "Dockerfile",
|
|
266
|
+
dockerfile: "Dockerfile",
|
|
267
|
+
go: "Go",
|
|
268
|
+
graphql: "GraphQL",
|
|
269
|
+
groovy: "Groovy",
|
|
270
|
+
hcl: "HCL",
|
|
271
|
+
html: "HTML",
|
|
272
|
+
http: "HTTP",
|
|
273
|
+
ini: "INI",
|
|
274
|
+
java: "Java",
|
|
275
|
+
javascript: "JavaScript",
|
|
276
|
+
js: "JavaScript",
|
|
277
|
+
json: "JSON",
|
|
278
|
+
jsx: "JSX",
|
|
279
|
+
kotlin: "Kotlin",
|
|
280
|
+
lua: "Lua",
|
|
281
|
+
makefile: "Makefile",
|
|
282
|
+
markdown: "Markdown",
|
|
283
|
+
md: "Markdown",
|
|
284
|
+
nginx: "Nginx",
|
|
285
|
+
perl: "Perl",
|
|
286
|
+
php: "PHP",
|
|
287
|
+
powershell: "PowerShell",
|
|
288
|
+
proto: "Protobuf",
|
|
289
|
+
py: "Python",
|
|
290
|
+
python: "Python",
|
|
291
|
+
r: "R",
|
|
292
|
+
rb: "Ruby",
|
|
293
|
+
ruby: "Ruby",
|
|
294
|
+
rust: "Rust",
|
|
295
|
+
scala: "Scala",
|
|
296
|
+
sh: "Shell",
|
|
297
|
+
shell: "Shell",
|
|
298
|
+
sql: "SQL",
|
|
299
|
+
swift: "Swift",
|
|
300
|
+
terraform: "Terraform",
|
|
301
|
+
toml: "TOML",
|
|
302
|
+
ts: "TypeScript",
|
|
303
|
+
tsx: "TSX",
|
|
304
|
+
typescript: "TypeScript",
|
|
305
|
+
xml: "XML",
|
|
306
|
+
yaml: "YAML",
|
|
307
|
+
yml: "YAML",
|
|
308
|
+
zsh: "Shell",
|
|
309
|
+
};
|
|
310
|
+
|
|
249
311
|
private static getDocsRenderer(): Renderer {
|
|
250
312
|
if (this.docsRenderer !== null) {
|
|
251
313
|
return this.docsRenderer;
|
|
@@ -253,8 +315,16 @@ export default class Markdown {
|
|
|
253
315
|
|
|
254
316
|
const renderer: Renderer = new Renderer();
|
|
255
317
|
|
|
318
|
+
/*
|
|
319
|
+
* The docs renderer emits semantic markup with a small set of stable class
|
|
320
|
+
* names and leaves every colour, size and spacing decision to
|
|
321
|
+
* Docs/Static/css/style.css. Utility classes used to be baked in here,
|
|
322
|
+
* which meant the same element was styled from two places at once and made
|
|
323
|
+
* a dark theme impossible without editing this file.
|
|
324
|
+
*/
|
|
325
|
+
|
|
256
326
|
renderer.paragraph = function (text) {
|
|
257
|
-
return `<p
|
|
327
|
+
return `<p>${text}</p>`;
|
|
258
328
|
};
|
|
259
329
|
|
|
260
330
|
renderer.blockquote = function (quote) {
|
|
@@ -264,130 +334,154 @@ export default class Markdown {
|
|
|
264
334
|
|
|
265
335
|
if (calloutMatch) {
|
|
266
336
|
const type: string = calloutMatch[1]!.toLowerCase();
|
|
267
|
-
const configMap: Record<
|
|
268
|
-
string,
|
|
269
|
-
{ border: string; bg: string; icon: string; label: string }
|
|
270
|
-
> = {
|
|
337
|
+
const configMap: Record<string, { icon: string; label: string }> = {
|
|
271
338
|
note: {
|
|
272
|
-
|
|
273
|
-
bg: "bg-blue-50",
|
|
274
|
-
icon: `<svg class="h-5 w-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>`,
|
|
339
|
+
icon: `<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>`,
|
|
275
340
|
label: "Note",
|
|
276
341
|
},
|
|
277
342
|
info: {
|
|
278
|
-
|
|
279
|
-
bg: "bg-blue-50",
|
|
280
|
-
icon: `<svg class="h-5 w-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>`,
|
|
343
|
+
icon: `<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>`,
|
|
281
344
|
label: "Info",
|
|
282
345
|
},
|
|
283
346
|
tip: {
|
|
284
|
-
|
|
285
|
-
bg: "bg-green-50",
|
|
286
|
-
icon: `<svg class="h-5 w-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>`,
|
|
347
|
+
icon: `<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/>`,
|
|
287
348
|
label: "Tip",
|
|
288
349
|
},
|
|
289
350
|
warning: {
|
|
290
|
-
|
|
291
|
-
bg: "bg-yellow-50",
|
|
292
|
-
icon: `<svg class="h-5 w-5 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/></svg>`,
|
|
351
|
+
icon: `<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/>`,
|
|
293
352
|
label: "Warning",
|
|
294
353
|
},
|
|
295
354
|
caution: {
|
|
296
|
-
|
|
297
|
-
bg: "bg-yellow-50",
|
|
298
|
-
icon: `<svg class="h-5 w-5 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/></svg>`,
|
|
355
|
+
icon: `<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/>`,
|
|
299
356
|
label: "Caution",
|
|
300
357
|
},
|
|
301
358
|
danger: {
|
|
302
|
-
|
|
303
|
-
bg: "bg-red-50",
|
|
304
|
-
icon: `<svg class="h-5 w-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>`,
|
|
359
|
+
icon: `<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>`,
|
|
305
360
|
label: "Danger",
|
|
306
361
|
},
|
|
307
362
|
};
|
|
308
363
|
|
|
309
|
-
const config: {
|
|
310
|
-
|
|
311
|
-
bg: string;
|
|
312
|
-
icon: string;
|
|
313
|
-
label: string;
|
|
314
|
-
} = configMap[type] || configMap["note"]!;
|
|
364
|
+
const config: { icon: string; label: string } =
|
|
365
|
+
configMap[type] || configMap["note"]!;
|
|
315
366
|
|
|
316
367
|
const content: string = quote.replace(
|
|
317
368
|
/<p[^>]*>\s*<strong>(Note|Warning|Tip|Danger|Info|Caution):?<\/strong>\s*/i,
|
|
318
|
-
|
|
369
|
+
"<p>",
|
|
319
370
|
);
|
|
320
371
|
|
|
321
|
-
return `<div class="callout callout
|
|
322
|
-
<div class="
|
|
323
|
-
|
|
324
|
-
<span class="
|
|
372
|
+
return `<div class="docs-callout docs-callout--${type}">
|
|
373
|
+
<div class="docs-callout__head">
|
|
374
|
+
<svg class="docs-callout__icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">${config.icon}</svg>
|
|
375
|
+
<span class="docs-callout__label">${config.label}</span>
|
|
325
376
|
</div>
|
|
326
|
-
<div class="
|
|
377
|
+
<div class="docs-callout__body">${content}</div>
|
|
327
378
|
</div>`;
|
|
328
379
|
}
|
|
329
380
|
|
|
330
|
-
return `<blockquote class="
|
|
331
|
-
<div class="leading-8 text-gray-600">${quote}</div>
|
|
332
|
-
</blockquote>`;
|
|
381
|
+
return `<blockquote class="docs-quote">${quote}</blockquote>`;
|
|
333
382
|
};
|
|
334
383
|
|
|
335
|
-
renderer.image = function (href,
|
|
336
|
-
|
|
384
|
+
renderer.image = function (href, title, text) {
|
|
385
|
+
const titleAttr: string = title
|
|
386
|
+
? ` title="${Markdown.escapeHtml(title)}"`
|
|
387
|
+
: "";
|
|
388
|
+
return `<img src="${href}" alt="${text || ""}"${titleAttr} class="docs-image" loading="lazy" decoding="async" />`;
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
renderer.link = function (href, title, text) {
|
|
392
|
+
if (!href) {
|
|
393
|
+
return text as string;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const target: string = href.toLowerCase();
|
|
397
|
+
const isExternal: boolean =
|
|
398
|
+
(target.startsWith("http://") || target.startsWith("https://")) &&
|
|
399
|
+
!target.includes("oneuptime.com");
|
|
400
|
+
const titleAttr: string = title
|
|
401
|
+
? ` title="${Markdown.escapeHtml(title)}"`
|
|
402
|
+
: "";
|
|
403
|
+
const externalAttrs: string = isExternal
|
|
404
|
+
? ' target="_blank" rel="noopener noreferrer"'
|
|
405
|
+
: "";
|
|
406
|
+
const marker: string = isExternal
|
|
407
|
+
? '<svg class="docs-link__external" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>'
|
|
408
|
+
: "";
|
|
409
|
+
|
|
410
|
+
return `<a class="docs-link" href="${href}"${titleAttr}${externalAttrs}>${text}${marker}</a>`;
|
|
337
411
|
};
|
|
338
412
|
|
|
339
413
|
renderer.code = function (code, language) {
|
|
340
|
-
|
|
341
|
-
|
|
414
|
+
const lang: string = (language || "").trim().toLowerCase();
|
|
415
|
+
|
|
416
|
+
if (lang === "mermaid") {
|
|
417
|
+
/*
|
|
418
|
+
* Mermaid reads the diagram from textContent, so escaping here keeps
|
|
419
|
+
* the diagram identical while making sure a `<` in a node label can
|
|
420
|
+
* never be parsed as markup.
|
|
421
|
+
*/
|
|
422
|
+
return `<div class="docs-diagram"><div class="mermaid">${Markdown.escapeHtml(code)}</div></div>`;
|
|
342
423
|
}
|
|
424
|
+
|
|
343
425
|
const escaped: string = Markdown.escapeHtml(code);
|
|
344
|
-
|
|
426
|
+
const label: string | undefined = Markdown.codeLanguageNames[lang];
|
|
427
|
+
/*
|
|
428
|
+
* `nohighlight` stops highlight.js auto-detecting a language for fences
|
|
429
|
+
* that never declared one — plain text is honest, a wrong grammar is not.
|
|
430
|
+
*/
|
|
431
|
+
const codeClass: string = lang ? `language-${lang}` : "nohighlight";
|
|
432
|
+
/*
|
|
433
|
+
* The copy button ships hidden and the page's script unhides it once it
|
|
434
|
+
* has wired up the click handler and filled in the translated label —
|
|
435
|
+
* without scripting it would be a dead control with an English name.
|
|
436
|
+
* The bar reserves its height either way, so nothing shifts.
|
|
437
|
+
*/
|
|
438
|
+
const bar: string = `<div class="docs-code__bar">
|
|
439
|
+
<span class="docs-code__lang">${label || ""}</span>
|
|
440
|
+
<button type="button" class="docs-code__copy" data-copy-code hidden>
|
|
441
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>
|
|
442
|
+
<span class="docs-code__copy-text"></span>
|
|
443
|
+
</button>
|
|
444
|
+
</div>`;
|
|
445
|
+
|
|
446
|
+
return `<div class="docs-code"${lang ? ` data-language="${lang}"` : ""}>${bar}<pre><code class="${codeClass}">${escaped}</code></pre></div>`;
|
|
345
447
|
};
|
|
346
448
|
|
|
347
449
|
renderer.heading = function (text, level) {
|
|
348
450
|
const slug: string = Markdown.slugify(text);
|
|
349
451
|
const anchor: string =
|
|
350
|
-
level
|
|
351
|
-
? `<a href="#${slug}"
|
|
452
|
+
level >= 2 && level <= 4
|
|
453
|
+
? `<a class="docs-anchor" href="#${slug}" aria-hidden="true" tabindex="-1">#</a>`
|
|
352
454
|
: "";
|
|
353
455
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
return `<h4 id="${slug}" class="my-5 mt-8 text-xl font-bold tracking-tight text-gray-800">${text}</h4>`;
|
|
362
|
-
} else if (level === 5) {
|
|
363
|
-
return `<h5 id="${slug}" class="my-5 mt-8 text-lg font-bold tracking-tight text-gray-800">${text}</h5>`;
|
|
364
|
-
}
|
|
365
|
-
return `<h6 id="${slug}" class="my-5 tracking-tight font-bold text-gray-800">${text}</h6>`;
|
|
456
|
+
const safeLevel: number = Math.min(Math.max(level, 1), 6);
|
|
457
|
+
|
|
458
|
+
return `<h${safeLevel} id="${slug}" class="docs-heading docs-h${safeLevel}"><span class="docs-heading__text">${text}</span>${anchor}</h${safeLevel}>`;
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
renderer.hr = function () {
|
|
462
|
+
return '<hr class="docs-hr" />';
|
|
366
463
|
};
|
|
367
464
|
|
|
368
465
|
renderer.table = function (header, body) {
|
|
369
|
-
return `<div class="docs-table-wrapper
|
|
370
|
-
<table class="min-w-full text-sm text-left">${header}${body}</table>
|
|
371
|
-
</div>`;
|
|
466
|
+
return `<div class="docs-table-wrapper" tabindex="0"><table class="docs-table">${header}${body}</table></div>`;
|
|
372
467
|
};
|
|
373
468
|
|
|
374
469
|
renderer.tablerow = function (content) {
|
|
375
|
-
return `<tr
|
|
470
|
+
return `<tr>${content}</tr>`;
|
|
376
471
|
};
|
|
377
472
|
|
|
378
473
|
renderer.tablecell = function (content, flags) {
|
|
379
474
|
const tag: string = flags.header ? "th" : "td";
|
|
380
|
-
const align: string = flags.align
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
return `<${tag} class="px-4 py-2.5${align}${headerClass}">${content}</${tag}>`;
|
|
475
|
+
const align: string = flags.align
|
|
476
|
+
? ` style="text-align:${flags.align}"`
|
|
477
|
+
: "";
|
|
478
|
+
return `<${tag}${align}>${content}</${tag}>`;
|
|
385
479
|
};
|
|
386
480
|
|
|
387
481
|
// Inline code
|
|
388
482
|
renderer.codespan = function (code) {
|
|
389
483
|
const escaped: string = Markdown.escapeHtml(code);
|
|
390
|
-
return `<code class="
|
|
484
|
+
return `<code class="docs-code-inline">${escaped}</code>`;
|
|
391
485
|
};
|
|
392
486
|
|
|
393
487
|
this.docsRenderer = renderer;
|
|
@@ -553,10 +553,18 @@ export const QueryOnCallPoliciesTool: ObservabilityTool = {
|
|
|
553
553
|
*/
|
|
554
554
|
|
|
555
555
|
/*
|
|
556
|
-
* Roster fields are persisted on the schedule and refreshed
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
556
|
+
* Roster fields are persisted on the schedule and refreshed by the
|
|
557
|
+
* RefreshHandoffTime worker — the same source the dashboard's "On Call Now"
|
|
558
|
+
* column reads. Reading them costs one RBAC-checked query instead of
|
|
559
|
+
* re-resolving schedule layers per request.
|
|
560
|
+
*
|
|
561
|
+
* They include user overrides, with one documented limit: the roster is
|
|
562
|
+
* resolved in a policy's context only when the schedule is attached to exactly
|
|
563
|
+
* one on-call policy (OnCallDutyPolicyScheduleService.getSingleAttachedPolicyId).
|
|
564
|
+
* A schedule shared by two or more policies gets a policy-blind roster —
|
|
565
|
+
* global overrides only — because a single stored roster cannot represent
|
|
566
|
+
* divergent per-policy substitutions. Alert routing always resolves live with
|
|
567
|
+
* the escalating policy's id, so it is unaffected.
|
|
560
568
|
*/
|
|
561
569
|
const scheduleRosterSelect: Select<OnCallDutyPolicySchedule> = {
|
|
562
570
|
_id: true,
|
|
@@ -26,6 +26,18 @@ export type StatementParameter = {
|
|
|
26
26
|
value: RecordValue;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
/*
|
|
30
|
+
* Escape LIKE/ILIKE metacharacters so a user-supplied value matches
|
|
31
|
+
* literally. Without this, "svc_" matches svcX (a false positive) and a
|
|
32
|
+
* value containing "%" silently corrupts the whole pattern — the worst
|
|
33
|
+
* possible failure mode for a security-events filter. ClickHouse honors
|
|
34
|
+
* backslash escapes inside (I)LIKE patterns; backslash itself must be
|
|
35
|
+
* escaped first.
|
|
36
|
+
*/
|
|
37
|
+
export function escapeIlikePattern(value: string): string {
|
|
38
|
+
return value.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
39
|
+
}
|
|
40
|
+
|
|
29
41
|
/**
|
|
30
42
|
* A table-qualified column reference (`table.column`) bound as TWO
|
|
31
43
|
* Identifier parameters. ClickHouse treats a dotted string bound as a
|
|
@@ -133,7 +145,7 @@ export class Statement implements BaseQueryParams {
|
|
|
133
145
|
} else if (v.value instanceof ObjectID) {
|
|
134
146
|
finalValue = v.value.toString();
|
|
135
147
|
} else if (v.value instanceof Search) {
|
|
136
|
-
finalValue = `%${v.value.toString()}%`;
|
|
148
|
+
finalValue = `%${escapeIlikePattern(v.value.toString())}%`;
|
|
137
149
|
} else if (
|
|
138
150
|
v.value instanceof LessThan ||
|
|
139
151
|
v.value instanceof LessThanOrEqual ||
|