From 08b8087190dd8b3cb59a71a21f687a979f6ff53f Mon Sep 17 00:00:00 2001 From: ktx-vaidehi Date: Mon, 3 Aug 2026 11:22:57 +0530 Subject: [PATCH] fix: i18n migration --- I18N_ENFORCEMENT_GUIDE.md | 256 +- web/eslint.config.js | 97 +- web/src/components/AutoRefreshInterval.vue | 9 +- web/src/components/CodeQueryEditor.vue | 7 +- web/src/components/ConfirmDialogProvider.vue | 6 +- web/src/components/CopyContent.spec.ts | 15 +- web/src/components/CopyContent.vue | 10 +- web/src/components/CustomDateTimePicker.vue | 47 +- web/src/components/DateTime.vue | 11 +- web/src/components/MenuLink.vue | 10 +- web/src/components/O2AIChat.vue | 81 +- web/src/components/O2AIConfirmDialog.vue | 19 +- web/src/components/OrganizationSelector.vue | 4 +- web/src/components/QueryEditor.vue | 12 +- web/src/components/QueryPlanDialog.vue | 5 +- web/src/components/RichTextInput.vue | 13 +- web/src/components/ThemeSwitcher.vue | 5 +- web/src/components/WebinarBanner.vue | 4 +- .../components/actionScripts/EditScript.vue | 12 +- .../ai-assistant/welcome/useGreeting.ts | 7 +- .../components/ai_toolsets/AddAiToolset.vue | 21 +- web/src/components/alerts/AddAlert.vue | 7 +- web/src/components/alerts/AddDestination.vue | 10 +- .../components/alerts/AlertHistory.spec.ts | 6 +- web/src/components/alerts/AlertHistory.vue | 8 +- .../alerts/AlertHistoryTimeline.vue | 34 +- web/src/components/alerts/AlertList.vue | 5 +- .../components/alerts/AlertTargetsSelect.vue | 10 +- .../components/alerts/CustomConfirmDialog.vue | 20 +- .../components/alerts/DestinationPreview.vue | 8 +- web/src/components/alerts/FieldsInput.vue | 8 +- web/src/components/alerts/FilterCondition.vue | 8 +- web/src/components/alerts/ImportAlert.vue | 54 +- .../components/alerts/ImportDestination.vue | 29 +- .../alerts/ImportSemanticGroups.vue | 6 +- .../alerts/ImportSemanticGroupsDrawer.vue | 6 +- web/src/components/alerts/ImportTemplate.vue | 28 +- .../alerts/IncidentAlertTriggersTable.vue | 5 +- .../alerts/IncidentDetailDrawer.spec.ts | 5 +- .../alerts/IncidentDetailDrawer.vue | 38 +- web/src/components/alerts/IncidentList.vue | 7 +- .../components/alerts/IncidentTimeline.vue | 4 +- .../OrganizationDeduplicationSettings.vue | 4 +- web/src/components/alerts/PreviewAlert.vue | 6 +- .../components/alerts/QueryEditorDialog.vue | 6 +- .../alerts/SemanticFieldGroupsConfig.vue | 6 +- web/src/components/alerts/steps/Advanced.vue | 7 +- .../components/alerts/steps/AlertSettings.vue | 7 +- .../alerts/steps/CompareWithPast.vue | 5 +- .../components/alerts/steps/QueryConfig.vue | 17 +- .../steps/AnomalyDetectionConfig.vue | 23 +- .../components/cipherkeys/AddAkeylessType.vue | 11 +- .../components/cipherkeys/AddCipherKey.vue | 8 +- .../cipherkeys/AddEncryptionMechanism.vue | 9 +- web/src/components/common/AppTabs.vue | 11 +- web/src/components/common/BaseImport.vue | 44 +- web/src/components/common/GroupHeader.vue | 13 +- web/src/components/common/JsonEditor.vue | 14 +- web/src/components/common/KpiCard.vue | 5 +- web/src/components/common/QueryErrorState.vue | 6 +- web/src/components/common/RelativeTime.vue | 8 +- web/src/components/common/SectionHub.vue | 11 +- web/src/components/common/SectionRail.vue | 3 +- web/src/components/common/ShareButton.vue | 7 +- .../common/empty-states/EmptyState.vue | 7 +- .../common/empty-states/QuickStartCard.vue | 5 +- .../common/sidebar/SearchFieldList.spec.ts | 5 + .../common/sidebar/SearchFieldList.vue | 2 +- .../cross-linking/CrossLinkDialog.vue | 4 +- .../cross-linking/CrossLinkManager.spec.ts | 5 +- .../cross-linking/CrossLinkManager.vue | 17 +- .../dashboards/AddDashboardFromGitHub.spec.ts | 2 +- .../dashboards/AddDashboardFromGitHub.vue | 11 +- .../PanelEditor/types/panelEditor.ts | 10 +- .../components/dashboards/QueryInspector.vue | 4 +- .../dashboards/addPanel/AddAnnotation.vue | 14 +- .../addPanel/AxisFieldChipLabel.vue | 3 +- .../addPanel/ColorPaletteDropDown.vue | 6 +- .../dashboards/addPanel/ConfigPanel.vue | 19 +- .../addPanel/DashboardQueryEditor.vue | 5 +- .../addPanel/DrilldownUserGuide.vue | 2 +- .../dashboards/addPanel/OverrideConfig.vue | 4 +- .../dashboards/addPanel/PanelFieldList.vue | 4 +- .../dashboards/addPanel/PanelSidebar.vue | 5 +- .../addPanel/TablePaginationControls.spec.ts | 3 + .../addPanel/TablePaginationControls.vue | 5 +- .../CustomChartConfirmDialog.vue | 8 +- .../CustomChartTypeSelector.vue | 8 +- .../customChartExampleTypes.ts | 54 +- .../settings/AddSettingVariable.vue | 21 +- .../settings/VariableAdHocValueSelector.vue | 7 +- .../settings/common/DashboardHeader.vue | 8 +- web/src/components/flow/NodePalette.vue | 5 +- web/src/components/flow/StepPickerDialog.vue | 16 +- .../functions/AddEnrichmentTable.vue | 12 +- web/src/components/functions/AddFunction.vue | 10 +- .../functions/FullViewContainer.vue | 5 +- web/src/components/functions/TestFunction.vue | 22 +- web/src/components/iam/IngestionTokens.vue | 4 +- web/src/components/iam/groups/EditGroup.vue | 4 +- web/src/components/iam/groups/GroupUsers.vue | 4 +- web/src/components/iam/quota/Quota.vue | 9 +- web/src/components/iam/roles/EditRole.vue | 4 +- .../iam/serviceAccounts/AddServiceAccount.vue | 4 +- .../serviceAccounts/ServiceAccountsList.vue | 9 +- web/src/components/iam/users/AddUser.vue | 11 +- .../components/iam/users/InvitationList.vue | 3 +- web/src/components/iam/users/User.vue | 4 +- .../components/ingestion/AIIntegrations.vue | 7 +- web/src/components/ingestion/Custom.vue | 4 +- .../ingestion/DataSourceSidebarLayout.vue | 10 +- web/src/components/ingestion/Languages.vue | 4 +- .../ingestion/ai/AIIntegrationDetail.vue | 6 +- .../components/ingestion/ai/McpServerCard.vue | 8 +- .../ai/content/AIIntegrationCard.vue | 6 +- .../ingestion/ai/content/manifest.ts | 4 +- .../ingestion/ai/content/parseCard.ts | 10 +- .../ai/content/richCard/buildFromMarkdown.ts | 40 +- .../ingestion/databases/CouchDB.vue | 3 +- .../ingestion/databases/Elasticsearch.vue | 3 +- .../ingestion/databases/SAPHana.vue | 3 +- .../components/ingestion/devops/Ansible.vue | 3 +- .../ingestion/devops/GithubActions.vue | 3 +- .../components/ingestion/devops/Jenkins.vue | 3 +- .../components/ingestion/devops/Terraform.vue | 3 +- .../ingestion/languages/DotNetLogs.vue | 3 +- .../ingestion/languages/DotNetTracing.vue | 3 +- .../ingestion/languages/FastAPI.vue | 3 +- web/src/components/ingestion/languages/Go.vue | 3 +- .../components/ingestion/languages/Java.vue | 3 +- .../components/ingestion/languages/NodeJS.vue | 3 +- .../components/ingestion/languages/Python.vue | 4 +- .../components/ingestion/languages/Rust.vue | 3 +- web/src/components/ingestion/logs/Curl.vue | 4 +- .../components/ingestion/logs/FileBeat.vue | 4 +- .../components/ingestion/logs/FluentBit.vue | 5 +- web/src/components/ingestion/logs/Fluentd.vue | 4 +- web/src/components/ingestion/logs/Index.vue | 4 +- .../ingestion/logs/LogstashDatasource.vue | 4 +- .../ingestion/logs/LoongCollector.vue | 5 +- .../components/ingestion/logs/SyslogNg.vue | 4 +- web/src/components/ingestion/logs/Vector.vue | 4 +- .../ingestion/messagequeues/Kafka.vue | 3 +- .../ingestion/messagequeues/Nats.vue | 3 +- .../ingestion/messagequeues/RabbitMQ.vue | 3 +- .../ingestion/metrics/CategrafConfig.vue | 5 +- .../ingestion/metrics/CloudWatchMetrics.vue | 5 +- .../ingestion/metrics/Index.spec.ts | 2 +- .../components/ingestion/metrics/Index.vue | 4 +- .../ingestion/metrics/NightingaleConfig.vue | 5 +- .../ingestion/metrics/OtelCollector.vue | 6 +- .../ingestion/metrics/PrometheusConfig.vue | 5 +- .../ingestion/metrics/TelegrafConfig.vue | 4 +- .../ingestion/metrics/VMagentConfig.vue | 7 +- .../ingestion/networking/Netflow.vue | 3 +- .../components/ingestion/others/Airbyte.vue | 3 +- .../components/ingestion/others/Airflow.vue | 3 +- web/src/components/ingestion/others/Cribl.vue | 3 +- .../components/ingestion/others/Heroku.vue | 3 +- .../components/ingestion/others/Vercel.vue | 3 +- .../ingestion/recommended/AWSConfig.vue | 5 +- .../recommended/AWSIndividualServices.spec.ts | 8 +- .../recommended/AWSIndividualServices.vue | 2 +- .../recommended/AWSIntegrationTile.spec.ts | 94 +- .../recommended/AWSIntegrationTile.vue | 20 +- .../ingestion/recommended/AWSQuickSetup.vue | 20 +- .../ingestion/recommended/AzureConfig.vue | 13 +- .../recommended/KubernetesConfig.spec.ts | 10 +- .../ingestion/recommended/OtelConfig.vue | 6 +- .../components/ingestion/security/Falco.vue | 3 +- .../ingestion/security/GoogleWorkspace.vue | 3 +- .../ingestion/security/Jumpcloud.vue | 3 +- .../components/ingestion/security/OSQuery.vue | 3 +- .../ingestion/security/Office365.vue | 3 +- .../components/ingestion/security/Okta.vue | 3 +- .../components/ingestion/security/OpenVPN.vue | 3 +- .../components/ingestion/servers/Apache.vue | 3 +- web/src/components/ingestion/servers/IIS.vue | 3 +- .../components/ingestion/servers/Nginx.vue | 3 +- .../setupCard/DataSourceSetupCard.vue | 3 +- .../setupCard/SetupCardRenderer.spec.ts | 47 + .../ingestion/setupCard/SetupCardRenderer.vue | 74 +- .../ingestion/setupCard/content/aerospike.ts | 35 +- .../ingestion/setupCard/content/cassandra.ts | 41 +- .../ingestion/setupCard/content/databricks.ts | 15 +- .../ingestion/setupCard/content/dynamodb.ts | 22 +- .../ingestion/setupCard/content/gcp.ts | 29 +- .../ingestion/setupCard/content/kubernetes.ts | 44 +- .../ingestion/setupCard/content/linux.ts | 20 +- .../ingestion/setupCard/content/macos.ts | 16 +- .../ingestion/setupCard/content/mongodb.ts | 48 +- .../ingestion/setupCard/content/mysql.ts | 47 +- .../ingestion/setupCard/content/oracle.ts | 42 +- .../ingestion/setupCard/content/osAgent.ts | 16 +- .../ingestion/setupCard/content/otelShared.ts | 28 +- .../ingestion/setupCard/content/otlpTraces.ts | 28 +- .../ingestion/setupCard/content/postgres.ts | 40 +- .../ingestion/setupCard/content/redis.ts | 35 +- .../ingestion/setupCard/content/rum.spec.ts | 14 +- .../ingestion/setupCard/content/rum.ts | 31 +- .../setupCard/content/rumReactNative.spec.ts | 2 +- .../setupCard/content/rumReactNative.ts | 41 +- .../ingestion/setupCard/content/snowflake.ts | 20 +- .../ingestion/setupCard/content/sqlServer.ts | 40 +- .../ingestion/setupCard/content/windows.ts | 20 +- .../ingestion/setupCard/content/zookeeper.ts | 35 +- .../components/ingestion/setupCard/types.ts | 84 +- web/src/components/ingestion/traces/Index.vue | 4 +- web/src/components/logstream/AddStream.vue | 8 +- .../logstream/StreamFieldInputs.vue | 47 +- web/src/components/logstream/schema.vue | 60 +- .../pipeline/ImportPipeline.spec.ts | 5 +- .../components/pipeline/ImportPipeline.vue | 83 +- .../NodeForm/CreateDestinationForm.vue | 32 +- .../components/pipeline/NodeForm/Query.vue | 4 +- .../pipeline/NodeForm/ScheduledPipeline.vue | 12 +- .../components/pipeline/NodeForm/Stream.vue | 6 +- .../components/pipeline/PipelineEditor.vue | 38 +- .../pipeline/PipelineSectionTabs.vue | 4 +- web/src/components/pipeline/PipelineView.vue | 34 +- web/src/components/pipeline/PipelinesList.vue | 4 +- .../components/pipeline/StreamSelection.vue | 8 +- .../pipelines/BackfillJobDetails.vue | 57 +- .../pipelines/CreateBackfillJobDialog.vue | 4 +- .../pipelines/EditBackfillJobDialog.vue | 8 +- .../promql/components/LabelFilterEditor.vue | 8 +- .../promql/components/OperationsList.vue | 23 +- web/src/components/promql/operations/index.ts | 100 +- web/src/components/promql/types/index.ts | 22 +- web/src/components/queries/RunningQueries.vue | 55 +- web/src/components/reports/CreateReport.vue | 61 +- .../rum/EventDetailDrawerContent.vue | 8 +- .../components/rum/MobileSessionPlayer.vue | 12 +- .../components/rum/PlayerEventsSidebar.vue | 12 +- web/src/components/rum/VideoPlayer.vue | 14 +- .../rum/common/EventDetailsSection.vue | 5 +- web/src/components/rum/common/KeyValueRow.vue | 3 +- .../rum/correlation/TraceCorrelationCard.vue | 2 +- .../rum/errorTracking/list/ErrorIssueCell.vue | 6 +- .../errorTracking/list/ErrorsFilterBar.vue | 4 +- .../sessionReplay/SessionsInsightBanner.vue | 4 +- .../components/settings/AddRegexPattern.vue | 3 +- .../settings/BuiltInPatternsTab.vue | 9 +- .../settings/DiscoveredServices.vue | 11 +- web/src/components/settings/General.vue | 5 +- .../settings/ImportSyntheticsLocations.vue | 4 +- .../settings/ModelPricingEditor.vue | 12 +- .../components/settings/OrgStorageEditor.vue | 10 +- .../settings/OrganizationManagement.spec.ts | 2 +- .../settings/ServiceIdentitySetup.vue | 88 +- .../settings/SyntheticsLocationForm.vue | 6 +- web/src/components/settings/index.vue | 11 +- web/src/components/shared/grid/NoData.vue | 4 +- .../synthetic-monitoring/AgentSetupDrawer.vue | 4 +- .../synthetic-monitoring/MonitorTable.vue | 24 +- .../synthetics/configure/CheckAlerts.vue | 4 +- .../synthetics/configure/CheckAuthNetwork.vue | 4 +- .../configure/CheckBrowserDevices.vue | 8 +- .../synthetics/configure/CheckDetails.vue | 14 +- .../synthetics/configure/CheckRetries.vue | 6 +- .../synthetics/configure/CheckSchedule.vue | 16 +- .../configure/types/CheckHttpConfig.vue | 4 +- .../synthetics/journey/BrowserJourney.vue | 19 +- .../synthetics/journey/BrowserJourneyStep.vue | 22 +- .../synthetics/journey/JourneySteps.vue | 4 +- .../synthetics/results/ProtocolRunSummary.vue | 12 +- .../synthetics/results/RunDetailDrawer.vue | 4 +- .../workflows/WorkflowLinkAlertsDialog.vue | 6 +- .../workflows/WorkflowNodeDrawer.vue | 4 +- .../workflows/WorkflowRunsPanel.vue | 6 +- .../workflows/WorkflowTestDialog.vue | 4 +- .../dashboard/useColumnFormatting.ts | 6 +- .../dashboard/usePanelPromQLExecutor.ts | 3 +- .../dashboard/useVariablesManager.ts | 6 +- .../metrics/useMetricsExplorerGrid.ts | 11 +- .../composables/rum/useMobileSessionReplay.ts | 4 +- .../synthetics/syntheticResultsSchema.spec.ts | 24 +- .../synthetics/syntheticResultsSchema.ts | 18 +- web/src/composables/useChatHistory.ts | 4 +- web/src/composables/useConfirmDialog.ts | 6 +- web/src/composables/useCorrelatedLogs.ts | 4 +- web/src/composables/useFavoriteDashboards.ts | 4 +- web/src/composables/useHomeDashboard.ts | 6 +- web/src/composables/useLogs/searchAround.ts | 6 +- web/src/composables/useLogs/searchState.ts | 10 +- .../composables/useLogs/useHistogram.spec.ts | 53 +- web/src/composables/useLogs/useHistogram.ts | 47 +- web/src/composables/useLogs/useSearchBar.ts | 2 +- .../useLogs/useSearchConnection.ts | 2 +- web/src/composables/useLogs/useSearchQuery.ts | 3 +- .../useLogs/useSearchResponseHandler.ts | 4 +- .../composables/useLogs/useSearchStream.ts | 4 +- .../useLogs/useSearchStreamRefactored.ts | 4 +- .../composables/useLogs/useStreamFields.ts | 4 +- .../composables/useMetricSubjectButtons.ts | 41 +- web/src/composables/useServiceGraphTree.ts | 4 +- web/src/composables/useStreams.ts | 4 +- web/src/composables/useTextHighlighter.ts | 4 +- web/src/composables/useTreeVisualization.ts | 4 +- .../useUnauthorizedErrorGrouper.ts | 10 +- web/src/constants/features.ts | 14 +- web/src/constants/synthetics.ts | 65 +- .../AIObservability/AiNoAgentsEmpty.vue | 7 +- .../AIObservability/AiPageShell.vue | 9 +- .../components/AIObservability/AiScopeBar.vue | 3 +- .../AIObservability/VersionCompareView.vue | 7 +- .../AIObservability/VersionDeltaStrip.vue | 4 +- web/src/enterprise/components/OnlineEvals.vue | 12 +- .../components/billings/Billing.vue | 31 +- .../onlineEvals/ImportScoreConfig.vue | 8 +- .../components/onlineEvals/ImportScorer.vue | 11 +- .../onlineEvals/ManualEvaluationDialog.vue | 4 +- .../components/onlineEvals/QualityPage.vue | 10 +- .../onlineEvals/ScoreConfigList.vue | 4 +- .../components/onlineEvals/ScorerLibrary.vue | 2 +- .../composables/useQualityDetailCharts.ts | 16 +- .../composables/useQualityScoreConfigs.ts | 6 +- .../onlineEvals/forms/EvalJobDetail.vue | 10 +- .../onlineEvals/forms/JobFormPage.vue | 20 +- .../onlineEvals/forms/ProviderFormPage.vue | 20 +- .../onlineEvals/forms/ScoreConfigDetail.vue | 4 +- .../onlineEvals/forms/ScoreConfigDialog.vue | 8 +- .../onlineEvals/forms/ScorerDetail.vue | 10 +- .../onlineEvals/forms/ScorerFormPage.vue | 21 +- .../onlineEvals/forms/ScorerTypeDialog.vue | 6 +- .../onlineEvals/forms/job/JobInputMapping.vue | 9 +- .../onlineEvals/forms/job/JobScorerPicker.vue | 4 +- .../forms/job/SpanSelectorBinding.vue | 6 +- .../quality/QualityBooleanTrendChart.vue | 3 +- .../quality/QualityDistributionChart.vue | 3 +- .../onlineEvals/quality/QualityTrendChart.vue | 3 +- .../utils/importScoreConfig.spec.ts | 8 +- .../onlineEvals/utils/importScoreConfig.ts | 52 +- .../onlineEvals/utils/importScorer.spec.ts | 8 +- .../onlineEvals/utils/importScorer.ts | 46 +- .../onlineEvals/utils/scoreThreshold.ts | 20 +- .../enterprise/composables/useAgentScope.ts | 4 +- .../AgentSignalDetailPanel.vue | 8 +- .../views/AIObservability/Index.vue | 6 +- .../AIObservability/PanelSectionHeader.vue | 5 +- web/src/lib/core/Badge/ODimensionChip.vue | 3 +- web/src/lib/core/Badge/OTag.vue | 7 +- web/src/lib/core/Badge/badgeGroups.spec.ts | 16 +- web/src/lib/core/Badge/badgeGroups.ts | 284 ++- web/src/lib/core/Code/OCodeBlock.types.ts | 10 +- web/src/lib/core/Code/OCodeBlock.vue | 15 +- .../core/Collapsible/OCollapsible.types.ts | 6 +- .../core/EmptyState/EmptyStateActionCard.vue | 5 +- .../EmptyState/EmptyStateIngestionCard.vue | 5 +- web/src/lib/core/EmptyState/OEmptyState.vue | 24 +- web/src/lib/core/Icon/OIcon.types.ts | 4 +- web/src/lib/core/Navbar/ONavGroup.vue | 4 +- web/src/lib/core/Navbar/ONavbar.types.ts | 6 +- web/src/lib/core/Navbar/navGroups.ts | 6 +- web/src/lib/core/PageHeader/OPageHeader.vue | 11 +- web/src/lib/core/PageLayout/OPageLayout.vue | 7 +- web/src/lib/core/Table/OTable.types.ts | 6 +- web/src/lib/core/Table/OTable.vue | 4 +- web/src/lib/core/Table/cells/OCodeCell.vue | 6 +- web/src/lib/core/Table/cells/ODataBarCell.vue | 5 +- web/src/lib/core/Table/cells/ONumberCell.vue | 5 +- web/src/lib/core/Table/cells/OTimeCell.vue | 5 +- web/src/lib/core/Table/cells/OUserCell.vue | 14 +- web/src/lib/core/Table/cells/statusVariant.ts | 11 +- .../core/Table/sub-components/OTableEmpty.vue | 4 +- .../core/Table/sub-components/OTableError.vue | 4 +- .../Table/sub-components/OTablePagination.vue | 8 +- .../core/ToggleGroup/OToggleGroup.types.ts | 4 +- .../ToggleGroup/OToggleGroupItem.types.ts | 4 +- web/src/lib/data/StatStrip/OStatCard.vue | 3 +- .../lib/data/StatStrip/OStatStrip.types.ts | 6 +- .../lib/data/Timeline/OTimelineItem.types.ts | 6 +- web/src/lib/data/Tree/OTree.types.ts | 4 +- web/src/lib/feedback/Banner/OBanner.vue | 3 +- .../InnerLoading/OInnerLoading.types.ts | 4 +- web/src/lib/feedback/Toast/OToast.types.ts | 2 +- web/src/lib/forms/Checkbox/OCheckbox.types.ts | 4 +- web/src/lib/forms/Color/OColor.types.ts | 10 +- web/src/lib/forms/Color/OFormColor.vue | 5 +- web/src/lib/forms/Combobox/OCombobox.types.ts | 12 +- web/src/lib/forms/Combobox/OFormCombobox.vue | 5 +- web/src/lib/forms/Date/ODate.types.ts | 10 +- web/src/lib/forms/Date/OFormDate.vue | 10 +- .../DateTime/OFormDateTimeRange.types.ts | 6 +- .../DateTimeRange/ODateTimeRange.types.ts | 10 +- .../forms/DateTimeRange/ODateTimeRange.vue | 13 +- web/src/lib/forms/File/OFile.types.ts | 10 +- web/src/lib/forms/File/OFormFile.vue | 3 +- web/src/lib/forms/Input/OFormInput.vue | 3 +- web/src/lib/forms/Input/OFormTextarea.vue | 5 +- web/src/lib/forms/Input/OInput.types.ts | 10 +- web/src/lib/forms/Input/OTextarea.types.ts | 10 +- .../forms/OptionGroup/OOptionGroup.types.ts | 10 +- web/src/lib/forms/Radio/ORadio.types.ts | 6 +- web/src/lib/forms/Range/ORange.types.ts | 8 +- .../forms/SearchInput/OSearchInput.types.ts | 4 +- .../lib/forms/SearchInput/OSearchInput.vue | 12 +- web/src/lib/forms/Select/OFormSelect.vue | 10 +- web/src/lib/forms/Select/OSelect.types.ts | 18 +- web/src/lib/forms/Select/OSelect.vue | 36 +- web/src/lib/forms/Slider/OSlider.types.ts | 8 +- web/src/lib/forms/Switch/OSwitch.types.ts | 4 +- .../lib/forms/TagInput/OFormTagInput.types.ts | 6 +- web/src/lib/forms/TagInput/OTagInput.vue | 16 +- web/src/lib/forms/Time/OFormTime.vue | 5 +- web/src/lib/forms/Time/OTime.types.ts | 10 +- web/src/lib/forms/Time/OTime.vue | 8 +- web/src/lib/lists/FieldList/OFieldLabel.vue | 3 +- .../lib/lists/FieldList/OFieldList.types.ts | 4 +- web/src/lib/lists/FieldList/OFieldList.vue | 10 +- web/src/lib/navigation/Stepper/OStep.types.ts | 6 +- .../lib/navigation/Stepper/OStepper.types.ts | 4 +- .../lib/navigation/Tabs/ORouteTab.types.ts | 4 +- web/src/lib/navigation/Tabs/OTab.types.ts | 6 +- web/src/lib/overlay/Dialog/ODialog.types.ts | 12 +- web/src/lib/overlay/Drawer/ODrawer.types.ts | 12 +- .../overlay/Dropdown/ODropdownGroup.types.ts | 4 +- web/src/lib/overlay/Popover/OPopover.vue | 3 +- web/src/lib/overlay/Tooltip/OTooltip.types.ts | 4 +- .../ShortcutCheatsheet.vue | 10 +- .../lib/vue-shortcut-manager/composables.ts | 4 +- web/src/lib/vue-shortcut-manager/types.ts | 4 +- web/src/locales/languages/en-US.json | 2193 ++++++----------- web/src/locales/localeKeys.spec.ts | 31 + .../correlation/CorrelatedLogsTable.spec.ts | 1 + .../correlation/CorrelatedLogsTable.vue | 10 +- .../correlation/CorrelationEventHeader.vue | 8 +- .../correlation/DimensionFiltersBar.vue | 8 +- .../TelemetryCorrelationDashboard.spec.ts | 11 +- .../TelemetryCorrelationDashboard.vue | 28 +- web/src/plugins/logs/DetailTable.vue | 21 +- web/src/plugins/logs/FunctionSelector.vue | 4 +- web/src/plugins/logs/IndexList.vue | 7 +- web/src/plugins/logs/LogsNoEventsState.vue | 4 +- web/src/plugins/logs/SearchHistory.vue | 6 +- web/src/plugins/logs/SearchJobInspector.vue | 7 +- web/src/plugins/logs/SearchResult.vue | 5 +- web/src/plugins/logs/SearchSchedulersList.vue | 6 +- web/src/plugins/logs/SyntaxGuide.vue | 9 +- web/src/plugins/logs/TransformSelector.vue | 6 +- web/src/plugins/logs/patterns/PatternCard.vue | 6 +- web/src/plugins/logs/patterns/PatternList.vue | 4 +- .../logs/patterns/WildcardValuePopover.vue | 4 +- .../explorer/FunctionConfigDialog.spec.ts | 6 +- .../metrics/explorer/FunctionConfigDialog.vue | 17 +- .../metrics/explorer/LabelFilterBar.vue | 24 +- .../plugins/metrics/explorer/MetricCard.vue | 11 +- .../metrics/explorer/MetricsExplorer.vue | 11 +- .../metrics/explorer/PrefixFilterPanel.vue | 4 +- web/src/plugins/pipelines/CustomNode.vue | 4 +- web/src/plugins/pipelines/useDnD.ts | 6 +- web/src/plugins/traces/IndexList.vue | 7 +- web/src/plugins/traces/LLMErrorTable.vue | 14 +- .../plugins/traces/LLMInsightsDashboard.vue | 6 +- web/src/plugins/traces/LLMSchemaPanel.vue | 10 +- web/src/plugins/traces/ServiceGraph.vue | 5 +- .../traces/ServiceGraphNoDataState.vue | 4 +- .../traces/ServiceGraphNodeSidePanel.spec.ts | 4 +- .../traces/ServiceGraphNodeSidePanel.vue | 64 +- web/src/plugins/traces/ServicesCatalog.vue | 30 +- .../traces/ServicesCatalogNoDataState.vue | 4 +- web/src/plugins/traces/SessionDetails.vue | 18 +- web/src/plugins/traces/SessionsList.vue | 12 +- web/src/plugins/traces/ThreadView.vue | 4 +- web/src/plugins/traces/TraceDetails.vue | 19 +- .../plugins/traces/TracesNoEventsState.vue | 4 +- web/src/plugins/traces/agentOptionFormat.ts | 12 +- .../components/ServiceCatalogBarCell.vue | 5 +- .../traces/components/SpanKindBadge.vue | 3 +- .../traces/components/SpanStatusCodeBadge.vue | 3 +- .../traces/components/SpanStatusPill.vue | 3 +- .../traces/components/TraceStatusCell.vue | 4 +- .../plugins/traces/composables/useSessions.ts | 4 +- .../composables/useTracesTableColumns.spec.ts | 10 +- .../composables/useTracesTableColumns.ts | 41 +- .../traces/config/llmInsightsPanels.ts | 84 +- web/src/plugins/traces/llmPanelSchema.ts | 8 +- .../metrics/TracesAnalysisDashboard.vue | 4 +- web/src/plugins/traces/threadView.utils.ts | 2 + web/src/plugins/workflows/alertFields.ts | 30 +- web/src/plugins/workflows/incidentFields.ts | 54 +- .../workflows/nodes/WorkflowTrigger.vue | 4 +- web/src/services/metrics.ts | 1 + web/src/stores/index.ts | 4 +- web/src/ts/interfaces/alert.ts | 8 +- web/src/ts/interfaces/chat.ts | 12 +- web/src/ts/interfaces/logs.ts | 6 +- web/src/ts/interfaces/query.ts | 6 +- web/src/types/synthetics.ts | 18 +- web/src/utils/alerts/alertPayload.ts | 6 +- web/src/utils/alerts/alertQueryBuilder.ts | 4 +- web/src/utils/alerts/alertValidation.ts | 4 +- web/src/utils/awsIntegrations.ts | 68 +- web/src/utils/azureIntegrations.ts | 39 +- web/src/utils/clipboard.ts | 4 +- .../utils/dashboard/promql/shared/types.ts | 4 +- web/src/utils/ingestionSearchIndex.ts | 84 +- web/src/utils/metrics/explorerUrlState.ts | 10 +- web/src/utils/metrics/metricDefaults.spec.ts | 2 +- web/src/utils/metrics/metricDefaults.ts | 87 +- web/src/utils/metrics/metricGrouping.spec.ts | 78 +- web/src/utils/metrics/metricGrouping.ts | 42 +- web/src/utils/metrics/metricIntent.ts | 16 +- web/src/utils/metrics/prefixGrouping.spec.ts | 22 +- web/src/utils/metrics/prefixGrouping.ts | 25 +- web/src/utils/prebuilt-templates/discord.ts | 4 +- web/src/utils/prebuilt-templates/email.ts | 2 +- web/src/utils/prebuilt-templates/msteams.ts | 2 +- web/src/utils/prebuilt-templates/opsgenie.ts | 4 +- web/src/utils/prebuilt-templates/pagerduty.ts | 2 +- .../utils/prebuilt-templates/servicenow.ts | 10 +- web/src/utils/prebuilt-templates/slack.ts | 6 +- web/src/utils/prebuilt-templates/types.ts | 14 +- web/src/utils/query/searchError.ts | 30 +- web/src/utils/query/sqlDiagnostics.ts | 4 +- web/src/utils/traces/applyGraphCollapse.ts | 8 +- web/src/utils/traces/computeTreeLayout.ts | 4 +- .../utils/traces/treeVisualizationEngine.ts | 4 +- web/src/views/Dashboards/Dashboards.vue | 6 +- .../Dashboards/addPanel/AddCondition.vue | 11 +- .../Dashboards/addPanel/AddJoinPopUp.vue | 8 +- web/src/views/Functions.vue | 15 +- web/src/views/IdentityAccessManagement.vue | 4 +- web/src/views/Ingestion.vue | 4 +- web/src/views/OverviewTab.vue | 2 +- web/src/views/RUM/AppSessions.vue | 4 +- web/src/views/RUM/SessionViewer.vue | 4 +- web/src/views/RUM/SourceMaps.spec.ts | 22 +- web/src/views/RUM/SourceMaps.vue | 13 +- web/src/views/RUM/UploadSourceMaps.vue | 2 +- web/src/views/SyntheticMonitoring.vue | 10 +- .../views/synthetics/CreateBrowserTest.vue | 6 +- web/src/views/synthetics/MonitorResults.vue | 12 +- web/src/views/synthetics/MonitorRuns.spec.ts | 11 + web/src/views/synthetics/MonitorRuns.vue | 44 +- .../synthetics/MonitorStatusTimeline.vue | 4 +- web/src/views/synthetics/RunDetail.vue | 12 +- 537 files changed, 5086 insertions(+), 4414 deletions(-) diff --git a/I18N_ENFORCEMENT_GUIDE.md b/I18N_ENFORCEMENT_GUIDE.md index ddf36e132e..c509d40e96 100644 --- a/I18N_ENFORCEMENT_GUIDE.md +++ b/I18N_ENFORCEMENT_GUIDE.md @@ -3,13 +3,28 @@ How the OpenObserve web app guarantees that user-facing text is translatable, and what to do when a check fires. -**Status: enforcement complete and green.** `lint:ci` 0 errors · `type-check:app` -0 errors · spec-inclusive `type-check` 0 errors · `format:check` clean. +**Status: enforcement complete.** `lint:ci` 0 errors · `type-check:app` **exit 0** +(with `--composite false`, which the npm script passes, no TS6307 surfaces) · +`format:check` clean. + +> **Known measurement gap:** the "spec-inclusive" `type-check` (tsconfig.vitest.json) +> currently checks **no spec files at all** — its include is `src/**/*.spec.{ts,js}`, +> and TypeScript globs do **not** brace-expand, so the pattern matches nothing. +> Any past "spec-inclusive type-check 0 errors" claim was vacuous. Fixing it means +> splitting the include into `src/**/*.spec.ts` + `src/**/*.spec.js` AND then fixing +> the spec-only type errors that surface (e.g. `metricGrouping.spec.ts` assigns keys +> that don't exist in en-US to `I18nKey` fixtures). Tracked in §9. The mechanisms are done and so is the message cleanup — **0 fake plurals** remain in -en-US. What is left is narrower: **non-English plural rules**, the last **6 `gt` sites**, -and **one CI gap**. See [§9 Outstanding work](#9-outstanding-work) — that section is the -to-do list, kept in sync with measurements. +en-US, the 10 surviving `gt()` calls are each individually justified (§8), `TEXT_ATTRS` +has been retired in favour of prop types (§8), and the dead-key sweep is complete (§9). +What is left is narrower: **non-English plural rules** and **spec type-checking** +(a broken tsconfig glob plus a missing PR gate, §9.3). See +[§9 Outstanding work](#9-outstanding-work) — that section is the to-do list, kept in +sync with measurements. + +Converting the 71 dynamic key sites so they can be type-checked was **considered and +declined** — it is recorded under §4 as an accepted limit, not pending work. --- @@ -89,11 +104,11 @@ only two remaining `(s)` values are the seconds unit. Keep it that way. `{{ t('common.save') }}` · `:label="t('x')"` · `:label="row.name"` (a variable contributes no literal) · `:label="'—'"` (no letters). -### Two curated lists +### One curated list + +`TEXT_ATTRS` is **gone** — prop types now decide what counts as a text prop, so there +is no list to maintain (§8). Declaring a prop `I18nText` is what makes it enforced. -- **`TEXT_ATTRS`** (47 names) — props that carry user-facing text. Feeds both the - static and bound rules, so "what counts as a text prop" is defined once. **Add a - name here when a component takes UI text through a new prop.** - **`NON_TRANSLATABLE`** (39 entries) — tokens that must read identically in every language: units (`px`, `ms`, `ns`, `min`), symbols (`×`, `→`, `~`), protocol and spec identifiers (`GET`, `UTC`, `SQL`, `PromQL`, the OpenTelemetry statuses @@ -121,7 +136,7 @@ follows a pattern the library already used for icons (`iconLeft?: IconName`). | **`I18nKey`** | a field holding an **i18n key as data** (`titleKey`, `labelKey`) | | **`useI18nTyped()`** | replaces `useI18n()` in components — `t` returns `I18nText` | | **`TranslateFn`** | the type of `t` when a composable/util takes it as a **parameter** | -| **`gt()`** | last resort for genuinely context-free code — **1 file**, see below | +| **`gt()`** | last resort for genuinely context-free code — **4 files**, see below | | **`raw()`** | the explicit opt-out for text that must not be translated | ```ts @@ -155,7 +170,7 @@ presets.ts(76,5): error TS2820: Type '"emptyState.noLogs.titel"' is not assignab to type 'I18nKey'. Did you mean '"emptyState.noLogs.title"'? ``` -Cost: **~31 s** for the full app type-check with the 10,665-key union. Not a +Cost: **~31 s** for the full app type-check with the ~9,800-key union. Not a perf concern. ### Getting a `t`: three cases, in order of preference @@ -179,7 +194,7 @@ perf concern. } ``` - This is the standard for non-component code (**27 files**). It is preferred over + This is the standard for non-component code (**35 files**). It is preferred over `gt()` because these functions are also called directly by specs, outside any component, where `useI18n()` would throw. Specs pass the real translator: @@ -192,13 +207,27 @@ perf concern. composable translates, `t` belongs on that function, not on the composable. 3. **Genuinely context-free code** → `gt("some.key")`. Only where there is neither a - setup context nor a caller to thread `t` through. Exactly **one** file qualifies: - `useUnauthorizedErrorGrouper.ts`, reached from an axios 403 interceptor registered - once at module load (interceptor → 300 ms `setTimeout` → toast → click handler). + setup context nor a caller to thread `t` through. Exactly **four** files qualify + (10 call sites), each for a distinct structural reason: + + - `useUnauthorizedErrorGrouper.ts` (6) — reached from an axios 403 interceptor + registered once at module load (interceptor → 300 ms `setTimeout` → toast → + click handler). The founding case. + - `ingestion/setupCard/content/kubernetes.ts` (2) — the setup-card registry pins + every builder to `(subs: CardSubstitutions) => RichCardContent`; threading `t` + would change that shared contract for ~20 cards. Static prose in cards uses + `descriptionKey`/`helpKey` (renderer-resolved); `gt` covers only the one + description that interpolates a URL, translated at card-build time. + - `utils/query/searchError.ts` (1) — the translated **default** of an optional + `fallback: I18nText` parameter, evaluated per call; callers that hold `t` + override it (e.g. `parseSearchError(err, gt("search.unknownError"))`). + - `usePanelPromQLExecutor.ts` (1) — reached through composable chains that are + not guaranteed to run in a setup context, where `useI18n()` would throw. `gt` is deliberately a narrow escape hatch, not an alternative to case 2. Before - reaching for it, check whether a caller can pass `t` instead — 43 of the original - 49 `gt` sites turned out to be case 2. + reaching for it, check whether a caller can pass `t` instead — the overwhelming + majority of historical `gt` sites (including the import validators and + `useQualityDetailCharts`, converted since) turned out to be case 2. > **Keys resolved at display time, not module load.** When storing keys as data, keep > the `I18nKey` map at module scope but resolve it inside the function that renders. @@ -250,11 +279,18 @@ annotation is made by hand at the declaration rather than by a pattern match. | `t()` keys — literal | enforced (ESLint, `.vue` **and** `.ts`) | | i18n keys stored as data | enforced (`I18nKey`, 19 files) | | Toast / notification text | enforced (`I18nText`, incl. the store + wrappers) | -| Text reached via `useI18nTyped()` | branded across **663** files | +| Text reached via `useI18nTyped()` | branded across **668** files | | Composables / utils taking `t: TranslateFn` | **27** files | -**Numbers:** en-US grew 10,216 → **10,665 keys**; **311** sit under `toastMessages.*` -(28 module groups). 62 `raw()` opt-outs. **6** `gt()` call sites, all in one file. +**Numbers** (re-measured 2026-07-31, after the post-review debt cleanup): en-US holds +**9,837 keys** across **72 namespaces** (10,216 → 11,002 as text was migrated in, +→ 9,648 after the dead-key sweep §9, → 9,837 as the remaining hardcoded prose — +import validators, setup-card descriptions, status labels, dialog buttons — was +keyed); **309** sit under `toastMessages.*`. **977** `raw()` opt-outs — the count +rose steeply when props became `I18nText`, since every genuinely non-translatable +value (units, tokens, glyphs, API data) has to say so explicitly, then fell as +`raw()`-wrapped prose was converted to keys. **10** `gt()` call sites in **4** +files (see §3 case 3 for the per-file justification). **Where the two checkers divide.** `no-missing-keys` validates `t('x.y')` **calls**; it cannot see a key assigned to a field. Keys stored as **data** are validated instead @@ -264,27 +300,54 @@ be green to claim key coverage; neither alone is sufficient. ### Not covered -- **Dynamic keys** — ``t(`about.feature_${id}`)`` (**312** sites). No lint or type - check can resolve these. The `t` key parameter is deliberately permissive - (`I18nKey | (string & {})`) so they keep compiling. +- **Dynamic keys — 71 sites. Considered and DECLINED; do not re-open as pending work.** + + ``t(`about.feature_${id}`)`` and similar. A renamed or deleted key reached this way is + caught by nothing: ESLint sees no literal, `t`'s permissive + `I18nKey | (string & {})` parameter accepts any string, vue-i18n returns the key + instead of throwing, and the production build strips its dev warning. It renders the + raw dotted path on screen. + + Nothing is currently broken — every key these sites can request was expanded and + verified present. The exposure is a future rename, concentrated in `onlineEvals` + (40 of the 71 sites). + + Closing it would mean removing the `(string & {})` arm, which surfaces **117 errors**: + ~80 are unrelated consumers declaring their translator loosely as + `(key: string) => string` (a contravariance failure, not a key problem), 15 need a + variable widened to a literal union, 9 need a `Record` map, and a + handful are genuine key/code mismatches. Two-thirds of the work is therefore not about + dynamic keys at all, which is why this was judged not worth it as a standalone project. + + If the guarantee is ever wanted, the cheap route is a second strict export + (`(key: I18nKey)`) used by new code only — no flag day, no 98-file PR. + + > Count these with a word boundary: `grep 't(\`'` also matches `` fetch(`…`) `` and any +other call ending in `t`, which inflates the figure roughly fourfold. A further 21 + > sites use backticks but interpolate nothing — those are ordinary static keys. + - **Interfaces not yet annotated.** `I18nText` guards what it is applied to. That is _incomplete_, never _wrong_ — coverage grows one declaration at a time, at the definition site, with no central registry to keep in sync. - **Other locales.** The 14 non-en locales are generated from en-US and lag behind; `localeDir` points at en-US only, on purpose. Never hand-edit them. -- **Unused keys.** `@intlify/vue-i18n/no-unused-keys` is available but **not - enabled**. Measured on this repo it reports 2,421 keys of which only ~1,302 are - genuinely dead — 681 are reached via a key-string, 437 via a dynamic prefix. If - you enable it, use `warn`, never `enableFix`, and populate `ignores` with the - dynamic prefixes; its autofix would delete live translations. +- **Unused keys.** `@intlify/vue-i18n/no-unused-keys` is available but **not enabled**. + It reports 2,421 keys, but it only sees `t('literal')` calls — so keys reached + through a variable or a dynamic prefix look unused to it, and its autofix would + delete them. A direct measurement (literal tokens + dynamic prefixes + the one + concatenation site) put the genuinely dead set at **1,363**, since deleted (§9). + If you ever enable the rule, use `warn`, never `enableFix`, and populate `ignores` + with the dynamic prefixes. Note that even the direct measurement missed 9 live keys + (§9) — no automated sweep sees keys held in JSON data files. --- ## 5. Deliberately deferred: `strictTemplates` -Typing a component prop `label: I18nText` only gates `` if -Vue's `strictTemplates` is on. It is **not** enabled, which is why `TEXT_ATTRS` -still exists. +A **declared** prop typed `label: I18nText` gates `` with or +without `strictTemplates` — declared props are always checked. `strictTemplates` +governs **undeclared** attributes only. This was verified by probe, and it is what +allowed `TEXT_ATTRS` to be retired (§8) while `strictTemplates` stays off. Measured twice on this branch: @@ -297,10 +360,9 @@ Of those, ~303 are genuine `TS2322` type mismatches (real latent bugs); the rest undeclared pass-through attributes. **It was left out on purpose.** It is a large _type-safety_ migration, not i18n work, -and its i18n payoff is only retiring the `TEXT_ATTRS` list — whose real gap was -measured at **five sites** (all fixed here: `reveal-tooltip`, `hide-tooltip`, -`unstable-dimension-tooltip`, `date-disabled-tooltip`). Worth doing as its own PR; -not worth burying this one under 2,655 unrelated errors. +and it turned out to carry **no i18n payoff at all** — retiring `TEXT_ATTRS` did not +require it. Worth doing as its own PR for the ~303 genuine `TS2322` mismatches; not +worth burying this one under 2,655 unrelated errors. --- @@ -320,8 +382,17 @@ not worth burying this one under 2,655 unrelated errors. | A recurring unit/symbol/code token | add to `NON_TRANSLATABLE` with a one-line reason | | A whole file that is genuinely code | add to the SyntaxGuide exemption block | -New text-carrying **component prop** → add its name to `TEXT_ATTRS`. +New text-carrying **component prop** → declare it `I18nText`. In ` diff --git a/web/src/components/common/empty-states/QuickStartCard.vue b/web/src/components/common/empty-states/QuickStartCard.vue index 6593d5a30c..514b4f17ed 100644 --- a/web/src/components/common/empty-states/QuickStartCard.vue +++ b/web/src/components/common/empty-states/QuickStartCard.vue @@ -46,12 +46,13 @@ along with this program. If not, see . diff --git a/web/src/components/common/sidebar/SearchFieldList.spec.ts b/web/src/components/common/sidebar/SearchFieldList.spec.ts index d7a7d1eb0b..a65535a711 100644 --- a/web/src/components/common/sidebar/SearchFieldList.spec.ts +++ b/web/src/components/common/sidebar/SearchFieldList.spec.ts @@ -114,6 +114,11 @@ const mockI18n = createI18n({ search: { searchField: "Search field", }, + // The component passes t("common.valueCopiedToClipboard") to + // copyToClipboard; without the key this mock echoes the key path. + common: { + valueCopiedToClipboard: "Value copied to clipboard", + }, }, }, }); diff --git a/web/src/components/common/sidebar/SearchFieldList.vue b/web/src/components/common/sidebar/SearchFieldList.vue index c35e443022..2e05d54544 100644 --- a/web/src/components/common/sidebar/SearchFieldList.vue +++ b/web/src/components/common/sidebar/SearchFieldList.vue @@ -654,7 +654,7 @@ const addSearchTerm = (term: string) => { }; const copyContentValue = (value: string) => { - copyToClipboard(value, t, { successMessage: "Value copied to clipboard" }); + copyToClipboard(value, t, { successMessage: t("common.valueCopiedToClipboard") }); }; diff --git a/web/src/components/cross-linking/CrossLinkDialog.vue b/web/src/components/cross-linking/CrossLinkDialog.vue index 1659e94b65..a2282eccb7 100644 --- a/web/src/components/cross-linking/CrossLinkDialog.vue +++ b/web/src/components/cross-linking/CrossLinkDialog.vue @@ -112,7 +112,7 @@ diff --git a/web/src/lib/core/EmptyState/EmptyStateIngestionCard.vue b/web/src/lib/core/EmptyState/EmptyStateIngestionCard.vue index c252884b89..814d4ba78a 100644 --- a/web/src/lib/core/EmptyState/EmptyStateIngestionCard.vue +++ b/web/src/lib/core/EmptyState/EmptyStateIngestionCard.vue @@ -44,6 +44,7 @@ along with this program. If not, see . diff --git a/web/src/lib/core/Table/cells/statusVariant.ts b/web/src/lib/core/Table/cells/statusVariant.ts index 23a4ca874a..92fc376ab3 100644 --- a/web/src/lib/core/Table/cells/statusVariant.ts +++ b/web/src/lib/core/Table/cells/statusVariant.ts @@ -9,6 +9,8 @@ // const { variant, label, dot } = statusVariant("paused", "pipeline"); // {{ label }} +import { raw, type I18nText } from "@/types/i18n"; + import type { BadgeVariant } from "@/lib/core/Badge/OBadge.types"; /** Semantic tone — the calm, low-chroma "soft" badge family reads best at @@ -131,7 +133,7 @@ const DOMAIN_TONE: Record> = { export interface StatusVariantResult { variant: BadgeVariant; tone: StatusTone; - label: string; + label: I18nText; dot: boolean; } @@ -150,8 +152,8 @@ export function humanizeStatus(value: string): string { * @param domain optional feature key for overrides ("invoice"|"eval"|"service"|"node"|…). */ export function statusVariant(value: unknown, domain?: string): StatusVariantResult { - const raw = typeof value === "boolean" ? String(value) : String(value ?? "").trim(); - const key = raw.toLowerCase(); + const rawValue = typeof value === "boolean" ? String(value) : String(value ?? "").trim(); + const key = rawValue.toLowerCase(); let tone: StatusTone | undefined; @@ -174,7 +176,8 @@ export function statusVariant(value: unknown, domain?: string): StatusVariantRes return { variant: TONE_VARIANT[tone], tone, - label: raw ? humanizeStatus(raw) : "—", + // A humanized status token, or an em-dash placeholder — neither is prose. + label: raw(rawValue ? humanizeStatus(rawValue) : "—"), dot: true, }; } diff --git a/web/src/lib/core/Table/sub-components/OTableEmpty.vue b/web/src/lib/core/Table/sub-components/OTableEmpty.vue index b3e14a57c0..9277a11516 100644 --- a/web/src/lib/core/Table/sub-components/OTableEmpty.vue +++ b/web/src/lib/core/Table/sub-components/OTableEmpty.vue @@ -1,7 +1,7 @@ diff --git a/web/src/lib/core/ToggleGroup/OToggleGroup.types.ts b/web/src/lib/core/ToggleGroup/OToggleGroup.types.ts index 8322a1a9e0..38bcdebf6e 100644 --- a/web/src/lib/core/ToggleGroup/OToggleGroup.types.ts +++ b/web/src/lib/core/ToggleGroup/OToggleGroup.types.ts @@ -2,6 +2,8 @@ * OToggleGroup.types.ts — public types for OToggleGroup. */ +import type { I18nText } from "@/types/i18n"; + import type { AcceptableValue } from "reka-ui"; import type { ComputedRef, InjectionKey } from "vue"; @@ -35,7 +37,7 @@ export interface ToggleGroupProps { /** Visual variant — use 'primary' when the toggle sits on a primary-colored bar */ variant?: ToggleGroupVariant; /** Label text rendered next to the toggle bar. For richer content use the `label` slot. */ - label?: string; + label?: I18nText; /** Position of the label relative to the toggle bar */ labelPosition?: "left" | "right" | "top"; /** diff --git a/web/src/lib/core/ToggleGroup/OToggleGroupItem.types.ts b/web/src/lib/core/ToggleGroup/OToggleGroupItem.types.ts index b29b072c04..8e76c30f3e 100644 --- a/web/src/lib/core/ToggleGroup/OToggleGroupItem.types.ts +++ b/web/src/lib/core/ToggleGroup/OToggleGroupItem.types.ts @@ -2,6 +2,8 @@ * OToggleGroupItem.types.ts — public types for OToggleGroupItem. */ +import type { I18nText } from "@/types/i18n"; + import type { AcceptableValue } from "reka-ui"; /** Size controls padding and font-size — height is determined by content */ @@ -13,7 +15,7 @@ export interface ToggleGroupItemProps { /** Disables only this item */ disabled?: boolean; /** Tooltip shown on hover — especially useful when disabled is true to explain why */ - tooltip?: string; + tooltip?: I18nText; /** Size controls padding and font-size. md (default) = full toolbar; sm = small toolbar; xs = compact inline toggle */ size?: ToggleGroupItemSize; /** Icon name (from OIcon registry) placed before the label. For custom icon components, use the `icon-left` slot. */ diff --git a/web/src/lib/data/StatStrip/OStatCard.vue b/web/src/lib/data/StatStrip/OStatCard.vue index 14fb596328..86d19ec336 100644 --- a/web/src/lib/data/StatStrip/OStatCard.vue +++ b/web/src/lib/data/StatStrip/OStatCard.vue @@ -1,4 +1,5 @@