@oneuptime/common 12.0.6 → 12.0.7
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/AIInsight.ts +1 -1
- package/Models/DatabaseModels/DatabaseBaseModel/FileModel.ts +2 -3
- package/Models/DatabaseModels/DeletedProject.ts +595 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/Monitor.ts +111 -0
- package/Models/DatabaseModels/Project.ts +3 -3
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -1
- package/Server/API/FileAPI.ts +15 -2
- package/Server/API/MicrosoftTeamsAPI.ts +6 -1
- package/Server/API/ProjectAPI.ts +214 -0
- package/Server/API/StatusPageAPI.ts +39 -6
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.ts +50 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.ts +67 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Services/AIAgentService.ts +20 -0
- package/Server/Services/DashboardDomainService.ts +73 -28
- package/Server/Services/DatabaseService.ts +1 -0
- package/Server/Services/DeletedProjectService.ts +138 -0
- package/Server/Services/FileService.ts +61 -0
- package/Server/Services/IncidentEpisodePublicNoteService.ts +18 -0
- package/Server/Services/IncidentPublicNoteService.ts +18 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MonitorService.ts +311 -0
- package/Server/Services/ProbeService.ts +20 -0
- package/Server/Services/ProjectService.ts +297 -1
- package/Server/Services/PushNotificationService.ts +71 -0
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +18 -0
- package/Server/Services/StatusPageAnnouncementService.ts +53 -0
- package/Server/Services/StatusPageDomainService.ts +73 -28
- package/Server/Services/TeamMemberService.ts +117 -12
- package/Server/Services/TelemetryIngestionKeyService.ts +1 -0
- package/Server/Services/UserWebhookService.ts +34 -109
- package/Server/Services/WorkspaceNotificationRuleService.ts +69 -0
- package/Server/Services/WorkspaceProjectAuthTokenService.ts +37 -1
- package/Server/Types/Database/DeleteById.ts +2 -0
- package/Server/Types/Database/DeleteOneBy.ts +6 -0
- package/Server/Types/Domain.ts +41 -0
- package/Server/Types/Workflow/Components/API/Delete.ts +2 -1
- package/Server/Types/Workflow/Components/API/Get.ts +2 -1
- package/Server/Types/Workflow/Components/API/Patch.ts +2 -1
- package/Server/Types/Workflow/Components/API/Post.ts +2 -1
- package/Server/Types/Workflow/Components/API/Put.ts +2 -1
- package/Server/Types/Workflow/Components/API/Utils.ts +41 -2
- package/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.ts +25 -19
- package/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.ts +6 -5
- package/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.ts +32 -14
- package/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.ts +31 -13
- package/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.ts +29 -20
- package/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.ts +28 -21
- package/Server/Types/Workflow/Components/BaseModel/LogComponentError.ts +89 -0
- package/Server/Types/Workflow/Components/BaseModel/ModelArguments.ts +208 -0
- package/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.ts +11 -0
- package/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.ts +41 -18
- package/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.ts +45 -19
- package/Server/Types/Workflow/Components/Discord/SendMessageToChannel.ts +16 -9
- package/Server/Types/Workflow/Components/IncomingWebhookUtils.ts +66 -0
- package/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.ts +15 -9
- package/Server/Types/Workflow/Components/Slack/SendMessageToChannel.ts +17 -0
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
- package/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.ts +171 -0
- package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +3 -3
- package/Server/Utils/AI/SRE/Insights/FixRouting.ts +3 -2
- package/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.ts +1 -1
- package/Server/Utils/AI/Toolbox/CodeWriteTools.ts +6 -6
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +43 -5
- package/Server/Utils/DataSource/EgressGuard.ts +176 -16
- package/Server/Utils/DataSource/HttpFetch.ts +6 -45
- package/Server/Utils/Execute.ts +8 -0
- package/Server/Utils/InlineImageAccessTokenSync.ts +23 -0
- package/Server/Utils/LLM/LLMService.ts +57 -12
- package/Server/Utils/Monitor/MonitorAlert.ts +40 -0
- package/Server/Utils/Monitor/MonitorDependencySuppression.ts +192 -0
- package/Server/Utils/Monitor/MonitorIncident.ts +40 -0
- package/Server/Utils/Monitor/MonitorResource.ts +36 -0
- package/Server/Utils/Response.ts +142 -6
- package/Server/Utils/SSRFProtection.ts +273 -60
- package/Server/Utils/StartServer.ts +8 -0
- package/Server/Utils/VM/VMRunner.ts +88 -1
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +555 -49
- package/Server/Utils/Workspace/Slack/Slack.ts +25 -2
- package/Server/Utils/Workspace/WorkspaceBase.ts +6 -0
- package/Tests/App/Dashboard/DangerZone.test.tsx +334 -0
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +539 -0
- package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +678 -0
- package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +706 -0
- package/Tests/App/Dashboard/DashboardVariablesModal.test.tsx +508 -0
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +470 -0
- package/Tests/App/StatusPage/StatusPageDetailPagesNotFound.test.tsx +308 -0
- package/Tests/Models/DatabaseModels/DeletedProjectModel.test.ts +251 -0
- package/Tests/Models/DatabaseModels/SavedViewJSONColumnTuples.test.ts +115 -0
- package/Tests/Server/API/FileAPIAccessControl.test.ts +316 -0
- package/Tests/Server/API/ProjectAPI.test.ts +299 -1
- package/Tests/Server/API/ProjectAPIAdjustBalance.test.ts +459 -0
- package/Tests/Server/API/ProjectAPIAdjustBalanceBillingDisabled.test.ts +177 -0
- package/Tests/Server/Services/DatabaseServiceDeletionReason.test.ts +123 -0
- package/Tests/Server/Services/DeletedProjectService.test.ts +415 -0
- package/Tests/Server/Services/DeletedProjectServiceSelfHosted.test.ts +70 -0
- package/Tests/Server/Services/DomainSubdomainHooks.test.ts +94 -0
- package/Tests/Server/Services/FileIsPublicBooleanMigration.test.ts +244 -0
- package/Tests/Server/Services/FileServiceMimeType.test.ts +89 -0
- package/Tests/Server/Services/MonitorServiceDependencyValidation.test.ts +702 -0
- package/Tests/Server/Services/ProjectServiceAdjustBalance.test.ts +615 -0
- package/Tests/Server/Services/ProjectServiceDeleteAudit.test.ts +406 -0
- package/Tests/Server/Services/PublishTimeImageVisibility.test.ts +450 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +669 -0
- package/Tests/Server/Services/UserWebhookSSRF.test.ts +174 -0
- package/Tests/Server/Services/WebPushEndpointAllowlist.test.ts +133 -0
- package/Tests/Server/Services/WorkspaceProjectAuthTokenRepoint.test.ts +618 -0
- package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +26 -1
- package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +215 -0
- package/Tests/Server/Types/Workflow/Components/BaseModelDatabaseComponents.test.ts +742 -0
- package/Tests/Server/Types/Workflow/Components/ChatWebhookComponents.test.ts +256 -0
- package/Tests/Server/Types/Workflow/Components/ModelArguments.test.ts +371 -0
- package/Tests/Server/Utils/AI/CodeAgentCommandGuard.test.ts +204 -0
- package/Tests/Server/Utils/AI/CodeAgentWriteLimits.test.ts +213 -0
- package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +52 -5
- package/Tests/Server/Utils/AI/LLMServiceBaseUrl.test.ts +3 -0
- package/Tests/Server/Utils/AI/LLMServiceEgressGuard.test.ts +315 -0
- package/Tests/Server/Utils/AI/LLMServiceModelCompatibility.test.ts +3 -0
- package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +17 -5
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +14 -1
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +35 -0
- package/Tests/Server/Utils/AI/StubLLMEgressGuard.ts +25 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +62 -7
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +69 -0
- package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +330 -0
- package/Tests/Server/Utils/GitHubCreatePullRequestWithToken.test.ts +393 -0
- package/Tests/Server/Utils/InlineImageAccessTokenSync.test.ts +202 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppression.test.ts +811 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +604 -0
- package/Tests/Server/Utils/ResponseSendFileResponse.test.ts +192 -0
- package/Tests/Server/Utils/SSRFProtectionBypasses.test.ts +406 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +1169 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +2 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +1605 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTenantResolution.test.ts +1218 -0
- package/Tests/Types/AI/AIChatMessageStatus.test.ts +79 -0
- package/Tests/Types/AI/AIInsightStatus.test.ts +40 -0
- package/Tests/Types/API/HostnameAuthorityParsing.test.ts +157 -0
- package/Tests/Types/Dashboard/DashboardTemplateInvariants.test.ts +27 -0
- package/Tests/Types/DataSource/DataSourceLimits.test.ts +71 -0
- package/Tests/Types/DataSource/DataSourceType.test.ts +181 -0
- package/Tests/Types/DomainSubdomainValidation.test.ts +90 -0
- package/Tests/Types/JSONFunctions.test.ts +252 -1
- package/Tests/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.test.ts +61 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.test.ts +62 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.test.ts +68 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpVersion.test.ts +51 -0
- package/Tests/UI/Components/404.test.tsx +1 -1
- package/Tests/UI/Components/Alert.test.tsx +1 -1
- package/Tests/UI/Components/Badge.test.tsx +1 -1
- package/Tests/UI/Components/BasicForm.test.tsx +39 -10
- package/Tests/UI/Components/Button.test.tsx +1 -1
- package/Tests/UI/Components/Card.test.tsx +1 -1
- package/Tests/UI/Components/Charts/AxisTickColor.test.tsx +1 -1
- package/Tests/UI/Components/ColorViewer.test.tsx +1 -1
- package/Tests/UI/Components/ComponentsModal.test.tsx +7 -1
- package/Tests/UI/Components/DictionaryOfStrings.test.tsx +1 -1
- package/Tests/UI/Components/Dropdown.test.tsx +1 -1
- package/Tests/UI/Components/FilePicker.test.tsx +1 -1
- package/Tests/UI/Components/HiddenText.test.tsx +1 -1
- package/Tests/UI/Components/Input.test.tsx +1 -1
- package/Tests/UI/Components/Loader.test.tsx +1 -1
- package/Tests/UI/Components/LogTimeRangePicker.test.tsx +1 -1
- package/Tests/UI/Components/MasterPage.test.tsx +1 -1
- package/Tests/UI/Components/ModalPortalDismissal.test.tsx +489 -0
- package/Tests/UI/Components/ModelDelete.test.tsx +214 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableUrlState.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1 -1
- package/Tests/UI/Components/NavBar.test.tsx +1 -1
- package/Tests/UI/Components/OperatorSelectorKeyboard.test.tsx +1 -1
- package/Tests/UI/Components/Pagination.test.tsx +1 -1
- package/Tests/UI/Components/Pill.test.tsx +1 -1
- package/Tests/UI/Components/Probe.test.tsx +1 -1
- package/Tests/UI/Components/ProgressBar.test.tsx +1 -1
- package/Tests/UI/Components/RadioButtons.test.tsx +1 -1
- package/Tests/UI/Components/SideMenuItem.test.tsx +1 -1
- package/Tests/UI/Components/SideOver.test.tsx +500 -6
- package/Tests/UI/Components/Tabs.test.tsx +1 -1
- package/Tests/UI/Components/TelemetrySearchBar.test.tsx +1 -1
- package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +1 -1
- package/Tests/UI/Components/TextArea.test.tsx +1 -1
- package/Tests/UI/Components/Toast.test.tsx +1 -1
- package/Tests/UI/Components/Toggle.test.tsx +1 -1
- package/Tests/UI/Components/TopSection.test.tsx +1 -1
- package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +1 -1
- package/Tests/UI/Rum/ReplayScrubber.test.tsx +1 -1
- package/Tests/UI/Rum/ReplayStage.test.tsx +1 -1
- package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +1 -1
- package/Tests/UI/Utils/LocalStorageArrayRoundTrip.test.ts +72 -0
- package/Tests/Utils/Dashboard/HtmlWidgetDocument.test.ts +19 -2
- package/Tests/Utils/Dashboard/ModelQueryVariableInterpolation.test.ts +44 -0
- package/Tests/Utils/Dashboard/VariableInterpolation.test.ts +288 -5
- package/Tests/Utils/Dashboard/VariableUrlState.test.ts +42 -0
- package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +27 -0
- package/Tests/Utils/LegacySerializedArray.test.ts +139 -0
- package/Tests/Utils/Monitor/MonitorDependencyRule.test.ts +190 -0
- package/Tests/Utils/Realtime.test.ts +78 -0
- package/Tests/Utils/Telemetry/SavedViewFilters.test.ts +246 -0
- package/Tests/__mocks__/i18next-browser-languagedetector.js +21 -0
- package/Types/AI/FixPullRequestCiStatus.ts +1 -1
- package/Types/AI/FixVerificationStatus.ts +2 -2
- package/Types/API/Hostname.ts +92 -4
- package/Types/API/URL.ts +43 -25
- package/Types/Billing/BalanceAdjustmentType.ts +14 -0
- package/Types/Billing/ProjectBalanceType.ts +13 -0
- package/Types/Domain.ts +26 -0
- package/Types/File/MimeType.ts +11 -0
- package/Types/JSONFunctions.ts +15 -0
- package/Types/Telemetry/TelemetrySavedViewState.ts +9 -1
- package/Types/Workflow/Components/BaseModel.ts +92 -28
- package/Typings/Index.d.ts +12 -0
- package/UI/Components/GanttChart/ChartContainer.tsx +4 -3
- package/UI/Components/Modal/ConfirmModal.tsx +10 -5
- package/UI/Components/Modal/Modal.tsx +27 -47
- package/UI/Components/ModelDelete/ModelDelete.tsx +23 -6
- package/UI/Components/SideOver/SideOver.tsx +195 -68
- package/UI/Utils/PageScrollLock.ts +66 -0
- package/Utils/Dashboard/HtmlWidgetDocument.ts +4 -2
- package/Utils/Dashboard/VariableInterpolation.ts +19 -1
- package/Utils/LegacySerializedArray.ts +60 -0
- package/Utils/Monitor/MonitorDependencyRule.ts +88 -0
- package/Utils/Telemetry/SavedViewFilters.ts +88 -0
- package/build/dist/Models/DatabaseModels/AIInsight.js +1 -1
- package/build/dist/Models/DatabaseModels/AIInsight.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js +2 -3
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DeletedProject.js +640 -0
- package/build/dist/Models/DatabaseModels/DeletedProject.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +106 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +3 -3
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/FileAPI.js +14 -2
- package/build/dist/Server/API/FileAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +6 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectAPI.js +157 -4
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +27 -3
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js +30 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.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/Services/AIAgentService.js +17 -0
- package/build/dist/Server/Services/AIAgentService.js.map +1 -1
- package/build/dist/Server/Services/DashboardDomainService.js +55 -18
- package/build/dist/Server/Services/DashboardDomainService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +1 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DeletedProjectService.js +124 -0
- package/build/dist/Server/Services/DeletedProjectService.js.map +1 -0
- package/build/dist/Server/Services/FileService.js +52 -0
- package/build/dist/Server/Services/FileService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +10 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +10 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +232 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +17 -0
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +228 -6
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/PushNotificationService.js +56 -0
- package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +10 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageAnnouncementService.js +54 -0
- package/build/dist/Server/Services/StatusPageAnnouncementService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageDomainService.js +55 -18
- package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +97 -6
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js +1 -0
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
- package/build/dist/Server/Services/UserWebhookService.js +31 -87
- package/build/dist/Server/Services/UserWebhookService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +65 -0
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +23 -0
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
- package/build/dist/Server/Types/Domain.js +37 -0
- package/build/dist/Server/Types/Domain.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Utils.js +35 -2
- package/build/dist/Server/Types/Workflow/Components/API/Utils.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js +15 -11
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js +2 -3
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js +21 -10
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js +21 -10
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js +18 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js +18 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js +43 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js +116 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js +7 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js +24 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js +27 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js +14 -6
- package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js +42 -0
- package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js +15 -6
- package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js +10 -2
- package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js +141 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.js +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js +6 -6
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +39 -5
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +94 -10
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +1 -19
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
- package/build/dist/Server/Utils/Execute.js +2 -2
- package/build/dist/Server/Utils/Execute.js.map +1 -1
- package/build/dist/Server/Utils/InlineImageAccessTokenSync.js +13 -0
- package/build/dist/Server/Utils/InlineImageAccessTokenSync.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +43 -12
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +44 -24
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js +158 -0
- package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +50 -30
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +32 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +112 -5
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +219 -53
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +7 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +73 -1
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +445 -43
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +18 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
- package/build/dist/Types/AI/FixPullRequestCiStatus.js +1 -1
- package/build/dist/Types/AI/FixVerificationStatus.js +2 -2
- package/build/dist/Types/API/Hostname.js +73 -4
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/API/URL.js +42 -24
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Billing/BalanceAdjustmentType.js +15 -0
- package/build/dist/Types/Billing/BalanceAdjustmentType.js.map +1 -0
- package/build/dist/Types/Billing/ProjectBalanceType.js +14 -0
- package/build/dist/Types/Billing/ProjectBalanceType.js.map +1 -0
- package/build/dist/Types/Domain.js +22 -0
- package/build/dist/Types/Domain.js.map +1 -1
- package/build/dist/Types/File/MimeType.js +11 -0
- package/build/dist/Types/File/MimeType.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +14 -0
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/Workflow/Components/BaseModel.js +83 -28
- package/build/dist/Types/Workflow/Components/BaseModel.js.map +1 -1
- package/build/dist/UI/Components/GanttChart/ChartContainer.js +4 -3
- package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js +3 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +24 -34
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/ModelDelete/ModelDelete.js +11 -6
- package/build/dist/UI/Components/ModelDelete/ModelDelete.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +105 -30
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Utils/PageScrollLock.js +52 -0
- package/build/dist/UI/Utils/PageScrollLock.js.map +1 -0
- package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js +4 -2
- package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js.map +1 -1
- package/build/dist/Utils/Dashboard/VariableInterpolation.js +19 -1
- package/build/dist/Utils/Dashboard/VariableInterpolation.js.map +1 -1
- package/build/dist/Utils/LegacySerializedArray.js +51 -0
- package/build/dist/Utils/LegacySerializedArray.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorDependencyRule.js +47 -0
- package/build/dist/Utils/Monitor/MonitorDependencyRule.js.map +1 -0
- package/build/dist/Utils/Telemetry/SavedViewFilters.js +52 -0
- package/build/dist/Utils/Telemetry/SavedViewFilters.js.map +1 -0
- package/jest.config.json +3 -0
- package/package.json +1 -1
- package/tsconfig.json +3 -1
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
import "@testing-library/jest-dom";
|
|
2
|
+
import {
|
|
3
|
+
afterEach,
|
|
4
|
+
beforeEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
jest,
|
|
8
|
+
test,
|
|
9
|
+
} from "@jest/globals";
|
|
10
|
+
import {
|
|
11
|
+
act,
|
|
12
|
+
cleanup,
|
|
13
|
+
fireEvent,
|
|
14
|
+
render,
|
|
15
|
+
screen,
|
|
16
|
+
waitFor,
|
|
17
|
+
} from "@testing-library/react";
|
|
18
|
+
import * as React from "react";
|
|
19
|
+
import getJestMockFunction, { MockFunction } from "../../MockType";
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* A dashboard variable has two readers that must never disagree: the toolbar
|
|
23
|
+
* control, which tells the user what the board is scoped to, and the query
|
|
24
|
+
* interpolation in Common/Utils/Dashboard/VariableInterpolation.ts, which
|
|
25
|
+
* decides what the widgets actually fetch.
|
|
26
|
+
*
|
|
27
|
+
* Picking "All" emits selectedValue: "" — an explicit choice, distinct from
|
|
28
|
+
* "the user has not touched this yet" (undefined). The interpolation side has
|
|
29
|
+
* always read it that way (`??`), so "" applies no filter. The toolbar used
|
|
30
|
+
* `||`, which folds "" back into defaultValue: the dropdown snapped back to
|
|
31
|
+
* "prod" while the widgets went right on showing every cluster, and no amount
|
|
32
|
+
* of clicking could get out of it.
|
|
33
|
+
*
|
|
34
|
+
* So these tests assert both halves together — what the control displays AND
|
|
35
|
+
* what the same variable resolves to for the query — because a selector that
|
|
36
|
+
* merely looks right while the widgets are filtered differently is the exact
|
|
37
|
+
* bug being pinned here.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
const getTelemetryAttributeValuesMock: MockFunction = getJestMockFunction();
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
* The arrow wrapper is load bearing: jest.mock is hoisted above the compiled
|
|
44
|
+
* requires, so the mock variable above is still unassigned when the factory
|
|
45
|
+
* runs. Dereferencing it lazily, at call time, is what makes this work.
|
|
46
|
+
*/
|
|
47
|
+
jest.mock(
|
|
48
|
+
"../../../../App/FeatureSet/Dashboard/src/Components/Metrics/Utils/Metrics",
|
|
49
|
+
() => {
|
|
50
|
+
return {
|
|
51
|
+
__esModule: true,
|
|
52
|
+
default: {
|
|
53
|
+
getTelemetryAttributeValues: (...args: Array<any>): unknown => {
|
|
54
|
+
return getTelemetryAttributeValuesMock(...args);
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
import DashboardVariableSelector, {
|
|
62
|
+
VariableValueChange,
|
|
63
|
+
} from "../../../../App/FeatureSet/Dashboard/src/Components/Dashboard/Toolbar/DashboardVariableSelector";
|
|
64
|
+
import DashboardVariable, {
|
|
65
|
+
DashboardVariableType,
|
|
66
|
+
} from "../../../Types/Dashboard/DashboardVariable";
|
|
67
|
+
import DashboardVariableInterpolation, {
|
|
68
|
+
ResolvedVariableValue,
|
|
69
|
+
} from "../../../Utils/Dashboard/VariableInterpolation";
|
|
70
|
+
|
|
71
|
+
const ATTRIBUTE_KEY: string = "k8s.cluster.name";
|
|
72
|
+
const OPTIONS: Array<string> = ["prod", "staging"];
|
|
73
|
+
|
|
74
|
+
type MakeVariableFunction = (
|
|
75
|
+
overrides?: Partial<DashboardVariable>,
|
|
76
|
+
) => DashboardVariable;
|
|
77
|
+
|
|
78
|
+
const telemetryVariable: MakeVariableFunction = (
|
|
79
|
+
overrides: Partial<DashboardVariable> = {},
|
|
80
|
+
): DashboardVariable => {
|
|
81
|
+
return {
|
|
82
|
+
id: "cluster",
|
|
83
|
+
name: "cluster",
|
|
84
|
+
label: "Cluster",
|
|
85
|
+
type: DashboardVariableType.TelemetryAttribute,
|
|
86
|
+
attributeKey: ATTRIBUTE_KEY,
|
|
87
|
+
...overrides,
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const customListVariable: MakeVariableFunction = (
|
|
92
|
+
overrides: Partial<DashboardVariable> = {},
|
|
93
|
+
): DashboardVariable => {
|
|
94
|
+
return {
|
|
95
|
+
id: "region",
|
|
96
|
+
name: "region",
|
|
97
|
+
label: "Region",
|
|
98
|
+
type: DashboardVariableType.CustomList,
|
|
99
|
+
customListValues: "eu-west-1, us-east-1",
|
|
100
|
+
...overrides,
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const textVariable: MakeVariableFunction = (
|
|
105
|
+
overrides: Partial<DashboardVariable> = {},
|
|
106
|
+
): DashboardVariable => {
|
|
107
|
+
return {
|
|
108
|
+
id: "service",
|
|
109
|
+
name: "service",
|
|
110
|
+
label: "Service",
|
|
111
|
+
type: DashboardVariableType.TextInput,
|
|
112
|
+
...overrides,
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/*
|
|
117
|
+
* Verbatim from DashboardView.tsx's onVariableValueChange. The bug only
|
|
118
|
+
* appears on the render AFTER the parent stores the change, so a harness that
|
|
119
|
+
* did not round-trip through the owner's state could not see it.
|
|
120
|
+
*/
|
|
121
|
+
type ApplyVariableChangeFunction = (
|
|
122
|
+
variables: Array<DashboardVariable>,
|
|
123
|
+
variableId: string,
|
|
124
|
+
change: VariableValueChange,
|
|
125
|
+
) => Array<DashboardVariable>;
|
|
126
|
+
|
|
127
|
+
const applyVariableChange: ApplyVariableChangeFunction = (
|
|
128
|
+
variables: Array<DashboardVariable>,
|
|
129
|
+
variableId: string,
|
|
130
|
+
change: VariableValueChange,
|
|
131
|
+
): Array<DashboardVariable> => {
|
|
132
|
+
return variables.map((v: DashboardVariable): DashboardVariable => {
|
|
133
|
+
if (v.id !== variableId) {
|
|
134
|
+
return v;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (change.selectedValues !== undefined) {
|
|
138
|
+
return {
|
|
139
|
+
...v,
|
|
140
|
+
selectedValues: change.selectedValues,
|
|
141
|
+
selectedValue: undefined,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return { ...v, selectedValue: change.selectedValue };
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
interface RecordedChange {
|
|
150
|
+
variableId: string;
|
|
151
|
+
change: VariableValueChange;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** What the dashboard owner is holding after the user's interactions. */
|
|
155
|
+
interface ToolbarState {
|
|
156
|
+
variables: Array<DashboardVariable>;
|
|
157
|
+
changes: Array<RecordedChange>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
interface HarnessProps {
|
|
161
|
+
state: ToolbarState;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const ToolbarHarness: React.FunctionComponent<HarnessProps> = (
|
|
165
|
+
props: HarnessProps,
|
|
166
|
+
): React.ReactElement => {
|
|
167
|
+
const [variables, setVariables] = React.useState<Array<DashboardVariable>>(
|
|
168
|
+
props.state.variables,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<DashboardVariableSelector
|
|
173
|
+
variables={variables}
|
|
174
|
+
onVariableValueChange={(
|
|
175
|
+
variableId: string,
|
|
176
|
+
change: VariableValueChange,
|
|
177
|
+
) => {
|
|
178
|
+
const updated: Array<DashboardVariable> = applyVariableChange(
|
|
179
|
+
variables,
|
|
180
|
+
variableId,
|
|
181
|
+
change,
|
|
182
|
+
);
|
|
183
|
+
props.state.changes.push({ variableId: variableId, change: change });
|
|
184
|
+
props.state.variables = updated;
|
|
185
|
+
setVariables(updated);
|
|
186
|
+
}}
|
|
187
|
+
/>
|
|
188
|
+
);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
type RenderToolbarFunction = (
|
|
192
|
+
variables: Array<DashboardVariable>,
|
|
193
|
+
) => ToolbarState;
|
|
194
|
+
|
|
195
|
+
const renderToolbar: RenderToolbarFunction = (
|
|
196
|
+
variables: Array<DashboardVariable>,
|
|
197
|
+
): ToolbarState => {
|
|
198
|
+
const state: ToolbarState = { variables: variables, changes: [] };
|
|
199
|
+
render(<ToolbarHarness state={state} />);
|
|
200
|
+
return state;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
type GetSelectFunction = (index?: number) => HTMLSelectElement;
|
|
204
|
+
|
|
205
|
+
const getSelect: GetSelectFunction = (index: number = 0): HTMLSelectElement => {
|
|
206
|
+
return screen.getAllByRole("combobox")[index] as HTMLSelectElement;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
type GetTextInputFunction = (index?: number) => HTMLInputElement;
|
|
210
|
+
|
|
211
|
+
const getTextInput: GetTextInputFunction = (
|
|
212
|
+
index: number = 0,
|
|
213
|
+
): HTMLInputElement => {
|
|
214
|
+
return screen.getAllByRole("textbox")[index] as HTMLInputElement;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/*
|
|
218
|
+
* A TelemetryAttribute select is disabled, and holds only the "All" option,
|
|
219
|
+
* until its values come back — so every assertion about what it displays has
|
|
220
|
+
* to wait for that.
|
|
221
|
+
*/
|
|
222
|
+
type WaitForOptionsFunction = (index?: number) => Promise<HTMLSelectElement>;
|
|
223
|
+
|
|
224
|
+
const waitForOptions: WaitForOptionsFunction = async (
|
|
225
|
+
index: number = 0,
|
|
226
|
+
): Promise<HTMLSelectElement> => {
|
|
227
|
+
await waitFor((): void => {
|
|
228
|
+
expect(getSelect(index)).not.toBeDisabled();
|
|
229
|
+
});
|
|
230
|
+
return getSelect(index);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
type SelectValueFunction = (element: HTMLElement, value: string) => void;
|
|
234
|
+
|
|
235
|
+
const selectValue: SelectValueFunction = (
|
|
236
|
+
element: HTMLElement,
|
|
237
|
+
value: string,
|
|
238
|
+
): void => {
|
|
239
|
+
fireEvent.change(element, { target: { value: value } });
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
type OptionLabelsFunction = (select: HTMLSelectElement) => Array<string>;
|
|
243
|
+
|
|
244
|
+
const optionLabels: OptionLabelsFunction = (
|
|
245
|
+
select: HTMLSelectElement,
|
|
246
|
+
): Array<string> => {
|
|
247
|
+
return Array.from(select.options).map((option: HTMLOptionElement): string => {
|
|
248
|
+
return option.textContent || "";
|
|
249
|
+
});
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/** What the widgets would be filtered by, given what the toolbar is holding. */
|
|
253
|
+
type ResolveFunction = (
|
|
254
|
+
variable: DashboardVariable,
|
|
255
|
+
) => ResolvedVariableValue | undefined;
|
|
256
|
+
|
|
257
|
+
const resolvedFilter: ResolveFunction = (
|
|
258
|
+
variable: DashboardVariable,
|
|
259
|
+
): ResolvedVariableValue | undefined => {
|
|
260
|
+
return DashboardVariableInterpolation.resolveValue(variable);
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
beforeEach((): void => {
|
|
264
|
+
getTelemetryAttributeValuesMock.mockReset();
|
|
265
|
+
getTelemetryAttributeValuesMock.mockResolvedValue(OPTIONS);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
afterEach((): void => {
|
|
269
|
+
cleanup();
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
describe("DashboardVariableSelector", () => {
|
|
273
|
+
describe('picking "All" on a variable that has a default', () => {
|
|
274
|
+
test('the select stays on "All" instead of snapping back to the default', async () => {
|
|
275
|
+
const state: ToolbarState = renderToolbar([
|
|
276
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
277
|
+
]);
|
|
278
|
+
|
|
279
|
+
const select: HTMLSelectElement = await waitForOptions();
|
|
280
|
+
|
|
281
|
+
// Untouched, the variable shows its default. That part was never broken.
|
|
282
|
+
expect(select).toHaveValue("prod");
|
|
283
|
+
expect(select).toHaveDisplayValue("prod");
|
|
284
|
+
|
|
285
|
+
selectValue(select, "");
|
|
286
|
+
|
|
287
|
+
/*
|
|
288
|
+
* The whole report in two assertions: the value is the empty string the
|
|
289
|
+
* user picked, and what they read is "All" — not "prod".
|
|
290
|
+
*/
|
|
291
|
+
expect(getSelect()).toHaveValue("");
|
|
292
|
+
expect(getSelect()).toHaveDisplayValue("All");
|
|
293
|
+
expect(state.variables[0]!.selectedValue).toBe("");
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test("the change handed to the dashboard is an empty string, not undefined", async () => {
|
|
297
|
+
const state: ToolbarState = renderToolbar([
|
|
298
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
299
|
+
]);
|
|
300
|
+
|
|
301
|
+
selectValue(await waitForOptions(), "");
|
|
302
|
+
|
|
303
|
+
expect(state.changes).toEqual([
|
|
304
|
+
{ variableId: "cluster", change: { selectedValue: "" } },
|
|
305
|
+
]);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("what the toolbar shows and what the widgets query agree", async () => {
|
|
309
|
+
const state: ToolbarState = renderToolbar([
|
|
310
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
311
|
+
]);
|
|
312
|
+
|
|
313
|
+
selectValue(await waitForOptions(), "");
|
|
314
|
+
|
|
315
|
+
/*
|
|
316
|
+
* The damage the display bug did was not cosmetic: the toolbar claimed
|
|
317
|
+
* "prod" while the interpolation, reading the same variable, applied no
|
|
318
|
+
* filter at all and the widgets showed every cluster.
|
|
319
|
+
*/
|
|
320
|
+
expect(getSelect()).toHaveDisplayValue("All");
|
|
321
|
+
expect(resolvedFilter(state.variables[0]!)).toBeUndefined();
|
|
322
|
+
expect(
|
|
323
|
+
DashboardVariableInterpolation.applyToAttributes({}, state.variables),
|
|
324
|
+
).toEqual({});
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
test('a pre-existing filter on the attribute key is dropped when "All" is picked', async () => {
|
|
328
|
+
const state: ToolbarState = renderToolbar([
|
|
329
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
330
|
+
]);
|
|
331
|
+
|
|
332
|
+
selectValue(await waitForOptions(), "");
|
|
333
|
+
|
|
334
|
+
expect(
|
|
335
|
+
DashboardVariableInterpolation.applyToAttributes(
|
|
336
|
+
{ [ATTRIBUTE_KEY]: "prod", "service.name": "checkout" },
|
|
337
|
+
state.variables,
|
|
338
|
+
),
|
|
339
|
+
).toEqual({ "service.name": "checkout" });
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test("the user can pick a real value again afterwards", async () => {
|
|
343
|
+
const state: ToolbarState = renderToolbar([
|
|
344
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
345
|
+
]);
|
|
346
|
+
|
|
347
|
+
selectValue(await waitForOptions(), "");
|
|
348
|
+
expect(getSelect()).toHaveDisplayValue("All");
|
|
349
|
+
|
|
350
|
+
selectValue(getSelect(), "staging");
|
|
351
|
+
|
|
352
|
+
expect(getSelect()).toHaveValue("staging");
|
|
353
|
+
expect(resolvedFilter(state.variables[0]!)).toEqual({
|
|
354
|
+
scalar: "staging",
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test('"All" survives a round trip through a concrete value', async () => {
|
|
359
|
+
const state: ToolbarState = renderToolbar([
|
|
360
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
361
|
+
]);
|
|
362
|
+
|
|
363
|
+
selectValue(await waitForOptions(), "");
|
|
364
|
+
selectValue(getSelect(), "staging");
|
|
365
|
+
selectValue(getSelect(), "");
|
|
366
|
+
|
|
367
|
+
expect(getSelect()).toHaveValue("");
|
|
368
|
+
expect(getSelect()).toHaveDisplayValue("All");
|
|
369
|
+
expect(state.variables[0]!.selectedValue).toBe("");
|
|
370
|
+
expect(resolvedFilter(state.variables[0]!)).toBeUndefined();
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
test('a variable restored with an empty selection opens on "All"', async () => {
|
|
374
|
+
/*
|
|
375
|
+
* An explicit "All" that is already in place on the very first render,
|
|
376
|
+
* with no change event to reveal it. DashboardVariableUrlState.
|
|
377
|
+
* parseFromSearch produces exactly this from `var-cluster=`, and the
|
|
378
|
+
* public dashboard's server-side variable policy passes an empty
|
|
379
|
+
* string straight through.
|
|
380
|
+
*
|
|
381
|
+
* Note the asymmetry it implies: writeToBrowserUrl skips an empty
|
|
382
|
+
* selectedValue (Common/Utils/Dashboard/VariableUrlState.ts:117), so
|
|
383
|
+
* the URL cannot yet record an "All" the reader would happily restore.
|
|
384
|
+
* That gap is untouched here — this pins only the render.
|
|
385
|
+
*/
|
|
386
|
+
renderToolbar([
|
|
387
|
+
telemetryVariable({ defaultValue: "prod", selectedValue: "" }),
|
|
388
|
+
]);
|
|
389
|
+
|
|
390
|
+
const select: HTMLSelectElement = await waitForOptions();
|
|
391
|
+
|
|
392
|
+
expect(select).toHaveValue("");
|
|
393
|
+
expect(select).toHaveDisplayValue("All");
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
describe("the default value still works", () => {
|
|
398
|
+
test("an untouched variable shows and queries its default", async () => {
|
|
399
|
+
const state: ToolbarState = renderToolbar([
|
|
400
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
401
|
+
]);
|
|
402
|
+
|
|
403
|
+
expect(await waitForOptions()).toHaveValue("prod");
|
|
404
|
+
expect(resolvedFilter(state.variables[0]!)).toEqual({ scalar: "prod" });
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
test("a selected value takes precedence over the default", async () => {
|
|
408
|
+
renderToolbar([
|
|
409
|
+
telemetryVariable({ defaultValue: "prod", selectedValue: "staging" }),
|
|
410
|
+
]);
|
|
411
|
+
|
|
412
|
+
expect(await waitForOptions()).toHaveValue("staging");
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
test('a variable with no default and no selection opens on "All"', async () => {
|
|
416
|
+
const state: ToolbarState = renderToolbar([telemetryVariable({})]);
|
|
417
|
+
|
|
418
|
+
const select: HTMLSelectElement = await waitForOptions();
|
|
419
|
+
|
|
420
|
+
expect(select).toHaveValue("");
|
|
421
|
+
expect(select).toHaveDisplayValue("All");
|
|
422
|
+
expect(resolvedFilter(state.variables[0]!)).toBeUndefined();
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
test("a default the attribute no longer reports does not select some other value", async () => {
|
|
426
|
+
/*
|
|
427
|
+
* The attribute stopped reporting "prod" in this time range. There is no
|
|
428
|
+
* option to select, so the control lands on "All" — the point being that
|
|
429
|
+
* it does not silently scope the board to a different cluster.
|
|
430
|
+
*/
|
|
431
|
+
getTelemetryAttributeValuesMock.mockResolvedValue(["staging"]);
|
|
432
|
+
|
|
433
|
+
renderToolbar([telemetryVariable({ defaultValue: "prod" })]);
|
|
434
|
+
|
|
435
|
+
const select: HTMLSelectElement = await waitForOptions();
|
|
436
|
+
|
|
437
|
+
expect(optionLabels(select)).toEqual(["All", "staging"]);
|
|
438
|
+
expect(select).toHaveValue("");
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
describe("fetching the options", () => {
|
|
443
|
+
test("the variable's attribute key is what gets asked for", async () => {
|
|
444
|
+
renderToolbar([telemetryVariable({ defaultValue: "prod" })]);
|
|
445
|
+
|
|
446
|
+
await waitForOptions();
|
|
447
|
+
|
|
448
|
+
expect(getTelemetryAttributeValuesMock).toHaveBeenCalledWith({
|
|
449
|
+
attributeKey: ATTRIBUTE_KEY,
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
test('while values load the select is disabled and reads "Loading…"', async () => {
|
|
454
|
+
let releaseValues: (values: Array<string>) => void = (): void => {
|
|
455
|
+
// Replaced synchronously by the executor below.
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
getTelemetryAttributeValuesMock.mockImplementation((): unknown => {
|
|
459
|
+
return new Promise<Array<string>>(
|
|
460
|
+
(resolve: (values: Array<string>) => void): void => {
|
|
461
|
+
releaseValues = resolve;
|
|
462
|
+
},
|
|
463
|
+
);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
renderToolbar([telemetryVariable({ defaultValue: "prod" })]);
|
|
467
|
+
|
|
468
|
+
expect(getSelect()).toBeDisabled();
|
|
469
|
+
expect(optionLabels(getSelect())).toEqual(["Loading…"]);
|
|
470
|
+
|
|
471
|
+
await act(async (): Promise<void> => {
|
|
472
|
+
releaseValues(OPTIONS);
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
expect(getSelect()).not.toBeDisabled();
|
|
476
|
+
expect(optionLabels(getSelect())).toEqual(["All", "prod", "staging"]);
|
|
477
|
+
expect(getSelect()).toHaveValue("prod");
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
test('a failed fetch leaves the control usable and on "All"', async () => {
|
|
481
|
+
getTelemetryAttributeValuesMock.mockRejectedValue(
|
|
482
|
+
new Error("attribute values unavailable"),
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
renderToolbar([telemetryVariable({ defaultValue: "prod" })]);
|
|
486
|
+
|
|
487
|
+
const select: HTMLSelectElement = await waitForOptions();
|
|
488
|
+
|
|
489
|
+
expect(optionLabels(select)).toEqual(["All"]);
|
|
490
|
+
expect(select).toHaveValue("");
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
describe("custom list variables", () => {
|
|
495
|
+
test("options come from the comma-separated list, trimmed", () => {
|
|
496
|
+
renderToolbar([customListVariable({ defaultValue: "eu-west-1" })]);
|
|
497
|
+
|
|
498
|
+
expect(optionLabels(getSelect())).toEqual([
|
|
499
|
+
"All",
|
|
500
|
+
"eu-west-1",
|
|
501
|
+
"us-east-1",
|
|
502
|
+
]);
|
|
503
|
+
expect(getSelect()).toHaveValue("eu-west-1");
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
test('picking "All" stays on "All"', () => {
|
|
507
|
+
const state: ToolbarState = renderToolbar([
|
|
508
|
+
customListVariable({ defaultValue: "eu-west-1" }),
|
|
509
|
+
]);
|
|
510
|
+
|
|
511
|
+
selectValue(getSelect(), "");
|
|
512
|
+
|
|
513
|
+
expect(getSelect()).toHaveValue("");
|
|
514
|
+
expect(getSelect()).toHaveDisplayValue("All");
|
|
515
|
+
expect(state.variables[0]!.selectedValue).toBe("");
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
test("no network call is made for a custom list", () => {
|
|
519
|
+
renderToolbar([customListVariable({})]);
|
|
520
|
+
|
|
521
|
+
expect(getTelemetryAttributeValuesMock).not.toHaveBeenCalled();
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
describe("free-text variables", () => {
|
|
526
|
+
test("the default is shown until the user types", () => {
|
|
527
|
+
renderToolbar([textVariable({ defaultValue: "checkout" })]);
|
|
528
|
+
|
|
529
|
+
expect(getTextInput()).toHaveValue("checkout");
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
test("clearing the box leaves it empty instead of restoring the default", () => {
|
|
533
|
+
const state: ToolbarState = renderToolbar([
|
|
534
|
+
textVariable({ defaultValue: "checkout" }),
|
|
535
|
+
]);
|
|
536
|
+
|
|
537
|
+
fireEvent.change(getTextInput(), { target: { value: "" } });
|
|
538
|
+
|
|
539
|
+
/*
|
|
540
|
+
* Same defect, other control: with `||` the field refilled itself with
|
|
541
|
+
* "checkout" the instant it was emptied, so the value could never be
|
|
542
|
+
* cleared.
|
|
543
|
+
*/
|
|
544
|
+
expect(getTextInput()).toHaveValue("");
|
|
545
|
+
expect(state.variables[0]!.selectedValue).toBe("");
|
|
546
|
+
expect(resolvedFilter(state.variables[0]!)).toBeUndefined();
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
test("typing replaces the default and is stored", () => {
|
|
550
|
+
const state: ToolbarState = renderToolbar([
|
|
551
|
+
textVariable({ defaultValue: "checkout" }),
|
|
552
|
+
]);
|
|
553
|
+
|
|
554
|
+
fireEvent.change(getTextInput(), { target: { value: "payments" } });
|
|
555
|
+
|
|
556
|
+
expect(getTextInput()).toHaveValue("payments");
|
|
557
|
+
expect(state.variables[0]!.selectedValue).toBe("payments");
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test("a cleared box can be typed into again", () => {
|
|
561
|
+
renderToolbar([textVariable({ defaultValue: "checkout" })]);
|
|
562
|
+
|
|
563
|
+
fireEvent.change(getTextInput(), { target: { value: "" } });
|
|
564
|
+
fireEvent.change(getTextInput(), { target: { value: "payments" } });
|
|
565
|
+
|
|
566
|
+
expect(getTextInput()).toHaveValue("payments");
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
describe("several variables on one toolbar", () => {
|
|
571
|
+
test("each is labelled and rendered with its own control", async () => {
|
|
572
|
+
renderToolbar([
|
|
573
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
574
|
+
customListVariable({ defaultValue: "eu-west-1" }),
|
|
575
|
+
textVariable({ defaultValue: "checkout" }),
|
|
576
|
+
]);
|
|
577
|
+
|
|
578
|
+
await waitForOptions();
|
|
579
|
+
|
|
580
|
+
expect(screen.getByText("Cluster")).toBeInTheDocument();
|
|
581
|
+
expect(screen.getByText("Region")).toBeInTheDocument();
|
|
582
|
+
expect(screen.getByText("Service")).toBeInTheDocument();
|
|
583
|
+
expect(screen.getAllByRole("combobox")).toHaveLength(2);
|
|
584
|
+
expect(screen.getAllByRole("textbox")).toHaveLength(1);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
test('picking "All" on one leaves the others on their defaults', async () => {
|
|
588
|
+
const state: ToolbarState = renderToolbar([
|
|
589
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
590
|
+
customListVariable({ defaultValue: "eu-west-1" }),
|
|
591
|
+
]);
|
|
592
|
+
|
|
593
|
+
selectValue(await waitForOptions(0), "");
|
|
594
|
+
|
|
595
|
+
expect(getSelect(0)).toHaveDisplayValue("All");
|
|
596
|
+
expect(getSelect(1)).toHaveValue("eu-west-1");
|
|
597
|
+
expect(state.variables[1]!.selectedValue).toBeUndefined();
|
|
598
|
+
expect(resolvedFilter(state.variables[1]!)).toEqual({
|
|
599
|
+
scalar: "eu-west-1",
|
|
600
|
+
});
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
test("a second variable changing does not resurrect the first one's default", async () => {
|
|
604
|
+
const state: ToolbarState = renderToolbar([
|
|
605
|
+
telemetryVariable({ defaultValue: "prod" }),
|
|
606
|
+
customListVariable({ defaultValue: "eu-west-1" }),
|
|
607
|
+
]);
|
|
608
|
+
|
|
609
|
+
selectValue(await waitForOptions(0), "");
|
|
610
|
+
selectValue(getSelect(1), "us-east-1");
|
|
611
|
+
|
|
612
|
+
/*
|
|
613
|
+
* The re-render that the second variable forces is exactly where the
|
|
614
|
+
* first one used to jump back to "prod".
|
|
615
|
+
*/
|
|
616
|
+
expect(getSelect(0)).toHaveValue("");
|
|
617
|
+
expect(getSelect(0)).toHaveDisplayValue("All");
|
|
618
|
+
expect(getSelect(1)).toHaveValue("us-east-1");
|
|
619
|
+
expect(state.variables[0]!.selectedValue).toBe("");
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
test("the variable label falls back to the name when unset", () => {
|
|
623
|
+
renderToolbar([customListVariable({ label: undefined })]);
|
|
624
|
+
|
|
625
|
+
expect(screen.getByText("region")).toBeInTheDocument();
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
describe("multi-select variables", () => {
|
|
630
|
+
test('the button reads "All" while nothing is picked, default or not', async () => {
|
|
631
|
+
renderToolbar([
|
|
632
|
+
telemetryVariable({ isMultiSelect: true, defaultValue: "prod" }),
|
|
633
|
+
]);
|
|
634
|
+
|
|
635
|
+
await waitFor((): void => {
|
|
636
|
+
expect(screen.getByRole("button")).not.toBeDisabled();
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
expect(screen.getByRole("button")).toHaveTextContent("All");
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
test("picking and then clearing values returns the button to All", async () => {
|
|
643
|
+
const state: ToolbarState = renderToolbar([
|
|
644
|
+
telemetryVariable({ isMultiSelect: true, defaultValue: "prod" }),
|
|
645
|
+
]);
|
|
646
|
+
|
|
647
|
+
await waitFor((): void => {
|
|
648
|
+
expect(screen.getByRole("button")).not.toBeDisabled();
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
fireEvent.click(screen.getByRole("button"));
|
|
652
|
+
fireEvent.click(screen.getByRole("checkbox", { name: "staging" }));
|
|
653
|
+
|
|
654
|
+
expect(state.variables[0]!.selectedValues).toEqual(["staging"]);
|
|
655
|
+
expect(
|
|
656
|
+
screen.getByRole("button", { name: /staging/ }),
|
|
657
|
+
).toBeInTheDocument();
|
|
658
|
+
|
|
659
|
+
fireEvent.click(screen.getByRole("button", { name: "Clear" }));
|
|
660
|
+
|
|
661
|
+
expect(state.variables[0]!.selectedValues).toEqual([]);
|
|
662
|
+
expect(screen.getAllByRole("button")[0]).toHaveTextContent("All");
|
|
663
|
+
});
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
test("no variables renders nothing at all", () => {
|
|
667
|
+
const { container }: { container: HTMLElement } = render(
|
|
668
|
+
<DashboardVariableSelector
|
|
669
|
+
variables={[]}
|
|
670
|
+
onVariableValueChange={(): void => {
|
|
671
|
+
// Never called: there is nothing to change.
|
|
672
|
+
}}
|
|
673
|
+
/>,
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
expect(container).toBeEmptyDOMElement();
|
|
677
|
+
});
|
|
678
|
+
});
|