@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
|
@@ -18,11 +18,49 @@ import {
|
|
|
18
18
|
DropResult,
|
|
19
19
|
} from "react-beautiful-dnd";
|
|
20
20
|
|
|
21
|
+
/*
|
|
22
|
+
* A pool of columns the viewer can bring INTO the picker, rather than one
|
|
23
|
+
* checklist entry per possibility.
|
|
24
|
+
*
|
|
25
|
+
* Attribute columns are the motivating case: the keys inside a row's
|
|
26
|
+
* `attributes` map differ per event class and per source, so a project can
|
|
27
|
+
* easily have several hundred of them. Listing every one as a checkbox turns
|
|
28
|
+
* "which columns do I want?" into a scroll through noise (and hands "Show all"
|
|
29
|
+
* a way to put 500 columns on screen), so they are offered through a search
|
|
30
|
+
* box that only materializes what was asked for.
|
|
31
|
+
*/
|
|
32
|
+
export interface AddableColumnsConfig<
|
|
33
|
+
TBaseModel extends BaseModel | AnalyticsBaseModel,
|
|
34
|
+
> {
|
|
35
|
+
title: string;
|
|
36
|
+
description?: string | undefined;
|
|
37
|
+
placeholder?: string | undefined;
|
|
38
|
+
// Still fetching the pool. The section says so rather than reading as empty.
|
|
39
|
+
isLoading?: boolean | undefined;
|
|
40
|
+
errorMessage?: string | undefined;
|
|
41
|
+
// Shown when the pool itself is empty, e.g. nothing has been ingested yet.
|
|
42
|
+
emptyMessage?: string | undefined;
|
|
43
|
+
/*
|
|
44
|
+
* Every column that could be added, in the order they should be offered.
|
|
45
|
+
* Ones already in the picker are filtered out here rather than by the
|
|
46
|
+
* caller, so a column added and then removed reappears in the pool.
|
|
47
|
+
*/
|
|
48
|
+
columns: Array<CustomizableColumn<TBaseModel>>;
|
|
49
|
+
/*
|
|
50
|
+
* How many matches to render at once. The pool can be in the thousands and
|
|
51
|
+
* an unbounded list would put all of it in the DOM; the search box is what
|
|
52
|
+
* gets you to the rest.
|
|
53
|
+
*/
|
|
54
|
+
maxResults?: number | undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
21
57
|
export interface ComponentProps<
|
|
22
58
|
TBaseModel extends BaseModel | AnalyticsBaseModel,
|
|
23
59
|
> {
|
|
24
60
|
// Every customizable column, already in the order the table renders them.
|
|
25
61
|
columns: Array<CustomizableColumn<TBaseModel>>;
|
|
62
|
+
// Optional pool of columns the viewer can add. Omit to hide the whole section.
|
|
63
|
+
addableColumns?: AddableColumnsConfig<TBaseModel> | undefined;
|
|
26
64
|
onSave: (columns: Array<CustomizableColumn<TBaseModel>>) => void;
|
|
27
65
|
onClose: () => void;
|
|
28
66
|
// Drop the stored layout and go back to what the table ships with.
|
|
@@ -97,6 +135,109 @@ const ColumnCustomizationModal: ColumnCustomizationModalFunction = <
|
|
|
97
135
|
const isEverythingVisible: boolean = visibleCount === entries.length;
|
|
98
136
|
const isOnlyOneVisible: boolean = visibleCount <= 1;
|
|
99
137
|
|
|
138
|
+
/*
|
|
139
|
+
* ---------------------------------------------------------------------
|
|
140
|
+
* The "add a column" pool
|
|
141
|
+
* ---------------------------------------------------------------------
|
|
142
|
+
*/
|
|
143
|
+
const [addSearchText, setAddSearchText] = useState<string>("");
|
|
144
|
+
|
|
145
|
+
const stagedIds: Set<string> = useMemo(() => {
|
|
146
|
+
return new Set(
|
|
147
|
+
entries.map((entry: CustomizableColumn<TBaseModel>) => {
|
|
148
|
+
return entry.id;
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
151
|
+
}, [entries]);
|
|
152
|
+
|
|
153
|
+
// Everything in the pool that is not already sitting in the list above.
|
|
154
|
+
const addableColumns: Array<CustomizableColumn<TBaseModel>> = useMemo(() => {
|
|
155
|
+
return (props.addableColumns?.columns || []).filter(
|
|
156
|
+
(entry: CustomizableColumn<TBaseModel>) => {
|
|
157
|
+
return !stagedIds.has(entry.id);
|
|
158
|
+
},
|
|
159
|
+
);
|
|
160
|
+
}, [props.addableColumns?.columns, stagedIds]);
|
|
161
|
+
|
|
162
|
+
const normalizedAddSearch: string = addSearchText.trim().toLowerCase();
|
|
163
|
+
|
|
164
|
+
const matchingAddableColumns: Array<CustomizableColumn<TBaseModel>> =
|
|
165
|
+
useMemo(() => {
|
|
166
|
+
if (normalizedAddSearch.length === 0) {
|
|
167
|
+
return addableColumns;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return addableColumns.filter((entry: CustomizableColumn<TBaseModel>) => {
|
|
171
|
+
return (entry.column.title || "")
|
|
172
|
+
.toLowerCase()
|
|
173
|
+
.includes(normalizedAddSearch);
|
|
174
|
+
});
|
|
175
|
+
}, [addableColumns, normalizedAddSearch]);
|
|
176
|
+
|
|
177
|
+
const addableResultLimit: number = props.addableColumns?.maxResults ?? 25;
|
|
178
|
+
|
|
179
|
+
const shownAddableColumns: Array<CustomizableColumn<TBaseModel>> =
|
|
180
|
+
useMemo(() => {
|
|
181
|
+
return matchingAddableColumns.slice(0, addableResultLimit);
|
|
182
|
+
}, [matchingAddableColumns, addableResultLimit]);
|
|
183
|
+
|
|
184
|
+
type AddColumnFunction = (entry: CustomizableColumn<TBaseModel>) => void;
|
|
185
|
+
|
|
186
|
+
/*
|
|
187
|
+
* An added column goes on the end and starts visible. Adding a column you
|
|
188
|
+
* then have to go and switch on would be a strange thing to ask of someone
|
|
189
|
+
* who just searched for it by name.
|
|
190
|
+
*/
|
|
191
|
+
const addColumn: AddColumnFunction = (
|
|
192
|
+
entry: CustomizableColumn<TBaseModel>,
|
|
193
|
+
): void => {
|
|
194
|
+
setEntries((current: Array<CustomizableColumn<TBaseModel>>) => {
|
|
195
|
+
if (
|
|
196
|
+
current.some((existing: CustomizableColumn<TBaseModel>) => {
|
|
197
|
+
return existing.id === entry.id;
|
|
198
|
+
})
|
|
199
|
+
) {
|
|
200
|
+
return current;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return [...current, { ...entry, isVisible: true, isPinned: false }];
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
type RemoveColumnFunction = (id: string) => void;
|
|
208
|
+
|
|
209
|
+
const removeColumn: RemoveColumnFunction = (id: string): void => {
|
|
210
|
+
setEntries((current: Array<CustomizableColumn<TBaseModel>>) => {
|
|
211
|
+
const target: CustomizableColumn<TBaseModel> | undefined = current.find(
|
|
212
|
+
(entry: CustomizableColumn<TBaseModel>) => {
|
|
213
|
+
return entry.id === id;
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
if (!target || !target.isRemovable) {
|
|
218
|
+
return current;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/*
|
|
222
|
+
* Removing is hiding plus forgetting, so it is bound by the same rule:
|
|
223
|
+
* the last column standing cannot go.
|
|
224
|
+
*/
|
|
225
|
+
const isLastVisible: boolean =
|
|
226
|
+
target.isVisible &&
|
|
227
|
+
current.filter((entry: CustomizableColumn<TBaseModel>) => {
|
|
228
|
+
return entry.isVisible;
|
|
229
|
+
}).length <= 1;
|
|
230
|
+
|
|
231
|
+
if (isLastVisible) {
|
|
232
|
+
return current;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return current.filter((entry: CustomizableColumn<TBaseModel>) => {
|
|
236
|
+
return entry.id !== id;
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
};
|
|
240
|
+
|
|
100
241
|
type ToggleFunction = (id: string, isVisible: boolean) => void;
|
|
101
242
|
|
|
102
243
|
const toggleColumn: ToggleFunction = (
|
|
@@ -303,6 +444,22 @@ const ColumnCustomizationModal: ColumnCustomizationModalFunction = <
|
|
|
303
444
|
moveColumn(index, index + 1);
|
|
304
445
|
}}
|
|
305
446
|
/>
|
|
447
|
+
{entry.isRemovable && (
|
|
448
|
+
<Button
|
|
449
|
+
buttonSize={ButtonSize.Small}
|
|
450
|
+
buttonStyle={ButtonStyleType.ICON}
|
|
451
|
+
icon={IconProp.Close}
|
|
452
|
+
title=""
|
|
453
|
+
tooltip="Remove column"
|
|
454
|
+
ariaLabel={`Remove ${entry.column.title}`}
|
|
455
|
+
className="text-gray-400 hover:bg-red-100 hover:text-red-600 disabled:text-gray-200 disabled:hover:bg-transparent"
|
|
456
|
+
dataTestId={`column-remove-${entry.id}`}
|
|
457
|
+
disabled={isOnlyVisibleColumn}
|
|
458
|
+
onClick={() => {
|
|
459
|
+
removeColumn(entry.id);
|
|
460
|
+
}}
|
|
461
|
+
/>
|
|
462
|
+
)}
|
|
306
463
|
</div>
|
|
307
464
|
</div>
|
|
308
465
|
);
|
|
@@ -413,6 +570,157 @@ const ColumnCustomizationModal: ColumnCustomizationModalFunction = <
|
|
|
413
570
|
);
|
|
414
571
|
};
|
|
415
572
|
|
|
573
|
+
type GetAddColumnSectionFunction = () => ReactElement;
|
|
574
|
+
|
|
575
|
+
const getAddColumnSection: GetAddColumnSectionFunction = (): ReactElement => {
|
|
576
|
+
const config: AddableColumnsConfig<TBaseModel> | undefined =
|
|
577
|
+
props.addableColumns;
|
|
578
|
+
|
|
579
|
+
if (!config) {
|
|
580
|
+
return <></>;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
type GetBodyFunction = () => ReactElement;
|
|
584
|
+
|
|
585
|
+
const getBody: GetBodyFunction = (): ReactElement => {
|
|
586
|
+
if (config.errorMessage) {
|
|
587
|
+
return (
|
|
588
|
+
<p
|
|
589
|
+
className="px-3 py-4 text-sm text-red-500"
|
|
590
|
+
data-testid="add-column-error"
|
|
591
|
+
>
|
|
592
|
+
{config.errorMessage}
|
|
593
|
+
</p>
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (config.isLoading) {
|
|
598
|
+
return (
|
|
599
|
+
<p
|
|
600
|
+
className="px-3 py-4 text-sm text-gray-500"
|
|
601
|
+
data-testid="add-column-loading"
|
|
602
|
+
>
|
|
603
|
+
Loading...
|
|
604
|
+
</p>
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (addableColumns.length === 0) {
|
|
609
|
+
return (
|
|
610
|
+
<p
|
|
611
|
+
className="px-3 py-4 text-sm text-gray-500"
|
|
612
|
+
data-testid="add-column-empty"
|
|
613
|
+
>
|
|
614
|
+
{(config.columns || []).length === 0
|
|
615
|
+
? config.emptyMessage || "Nothing to add."
|
|
616
|
+
: "Every one of these is already in the list above."}
|
|
617
|
+
</p>
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (shownAddableColumns.length === 0) {
|
|
622
|
+
return (
|
|
623
|
+
<p
|
|
624
|
+
className="px-3 py-4 text-sm text-gray-500"
|
|
625
|
+
data-testid="add-column-no-results"
|
|
626
|
+
>
|
|
627
|
+
No matches for "{addSearchText}".
|
|
628
|
+
</p>
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return (
|
|
633
|
+
<div className="divide-y divide-gray-100">
|
|
634
|
+
{shownAddableColumns.map((entry: CustomizableColumn<TBaseModel>) => {
|
|
635
|
+
return (
|
|
636
|
+
<div
|
|
637
|
+
key={entry.id}
|
|
638
|
+
className="flex items-center gap-2 px-3 py-2 transition-colors hover:bg-gray-50"
|
|
639
|
+
>
|
|
640
|
+
<span className="min-w-0 flex-1 break-words text-sm text-gray-700">
|
|
641
|
+
{entry.column.title}
|
|
642
|
+
</span>
|
|
643
|
+
<Button
|
|
644
|
+
buttonSize={ButtonSize.Small}
|
|
645
|
+
buttonStyle={ButtonStyleType.ICON}
|
|
646
|
+
icon={IconProp.Add}
|
|
647
|
+
title=""
|
|
648
|
+
tooltip="Add column"
|
|
649
|
+
ariaLabel={`Add ${entry.column.title}`}
|
|
650
|
+
className="flex-none text-gray-400 hover:bg-gray-200 hover:text-gray-700"
|
|
651
|
+
dataTestId={`add-column-${entry.id}`}
|
|
652
|
+
onClick={() => {
|
|
653
|
+
addColumn(entry);
|
|
654
|
+
}}
|
|
655
|
+
/>
|
|
656
|
+
</div>
|
|
657
|
+
);
|
|
658
|
+
})}
|
|
659
|
+
</div>
|
|
660
|
+
);
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
return (
|
|
664
|
+
<div className="space-y-2 pt-1" data-testid="add-column-section">
|
|
665
|
+
<div>
|
|
666
|
+
<h4 className="text-sm font-medium text-gray-900">{config.title}</h4>
|
|
667
|
+
{config.description ? (
|
|
668
|
+
<p className="text-xs text-gray-500">{config.description}</p>
|
|
669
|
+
) : (
|
|
670
|
+
<></>
|
|
671
|
+
)}
|
|
672
|
+
</div>
|
|
673
|
+
|
|
674
|
+
<div className="relative">
|
|
675
|
+
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
|
676
|
+
<Icon icon={IconProp.Search} className="h-4 w-4 text-gray-400" />
|
|
677
|
+
</div>
|
|
678
|
+
<Input
|
|
679
|
+
type={InputType.TEXT}
|
|
680
|
+
placeholder={config.placeholder || "Search..."}
|
|
681
|
+
value={addSearchText}
|
|
682
|
+
dataTestId="add-column-search"
|
|
683
|
+
outerDivClassName="w-full"
|
|
684
|
+
className="block w-full rounded-md border border-gray-300 bg-white py-2 pl-9 pr-9 text-sm placeholder-gray-400 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
|
685
|
+
onChange={(value: string) => {
|
|
686
|
+
setAddSearchText(value);
|
|
687
|
+
}}
|
|
688
|
+
/>
|
|
689
|
+
{addSearchText.length > 0 && (
|
|
690
|
+
<button
|
|
691
|
+
type="button"
|
|
692
|
+
aria-label="Clear search"
|
|
693
|
+
title="Clear search"
|
|
694
|
+
data-testid="add-column-search-clear"
|
|
695
|
+
onClick={() => {
|
|
696
|
+
setAddSearchText("");
|
|
697
|
+
}}
|
|
698
|
+
className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 transition-colors hover:text-gray-600 focus:outline-none focus-visible:text-gray-600"
|
|
699
|
+
>
|
|
700
|
+
<Icon icon={IconProp.Close} className="h-4 w-4" />
|
|
701
|
+
</button>
|
|
702
|
+
)}
|
|
703
|
+
</div>
|
|
704
|
+
|
|
705
|
+
<div className="max-h-48 overflow-y-auto overscroll-contain rounded-md border border-gray-200 bg-white">
|
|
706
|
+
{getBody()}
|
|
707
|
+
</div>
|
|
708
|
+
|
|
709
|
+
{/*
|
|
710
|
+
* Said out loud rather than silently truncating: a viewer who cannot
|
|
711
|
+
* see their key otherwise has no way to know that typing more of it
|
|
712
|
+
* would find it.
|
|
713
|
+
*/}
|
|
714
|
+
{matchingAddableColumns.length > shownAddableColumns.length && (
|
|
715
|
+
<p className="text-xs text-gray-400" data-testid="add-column-hint">
|
|
716
|
+
Showing {shownAddableColumns.length} of{" "}
|
|
717
|
+
{matchingAddableColumns.length}. Search to narrow this down.
|
|
718
|
+
</p>
|
|
719
|
+
)}
|
|
720
|
+
</div>
|
|
721
|
+
);
|
|
722
|
+
};
|
|
723
|
+
|
|
416
724
|
return (
|
|
417
725
|
<Modal
|
|
418
726
|
title={props.title || "Customize Columns"}
|
|
@@ -515,6 +823,8 @@ const ColumnCustomizationModal: ColumnCustomizationModalFunction = <
|
|
|
515
823
|
? "Clear the search to reorder columns."
|
|
516
824
|
: "Drag a row, or use the arrows, to change the column order."}
|
|
517
825
|
</p>
|
|
826
|
+
|
|
827
|
+
{getAddColumnSection()}
|
|
518
828
|
</div>
|
|
519
829
|
</Modal>
|
|
520
830
|
);
|
|
@@ -153,6 +153,12 @@ export interface CustomizableColumn<
|
|
|
153
153
|
isVisible: boolean;
|
|
154
154
|
// Pinned columns are always shown and cannot be moved.
|
|
155
155
|
isPinned: boolean;
|
|
156
|
+
/*
|
|
157
|
+
* The picker may drop this column entirely, not just switch it off. True
|
|
158
|
+
* only for columns the viewer added themselves (attribute columns); a
|
|
159
|
+
* pinned column is never removable, since it is not the viewer's to touch.
|
|
160
|
+
*/
|
|
161
|
+
isRemovable?: boolean | undefined;
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
export type IsDefaultHiddenFunction = <
|
|
@@ -214,7 +220,13 @@ export const getCustomizableColumns: GetCustomizableColumnsFunction = <
|
|
|
214
220
|
}
|
|
215
221
|
}
|
|
216
222
|
|
|
217
|
-
return {
|
|
223
|
+
return {
|
|
224
|
+
id,
|
|
225
|
+
column,
|
|
226
|
+
isVisible,
|
|
227
|
+
isPinned,
|
|
228
|
+
isRemovable: Boolean(column.isRemovable) && !isPinned,
|
|
229
|
+
};
|
|
218
230
|
},
|
|
219
231
|
);
|
|
220
232
|
|
|
@@ -32,8 +32,8 @@ export interface ComponentProps {
|
|
|
32
32
|
* that scales when a user groups by many attributes.
|
|
33
33
|
*
|
|
34
34
|
* Click a variable to copy `{{var}}` to the clipboard; the chip flips
|
|
35
|
-
* to a "Copied" state briefly so the
|
|
36
|
-
*
|
|
35
|
+
* to a "Copied" state briefly so the feedback lands on the thing that
|
|
36
|
+
* was clicked.
|
|
37
37
|
*/
|
|
38
38
|
const TemplateVariablesModal: FunctionComponent<ComponentProps> = (
|
|
39
39
|
props: ComponentProps,
|
|
@@ -150,11 +150,11 @@ const SideOver: FunctionComponent<ComponentProps> = (
|
|
|
150
150
|
/*
|
|
151
151
|
* z-30 clears every tier of page chrome (sticky headers and table headers
|
|
152
152
|
* at z-10/z-20, map and log-viewer toolbars at z-20) while staying under
|
|
153
|
-
* the app-wide overlays that must remain visible over a panel:
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
153
|
+
* the app-wide overlays that must remain visible over a panel: the AI chat
|
|
154
|
+
* panel at z-40, Modal at z-50, portalled dropdown menus at z-60.
|
|
155
|
+
* Deliberately NOT z-40 — AIChatPanel is mounted ahead of the routed page
|
|
156
|
+
* in App.tsx, so an equal z-index would be broken in this panel's favour
|
|
157
|
+
* by document order and the AI drawer would disappear behind it.
|
|
158
158
|
*
|
|
159
159
|
* role="dialog" without aria-modal, because the panel genuinely is not
|
|
160
160
|
* modal: everything outside it stays clickable by design (both topology
|
|
@@ -4,6 +4,7 @@ import StatusPageResourceExplorerUtil, {
|
|
|
4
4
|
StatusPageResourceGridModel,
|
|
5
5
|
} from "../../../Utils/StatusPage/ResourceExplorer";
|
|
6
6
|
import Button, { ButtonSize, ButtonStyleType } from "../Button/Button";
|
|
7
|
+
import CheckboxElement from "../Checkbox/Checkbox";
|
|
7
8
|
import Icon, { ThickProp } from "../Icon/Icon";
|
|
8
9
|
import React, { FunctionComponent, ReactElement, useMemo } from "react";
|
|
9
10
|
|
|
@@ -22,6 +23,18 @@ export interface ComponentProps {
|
|
|
22
23
|
isEditable: boolean;
|
|
23
24
|
isDeleteable: boolean;
|
|
24
25
|
|
|
26
|
+
/*
|
|
27
|
+
* See ResourceList: a checkbox whose only action is removing, so it is drawn
|
|
28
|
+
* only for somebody who may remove. A grid group is the same resources as a
|
|
29
|
+
* list group in a different arrangement, and clearing twenty seven of them
|
|
30
|
+
* one at a time is no better here than it is there (issue #3419) - so the
|
|
31
|
+
* chips carry the same box the rows do, and the bulk bar the pane draws above
|
|
32
|
+
* is shared between the two.
|
|
33
|
+
*/
|
|
34
|
+
isSelectable: boolean;
|
|
35
|
+
selectedResourceIds: Set<string>;
|
|
36
|
+
onToggleResourceSelected: (statusPageResource: StatusPageResource) => void;
|
|
37
|
+
|
|
25
38
|
onAddToCell: (rowValue: string | null, columnValue: string | null) => void;
|
|
26
39
|
onEdit: (statusPageResource: StatusPageResource) => void;
|
|
27
40
|
onDelete: (statusPageResource: StatusPageResource) => void;
|
|
@@ -50,6 +63,57 @@ const ResourceGrid: FunctionComponent<ComponentProps> = (
|
|
|
50
63
|
});
|
|
51
64
|
}, [props.statusPageResources, props.rowValues, props.columnValues]);
|
|
52
65
|
|
|
66
|
+
type IsResourceSelectedFunction = (
|
|
67
|
+
statusPageResource: StatusPageResource,
|
|
68
|
+
) => boolean;
|
|
69
|
+
|
|
70
|
+
const isResourceSelected: IsResourceSelectedFunction = (
|
|
71
|
+
statusPageResource: StatusPageResource,
|
|
72
|
+
): boolean => {
|
|
73
|
+
if (!props.isSelectable) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const resourceId: string | null =
|
|
78
|
+
StatusPageResourceExplorerUtil.getResourceId(statusPageResource);
|
|
79
|
+
|
|
80
|
+
return Boolean(resourceId && props.selectedResourceIds.has(resourceId));
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
type RenderSelectFunction = (
|
|
84
|
+
statusPageResource: StatusPageResource,
|
|
85
|
+
) => ReactElement;
|
|
86
|
+
|
|
87
|
+
const renderSelect: RenderSelectFunction = (
|
|
88
|
+
statusPageResource: StatusPageResource,
|
|
89
|
+
): ReactElement => {
|
|
90
|
+
if (!props.isSelectable) {
|
|
91
|
+
return <></>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const resourceId: string | null =
|
|
95
|
+
StatusPageResourceExplorerUtil.getResourceId(statusPageResource);
|
|
96
|
+
const name: string =
|
|
97
|
+
StatusPageResourceExplorerUtil.getResourceName(statusPageResource);
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<span
|
|
101
|
+
className="flex flex-shrink-0 items-center"
|
|
102
|
+
data-testid="status-page-resource-grid-select"
|
|
103
|
+
>
|
|
104
|
+
<CheckboxElement
|
|
105
|
+
value={isResourceSelected(statusPageResource)}
|
|
106
|
+
disabled={!resourceId}
|
|
107
|
+
ariaLabel={`Select ${name}`}
|
|
108
|
+
hoverText={`Select ${name}`}
|
|
109
|
+
onChange={() => {
|
|
110
|
+
props.onToggleResourceSelected(statusPageResource);
|
|
111
|
+
}}
|
|
112
|
+
/>
|
|
113
|
+
</span>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
53
117
|
type RenderResourceChipFunction = (
|
|
54
118
|
statusPageResource: StatusPageResource,
|
|
55
119
|
) => ReactElement;
|
|
@@ -60,12 +124,21 @@ const ResourceGrid: FunctionComponent<ComponentProps> = (
|
|
|
60
124
|
const name: string =
|
|
61
125
|
StatusPageResourceExplorerUtil.getResourceName(statusPageResource);
|
|
62
126
|
|
|
127
|
+
const isSelected: boolean = isResourceSelected(statusPageResource);
|
|
128
|
+
|
|
63
129
|
return (
|
|
64
130
|
<div
|
|
65
131
|
key={statusPageResource._id?.toString()}
|
|
66
|
-
className=
|
|
132
|
+
className={`group flex items-center justify-between gap-2 rounded-lg border px-2 py-1.5 text-xs shadow-sm transition-shadow hover:shadow ${
|
|
133
|
+
isSelected
|
|
134
|
+
? "border-indigo-300 bg-indigo-50"
|
|
135
|
+
: "border-gray-200 bg-white"
|
|
136
|
+
}`}
|
|
67
137
|
data-testid="status-page-resource-grid-cell-item"
|
|
138
|
+
data-selected={isSelected}
|
|
68
139
|
>
|
|
140
|
+
{renderSelect(statusPageResource)}
|
|
141
|
+
|
|
69
142
|
<div className="min-w-0 flex-1">
|
|
70
143
|
<div className="truncate font-medium text-gray-900">
|
|
71
144
|
{props.getResourceElement(statusPageResource)}
|
|
@@ -248,9 +321,16 @@ const ResourceGrid: FunctionComponent<ComponentProps> = (
|
|
|
248
321
|
return (
|
|
249
322
|
<div
|
|
250
323
|
key={statusPageResource._id?.toString()}
|
|
251
|
-
className=
|
|
324
|
+
className={`flex items-center justify-between gap-2 rounded-lg border border-amber-200 px-3 py-2 text-xs ${
|
|
325
|
+
isResourceSelected(statusPageResource)
|
|
326
|
+
? "bg-indigo-50"
|
|
327
|
+
: "bg-white"
|
|
328
|
+
}`}
|
|
252
329
|
data-testid="status-page-resource-grid-orphan"
|
|
330
|
+
data-selected={isResourceSelected(statusPageResource)}
|
|
253
331
|
>
|
|
332
|
+
{renderSelect(statusPageResource)}
|
|
333
|
+
|
|
254
334
|
<div className="min-w-0 flex-1">
|
|
255
335
|
<div className="truncate font-medium text-gray-900">
|
|
256
336
|
{props.getResourceElement(statusPageResource)}
|