@oneuptime/common 12.0.23 → 12.0.24
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/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/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/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 +130 -0
- 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/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/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/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 +368 -4
- package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +245 -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 +193 -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 +472 -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/LlmMetricConventions.ts +124 -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 +204 -0
- 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/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/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 +102 -0
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
- 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/LlmMetricConventions.js +98 -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 +119 -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
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
1
2
|
import React from "react";
|
|
2
3
|
import { fireEvent, render, screen } from "@testing-library/react";
|
|
3
|
-
import { describe, expect, test } from "@jest/globals";
|
|
4
|
+
import { beforeEach, describe, expect, test } from "@jest/globals";
|
|
4
5
|
import CodeType from "../../../Types/Code/CodeType";
|
|
5
6
|
|
|
6
7
|
/*
|
|
@@ -13,10 +14,28 @@ import CodeType from "../../../Types/Code/CodeType";
|
|
|
13
14
|
interface RecordedEditorProps {
|
|
14
15
|
value?: string | undefined;
|
|
15
16
|
defaultValue?: string | undefined;
|
|
17
|
+
/*
|
|
18
|
+
* The grammar Monaco would tokenise with, and the option bag it would be
|
|
19
|
+
* configured from. Both are recorded because for YAML they are the feature:
|
|
20
|
+
* the wrong grammar highlights a Sigma rule as HTML, and the wrong
|
|
21
|
+
* indentation options emit tabs the parser rejects.
|
|
22
|
+
*/
|
|
23
|
+
defaultLanguage?: string | undefined;
|
|
24
|
+
language?: string | undefined;
|
|
25
|
+
height?: string | undefined;
|
|
26
|
+
options?: Record<string, unknown> | undefined;
|
|
16
27
|
}
|
|
17
28
|
|
|
18
29
|
const mockEditorRenders: Array<RecordedEditorProps> = [];
|
|
19
30
|
|
|
31
|
+
/*
|
|
32
|
+
* Everything the component pushes onto the MODEL rather than into the options
|
|
33
|
+
* bag. tabSize/insertSpaces live here on purpose - they are global config in
|
|
34
|
+
* monaco's standalone build, so setting them per-editor would have the last
|
|
35
|
+
* editor to mount dictate indentation for every other one on the page.
|
|
36
|
+
*/
|
|
37
|
+
const mockModelOptionUpdates: Array<Record<string, unknown>> = [];
|
|
38
|
+
|
|
20
39
|
jest.mock("@monaco-editor/react", () => {
|
|
21
40
|
return {
|
|
22
41
|
__esModule: true,
|
|
@@ -26,23 +45,65 @@ jest.mock("@monaco-editor/react", () => {
|
|
|
26
45
|
default: (editorProps: {
|
|
27
46
|
value?: string | undefined;
|
|
28
47
|
defaultValue?: string | undefined;
|
|
48
|
+
defaultLanguage?: string | undefined;
|
|
49
|
+
language?: string | undefined;
|
|
50
|
+
height?: string | undefined;
|
|
51
|
+
options?: Record<string, unknown> | undefined;
|
|
29
52
|
onChange?: ((value: string | undefined) => void) | undefined;
|
|
53
|
+
onMount?: ((editor: unknown, monaco: unknown) => void) | undefined;
|
|
30
54
|
}) => {
|
|
31
55
|
mockEditorRenders.push({
|
|
32
56
|
value: editorProps.value,
|
|
33
57
|
defaultValue: editorProps.defaultValue,
|
|
58
|
+
defaultLanguage: editorProps.defaultLanguage,
|
|
59
|
+
language: editorProps.language,
|
|
60
|
+
height: editorProps.height,
|
|
61
|
+
options: editorProps.options,
|
|
34
62
|
});
|
|
35
63
|
|
|
64
|
+
const hostRef: React.MutableRefObject<HTMLDivElement | null> =
|
|
65
|
+
React.useRef<HTMLDivElement | null>(null);
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* Monaco calls onMount once the editor and its model exist. Child
|
|
69
|
+
* effects run before the parent's, which is the same order the real
|
|
70
|
+
* editor mounts in.
|
|
71
|
+
*/
|
|
72
|
+
React.useEffect(() => {
|
|
73
|
+
if (!editorProps.onMount) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
editorProps.onMount(
|
|
78
|
+
{
|
|
79
|
+
getDomNode: () => {
|
|
80
|
+
return hostRef.current;
|
|
81
|
+
},
|
|
82
|
+
getModel: () => {
|
|
83
|
+
return {
|
|
84
|
+
updateOptions: (options: Record<string, unknown>) => {
|
|
85
|
+
mockModelOptionUpdates.push(options);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{},
|
|
91
|
+
);
|
|
92
|
+
// eslint-disable-next-line
|
|
93
|
+
}, []);
|
|
94
|
+
|
|
36
95
|
return (
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
editorProps.onChange
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
96
|
+
<div ref={hostRef}>
|
|
97
|
+
<textarea
|
|
98
|
+
data-testid="monaco"
|
|
99
|
+
value={editorProps.value || ""}
|
|
100
|
+
onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
101
|
+
if (editorProps.onChange) {
|
|
102
|
+
editorProps.onChange(event.target.value);
|
|
103
|
+
}
|
|
104
|
+
}}
|
|
105
|
+
/>
|
|
106
|
+
</div>
|
|
46
107
|
);
|
|
47
108
|
},
|
|
48
109
|
};
|
|
@@ -172,3 +233,406 @@ describe("CodeEditor", () => {
|
|
|
172
233
|
expect(getEditor().value).toBe(JSON.stringify({ hello: "world" }, null, 4));
|
|
173
234
|
});
|
|
174
235
|
});
|
|
236
|
+
|
|
237
|
+
type LastRenderFunction = () => RecordedEditorProps;
|
|
238
|
+
|
|
239
|
+
const lastRender: LastRenderFunction = (): RecordedEditorProps => {
|
|
240
|
+
expect(mockEditorRenders.length).toBeGreaterThan(0);
|
|
241
|
+
|
|
242
|
+
return mockEditorRenders[mockEditorRenders.length - 1] as RecordedEditorProps;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
describe("CodeEditor — the grammar Monaco is given", () => {
|
|
246
|
+
beforeEach(() => {
|
|
247
|
+
mockEditorRenders.length = 0;
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test.each([
|
|
251
|
+
[CodeType.YAML, "yaml"],
|
|
252
|
+
[CodeType.JSON, "json"],
|
|
253
|
+
[CodeType.JavaScript, "javascript"],
|
|
254
|
+
[CodeType.CSS, "css"],
|
|
255
|
+
[CodeType.HTML, "html"],
|
|
256
|
+
[CodeType.Markdown, "markdown"],
|
|
257
|
+
])("%s is handed to Monaco as %s", (type: CodeType, expected: string) => {
|
|
258
|
+
render(<CodeEditor type={type} value="" />);
|
|
259
|
+
|
|
260
|
+
expect(lastRender().defaultLanguage).toBe(expected);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
/*
|
|
264
|
+
* `defaultLanguage` is only read when the model is created, so a caller that
|
|
265
|
+
* swaps CodeType after mount keeps the old grammar unless `language` is also
|
|
266
|
+
* passed - the prop that drives setModelLanguage.
|
|
267
|
+
*/
|
|
268
|
+
test("the language prop is passed too, so a type change after mount lands", () => {
|
|
269
|
+
const { rerender } = render(<CodeEditor type={CodeType.Text} value="" />);
|
|
270
|
+
|
|
271
|
+
expect(lastRender().language).toBe("text");
|
|
272
|
+
|
|
273
|
+
rerender(<CodeEditor type={CodeType.YAML} value="" />);
|
|
274
|
+
|
|
275
|
+
expect(lastRender().language).toBe("yaml");
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe("CodeEditor — YAML gets YAML-safe editing options", () => {
|
|
280
|
+
beforeEach(() => {
|
|
281
|
+
mockEditorRenders.length = 0;
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
type YamlOptionsFunction = () => Record<string, unknown>;
|
|
285
|
+
|
|
286
|
+
const yamlOptions: YamlOptionsFunction = (): Record<string, unknown> => {
|
|
287
|
+
render(<CodeEditor type={CodeType.YAML} value="title: x" />);
|
|
288
|
+
|
|
289
|
+
return (lastRender().options || {}) as Record<string, unknown>;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
/*
|
|
293
|
+
* A literal tab is illegal as YAML indentation, and Monaco's model defaults
|
|
294
|
+
* are four spaces with the indentation detected from the initial content -
|
|
295
|
+
* so a rule pasted in tab-indented would keep emitting tabs the parser
|
|
296
|
+
* rejects.
|
|
297
|
+
*/
|
|
298
|
+
test("two spaces, always spaces - set on this editor's own model", () => {
|
|
299
|
+
mockModelOptionUpdates.length = 0;
|
|
300
|
+
|
|
301
|
+
render(<CodeEditor type={CodeType.YAML} value={"a:\n b: 1"} />);
|
|
302
|
+
|
|
303
|
+
expect(mockModelOptionUpdates).toContainEqual({
|
|
304
|
+
tabSize: 2,
|
|
305
|
+
insertSpaces: true,
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
/*
|
|
310
|
+
* The regression guard for the reason those three live on the model.
|
|
311
|
+
* tabSize, insertSpaces and detectIndentation are IGlobalEditorOptions:
|
|
312
|
+
* monaco's standalone editor writes every registered `editor.*` key it is
|
|
313
|
+
* constructed with into a PROCESS-WIDE configuration service, and those
|
|
314
|
+
* three are exactly the ones ModelService reads back and pushes onto every
|
|
315
|
+
* model on the page. Put them in the options bag and the last editor to
|
|
316
|
+
* mount silently re-indents all the others.
|
|
317
|
+
*/
|
|
318
|
+
test.each(["tabSize", "insertSpaces", "detectIndentation"])(
|
|
319
|
+
"%s is never passed as an editor option - it is global config",
|
|
320
|
+
(key: string) => {
|
|
321
|
+
for (const type of [
|
|
322
|
+
CodeType.YAML,
|
|
323
|
+
CodeType.JSON,
|
|
324
|
+
CodeType.JavaScript,
|
|
325
|
+
CodeType.Markdown,
|
|
326
|
+
CodeType.Text,
|
|
327
|
+
]) {
|
|
328
|
+
mockEditorRenders.length = 0;
|
|
329
|
+
|
|
330
|
+
render(<CodeEditor type={type} value="x" />);
|
|
331
|
+
|
|
332
|
+
expect(
|
|
333
|
+
Object.keys((lastRender().options || {}) as Record<string, unknown>),
|
|
334
|
+
).not.toContain(key);
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
test("a non-YAML editor touches no model options at all", () => {
|
|
340
|
+
mockModelOptionUpdates.length = 0;
|
|
341
|
+
|
|
342
|
+
render(<CodeEditor type={CodeType.JSON} value="{}" />);
|
|
343
|
+
|
|
344
|
+
expect(mockModelOptionUpdates).toHaveLength(0);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test("the YAML chrome's padding is supplied by the editor", () => {
|
|
348
|
+
expect(yamlOptions()["padding"]).toEqual({ top: 10, bottom: 10 });
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test("the gutter is on, because every parse error names a line", () => {
|
|
352
|
+
expect(yamlOptions()["lineNumbers"]).toBe("on");
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
/*
|
|
356
|
+
* Wrapping YAML is not an option - the indentation IS the syntax and a
|
|
357
|
+
* wrapped line reads as a deeper one - so the horizontal scrollbar is the
|
|
358
|
+
* only way to reach a long scalar.
|
|
359
|
+
*/
|
|
360
|
+
test("long lines stay reachable: no wrapping, but a real scrollbar", () => {
|
|
361
|
+
const options: Record<string, unknown> = yamlOptions();
|
|
362
|
+
|
|
363
|
+
expect(options["wordWrap"]).toBe("off");
|
|
364
|
+
expect(options["scrollbar"]).toEqual({ horizontal: "auto" });
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
test("whitespace is rendered, because in YAML it is the syntax", () => {
|
|
368
|
+
expect(yamlOptions()["renderWhitespace"]).toBe("boundary");
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
test("no blank runway below the last line in a short form field", () => {
|
|
372
|
+
expect(yamlOptions()["scrollBeyondLastLine"]).toBe(false);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
test("folding is on, which YAML's offside rule makes work", () => {
|
|
376
|
+
expect(yamlOptions()["folding"]).toBe(true);
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
describe("CodeEditor — the other languages are left exactly as they were", () => {
|
|
381
|
+
beforeEach(() => {
|
|
382
|
+
mockEditorRenders.length = 0;
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
type OptionsForFunction = (type: CodeType) => Record<string, unknown>;
|
|
386
|
+
|
|
387
|
+
const optionsFor: OptionsForFunction = (
|
|
388
|
+
type: CodeType,
|
|
389
|
+
): Record<string, unknown> => {
|
|
390
|
+
render(<CodeEditor type={type} value="x" />);
|
|
391
|
+
|
|
392
|
+
return (lastRender().options || {}) as Record<string, unknown>;
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
test.each([
|
|
396
|
+
CodeType.JSON,
|
|
397
|
+
CodeType.JavaScript,
|
|
398
|
+
CodeType.CSS,
|
|
399
|
+
CodeType.HTML,
|
|
400
|
+
CodeType.Markdown,
|
|
401
|
+
CodeType.Text,
|
|
402
|
+
])("%s keeps Monaco's own indentation behaviour", (type: CodeType) => {
|
|
403
|
+
const options: Record<string, unknown> = optionsFor(type);
|
|
404
|
+
|
|
405
|
+
expect(options["tabSize"]).toBeUndefined();
|
|
406
|
+
expect(options["insertSpaces"]).toBeUndefined();
|
|
407
|
+
expect(options["detectIndentation"]).toBeUndefined();
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
test.each([
|
|
411
|
+
CodeType.JSON,
|
|
412
|
+
CodeType.JavaScript,
|
|
413
|
+
CodeType.CSS,
|
|
414
|
+
CodeType.HTML,
|
|
415
|
+
CodeType.Markdown,
|
|
416
|
+
CodeType.Text,
|
|
417
|
+
])(
|
|
418
|
+
"%s keeps its scrolling and padding exactly as before",
|
|
419
|
+
(type: CodeType) => {
|
|
420
|
+
const options: Record<string, unknown> = optionsFor(type);
|
|
421
|
+
|
|
422
|
+
expect(options["scrollbar"]).toEqual({ horizontal: "hidden" });
|
|
423
|
+
expect(options["scrollBeyondLastLine"]).toBe(true);
|
|
424
|
+
expect(options["padding"]).toBeUndefined();
|
|
425
|
+
},
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
test.each([
|
|
429
|
+
CodeType.JSON,
|
|
430
|
+
CodeType.JavaScript,
|
|
431
|
+
CodeType.CSS,
|
|
432
|
+
CodeType.HTML,
|
|
433
|
+
CodeType.Text,
|
|
434
|
+
])("%s keeps its gutter off unless asked", (type: CodeType) => {
|
|
435
|
+
expect(optionsFor(type)["lineNumbers"]).toBe("off");
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test("showLineNumbers still turns the gutter on for any type", () => {
|
|
439
|
+
render(
|
|
440
|
+
<CodeEditor type={CodeType.JSON} value="{}" showLineNumbers={true} />,
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
expect(
|
|
444
|
+
((lastRender().options || {}) as Record<string, unknown>)["lineNumbers"],
|
|
445
|
+
).toBe("on");
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
test.each([
|
|
449
|
+
CodeType.JSON,
|
|
450
|
+
CodeType.JavaScript,
|
|
451
|
+
CodeType.CSS,
|
|
452
|
+
CodeType.HTML,
|
|
453
|
+
CodeType.Markdown,
|
|
454
|
+
])("%s keeps rendering no whitespace", (type: CodeType) => {
|
|
455
|
+
expect(optionsFor(type)["renderWhitespace"]).toBe("none");
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
test("Markdown still wraps", () => {
|
|
459
|
+
expect(optionsFor(CodeType.Markdown)["wordWrap"]).toBe("on");
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
describe("CodeEditor — height", () => {
|
|
464
|
+
beforeEach(() => {
|
|
465
|
+
mockEditorRenders.length = 0;
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
test("defaults to 30vh, as every existing caller expects", () => {
|
|
469
|
+
render(<CodeEditor type={CodeType.JSON} value="{}" />);
|
|
470
|
+
|
|
471
|
+
expect(lastRender().height).toBe("30vh");
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
test("a caller can ask for its own", () => {
|
|
475
|
+
render(<CodeEditor type={CodeType.YAML} value="a: 1" height="22rem" />);
|
|
476
|
+
|
|
477
|
+
expect(lastRender().height).toBe("22rem");
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
describe("CodeEditor — a YAML placeholder never becomes document text", () => {
|
|
482
|
+
beforeEach(() => {
|
|
483
|
+
mockEditorRenders.length = 0;
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
/*
|
|
487
|
+
* `defaultValue` seeds the Monaco model, so anything routed there is real
|
|
488
|
+
* content the user can accidentally save. The JS and CSS arms get away with
|
|
489
|
+
* it by wrapping the hint in a comment; YAML has no such wrapper, so its
|
|
490
|
+
* hint has to go to the help text instead.
|
|
491
|
+
*/
|
|
492
|
+
test("the hint is shown as help text, not seeded into the editor", () => {
|
|
493
|
+
render(
|
|
494
|
+
<CodeEditor
|
|
495
|
+
type={CodeType.YAML}
|
|
496
|
+
value=""
|
|
497
|
+
placeholder="Sigma rule YAML — title, logsource, detection and condition."
|
|
498
|
+
/>,
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
expect(lastRender().defaultValue).toBe("");
|
|
502
|
+
expect(
|
|
503
|
+
screen.getByText(/Sigma rule YAML/, { exact: false }),
|
|
504
|
+
).toBeInTheDocument();
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
test("an empty YAML editor still starts empty when no hint is given", () => {
|
|
508
|
+
render(<CodeEditor type={CodeType.YAML} value="" />);
|
|
509
|
+
|
|
510
|
+
expect(lastRender().defaultValue).toBe("");
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
describe("CodeEditor — accessibility lands on Monaco's input, not the wrapper", () => {
|
|
514
|
+
beforeEach(() => {
|
|
515
|
+
mockEditorRenders.length = 0;
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
type InputAreaFunction = () => HTMLTextAreaElement;
|
|
519
|
+
|
|
520
|
+
const inputArea: InputAreaFunction = (): HTMLTextAreaElement => {
|
|
521
|
+
return screen.getByTestId("monaco") as HTMLTextAreaElement;
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
/*
|
|
525
|
+
* The wrapper this component returns is a bare <div>, i.e. role=generic,
|
|
526
|
+
* and ARIA forbids naming one - browsers compute no name for it and
|
|
527
|
+
* assistive technology ignores it. The element that actually takes focus is
|
|
528
|
+
* Monaco's own textarea, whose default name is the string "Editor content".
|
|
529
|
+
*/
|
|
530
|
+
test("the field's label names the editor's textarea", () => {
|
|
531
|
+
render(
|
|
532
|
+
<CodeEditor
|
|
533
|
+
type={CodeType.YAML}
|
|
534
|
+
value="a: 1"
|
|
535
|
+
ariaLabelledby="the-field-label"
|
|
536
|
+
/>,
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
expect(inputArea().getAttribute("aria-labelledby")).toBe("the-field-label");
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
test("descriptions are associated with the textarea", () => {
|
|
543
|
+
render(
|
|
544
|
+
<CodeEditor
|
|
545
|
+
type={CodeType.YAML}
|
|
546
|
+
value="a: 1"
|
|
547
|
+
ariaDescribedby="hint-id status-id"
|
|
548
|
+
/>,
|
|
549
|
+
);
|
|
550
|
+
|
|
551
|
+
expect(inputArea().getAttribute("aria-describedby")).toBe(
|
|
552
|
+
"hint-id status-id",
|
|
553
|
+
);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
test("an invalid document is announced as invalid", () => {
|
|
557
|
+
render(<CodeEditor type={CodeType.YAML} value="a: [" ariaInvalid={true} />);
|
|
558
|
+
|
|
559
|
+
expect(inputArea().getAttribute("aria-invalid")).toBe("true");
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
test("a valid document carries no aria-invalid at all", () => {
|
|
563
|
+
render(<CodeEditor type={CodeType.YAML} value="a: 1" />);
|
|
564
|
+
|
|
565
|
+
expect(inputArea().hasAttribute("aria-invalid")).toBe(false);
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
test("the attributes follow their props after mount", () => {
|
|
569
|
+
const { rerender } = render(
|
|
570
|
+
<CodeEditor type={CodeType.YAML} value="a: 1" ariaInvalid={false} />,
|
|
571
|
+
);
|
|
572
|
+
|
|
573
|
+
expect(inputArea().hasAttribute("aria-invalid")).toBe(false);
|
|
574
|
+
|
|
575
|
+
rerender(
|
|
576
|
+
<CodeEditor type={CodeType.YAML} value="a: [" ariaInvalid={true} />,
|
|
577
|
+
);
|
|
578
|
+
|
|
579
|
+
expect(inputArea().getAttribute("aria-invalid")).toBe("true");
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
test("no aria attributes are invented when the caller passes none", () => {
|
|
583
|
+
render(<CodeEditor type={CodeType.JSON} value="{}" />);
|
|
584
|
+
|
|
585
|
+
expect(inputArea().hasAttribute("aria-labelledby")).toBe(false);
|
|
586
|
+
expect(inputArea().hasAttribute("aria-describedby")).toBe(false);
|
|
587
|
+
});
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
describe("CodeEditor — spell check", () => {
|
|
591
|
+
beforeEach(() => {
|
|
592
|
+
mockEditorRenders.length = 0;
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
type SpellCheckFunction = () => boolean;
|
|
596
|
+
|
|
597
|
+
const spellCheck: SpellCheckFunction = (): boolean => {
|
|
598
|
+
return (screen.getByTestId("monaco") as HTMLTextAreaElement).spellcheck;
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
// YAML is code: squiggles under every Sigma key name are pure noise.
|
|
602
|
+
test("is always off for YAML, whatever the caller asked for", () => {
|
|
603
|
+
render(<CodeEditor type={CodeType.YAML} value="a: 1" />);
|
|
604
|
+
|
|
605
|
+
expect(spellCheck()).toBe(false);
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
test("is still off for YAML when the caller explicitly enables it", () => {
|
|
609
|
+
render(
|
|
610
|
+
<CodeEditor
|
|
611
|
+
type={CodeType.YAML}
|
|
612
|
+
value="a: 1"
|
|
613
|
+
disableSpellCheck={false}
|
|
614
|
+
/>,
|
|
615
|
+
);
|
|
616
|
+
|
|
617
|
+
expect(spellCheck()).toBe(false);
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// Markdown is prose, and keeps following the caller exactly as it did.
|
|
621
|
+
test("follows the caller for Markdown", () => {
|
|
622
|
+
render(<CodeEditor type={CodeType.Markdown} value="# hi" />);
|
|
623
|
+
|
|
624
|
+
expect(spellCheck()).toBe(true);
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
test("is off for Markdown when the caller disables it", () => {
|
|
628
|
+
render(
|
|
629
|
+
<CodeEditor
|
|
630
|
+
type={CodeType.Markdown}
|
|
631
|
+
value="# hi"
|
|
632
|
+
disableSpellCheck={true}
|
|
633
|
+
/>,
|
|
634
|
+
);
|
|
635
|
+
|
|
636
|
+
expect(spellCheck()).toBe(false);
|
|
637
|
+
});
|
|
638
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import { afterEach, describe, expect, test } from "@jest/globals";
|
|
3
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
4
|
+
import React from "react";
|
|
5
|
+
|
|
6
|
+
import Detail from "../../../../UI/Components/Detail/Detail";
|
|
7
|
+
import Field from "../../../../UI/Components/Detail/Field";
|
|
8
|
+
import FieldType from "../../../../UI/Components/Types/FieldType";
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* The read-only half of the YAML field type. A YAML value must render as a
|
|
12
|
+
* highlighted code block - never as prose, and never re-emitted through a
|
|
13
|
+
* parser: dumping YAML back out drops the comments, anchors and key ordering
|
|
14
|
+
* a hand-written document (a Sigma rule, a collector config) is written with.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
interface TestItem {
|
|
18
|
+
sigmaRuleYaml: string;
|
|
19
|
+
description: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const SIGMA_RULE_WITH_COMMENT: string = `# catches password spraying
|
|
23
|
+
title: Failed logon burst
|
|
24
|
+
logsource:
|
|
25
|
+
category: authentication
|
|
26
|
+
detection:
|
|
27
|
+
selection:
|
|
28
|
+
className: Authentication
|
|
29
|
+
condition: selection
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
type RenderDetailFunction = (fieldType: FieldType, value: string) => void;
|
|
33
|
+
|
|
34
|
+
const renderDetail: RenderDetailFunction = (
|
|
35
|
+
fieldType: FieldType,
|
|
36
|
+
value: string,
|
|
37
|
+
): void => {
|
|
38
|
+
const fields: Array<Field<TestItem>> = [
|
|
39
|
+
{
|
|
40
|
+
key: "sigmaRuleYaml",
|
|
41
|
+
title: "Sigma Rule (YAML)",
|
|
42
|
+
fieldType,
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
render(
|
|
47
|
+
<Detail<TestItem>
|
|
48
|
+
item={{ sigmaRuleYaml: value, description: "unused" }}
|
|
49
|
+
fields={fields}
|
|
50
|
+
/>,
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
afterEach(() => {
|
|
55
|
+
cleanup();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("Detail — a YAML field renders as highlighted YAML", () => {
|
|
59
|
+
test("the value reaches the page", () => {
|
|
60
|
+
renderDetail(FieldType.YAML, SIGMA_RULE_WITH_COMMENT);
|
|
61
|
+
|
|
62
|
+
expect(document.body.textContent).toContain("title: Failed logon burst");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("it renders inside a code block, not as prose", () => {
|
|
66
|
+
renderDetail(FieldType.YAML, SIGMA_RULE_WITH_COMMENT);
|
|
67
|
+
|
|
68
|
+
expect(document.querySelector("pre code")).not.toBeNull();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("it is tagged as the yaml language for the highlighter", () => {
|
|
72
|
+
renderDetail(FieldType.YAML, SIGMA_RULE_WITH_COMMENT);
|
|
73
|
+
|
|
74
|
+
expect(document.querySelector("code.language-yaml")).not.toBeNull();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
/*
|
|
78
|
+
* The JSON arm of the same branch pretty-prints by round-tripping through
|
|
79
|
+
* JSON.parse/stringify. Doing that to YAML would silently rewrite the user's
|
|
80
|
+
* document; comments are the most visible casualty.
|
|
81
|
+
*/
|
|
82
|
+
test("comments survive - the document is rendered verbatim", () => {
|
|
83
|
+
renderDetail(FieldType.YAML, SIGMA_RULE_WITH_COMMENT);
|
|
84
|
+
|
|
85
|
+
expect(document.body.textContent).toContain("# catches password spraying");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("indentation survives verbatim", () => {
|
|
89
|
+
renderDetail(FieldType.YAML, SIGMA_RULE_WITH_COMMENT);
|
|
90
|
+
|
|
91
|
+
expect(document.body.textContent).toContain(" condition: selection");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("the field title is still rendered", () => {
|
|
95
|
+
renderDetail(FieldType.YAML, SIGMA_RULE_WITH_COMMENT);
|
|
96
|
+
|
|
97
|
+
expect(screen.getByText("Sigma Rule (YAML)")).toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("a syntactically broken document is still displayed, not swallowed", () => {
|
|
101
|
+
renderDetail(FieldType.YAML, "title: [unclosed");
|
|
102
|
+
|
|
103
|
+
expect(document.body.textContent).toContain("title: [unclosed");
|
|
104
|
+
});
|
|
105
|
+
});
|