├── .editorconfig ├── .env.example ├── .eslintignore ├── .eslintrc ├── .github └── workflows │ ├── ci.yml │ ├── cleanup-gh-pages.yml │ ├── pr-title.yml │ ├── publication.yml │ ├── quality.yml │ ├── release.yml │ └── scripts │ ├── __tests__ │ ├── bundle.test.ts │ ├── format.test.ts │ ├── results.test.ts │ ├── test.test.ts │ ├── types.ts │ └── update-pr-description.test.ts │ ├── update-pr-description.js │ └── utils │ ├── bundle.js │ ├── format.js │ ├── results.js │ └── test.js ├── .gitignore ├── .husky └── pre-commit ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc.js ├── .release-please-manifest.json ├── .stylelintrc ├── AUTHORS ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── ROADMAP.md ├── commitlint.config.js ├── config-overrides.js ├── package-lock.json ├── package.json ├── playwright.config.ts ├── public ├── index.html └── static │ └── favicon.png ├── release-please-config.json ├── src ├── .eslintrc ├── assets │ ├── icons │ │ ├── cluster.svg │ │ ├── cry-cat.svg │ │ ├── databases.svg │ │ ├── decommission.svg │ │ ├── disableFullscreen.svg │ │ ├── emptyState.svg │ │ ├── key.svg │ │ ├── monitoring.svg │ │ ├── network.svg │ │ ├── overview.svg │ │ ├── user-secret.svg │ │ └── ydb.svg │ └── illustrations │ │ ├── dark │ │ ├── 403.svg │ │ ├── error.svg │ │ └── thumbsUp.svg │ │ └── light │ │ ├── 403.svg │ │ ├── error.svg │ │ └── thumbsUp.svg ├── components │ ├── AsyncReplicationState │ │ ├── AsyncReplicationState.tsx │ │ └── index.ts │ ├── AutoRefreshControl │ │ ├── AutoRefreshControl.scss │ │ ├── AutoRefreshControl.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── ButtonWithConfirmDialog │ │ └── ButtonWithConfirmDialog.tsx │ ├── CellWithPopover │ │ ├── CellWithPopover.scss │ │ └── CellWithPopover.tsx │ ├── CircularProgressBar │ │ ├── CircularProgressBar.scss │ │ └── CircularProgressBar.tsx │ ├── ComponentsProvider │ │ ├── ComponentsProvider.tsx │ │ ├── componentsRegistry.ts │ │ └── registry.ts │ ├── ConfirmationDialog │ │ ├── ConfirmationDialog.scss │ │ ├── ConfirmationDialog.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── ConnectToDB │ │ ├── ConnectToDB.scss │ │ ├── ConnectToDBDialog.tsx │ │ ├── __test__ │ │ │ └── utils.test.ts │ │ ├── getDocsLink.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── snippets.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── ContentWithPopup │ │ └── ContentWithPopup.tsx │ ├── CopyLinkButton │ │ ├── CopyLinkButton.scss │ │ ├── CopyLinkButton.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── CriticalActionDialog │ │ ├── CriticalActionDialog.scss │ │ ├── CriticalActionDialog.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ └── utils.ts │ ├── DateRange │ │ ├── DateRange.scss │ │ ├── DateRange.tsx │ │ ├── __test__ │ │ │ ├── fromDateRangeValues.test.ts │ │ │ ├── getdatePickerSize.test.ts │ │ │ └── toDateRangeValues.test.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ │ ├── index.ts │ │ └── utils.ts │ ├── DebouncedInput │ │ └── DebouncedTextInput.tsx │ ├── DeveloperUILinkButton │ │ ├── DeveloperUILinkButton.scss │ │ ├── DeveloperUILinkButton.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── DiagnosticCard │ │ ├── DiagnosticCard.scss │ │ └── DiagnosticCard.tsx │ ├── DiskStateProgressBar │ │ ├── DiskStateProgressBar.scss │ │ └── DiskStateProgressBar.tsx │ ├── Divider │ │ ├── Divider.scss │ │ └── Divider.tsx │ ├── DoughnutMetrics │ │ ├── DoughnutMetrics.scss │ │ └── DoughnutMetrics.tsx │ ├── Drawer │ │ ├── Drawer.scss │ │ ├── Drawer.tsx │ │ ├── DrawerContext.tsx │ │ └── index.ts │ ├── EmptyState │ │ ├── EmptyState.scss │ │ ├── EmptyState.tsx │ │ └── index.ts │ ├── EnableFullscreenButton │ │ └── EnableFullscreenButton.tsx │ ├── EntitiesCount │ │ ├── EntitiesCount.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ │ └── index.ts │ ├── EntityPageTitle │ │ ├── EntityPageTitle.scss │ │ └── EntityPageTitle.tsx │ ├── EntityStatus │ │ ├── EntityStatus.scss │ │ └── EntityStatus.tsx │ ├── EntityStatusNew │ │ ├── EntityStatus.scss │ │ ├── EntityStatus.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ └── utils.ts │ ├── ErrorBoundary │ │ ├── ErrorBoundary.scss │ │ ├── ErrorBoundary.tsx │ │ ├── __tests__ │ │ │ └── prepareErrorStack.test.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ └── utils.tsx │ ├── Errors │ │ ├── 403 │ │ │ ├── AccessDenied.tsx │ │ │ └── index.ts │ │ ├── PageError │ │ │ └── PageError.tsx │ │ ├── ResponseError │ │ │ ├── ResponseError.tsx │ │ │ └── index.ts │ │ └── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ ├── FormattedBytes │ │ ├── FormattedBytes.tsx │ │ └── utils.tsx │ ├── FullNodeViewer │ │ ├── FullNodeViewer.scss │ │ ├── FullNodeViewer.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── Fullscreen │ │ ├── Fullscreen.scss │ │ └── Fullscreen.tsx │ ├── Graph │ │ └── Graph.tsx │ ├── HoverPopup │ │ ├── HoverPopup.scss │ │ └── HoverPopup.tsx │ ├── Illustration │ │ ├── Illustration.tsx │ │ └── index.ts │ ├── InfoViewer │ │ ├── InfoViewer.scss │ │ ├── InfoViewer.tsx │ │ ├── formatters │ │ │ ├── cdcStream.ts │ │ │ ├── common.ts │ │ │ ├── index.ts │ │ │ ├── pqGroup.ts │ │ │ ├── schema.ts │ │ │ └── table.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── schemaInfo │ │ │ ├── TableIndexInfo.tsx │ │ │ └── index.ts │ │ └── utils.ts │ ├── InfoViewerSkeleton │ │ ├── InfoViewerSkeleton.scss │ │ └── InfoViewerSkeleton.tsx │ ├── InternalLink │ │ ├── InternalLink.tsx │ │ └── index.ts │ ├── JsonViewer │ │ ├── JsonViewer.scss │ │ ├── JsonViewer.tsx │ │ ├── components │ │ │ ├── Cell.tsx │ │ │ ├── Filter.tsx │ │ │ ├── FullValueDialog.tsx │ │ │ ├── HighlightedText.tsx │ │ │ └── ToggleCollapseButton.tsx │ │ ├── constants.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── unipika │ │ │ ├── StructuredYsonTypes.ts │ │ │ ├── flattenUnipika.ts │ │ │ └── unipika.ts │ │ └── utils.ts │ ├── LabelWithPopover │ │ ├── LabelWithPopover.tsx │ │ └── index.ts │ ├── LagImages │ │ ├── LagImages.tsx │ │ └── index.ts │ ├── LagPopoverContent │ │ ├── LagPopoverContent.scss │ │ ├── LagPopoverContent.tsx │ │ └── index.ts │ ├── LinkToSchemaObject │ │ └── LinkToSchemaObject.tsx │ ├── LinkWithIcon │ │ ├── LinkWithIcon.scss │ │ └── LinkWithIcon.tsx │ ├── Loader │ │ ├── Loader.scss │ │ ├── Loader.tsx │ │ └── index.ts │ ├── LoaderWrapper │ │ └── LoaderWrapper.tsx │ ├── LogsButton │ │ └── LogsButton.tsx │ ├── MemoryViewer │ │ ├── MemoryViewer.scss │ │ ├── MemoryViewer.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ └── utils.ts │ ├── MetricChart │ │ ├── MetricChart.scss │ │ ├── MetricChart.tsx │ │ ├── colors.ts │ │ ├── convertResponse.ts │ │ ├── getChartData.ts │ │ ├── getDefaultDataFormatter.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── reducer.ts │ │ └── types.ts │ ├── MonacoEditor │ │ └── MonacoEditor.tsx │ ├── MonitoringButton │ │ └── MonitoringButton.tsx │ ├── MultilineTableHeader │ │ ├── MultilineTableHeader.scss │ │ └── MultilineTableHeader.tsx │ ├── NodeHostWrapper │ │ └── NodeHostWrapper.tsx │ ├── PDiskInfo │ │ ├── PDiskInfo.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── PDiskPopup │ │ └── PDiskPopup.tsx │ ├── PageMeta │ │ ├── PageMeta.scss │ │ └── PageMeta.tsx │ ├── PaginatedTable │ │ ├── PaginatedTable.scss │ │ ├── PaginatedTable.tsx │ │ ├── PaginatedTableContext.tsx │ │ ├── PaginatedTableWithLayout.tsx │ │ ├── ResizeHandler.tsx │ │ ├── ResizeablePaginatedTable.tsx │ │ ├── TableChunk.tsx │ │ ├── TableChunksRenderer.tsx │ │ ├── TableHead.tsx │ │ ├── TableRow.tsx │ │ ├── constants.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ │ ├── index.ts │ │ ├── requestBatcher.ts │ │ ├── shared.ts │ │ ├── types.ts │ │ ├── useScrollBasedChunks.ts │ │ └── utils.tsx │ ├── PoolBar │ │ ├── PoolBar.scss │ │ └── PoolBar.tsx │ ├── PoolUsage │ │ ├── PoolUsage.scss │ │ └── PoolUsage.tsx │ ├── PoolsGraph │ │ ├── PoolsGraph.scss │ │ └── PoolsGraph.tsx │ ├── ProblemFilter │ │ ├── ProblemFilter.tsx │ │ └── index.ts │ ├── ProgressViewer │ │ ├── ProgressViewer.scss │ │ └── ProgressViewer.tsx │ ├── QueryExecutionStatus │ │ ├── QueryExecutionStatus.scss │ │ ├── QueryExecutionStatus.tsx │ │ └── index.ts │ ├── QueryResultTable │ │ ├── Cell │ │ │ ├── Cell.tsx │ │ │ └── index.ts │ │ ├── QueryResultTable.scss │ │ ├── QueryResultTable.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ │ └── index.ts │ ├── QuerySettingsDescription │ │ ├── QuerySettingsDescription.scss │ │ └── QuerySettingsDescription.tsx │ ├── ResizeableDataTable │ │ ├── ResizeableDataTable.scss │ │ └── ResizeableDataTable.tsx │ ├── Search │ │ ├── Search.scss │ │ ├── Search.tsx │ │ └── index.ts │ ├── ShardsTable │ │ ├── ShardsTable.tsx │ │ ├── columns.tsx │ │ ├── constants.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── ShortyString │ │ ├── ShortyString.scss │ │ ├── ShortyString.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ ├── Skeleton │ │ └── Skeleton.tsx │ ├── SpeedMultiMeter │ │ ├── SpeedMultiMeter.scss │ │ ├── SpeedMultiMeter.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ │ └── index.ts │ ├── SplitPane │ │ ├── SplitPane.scss │ │ ├── SplitPane.tsx │ │ └── index.ts │ ├── Stack │ │ ├── Stack.scss │ │ └── Stack.tsx │ ├── StatusIcon │ │ ├── StatusIcon.scss │ │ └── StatusIcon.tsx │ ├── StatusIconNew │ │ └── StatusIcon.tsx │ ├── StorageGroupInfo │ │ ├── StorageGroupInfo.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── SyntaxHighlighter │ │ ├── YDBSyntaxHighlighter.scss │ │ ├── YDBSyntaxHighlighter.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── lazy.ts │ │ ├── shared.ts │ │ ├── themes.ts │ │ ├── types.ts │ │ └── yql.ts │ ├── Table │ │ ├── Table.scss │ │ └── Table.tsx │ ├── TableSkeleton │ │ ├── TableSkeleton.scss │ │ └── TableSkeleton.tsx │ ├── TableWithControlsLayout │ │ ├── TableWithControlsLayout.scss │ │ ├── TableWithControlsLayout.tsx │ │ └── useTableScroll.ts │ ├── TabletIcon │ │ ├── TabletIcon.scss │ │ └── TabletIcon.tsx │ ├── TabletNameWrapper │ │ ├── TabletNameWrapper.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── TabletState │ │ └── TabletState.tsx │ ├── TabletsStatistic │ │ ├── TabletsStatistic.scss │ │ ├── TabletsStatistic.tsx │ │ └── index.ts │ ├── Tags │ │ ├── Tags.scss │ │ ├── Tags.tsx │ │ └── index.ts │ ├── TenantNameWrapper │ │ ├── TenantNameWrapper.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── TimeFrameSelector │ │ ├── TimeFrameSelector.scss │ │ └── TimeFrameSelector.tsx │ ├── TooltipsContent │ │ ├── NodeEndpointsTooltipContent │ │ │ ├── NodeEndpointsTooltipContent.scss │ │ │ ├── NodeEndpointsTooltipContent.tsx │ │ │ └── i18n │ │ │ │ ├── en.json │ │ │ │ └── index.ts │ │ ├── PoolTooltipContent │ │ │ └── PoolTooltipContent.tsx │ │ ├── TabletTooltipContent │ │ │ └── TabletTooltipContent.tsx │ │ └── index.ts │ ├── TruncatedQuery │ │ ├── TruncatedQuery.scss │ │ └── TruncatedQuery.tsx │ ├── UptimeFIlter │ │ ├── UptimeFilter.tsx │ │ └── index.ts │ ├── UptimeViewer │ │ ├── UptimeViewer.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── UsageLabel │ │ ├── UsageLabel.scss │ │ └── UsageLabel.tsx │ ├── User │ │ ├── StaffCard.tsx │ │ ├── User.scss │ │ └── User.tsx │ ├── VDisk │ │ ├── VDisk.scss │ │ ├── VDisk.tsx │ │ ├── VDiskWithDonorsStack.tsx │ │ └── utils.ts │ ├── VDiskInfo │ │ ├── VDiskInfo.scss │ │ ├── VDiskInfo.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── VDiskPopup │ │ ├── VDiskPopup.scss │ │ └── VDiskPopup.tsx │ ├── YDBDefinitionList │ │ ├── YDBDefinitionList.scss │ │ ├── YDBDefinitionList.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── nodesColumns │ │ ├── NodesColumns.scss │ │ ├── __test__ │ │ │ └── utils.test.ts │ │ ├── columns.tsx │ │ ├── constants.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── types.ts │ │ └── utils.ts │ └── slots │ │ ├── SlotMap.ts │ │ ├── createSlot.ts │ │ ├── index.ts │ │ ├── types.ts │ │ ├── useSlots.ts │ │ └── utils.ts ├── containers │ ├── App │ │ ├── App.scss │ │ ├── App.tsx │ │ ├── Content.tsx │ │ ├── Providers.tsx │ │ ├── appSlots.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ │ └── index.ts │ ├── AppWithClusters │ │ ├── AppWithClusters.tsx │ │ ├── ExtendedCluster │ │ │ ├── ExtendedCluster.scss │ │ │ └── ExtendedCluster.tsx │ │ └── ExtendedTenant │ │ │ └── ExtendedTenant.tsx │ ├── AsideNavigation │ │ ├── AsideNavigation.scss │ │ ├── AsideNavigation.tsx │ │ ├── InformationPopup │ │ │ ├── InformationPopup.scss │ │ │ ├── InformationPopup.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── Navigation.tsx │ │ ├── YdbInternalUser │ │ │ ├── YdbInternalUser.scss │ │ │ └── YdbInternalUser.tsx │ │ ├── hooks │ │ │ └── useHotkeysPanel.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ ├── Authentication │ │ ├── Authentication.scss │ │ ├── Authentication.tsx │ │ └── utils.ts │ ├── Cluster │ │ ├── Cluster.scss │ │ ├── Cluster.tsx │ │ ├── ClusterInfo │ │ │ ├── ClusterInfo.scss │ │ │ ├── ClusterInfo.tsx │ │ │ ├── components │ │ │ │ └── DiskGroupsStatsBars │ │ │ │ │ ├── DiskGroupsStats.scss │ │ │ │ │ └── DiskGroupsStats.tsx │ │ │ ├── shared.ts │ │ │ └── utils │ │ │ │ ├── __tests__ │ │ │ │ └── prepareLinks.test.ts │ │ │ │ ├── useClusterLinks.ts │ │ │ │ └── utils.tsx │ │ ├── ClusterOverview │ │ │ ├── ClusterOverview.scss │ │ │ ├── ClusterOverview.tsx │ │ │ ├── components │ │ │ │ ├── ClusterMetricsCard.tsx │ │ │ │ ├── ClusterMetricsCores.tsx │ │ │ │ ├── ClusterMetricsMemory.tsx │ │ │ │ ├── ClusterMetricsNetwork.tsx │ │ │ │ └── ClusterMetricsStorage.tsx │ │ │ ├── shared.ts │ │ │ └── utils.tsx │ │ ├── VersionsBar │ │ │ ├── VersionsBar.scss │ │ │ └── VersionsBar.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ └── utils.tsx │ ├── ClusterModeGuard │ │ └── ClusterModeGuard.tsx │ ├── Clusters │ │ ├── Clusters.scss │ │ ├── Clusters.tsx │ │ ├── ClustersStatistics.tsx │ │ ├── columns.tsx │ │ ├── constants.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ ├── index.ts │ │ │ └── ru.json │ │ └── shared.ts │ ├── Header │ │ ├── Header.scss │ │ ├── Header.tsx │ │ ├── breadcrumbs.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── Heatmap │ │ ├── Heatmap.scss │ │ ├── Heatmap.tsx │ │ ├── HeatmapCanvas │ │ │ └── HeatmapCanvas.js │ │ ├── Histogram │ │ │ ├── Histogram.js │ │ │ └── Histogram.scss │ │ ├── index.ts │ │ └── util.js │ ├── Node │ │ ├── Node.scss │ │ ├── Node.tsx │ │ ├── NodePages.ts │ │ ├── NodeStructure │ │ │ ├── NodeStructure.scss │ │ │ ├── NodeStructure.tsx │ │ │ ├── PDiskTitleBadge.tsx │ │ │ └── Pdisk.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── Nodes │ │ ├── Nodes.scss │ │ ├── Nodes.tsx │ │ ├── NodesControls │ │ │ └── NodesControls.tsx │ │ ├── NodesTable.tsx │ │ ├── PaginatedNodes │ │ │ ├── GroupedNodesComponent.tsx │ │ │ ├── NodesComponent.tsx │ │ │ ├── NodesControlsWithTableState.tsx │ │ │ ├── PaginatedNodes.tsx │ │ │ └── index.ts │ │ ├── PeerRoleFilter │ │ │ ├── PeerRoleFilter.tsx │ │ │ └── utils.tsx │ │ ├── columns │ │ │ ├── columns.tsx │ │ │ └── constants.ts │ │ ├── getNodes.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── shared.tsx │ │ └── useNodesPageQueryParams.ts │ ├── Operations │ │ ├── Operations.scss │ │ ├── Operations.tsx │ │ ├── OperationsControls.tsx │ │ ├── columns.tsx │ │ ├── constants.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── shared.ts │ │ └── useOperationsQueryParams.ts │ ├── PDiskPage │ │ ├── DecommissionButton │ │ │ ├── DecommissionButton.scss │ │ │ └── DecommissionButton.tsx │ │ ├── DecommissionLabel │ │ │ └── DecommissionLabel.tsx │ │ ├── PDiskPage.scss │ │ ├── PDiskPage.tsx │ │ ├── PDiskSpaceDistribution │ │ │ ├── PDiskSpaceDistribution.scss │ │ │ ├── PDiskSpaceDistribution.tsx │ │ │ └── utils.ts │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── ReduxTooltip │ │ ├── ReduxTooltip.js │ │ └── ReduxTooltip.scss │ ├── Storage │ │ ├── Disks │ │ │ ├── Disks.scss │ │ │ └── Disks.tsx │ │ ├── EmptyFilter │ │ │ ├── EmptyFilter.tsx │ │ │ └── i18n │ │ │ │ ├── en.json │ │ │ │ ├── index.ts │ │ │ │ └── ru.json │ │ ├── PDisk │ │ │ ├── PDisk.scss │ │ │ ├── PDisk.tsx │ │ │ └── index.ts │ │ ├── PaginatedStorage.tsx │ │ ├── PaginatedStorageGroups │ │ │ ├── GroupedStorageGroupsComponent.tsx │ │ │ ├── PaginatedStorageGroups.tsx │ │ │ ├── StorageGroupsComponent.tsx │ │ │ ├── StorageGroupsControls.tsx │ │ │ └── index.ts │ │ ├── PaginatedStorageGroupsTable │ │ │ ├── PaginatedStorageGroupsTable.tsx │ │ │ ├── StorageGroupsEmptyDataMessage.tsx │ │ │ ├── columns │ │ │ │ ├── StorageGroupsColumns.scss │ │ │ │ ├── columns.tsx │ │ │ │ ├── constants.ts │ │ │ │ ├── hooks.ts │ │ │ │ ├── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ │ └── types.ts │ │ │ ├── getGroups.ts │ │ │ ├── i18n │ │ │ │ ├── en.json │ │ │ │ ├── index.ts │ │ │ │ └── ru.json │ │ │ └── index.tsx │ │ ├── PaginatedStorageNodes │ │ │ ├── GroupedStorageNodesComponent.tsx │ │ │ ├── PaginatedStorageNodes.tsx │ │ │ ├── StorageNodesComponent.tsx │ │ │ ├── StorageNodesControls.tsx │ │ │ ├── index.ts │ │ │ └── useStorageNodesColumnsToSelect.ts │ │ ├── PaginatedStorageNodesTable │ │ │ ├── PaginatedStorageNodesTable.tsx │ │ │ ├── StorageNodes.scss │ │ │ ├── StorageNodesEmptyDataMessage.tsx │ │ │ ├── columns │ │ │ │ ├── StorageNodesColumns.scss │ │ │ │ ├── columns.tsx │ │ │ │ ├── constants.ts │ │ │ │ ├── hooks.ts │ │ │ │ └── types.ts │ │ │ ├── getNodes.ts │ │ │ ├── i18n │ │ │ │ ├── en.json │ │ │ │ ├── index.ts │ │ │ │ └── ru.json │ │ │ └── index.tsx │ │ ├── Storage.scss │ │ ├── StorageTypeFilter │ │ │ └── StorageTypeFilter.tsx │ │ ├── StorageVisibleEntitiesFilter │ │ │ └── StorageVisibleEntitiesFilter.tsx │ │ ├── TableGroup │ │ │ ├── TableGroup.scss │ │ │ ├── TableGroup.tsx │ │ │ └── useExpandedTableGroups.ts │ │ ├── VDisks │ │ │ ├── VDisks.scss │ │ │ └── VDisks.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── shared.tsx │ │ ├── types.ts │ │ ├── useStorageQueryParams.ts │ │ └── utils │ │ │ ├── index.ts │ │ │ └── useStorageColumnsSettings.ts │ ├── StorageGroupPage │ │ ├── StorageGroupPage.scss │ │ ├── StorageGroupPage.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── Tablet │ │ ├── Tablet.scss │ │ ├── Tablet.tsx │ │ ├── components │ │ │ ├── TabletControls │ │ │ │ ├── TabletControls.tsx │ │ │ │ └── index.ts │ │ │ ├── TabletInfo │ │ │ │ ├── TabletInfo.scss │ │ │ │ ├── TabletInfo.tsx │ │ │ │ ├── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── TabletStorageInfo │ │ │ │ ├── TabletStorageInfo.scss │ │ │ │ ├── TabletStorageInfo.tsx │ │ │ │ ├── columns.tsx │ │ │ │ ├── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ │ ├── shared.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ └── TabletTable │ │ │ │ ├── TabletTable.tsx │ │ │ │ └── index.ts │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ ├── index.ts │ │ └── utils.ts │ ├── Tablets │ │ ├── Tablets.tsx │ │ ├── TabletsTable.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── Tenant │ │ ├── Acl │ │ │ ├── Acl.scss │ │ │ ├── Acl.tsx │ │ │ └── i18n │ │ │ │ ├── en.json │ │ │ │ └── index.ts │ │ ├── Diagnostics │ │ │ ├── Configs │ │ │ │ ├── Configs.scss │ │ │ │ ├── Configs.tsx │ │ │ │ └── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ ├── Consumers │ │ │ │ ├── Consumers.scss │ │ │ │ ├── Consumers.tsx │ │ │ │ ├── Headers │ │ │ │ │ ├── Headers.scss │ │ │ │ │ ├── Headers.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TopicStats │ │ │ │ │ ├── ConsumersTopicStats.scss │ │ │ │ │ ├── ConsumersTopicStats.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── columns │ │ │ │ │ ├── Columns.scss │ │ │ │ │ ├── columns.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ru.json │ │ │ │ ├── index.ts │ │ │ │ └── utils │ │ │ │ │ └── constants.ts │ │ │ ├── Describe │ │ │ │ ├── Describe.scss │ │ │ │ └── Describe.tsx │ │ │ ├── DetailedOverview │ │ │ │ ├── DetailedOverview.scss │ │ │ │ └── DetailedOverview.tsx │ │ │ ├── Diagnostics.scss │ │ │ ├── Diagnostics.tsx │ │ │ ├── DiagnosticsPages.ts │ │ │ ├── HotKeys │ │ │ │ ├── HotKeys.scss │ │ │ │ ├── HotKeys.tsx │ │ │ │ └── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ ├── Network │ │ │ │ ├── Network.scss │ │ │ │ ├── Network.tsx │ │ │ │ ├── NetworkTable │ │ │ │ │ ├── columns.tsx │ │ │ │ │ └── constants.ts │ │ │ │ ├── NetworkWrapper.tsx │ │ │ │ ├── NodeNetwork │ │ │ │ │ ├── NodeNetwork.scss │ │ │ │ │ └── NodeNetwork.tsx │ │ │ │ └── utils.ts │ │ │ ├── Overview │ │ │ │ ├── AsyncReplicationInfo │ │ │ │ │ ├── AsyncReplicationInfo.tsx │ │ │ │ │ ├── Credentials.tsx │ │ │ │ │ ├── i18n │ │ │ │ │ │ ├── en.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── AsyncReplicationPaths │ │ │ │ │ ├── AsyncReplicationPaths.scss │ │ │ │ │ ├── AsyncReplicationPaths.tsx │ │ │ │ │ ├── i18n │ │ │ │ │ │ ├── en.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── ChangefeedInfo │ │ │ │ │ ├── ChangefeedInfo.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Overview.tsx │ │ │ │ ├── TableInfo │ │ │ │ │ ├── TableInfo.scss │ │ │ │ │ ├── TableInfo.tsx │ │ │ │ │ ├── i18n │ │ │ │ │ │ ├── en.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── prepareTableInfo.tsx │ │ │ │ ├── TopicInfo │ │ │ │ │ ├── TopicInfo.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TopicStats │ │ │ │ │ ├── TopicStats.scss │ │ │ │ │ ├── TopicStats.tsx │ │ │ │ │ ├── i18n │ │ │ │ │ │ ├── en.json │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── ru.json │ │ │ │ │ └── index.ts │ │ │ │ ├── TransferInfo │ │ │ │ │ ├── Credentials.tsx │ │ │ │ │ ├── TransferInfo.tsx │ │ │ │ │ ├── i18n │ │ │ │ │ │ ├── en.json │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ └── utils │ │ │ │ │ ├── index.ts │ │ │ │ │ └── prepareTopicSchemaInfo.ts │ │ │ ├── Partitions │ │ │ │ ├── Headers │ │ │ │ │ ├── Headers.scss │ │ │ │ │ ├── Headers.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Partitions.scss │ │ │ │ ├── Partitions.tsx │ │ │ │ ├── PartitionsControls │ │ │ │ │ └── PartitionsControls.tsx │ │ │ │ ├── columns │ │ │ │ │ ├── Columns.scss │ │ │ │ │ ├── columns.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ru.json │ │ │ │ └── utils │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── useGetPartitionsColumns.ts │ │ │ ├── TenantOverview │ │ │ │ ├── DefaultOverviewContent │ │ │ │ │ ├── DefaultOverviewContent.tsx │ │ │ │ │ └── defaultDashboardConfig.ts │ │ │ │ ├── Healthcheck │ │ │ │ │ ├── Healthcheck.scss │ │ │ │ │ ├── HealthcheckDetails.tsx │ │ │ │ │ ├── HealthcheckPreview.tsx │ │ │ │ │ ├── IssuesViewer │ │ │ │ │ │ ├── IssueTree.scss │ │ │ │ │ │ ├── IssueTree.tsx │ │ │ │ │ │ └── IssueTreeItem │ │ │ │ │ │ │ ├── IssueTreeItem.scss │ │ │ │ │ │ │ ├── IssueTreeItem.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── i18n │ │ │ │ │ │ ├── en.json │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── ru.json │ │ │ │ ├── MetricsCards │ │ │ │ │ ├── MetricCard │ │ │ │ │ │ ├── MetricCard.scss │ │ │ │ │ │ └── MetricCard.tsx │ │ │ │ │ ├── MetricsCards.scss │ │ │ │ │ └── MetricsCards.tsx │ │ │ │ ├── TenantCpu │ │ │ │ │ ├── TenantCpu.tsx │ │ │ │ │ ├── TopNodesByCpu.tsx │ │ │ │ │ ├── TopNodesByLoad.tsx │ │ │ │ │ ├── TopQueries.tsx │ │ │ │ │ ├── TopShards.tsx │ │ │ │ │ └── cpuDashboardConfig.ts │ │ │ │ ├── TenantDashboard │ │ │ │ │ ├── TenantDashboard.scss │ │ │ │ │ └── TenantDashboard.tsx │ │ │ │ ├── TenantMemory │ │ │ │ │ ├── TenantMemory.tsx │ │ │ │ │ ├── TopNodesByMemory.tsx │ │ │ │ │ └── memoryDashboardConfig.ts │ │ │ │ ├── TenantOverview.scss │ │ │ │ ├── TenantOverview.tsx │ │ │ │ ├── TenantOverviewTableLayout.tsx │ │ │ │ ├── TenantStorage │ │ │ │ │ ├── TenantStorage.tsx │ │ │ │ │ ├── TopGroups.tsx │ │ │ │ │ ├── TopTables.tsx │ │ │ │ │ └── storageDashboardConfig.ts │ │ │ │ ├── getSectionTitle.tsx │ │ │ │ ├── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ │ ├── useHealthcheck.ts │ │ │ │ └── utils.ts │ │ │ ├── TopQueries │ │ │ │ ├── QueryDetails │ │ │ │ │ ├── NotFoundContainer.tsx │ │ │ │ │ ├── QueryDetails.scss │ │ │ │ │ ├── QueryDetails.tsx │ │ │ │ │ └── QueryDetailsDrawerContent.tsx │ │ │ │ ├── RunningQueriesData.tsx │ │ │ │ ├── TopQueries.scss │ │ │ │ ├── TopQueries.tsx │ │ │ │ ├── TopQueriesData.tsx │ │ │ │ ├── columns │ │ │ │ │ ├── columns.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ └── i18n │ │ │ │ │ │ ├── en.json │ │ │ │ │ │ └── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── hooks │ │ │ │ │ ├── useRunningQueriesSort.ts │ │ │ │ │ ├── useSetSelectedTopQueryRowFromParams.ts │ │ │ │ │ ├── useSortParam.ts │ │ │ │ │ └── useTopQueriesSort.ts │ │ │ │ ├── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── utils.ts │ │ │ │ └── utils │ │ │ │ │ ├── generateShareableUrl.ts │ │ │ │ │ └── getTopQueryRowQueryParams.ts │ │ │ ├── TopShards │ │ │ │ ├── Filters │ │ │ │ │ ├── Filters.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── TopShards.scss │ │ │ │ ├── TopShards.tsx │ │ │ │ ├── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ru.json │ │ │ │ ├── index.ts │ │ │ │ └── utils.ts │ │ │ └── TopicData │ │ │ │ ├── FullValue.tsx │ │ │ │ ├── TopicData.scss │ │ │ │ ├── TopicData.tsx │ │ │ │ ├── TopicDataControls │ │ │ │ └── TopicDataControls.tsx │ │ │ │ ├── TopicMessageDetails │ │ │ │ ├── TopicMessageDetails.scss │ │ │ │ ├── TopicMessageDetails.tsx │ │ │ │ ├── components │ │ │ │ │ ├── TopicDataSection.tsx │ │ │ │ │ ├── TopicMessage.tsx │ │ │ │ │ ├── TopicMessageGeneralInfo.tsx │ │ │ │ │ ├── TopicMessageMetadata.tsx │ │ │ │ │ └── fields.tsx │ │ │ │ └── shared.ts │ │ │ │ ├── __test__ │ │ │ │ └── getData.test.ts │ │ │ │ ├── columns │ │ │ │ ├── Columns.scss │ │ │ │ └── columns.tsx │ │ │ │ ├── getData.ts │ │ │ │ ├── i18n │ │ │ │ ├── en.json │ │ │ │ └── index.ts │ │ │ │ ├── useTopicDataQueryParams.ts │ │ │ │ └── utils │ │ │ │ ├── constants.ts │ │ │ │ └── types.ts │ │ ├── EntityTitle │ │ │ └── EntityTitle.tsx │ │ ├── Info │ │ │ ├── ExternalDataSource │ │ │ │ ├── ExternalDataSource.scss │ │ │ │ └── ExternalDataSource.tsx │ │ │ ├── ExternalTable │ │ │ │ ├── ExternalTable.scss │ │ │ │ └── ExternalTable.tsx │ │ │ ├── View │ │ │ │ └── View.tsx │ │ │ └── i18n │ │ │ │ ├── en.json │ │ │ │ └── index.ts │ │ ├── ObjectGeneral │ │ │ ├── ObjectGeneral.scss │ │ │ └── ObjectGeneral.tsx │ │ ├── ObjectSummary │ │ │ ├── CreateDirectoryDialog │ │ │ │ ├── CreateDirectoryDialog.scss │ │ │ │ └── CreateDirectoryDialog.tsx │ │ │ ├── ObjectSummary.scss │ │ │ ├── ObjectSummary.tsx │ │ │ ├── ObjectTree.tsx │ │ │ ├── SchemaActions.tsx │ │ │ ├── SchemaTree │ │ │ │ ├── RefreshTreeButton.tsx │ │ │ │ └── SchemaTree.tsx │ │ │ ├── UpdateTreeContext.tsx │ │ │ ├── __test__ │ │ │ │ └── transformPath.test.ts │ │ │ ├── i18n │ │ │ │ ├── en.json │ │ │ │ └── index.ts │ │ │ ├── shared.ts │ │ │ └── transformPath.ts │ │ ├── Query │ │ │ ├── Issues │ │ │ │ ├── Issues.scss │ │ │ │ ├── Issues.tsx │ │ │ │ └── models.ts │ │ │ ├── NewSQL │ │ │ │ ├── NewSQL.tsx │ │ │ │ └── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ ├── Preview │ │ │ │ ├── Preview.scss │ │ │ │ ├── Preview.tsx │ │ │ │ ├── components │ │ │ │ │ ├── PreviewView.tsx │ │ │ │ │ ├── TablePreview.tsx │ │ │ │ │ ├── TopicPreview.tsx │ │ │ │ │ └── TopicPreviewTable.tsx │ │ │ │ ├── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ │ ├── shared.ts │ │ │ │ └── types.ts │ │ │ ├── QueriesHistory │ │ │ │ ├── QueriesHistory.scss │ │ │ │ └── QueriesHistory.tsx │ │ │ ├── Query.scss │ │ │ ├── Query.tsx │ │ │ ├── QueryEditor │ │ │ │ ├── QueryEditor.scss │ │ │ │ ├── QueryEditor.tsx │ │ │ │ ├── YqlEditor.tsx │ │ │ │ ├── helpers.ts │ │ │ │ └── keybindings.ts │ │ │ ├── QueryEditorControls │ │ │ │ ├── EditorButton.scss │ │ │ │ ├── EditorButton.tsx │ │ │ │ ├── QueryEditorControls.scss │ │ │ │ ├── QueryEditorControls.tsx │ │ │ │ └── utils │ │ │ │ │ ├── getChangedQueryExecutionSettings.test.ts │ │ │ │ │ ├── getChangedQueryExecutionSettings.ts │ │ │ │ │ ├── getChangedQueryExecutionSettingsDescription.test.ts │ │ │ │ │ └── getChangedQueryExecutionSettingsDescription.ts │ │ │ ├── QueryResult │ │ │ │ ├── QueryResultViewer.scss │ │ │ │ ├── QueryResultViewer.tsx │ │ │ │ ├── components │ │ │ │ │ ├── Ast │ │ │ │ │ │ ├── Ast.scss │ │ │ │ │ │ └── Ast.tsx │ │ │ │ │ ├── Graph │ │ │ │ │ │ ├── Graph.scss │ │ │ │ │ │ └── Graph.tsx │ │ │ │ │ ├── QueryInfoDropdown │ │ │ │ │ │ ├── QueryInfoDropdown.scss │ │ │ │ │ │ ├── QueryInfoDropdown.tsx │ │ │ │ │ │ ├── shared.ts │ │ │ │ │ │ └── useQueryInfoMenuItems.tsx │ │ │ │ │ ├── QueryJSONViewer │ │ │ │ │ │ ├── QueryJSONViewer.scss │ │ │ │ │ │ └── QueryJSONViewer.tsx │ │ │ │ │ ├── QueryResultError │ │ │ │ │ │ ├── QueryResultError.scss │ │ │ │ │ │ └── QueryResultError.tsx │ │ │ │ │ ├── ResultSetsViewer │ │ │ │ │ │ ├── ResultSetsViewer.scss │ │ │ │ │ │ └── ResultSetsViewer.tsx │ │ │ │ │ ├── SimplifiedPlan │ │ │ │ │ │ ├── MetricsCell.tsx │ │ │ │ │ │ ├── OperationCell.tsx │ │ │ │ │ │ ├── OperationParams.tsx │ │ │ │ │ │ ├── SimplifiedPlan.scss │ │ │ │ │ │ ├── SimplifiedPlan.tsx │ │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ │ └── utils.test.ts │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── Stub │ │ │ │ │ │ ├── Stub.scss │ │ │ │ │ │ └── Stub.tsx │ │ │ │ │ └── TraceButton │ │ │ │ │ │ └── TraceButton.tsx │ │ │ │ └── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ ├── QuerySettingsBanner │ │ │ │ ├── QuerySettingsBanner.scss │ │ │ │ └── QuerySettingsBanner.tsx │ │ │ ├── QuerySettingsDialog │ │ │ │ ├── QuerySettingsDialog.scss │ │ │ │ ├── QuerySettingsDialog.tsx │ │ │ │ ├── QuerySettingsSelect.scss │ │ │ │ ├── QuerySettingsSelect.tsx │ │ │ │ ├── QuerySettingsTimeout.scss │ │ │ │ ├── QuerySettingsTimeout.tsx │ │ │ │ ├── TimeoutLabel.scss │ │ │ │ ├── TimeoutLabel.tsx │ │ │ │ ├── constants.ts │ │ │ │ └── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── ru.json │ │ │ ├── QueryStoppedBanner │ │ │ │ ├── QueryStoppedBanner.scss │ │ │ │ └── QueryStoppedBanner.tsx │ │ │ ├── QueryTabs │ │ │ │ └── QueryTabs.tsx │ │ │ ├── SaveQuery │ │ │ │ ├── SaveQuery.scss │ │ │ │ ├── SaveQuery.tsx │ │ │ │ └── i18n │ │ │ │ │ ├── en.json │ │ │ │ │ └── index.ts │ │ │ ├── SavedQueries │ │ │ │ ├── SavedQueries.scss │ │ │ │ └── SavedQueries.tsx │ │ │ ├── i18n │ │ │ │ ├── en.json │ │ │ │ └── index.ts │ │ │ └── utils │ │ │ │ ├── __test__ │ │ │ │ └── replaceParams.test.ts │ │ │ │ ├── getPreparedResult.ts │ │ │ │ ├── isQueryCancelledError.ts │ │ │ │ ├── replaceParams.ts │ │ │ │ └── useSavedQueries.tsx │ │ ├── Schema │ │ │ └── SchemaViewer │ │ │ │ ├── KeysView.tsx │ │ │ │ ├── SchemaViewer.scss │ │ │ │ ├── SchemaViewer.tsx │ │ │ │ ├── __tests__ │ │ │ │ ├── prepareData.test.ts │ │ │ │ └── utils.test.ts │ │ │ │ ├── columns.tsx │ │ │ │ ├── i18n │ │ │ │ ├── en.json │ │ │ │ └── index.ts │ │ │ │ ├── prepareData.ts │ │ │ │ ├── shared.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ ├── Tenant.scss │ │ ├── Tenant.tsx │ │ ├── TenantNavigation │ │ │ ├── TenantNavigation.scss │ │ │ ├── TenantNavigation.tsx │ │ │ └── useTenantNavigation.tsx │ │ ├── TenantPages.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ └── utils │ │ │ ├── ToggleButton.scss │ │ │ ├── constants.ts │ │ │ ├── controls.tsx │ │ │ ├── index.ts │ │ │ ├── newSQLQueryActions.ts │ │ │ ├── paneVisibilityToggleHelpers.tsx │ │ │ ├── schema.ts │ │ │ ├── schemaActions.tsx │ │ │ ├── schemaQueryTemplates.ts │ │ │ └── types.ts │ ├── Tenants │ │ ├── Tenants.scss │ │ ├── Tenants.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ ├── UserSettings │ │ ├── Setting.tsx │ │ ├── UserSettings.tsx │ │ ├── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ │ └── settings.tsx │ ├── VDiskPage │ │ ├── VDiskPage.scss │ │ ├── VDiskPage.tsx │ │ └── i18n │ │ │ ├── en.json │ │ │ └── index.ts │ └── Versions │ │ ├── GroupedNodesTree │ │ ├── GroupedNodesTree.scss │ │ └── GroupedNodesTree.tsx │ │ ├── NodesTable │ │ └── NodesTable.tsx │ │ ├── NodesTreeTitle │ │ ├── NodesTreeTitle.scss │ │ └── NodesTreeTitle.tsx │ │ ├── Versions.scss │ │ ├── Versions.tsx │ │ ├── groupNodes.test.ts │ │ ├── groupNodes.ts │ │ ├── i18n │ │ ├── en.json │ │ └── index.ts │ │ ├── types.ts │ │ └── utils.ts ├── index.tsx ├── lib.ts ├── react-app-env.d.ts ├── reportWebVitals.ts ├── routes.ts ├── services │ ├── api │ │ ├── auth.ts │ │ ├── base.ts │ │ ├── codeAssist.ts │ │ ├── index.ts │ │ ├── meta.ts │ │ ├── operation.ts │ │ ├── pdisk.ts │ │ ├── scheme.ts │ │ ├── storage.ts │ │ ├── streaming.ts │ │ ├── tablets.ts │ │ ├── vdisk.ts │ │ └── viewer.ts │ ├── parsers │ │ ├── parseMetaCluster.ts │ │ └── parseMetaTenants.ts │ └── settings.ts ├── setupProxy.js ├── setupTests.js ├── store │ ├── __test__ │ │ └── getUrlData.test.ts │ ├── configureStore.ts │ ├── defaultStore.ts │ ├── getUrlData.ts │ ├── index.ts │ ├── reducers │ │ ├── api.ts │ │ ├── authentication │ │ │ ├── authentication.ts │ │ │ └── types.ts │ │ ├── cancelQuery.ts │ │ ├── capabilities │ │ │ ├── capabilities.ts │ │ │ └── hooks.ts │ │ ├── cluster │ │ │ ├── __test__ │ │ │ │ └── parseGroupsStatsQueryResponse.test.ts │ │ │ ├── cluster.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── clusters │ │ │ ├── clusters.ts │ │ │ ├── selectors.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── codeAssist │ │ │ └── codeAssist.ts │ │ ├── executeTopQueries │ │ │ ├── constants.ts │ │ │ ├── executeTopQueries.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── fullscreen.ts │ │ ├── header │ │ │ ├── header.ts │ │ │ └── types.ts │ │ ├── healthcheckInfo │ │ │ ├── healthcheckInfo.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── heatmap.ts │ │ ├── hotKeys │ │ │ └── hotKeys.ts │ │ ├── index.ts │ │ ├── network │ │ │ └── network.ts │ │ ├── node │ │ │ ├── node.ts │ │ │ ├── selectors.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── nodes │ │ │ ├── nodes.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── nodesList.ts │ │ ├── operations.ts │ │ ├── overview │ │ │ └── overview.ts │ │ ├── partitions │ │ │ ├── partitions.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── pdisk │ │ │ ├── __tests__ │ │ │ │ └── preparePDiskDataResponse.test.ts │ │ │ ├── pdisk.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── planToSvg.ts │ │ ├── preview.ts │ │ ├── query │ │ │ ├── __test__ │ │ │ │ └── utils.test.ts │ │ │ ├── preparePlanData.ts │ │ │ ├── prepareQueryData.ts │ │ │ ├── query.ts │ │ │ ├── streamingReducers.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── queryActions │ │ │ ├── queryActions.ts │ │ │ └── types.ts │ │ ├── replication.ts │ │ ├── schema │ │ │ └── schema.ts │ │ ├── schemaAcl │ │ │ └── schemaAcl.ts │ │ ├── settings │ │ │ ├── hooks.ts │ │ │ ├── settings.ts │ │ │ └── types.ts │ │ ├── shardsWorkload │ │ │ ├── shardsWorkload.ts │ │ │ └── types.ts │ │ ├── singleClusterMode.ts │ │ ├── storage │ │ │ ├── __tests__ │ │ │ │ ├── calculateMaximumDisksPerNode.test.ts │ │ │ │ ├── calculateMaximumSlotsPerDisk.test.ts │ │ │ │ └── prepareGroupsDisks.test.ts │ │ │ ├── constants.ts │ │ │ ├── prepareGroupsDisks.ts │ │ │ ├── requestStorageData.ts │ │ │ ├── storage.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── tableData.ts │ │ ├── tableSchemaData.ts │ │ ├── tablet.ts │ │ ├── tablets.ts │ │ ├── tenant │ │ │ ├── constants.ts │ │ │ ├── tenant.ts │ │ │ └── types.ts │ │ ├── tenantOverview │ │ │ ├── executeTopTables │ │ │ │ └── executeTopTables.ts │ │ │ └── topShards │ │ │ │ └── tenantOverviewTopShards.ts │ │ ├── tenants │ │ │ ├── contants.ts │ │ │ ├── selectors.ts │ │ │ ├── tenants.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── tooltip.ts │ │ ├── topic.ts │ │ ├── vdisk │ │ │ ├── types.ts │ │ │ ├── utils.ts │ │ │ └── vdisk.ts │ │ └── viewSchema │ │ │ └── viewSchema.ts │ └── state-url-mapping.ts ├── styles │ ├── illustrations.scss │ ├── index.scss │ ├── mixins.scss │ ├── themes.scss │ ├── themes │ │ ├── dark-hc.scss │ │ ├── dark.scss │ │ ├── light-hc.scss │ │ └── light.scss │ └── unipika.scss ├── types │ ├── additionalProps.ts │ ├── api │ │ ├── acl.ts │ │ ├── autocomplete.ts │ │ ├── capabilities.ts │ │ ├── cluster.ts │ │ ├── codeAssist.ts │ │ ├── common.ts │ │ ├── consumer.ts │ │ ├── enums.ts │ │ ├── error.ts │ │ ├── featureFlags.ts │ │ ├── healthcheck.ts │ │ ├── hotkeys.ts │ │ ├── meta.ts │ │ ├── modifyDisk.ts │ │ ├── netInfo.ts │ │ ├── nodes.ts │ │ ├── nodesList.ts │ │ ├── operations.ts │ │ ├── pdisk.ts │ │ ├── query.ts │ │ ├── render.ts │ │ ├── replication.ts │ │ ├── schema │ │ │ ├── cdcStream.ts │ │ │ ├── columnEntity.ts │ │ │ ├── externalDataSource.ts │ │ │ ├── externalTable.ts │ │ │ ├── index.ts │ │ │ ├── persQueueGroup.ts │ │ │ ├── replication.ts │ │ │ ├── schema.ts │ │ │ ├── shared.ts │ │ │ ├── table.ts │ │ │ ├── tableIndex.ts │ │ │ └── view.ts │ │ ├── storage.ts │ │ ├── systemState.ts │ │ ├── tablet.ts │ │ ├── tenant.ts │ │ ├── topic.ts │ │ ├── trace.ts │ │ ├── vdisk.ts │ │ └── whoami.ts │ ├── assets.d.ts │ ├── common.ts │ ├── components.ts │ ├── global.d.ts │ ├── index.ts │ ├── react-table.d.ts │ ├── redux-location-state.d.ts │ ├── store │ │ ├── describe.ts │ │ ├── heatmap.ts │ │ ├── nodesList.ts │ │ ├── query.ts │ │ ├── streaming.ts │ │ ├── tablet.ts │ │ ├── tablets.ts │ │ ├── tooltip.ts │ │ └── topic.ts │ ├── unipika.d.ts │ ├── versions.ts │ └── window.d.ts ├── uiFactory │ ├── types.ts │ └── uiFactory.ts └── utils │ ├── __test__ │ ├── getColumnWidth.test.ts │ ├── index.test.ts │ ├── monitoring.test.ts │ ├── parseBalancer.test.ts │ ├── prepareBackend.test.ts │ ├── prepareQueryExplain.test.ts │ └── response.test.ts │ ├── additionalProps.ts │ ├── bytesParsers │ ├── __test__ │ │ └── formatBytes.test.ts │ ├── convertBytesObjectToSpeed.ts │ ├── formatBytes.ts │ ├── i18n │ │ ├── en.json │ │ └── index.ts │ └── index.ts │ ├── clusterVersionColors.ts │ ├── cn.ts │ ├── constants.ts │ ├── createToast.tsx │ ├── dataFormatters │ ├── __test__ │ │ ├── formatNumbers.test.ts │ │ ├── formatStorageValues.test.ts │ │ ├── formatUptime.test.ts │ │ └── roundToSignificant.test.ts │ ├── common.ts │ ├── dataFormatters.ts │ ├── formatNumber.ts │ └── i18n │ │ ├── en.json │ │ └── index.ts │ ├── developerUI │ ├── __test__ │ │ └── developerUI.test.ts │ └── developerUI.ts │ ├── disks │ ├── __test__ │ │ ├── calculatePDiskSeverity.test.ts │ │ ├── calculateVDiskSeverity.test.ts │ │ └── prepareDisks.test.ts │ ├── calculatePDiskSeverity.ts │ ├── calculateVDiskSeverity.ts │ ├── constants.ts │ ├── getPDiskType.ts │ ├── helpers.ts │ ├── prepareDisks.ts │ └── types.ts │ ├── downloadFile.ts │ ├── errors │ ├── i18n │ │ ├── en.json │ │ └── index.ts │ └── index.ts │ ├── filters.ts │ ├── generateEvaluator.ts │ ├── generateHash.ts │ ├── getColumnWidth.ts │ ├── hooks │ ├── __test__ │ │ └── useTableSort.test.ts │ ├── index.ts │ ├── useAdditionalNodesProps.ts │ ├── useAutoRefreshInterval.ts │ ├── useCancellable.ts │ ├── useChangedQuerySettings.ts │ ├── useDatabaseFromQuery.ts │ ├── useDebouncedValue.ts │ ├── useDelayed.ts │ ├── useEventHandler.ts │ ├── useIsUserAllowedToMakeChanges.ts │ ├── useLastQueryExecutionSettings.ts │ ├── useNodeDeveloperUIHref.ts │ ├── useQueryExecutionSettings.ts │ ├── useSearchQuery.ts │ ├── useSelectedColumns.ts │ ├── useSetting.ts │ ├── useTableResize.ts │ ├── useTableSort.ts │ ├── useTypedDispatch.ts │ ├── useTypedSelector.ts │ └── withConfirmation │ │ ├── i18n │ │ ├── en.json │ │ └── index.ts │ │ └── useChangeInputWithConfirmation.tsx │ ├── i18n │ ├── i18n.ts │ └── index.ts │ ├── index.ts │ ├── lazyComponent.tsx │ ├── logs.ts │ ├── monaco │ ├── constats.ts │ ├── highlightErrors.ts │ ├── i18n │ │ ├── en.json │ │ └── index.ts │ ├── insertSnippet.ts │ └── yql │ │ ├── constants.ts │ │ ├── generateSuggestions.ts │ │ └── yql.completionItemProvider.ts │ ├── monitoring.ts │ ├── nodes.ts │ ├── numeral.ts │ ├── parseBalancer.ts │ ├── prepareBackend.ts │ ├── prepareErrorMessage.ts │ ├── prepareQueryExplain.ts │ ├── progress.ts │ ├── query.test.ts │ ├── query.ts │ ├── registerError.ts │ ├── renderPaginatedTableErrorMessage.tsx │ ├── response.ts │ ├── storage.ts │ ├── tableUtils │ ├── getRequiredDataFields.ts │ └── types.ts │ ├── tablet.ts │ ├── tests │ └── providers.tsx │ ├── timeParsers │ ├── __test__ │ │ ├── formatDuration.test.ts │ │ └── protobuf.test.ts │ ├── formatDuration.ts │ ├── i18n │ │ ├── en.json │ │ ├── index.ts │ │ └── ru.json │ ├── index.ts │ ├── parsers.ts │ └── protobufParsers.ts │ ├── timeframes.ts │ ├── tooltip.js │ ├── typecheckers.ts │ ├── utils.ts │ └── versions │ ├── getVersionsColors.ts │ ├── index.ts │ ├── parseNodesToVersionsValues.ts │ └── parseVersion.ts ├── tests ├── models │ ├── BaseModel.ts │ └── PageModel.ts ├── playwrightSetup.ts ├── suites │ ├── internalViewer │ │ └── internalViewer.test.ts │ ├── memoryViewer │ │ ├── MemoryViewer.ts │ │ └── memoryViewer.test.ts │ ├── nodes │ │ ├── NodesPage.ts │ │ └── nodes.test.ts │ ├── paginatedTable │ │ ├── mocks.ts │ │ ├── paginatedTable.test.ts │ │ └── paginatedTable.ts │ ├── sidebar │ │ ├── Sidebar.ts │ │ └── sidebar.test.ts │ ├── storage │ │ ├── StoragePage.ts │ │ └── storage.test.ts │ ├── tenant │ │ ├── TenantPage.ts │ │ ├── constants.ts │ │ ├── diagnostics │ │ │ ├── Diagnostics.ts │ │ │ ├── mocks.ts │ │ │ └── tabs │ │ │ │ ├── info.test.ts │ │ │ │ ├── nodes.test.ts │ │ │ │ ├── queries.test.ts │ │ │ │ ├── schema.test.ts │ │ │ │ ├── storage.test.ts │ │ │ │ └── topShards.test.ts │ │ ├── initialLoad.test.ts │ │ ├── queryEditor │ │ │ ├── models │ │ │ │ ├── NewSqlDropdownMenu.ts │ │ │ │ ├── QueryEditor.ts │ │ │ │ ├── QueryTabsNavigation.ts │ │ │ │ ├── ResultTable.ts │ │ │ │ ├── SaveQueryDialog.ts │ │ │ │ ├── SettingsDialog.ts │ │ │ │ └── UnsavedChangesModal.ts │ │ │ ├── planToSvg.test.ts │ │ │ ├── queryEditor.test.ts │ │ │ ├── querySettings.test.ts │ │ │ ├── queryStatus.test.ts │ │ │ ├── queryTemplates.test.ts │ │ │ └── utils.ts │ │ ├── queryHistory │ │ │ ├── models │ │ │ │ └── QueriesHistoryTable.ts │ │ │ ├── queryHistory.test.ts │ │ │ └── utils.ts │ │ ├── savedQueries │ │ │ ├── models │ │ │ │ └── SavedQueriesTable.ts │ │ │ └── savedQueries.test.ts │ │ └── summary │ │ │ ├── ActionsMenu.ts │ │ │ ├── ObjectSummary.ts │ │ │ ├── objectSummary.test.ts │ │ │ └── types.ts │ └── tenants │ │ ├── TenantsPage.ts │ │ └── tenants.test.ts └── utils │ ├── clipboard.ts │ ├── constants.ts │ ├── dom.ts │ ├── retryAction.ts │ ├── selectContentTable.ts │ └── toggleExperiment.ts ├── tsconfig.json └── tsconfig.package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | max_line_length = 100 10 | trim_trailing_whitespace = true 11 | 12 | [{*.json, *.yaml, *.yml}] 13 | indent_size = 2 14 | 15 | [*.md] 16 | max_line_length = 0 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | DISABLE_ESLINT_PLUGIN=true 2 | TSC_COMPILE_ON_ERROR=true 3 | 4 | REACT_APP_BACKEND=http://localhost:8765 5 | REACT_APP_META_BACKEND=undefined 6 | META_YDB_BACKEND=undefined 7 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | dist 3 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | - hotfix/v[0-9]+.[0-9]+.[0-9]+ # match branches in format hotfix/v6.20.10 6 | 7 | name: Release 8 | 9 | jobs: 10 | release: 11 | if: github.repository == 'ydb-platform/ydb-embedded-ui' 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/setup-node@v4 16 | with: 17 | node-version: 20 18 | - run: npm ci 19 | - run: npm test 20 | - uses: googleapis/release-please-action@v4 21 | with: 22 | token: ${{ secrets.YDB_PLATFORM_BOT_TOKEN_REPO }} 23 | target-branch: ${{ github.ref_name }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | playwright-artifacts 11 | 12 | # production 13 | /build 14 | /dist 15 | *.zip 16 | 17 | # misc 18 | .idea 19 | .DS_Store 20 | .env.local 21 | .env.development.local 22 | .env.test.local 23 | .env.production.local 24 | .vscode 25 | 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | 30 | .env 31 | 32 | 33 | embedded-ui.tar.bz2 -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | 3 | build 4 | dist 5 | CHANGELOG.md 6 | CONTRIBUTING.md 7 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@gravity-ui/prettier-config'); 2 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "9.3.0" 3 | } 4 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@gravity-ui/stylelint-config", 4 | "@gravity-ui/stylelint-config/order", 5 | "@gravity-ui/stylelint-config/prettier" 6 | ], 7 | "rules": { 8 | "declaration-no-important": null 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The following authors have created the source code of "Yandex Database Embedded UI" 2 | published and distributed by YANDEX LLC as the owner: 3 | 4 | Artem Luchin 5 | Evgeniy Biriulin 6 | Elena Makarova 7 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'header-max-length': [2, 'always', 72], 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ydb-platform/ydb-embedded-ui/ce13b7fca36d1e77f31221156ce09d1b6f35c418/public/static/favicon.png -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", 3 | "bootstrap-sha": "a3a39782af968677866b86dc590d4150d4af4211", 4 | "release-type": "node", 5 | "include-component-in-tag": false, 6 | "pull-request-title-pattern": "chore(${branch}): release ${version}", 7 | "packages": { 8 | ".": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/assets/icons/key.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/assets/icons/monitoring.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/assets/icons/user-secret.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/AsyncReplicationState/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AsyncReplicationState'; 2 | -------------------------------------------------------------------------------- /src/components/AutoRefreshControl/AutoRefreshControl.scss: -------------------------------------------------------------------------------- 1 | .auto-refresh-control { 2 | display: flex; 3 | align-items: center; 4 | gap: var(--g-spacing-1); 5 | } 6 | -------------------------------------------------------------------------------- /src/components/AutoRefreshControl/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "None": "None", 3 | "15 sec": "15 sec", 4 | "1 min": "1 min", 5 | "2 min": "2 min", 6 | "5 min": "5 min", 7 | "Refresh": "Refresh" 8 | } 9 | -------------------------------------------------------------------------------- /src/components/AutoRefreshControl/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-diagnostics-autorefresh-control'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/CellWithPopover/CellWithPopover.scss: -------------------------------------------------------------------------------- 1 | .ydb-cell-with-popover { 2 | display: inline-flex; 3 | 4 | max-width: 100%; 5 | 6 | &_full-width { 7 | display: flex; 8 | } 9 | 10 | &__popover { 11 | display: inline-block; 12 | overflow: hidden; 13 | 14 | max-width: 100%; 15 | 16 | vertical-align: middle; 17 | white-space: nowrap; 18 | text-overflow: ellipsis; 19 | 20 | .g-popover__handler { 21 | display: inline; 22 | } 23 | 24 | &_full-width { 25 | width: 100%; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/components/ConfirmationDialog/ConfirmationDialog.scss: -------------------------------------------------------------------------------- 1 | .confirmation-dialog { 2 | &__message, 3 | &__caption { 4 | white-space: pre-wrap; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/components/ConfirmationDialog/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "action_cancel": "Cancel" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/ConfirmationDialog/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-confirmation-dialog'; 6 | 7 | export const confirmationDialogKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/ConnectToDB/ConnectToDB.scss: -------------------------------------------------------------------------------- 1 | .ydb-connect-to-db { 2 | &__dialog-tabs { 3 | margin-top: var(--g-spacing-4); 4 | } 5 | 6 | &__docs { 7 | margin-top: var(--g-spacing-4); 8 | } 9 | 10 | &__snippet-container { 11 | height: 270px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/ConnectToDB/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-connect-to-db'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/ConnectToDB/types.ts: -------------------------------------------------------------------------------- 1 | export type SnippetLanguage = 2 | | 'bash' 3 | | 'cpp' 4 | | 'csharp' 5 | | 'go' 6 | | 'java' 7 | | 'javascript' 8 | | 'php' 9 | | 'python'; 10 | 11 | export interface SnippetParams { 12 | database?: string; 13 | endpoint?: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/components/ConnectToDB/utils.ts: -------------------------------------------------------------------------------- 1 | // We have endpoint in format grpc://example.com:2139/?database=/root/test 2 | // We need it to be like grpc://example.com:2139 to make code in snippets work 3 | // We pass database to snippets as a separate param 4 | export function prepareEndpoint(connectionString = '') { 5 | try { 6 | const urlObj = new URL(connectionString); 7 | urlObj.search = ''; 8 | 9 | let endpoint = urlObj.toString(); 10 | 11 | // Remove trailing slash if present 12 | if (endpoint.endsWith('/')) { 13 | endpoint = endpoint.slice(0, -1); 14 | } 15 | 16 | return endpoint; 17 | } catch { 18 | return undefined; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/components/CopyLinkButton/CopyLinkButton.scss: -------------------------------------------------------------------------------- 1 | .ydb-copy-link-button { 2 | &__icon { 3 | // prevent button icon from firing onMouseEnter/onFocus through parent button's handler 4 | pointer-events: none; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/components/CopyLinkButton/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "description_copy": "Copy link to clipboard", 3 | "description_copied": "Copied to clipboard" 4 | } 5 | -------------------------------------------------------------------------------- /src/components/CopyLinkButton/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-copy-link-button'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/CriticalActionDialog/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "default-error": "Something went wrong, action cannot be completed", 3 | "no-rights-error": "You don't have enough rights to complete the operation", 4 | 5 | "button-confirm": "Confirm", 6 | "button-retry": "Retry", 7 | "button-cancel": "Cancel", 8 | "button-close": "Close", 9 | 10 | "checkbox-text": "I understand what I'm doing" 11 | } 12 | -------------------------------------------------------------------------------- /src/components/CriticalActionDialog/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-critical-action-dialog'; 6 | 7 | export const criticalActionDialogKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/CriticalActionDialog/utils.ts: -------------------------------------------------------------------------------- 1 | interface ErrorWithRetry { 2 | retryPossible: boolean; 3 | } 4 | 5 | export const isErrorWithRetry = (error: unknown): error is ErrorWithRetry => { 6 | return Boolean( 7 | error && typeof error === 'object' && 'retryPossible' in error && error.retryPossible, 8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /src/components/DateRange/DateRange.scss: -------------------------------------------------------------------------------- 1 | .date-range { 2 | &__range-input { 3 | &_s { 4 | width: 130px; 5 | } 6 | 7 | &_m { 8 | width: 300px; 9 | } 10 | 11 | &_l { 12 | width: 350px; 13 | } 14 | 15 | input { 16 | cursor: pointer; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/DateRange/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "date-format": "MM/DD/YYYY", 3 | "date-time-format": "MM/DD/YYYY HH:mm" 4 | } 5 | -------------------------------------------------------------------------------- /src/components/DateRange/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-date-range'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/components/DateRange/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "date-format": "DD.MM.YYYY", 3 | "date-time-format": "DD.MM.YYYY HH:mm" 4 | } 5 | -------------------------------------------------------------------------------- /src/components/DateRange/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DateRange'; 2 | -------------------------------------------------------------------------------- /src/components/DebouncedInput/DebouncedTextInput.tsx: -------------------------------------------------------------------------------- 1 | import type {TextInputProps} from '@gravity-ui/uikit'; 2 | import {TextInput} from '@gravity-ui/uikit'; 3 | 4 | import {useDebouncedValue} from '../../utils/hooks/useDebouncedValue'; 5 | 6 | interface DebouncedInputProps extends TextInputProps { 7 | debounce?: number; 8 | } 9 | 10 | export const DebouncedInput = ({ 11 | onUpdate, 12 | value = '', 13 | debounce = 200, 14 | ...rest 15 | }: DebouncedInputProps) => { 16 | const [currentValue, handleUpdate] = useDebouncedValue({value, onUpdate, debounce}); 17 | 18 | return ; 19 | }; 20 | -------------------------------------------------------------------------------- /src/components/DeveloperUILinkButton/DeveloperUILinkButton.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .developer-ui-link-button { 4 | @include mixins.table-hover-appearing-button(); 5 | } 6 | -------------------------------------------------------------------------------- /src/components/DeveloperUILinkButton/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "action_go-to": "Go to {{href}}" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/DeveloperUILinkButton/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-developer-ui-button'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/DiagnosticCard/DiagnosticCard.tsx: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | 3 | import './DiagnosticCard.scss'; 4 | 5 | const b = cn('ydb-diagnostic-card'); 6 | 7 | export interface DiagnosticCardProps { 8 | children?: React.ReactNode; 9 | className?: string; 10 | active?: boolean; 11 | size?: 'm' | 'l' | 's'; 12 | interactive?: boolean; 13 | } 14 | 15 | export function DiagnosticCard({ 16 | children, 17 | className, 18 | active, 19 | size = 'm', 20 | interactive = true, 21 | }: DiagnosticCardProps) { 22 | return
{children}
; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/Divider/Divider.scss: -------------------------------------------------------------------------------- 1 | .kv-divider { 2 | width: 1px; 3 | height: 100%; 4 | margin: 0 4px; 5 | 6 | background-color: var(--g-color-line-generic); 7 | } 8 | -------------------------------------------------------------------------------- /src/components/Divider/Divider.tsx: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | 3 | import './Divider.scss'; 4 | 5 | const b = cn('kv-divider'); 6 | 7 | function Divider() { 8 | return
; 9 | } 10 | 11 | export default Divider; 12 | -------------------------------------------------------------------------------- /src/components/Drawer/index.ts: -------------------------------------------------------------------------------- 1 | export {DrawerWrapper} from './Drawer'; 2 | export {useDrawerContext} from './DrawerContext'; 3 | export type {DrawerContextType} from './DrawerContext'; 4 | -------------------------------------------------------------------------------- /src/components/EmptyState/index.ts: -------------------------------------------------------------------------------- 1 | export * from './EmptyState'; 2 | -------------------------------------------------------------------------------- /src/components/EntitiesCount/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "of": "of" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/EntitiesCount/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-entities-count'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/components/EntitiesCount/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "of": "из" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/EntitiesCount/index.ts: -------------------------------------------------------------------------------- 1 | export * from './EntitiesCount'; 2 | -------------------------------------------------------------------------------- /src/components/EntityPageTitle/EntityPageTitle.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .ydb-entity-page-title { 4 | display: flex; 5 | flex-flow: row nowrap; 6 | align-items: baseline; 7 | 8 | text-wrap: nowrap; 9 | 10 | @include mixins.header-2-typography(); 11 | 12 | &__prefix { 13 | margin-right: 6px; 14 | 15 | color: var(--g-color-text-secondary); 16 | } 17 | 18 | &__icon { 19 | margin-right: 8px; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/EntityStatusNew/EntityStatus.scss: -------------------------------------------------------------------------------- 1 | .ydb-entity-status-new { 2 | .g-help-mark__button { 3 | color: inherit; 4 | } 5 | 6 | &_orange.g-label { 7 | color: var(--g-color-private-orange-500); 8 | background-color: var(--g-color-private-orange-100); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/EntityStatusNew/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "title_red": "Critical", 3 | "title_blue": "Normal", 4 | "title_green": "Good", 5 | "title_grey": "Unknown", 6 | "title_orange": "Caution", 7 | "title_yellow": "Warning", 8 | "context_red": "Some systems are failed and not available", 9 | "context_yellow": "There are minor issues", 10 | "context_orange": "Critical state, requires immediate attention", 11 | "context_green": "Everything is working as expected", 12 | "context_grey": "The condition cannot be determined", 13 | "context_blue": "All good, some parts of the system are restoring" 14 | } 15 | -------------------------------------------------------------------------------- /src/components/EntityStatusNew/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-entity-status'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/EntityStatusNew/utils.ts: -------------------------------------------------------------------------------- 1 | import {EFlag} from '../../types/api/enums'; 2 | 3 | import i18n from './i18n'; 4 | 5 | export const EFlagToDescription: Record = { 6 | get [EFlag.Red]() { 7 | return i18n('context_red'); 8 | }, 9 | get [EFlag.Yellow]() { 10 | return i18n('context_yellow'); 11 | }, 12 | get [EFlag.Orange]() { 13 | return i18n('context_orange'); 14 | }, 15 | get [EFlag.Green]() { 16 | return i18n('context_green'); 17 | }, 18 | get [EFlag.Grey]() { 19 | return i18n('context_grey'); 20 | }, 21 | get [EFlag.Blue]() { 22 | return i18n('context_blue'); 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /src/components/ErrorBoundary/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "error-title": "Oops! Something went wrong...", 3 | "error-description": "Something seems to be broken. Please contact support for help.", 4 | "send-qr-message": "Send QR code to the support", 5 | "stack-title": "Trace", 6 | 7 | "ui-version": "UI version", 8 | "backend-version": "Backend version", 9 | "error": "Error" 10 | } 11 | -------------------------------------------------------------------------------- /src/components/ErrorBoundary/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-error-boundary'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/Errors/403/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AccessDenied'; 2 | -------------------------------------------------------------------------------- /src/components/Errors/ResponseError/ResponseError.tsx: -------------------------------------------------------------------------------- 1 | import {prepareErrorMessage} from '../../../utils/prepareErrorMessage'; 2 | import i18n from '../i18n'; 3 | 4 | interface ResponseErrorProps { 5 | error?: unknown; 6 | className?: string; 7 | defaultMessage?: string; 8 | } 9 | 10 | export const ResponseError = ({ 11 | error, 12 | className, 13 | defaultMessage = i18n('responseError.defaultMessage'), 14 | }: ResponseErrorProps) => { 15 | const message = prepareErrorMessage(error) || defaultMessage; 16 | 17 | return
{message}
; 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/Errors/ResponseError/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ResponseError'; 2 | -------------------------------------------------------------------------------- /src/components/Errors/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "403.title": "Access denied", 3 | "403.description": "You don’t have the necessary roles to view this page.", 4 | "responseError.defaultMessage": "Response error", 5 | "error.title": "Error" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Errors/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-errors-access-denied'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/components/Errors/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "403.title": "Доступ запрещен", 3 | "403.description": "У вас недостаточно прав для просмотра данной страницы.", 4 | "responseError.defaultMessage": "Ошибка запроса", 5 | "error.title": "Ошибка" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/FormattedBytes/FormattedBytes.tsx: -------------------------------------------------------------------------------- 1 | import type {BytesSizes} from '../../utils/bytesParsers'; 2 | import {formatBytes} from '../../utils/bytesParsers'; 3 | import type {FormatValuesArgs} from '../../utils/dataFormatters/common'; 4 | 5 | type FormattedBytesProps = FormatValuesArgs; 6 | 7 | export const FormattedBytes = ({value, withSpeedLabel, ...params}: FormattedBytesProps) => { 8 | const formatted = formatBytes({value, withSpeedLabel, ...params}); 9 | const bytes = formatBytes({value, withSpeedLabel, size: 'b'}); 10 | 11 | return {formatted}; 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/FormattedBytes/utils.tsx: -------------------------------------------------------------------------------- 1 | import type {BytesSizes} from '../../utils/bytesParsers'; 2 | import type {FormatValuesArgs} from '../../utils/dataFormatters/common'; 3 | 4 | import {FormattedBytes} from './FormattedBytes'; 5 | 6 | export const toFormattedSize = ( 7 | value: number | string | undefined, 8 | params?: Omit, 'value'>, 9 | ) => { 10 | if (!value) { 11 | return null; 12 | } 13 | 14 | return ; 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/FullNodeViewer/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": "Database", 3 | "uptime": "Uptime", 4 | "version": "Version", 5 | "dc": "DC", 6 | "rack": "Rack", 7 | "links": "Links", 8 | 9 | "la-interval-1m": "1 min", 10 | "la-interval-5m": "5 min", 11 | "la-interval-15m": "15 min", 12 | 13 | "developer-ui": "Developer UI", 14 | "no-data": "No data", 15 | 16 | "title.common-info": "Common info", 17 | "title.endpoints": "Endpoints", 18 | "title.roles": "Roles", 19 | "title.pools": "Pools", 20 | "title.load-average": "Load average" 21 | } 22 | -------------------------------------------------------------------------------- /src/components/FullNodeViewer/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-node-info'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/HoverPopup/HoverPopup.scss: -------------------------------------------------------------------------------- 1 | .hover-popup { 2 | padding: var(--g-spacing-3); 3 | } 4 | -------------------------------------------------------------------------------- /src/components/Illustration/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Illustration'; 2 | -------------------------------------------------------------------------------- /src/components/InfoViewer/formatters/cdcStream.ts: -------------------------------------------------------------------------------- 1 | import type {TCdcStreamDescription} from '../../../types/api/schema'; 2 | import {createInfoFormatter} from '../utils'; 3 | 4 | export const formatCdcStreamItem = createInfoFormatter({ 5 | values: { 6 | Mode: (value) => value?.substring('ECdcStreamMode'.length), 7 | Format: (value) => value?.substring('ECdcStreamFormat'.length), 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /src/components/InfoViewer/formatters/common.ts: -------------------------------------------------------------------------------- 1 | import type {TDirEntry} from '../../../types/api/schema'; 2 | import {EMPTY_DATA_PLACEHOLDER} from '../../../utils/constants'; 3 | import {formatDateTime} from '../../../utils/dataFormatters/dataFormatters'; 4 | import i18n from '../i18n'; 5 | import {createInfoFormatter} from '../utils'; 6 | 7 | export const formatCommonItem = createInfoFormatter({ 8 | values: { 9 | PathType: (value) => value?.substring('EPathType'.length), 10 | CreateStep: (value) => formatDateTime(value, {defaultValue: EMPTY_DATA_PLACEHOLDER}), 11 | }, 12 | labels: { 13 | PathType: i18n('common.type'), 14 | CreateStep: i18n('common.created'), 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /src/components/InfoViewer/formatters/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './schema'; 3 | export * from './pqGroup'; 4 | export * from './cdcStream'; 5 | export * from './table'; 6 | -------------------------------------------------------------------------------- /src/components/InfoViewer/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "common.created": "Created", 3 | "common.type": "Type", 4 | "no-data": "No data" 5 | } 6 | -------------------------------------------------------------------------------- /src/components/InfoViewer/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-components-info-viewer'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/InfoViewer/index.ts: -------------------------------------------------------------------------------- 1 | import {InfoViewer} from './InfoViewer'; 2 | 3 | export {InfoViewer}; 4 | export * from './utils'; 5 | export type {InfoViewerItem} from './InfoViewer'; 6 | -------------------------------------------------------------------------------- /src/components/InfoViewer/schemaInfo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableIndexInfo'; 2 | -------------------------------------------------------------------------------- /src/components/InternalLink/InternalLink.tsx: -------------------------------------------------------------------------------- 1 | import type {LinkProps} from 'react-router-dom'; 2 | import {Link} from 'react-router-dom'; 3 | 4 | import {cn} from '../../utils/cn'; 5 | 6 | const bLink = cn('g-link'); 7 | 8 | interface InternalLinkProps extends Omit { 9 | to?: LinkProps['to']; 10 | } 11 | 12 | export const InternalLink = ({className, to, onClick, ...props}: InternalLinkProps) => 13 | to ? ( 14 | 15 | ) : ( 16 | 17 | {props.children} 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /src/components/InternalLink/index.ts: -------------------------------------------------------------------------------- 1 | export * from './InternalLink'; 2 | -------------------------------------------------------------------------------- /src/components/JsonViewer/constants.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | export const block = cn('ydb-json-viewer'); 3 | -------------------------------------------------------------------------------- /src/components/JsonViewer/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "action_collapse-all": "Collapse all", 3 | "action_expand-all": "Expand all", 4 | "action_next": "Next", 5 | "action_back": "Back", 6 | "description_search": "Search...", 7 | "description_matched-rows": "Matched rows", 8 | "description_full-value": "Full value", 9 | "context_case-sensitive-search": "Case sensitive search enadled", 10 | "context_case-sensitive-search-disabled": "Case sensitive search disabled", 11 | "context_items-count": [ 12 | " {{count}} item ", 13 | " {{count}} items ", 14 | " {{count}} items ", 15 | " {{count}} items " 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /src/components/JsonViewer/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-json-viewer'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/JsonViewer/utils.ts: -------------------------------------------------------------------------------- 1 | import type {ClassNameList, NoStrictEntityMods} from '@bem-react/classname'; 2 | 3 | import {block} from './constants'; 4 | 5 | export function getHightLightedClassName(mix?: ClassNameList) { 6 | return (mods?: NoStrictEntityMods) => block('filtered', mods, mix); 7 | } 8 | -------------------------------------------------------------------------------- /src/components/LabelWithPopover/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LabelWithPopover'; 2 | -------------------------------------------------------------------------------- /src/components/LagImages/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LagImages'; 2 | -------------------------------------------------------------------------------- /src/components/LagPopoverContent/LagPopoverContent.scss: -------------------------------------------------------------------------------- 1 | .ydb-lag-popover-content { 2 | &__text { 3 | margin-bottom: 10px; 4 | } 5 | 6 | &_type_read { 7 | max-width: 280px; 8 | } 9 | 10 | &_type_write { 11 | max-width: 220px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/LagPopoverContent/LagPopoverContent.tsx: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | import {ReadLagImage, WriteLagImage} from '../LagImages'; 3 | 4 | import './LagPopoverContent.scss'; 5 | 6 | const b = cn('ydb-lag-popover-content'); 7 | 8 | interface LagPopoverContentProps { 9 | text: string; 10 | type: 'read' | 'write'; 11 | } 12 | 13 | export const LagPopoverContent = ({text, type}: LagPopoverContentProps) => ( 14 |
15 |
{text}
16 |
{type === 'read' ? : }
17 |
18 | ); 19 | -------------------------------------------------------------------------------- /src/components/LagPopoverContent/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LagPopoverContent'; 2 | -------------------------------------------------------------------------------- /src/components/LinkWithIcon/LinkWithIcon.scss: -------------------------------------------------------------------------------- 1 | .ydb-link-with-icon { 2 | display: inline-flex; 3 | flex-wrap: nowrap; 4 | align-items: center; 5 | 6 | white-space: nowrap; 7 | } 8 | -------------------------------------------------------------------------------- /src/components/Loader/Loader.scss: -------------------------------------------------------------------------------- 1 | .ydb-loader { 2 | display: flex; 3 | flex: 1 1 auto; 4 | justify-content: center; 5 | align-items: center; 6 | 7 | height: 100%; 8 | } 9 | -------------------------------------------------------------------------------- /src/components/Loader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Loader'; 2 | -------------------------------------------------------------------------------- /src/components/LoaderWrapper/LoaderWrapper.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import type {LoaderSize} from '@gravity-ui/uikit'; 4 | 5 | import {Loader} from '../Loader/Loader'; 6 | 7 | interface LoaderWrapperProps { 8 | loading?: boolean; 9 | size?: LoaderSize; 10 | className?: string; 11 | children: React.ReactNode; 12 | } 13 | 14 | export function LoaderWrapper({loading, size = 'm', className, children}: LoaderWrapperProps) { 15 | if (loading) { 16 | return ; 17 | } 18 | return children; 19 | } 20 | -------------------------------------------------------------------------------- /src/components/LogsButton/LogsButton.tsx: -------------------------------------------------------------------------------- 1 | import {FileText} from '@gravity-ui/icons'; 2 | import type {ButtonSize} from '@gravity-ui/uikit'; 3 | import {Button, Icon} from '@gravity-ui/uikit'; 4 | 5 | interface LogsButtonProps { 6 | className?: string; 7 | href: string; 8 | size?: ButtonSize; 9 | } 10 | 11 | export function LogsButton({href, className, size = 'xs'}: LogsButtonProps) { 12 | return ( 13 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/components/MemoryViewer/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "text_external-consumption": "External Consumption", 3 | "text_allocator-caches": "Allocator Caches", 4 | "text_shared-cache": "Shared Cache", 5 | "text_memtable": "MemTable", 6 | "text_query-execution": "Query Execution", 7 | "text_usage": "Usage", 8 | "text_soft-limit": "Soft Limit", 9 | "text_hard-limit": "Hard Limit", 10 | "text_other": "Other" 11 | } 12 | -------------------------------------------------------------------------------- /src/components/MemoryViewer/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-memory-viewer'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/MetricChart/MetricChart.scss: -------------------------------------------------------------------------------- 1 | .ydb-metric-chart { 2 | display: flex; 3 | flex-direction: column; 4 | 5 | padding: 16px 16px 8px; 6 | 7 | border: 1px solid var(--g-color-line-generic); 8 | border-radius: 8px; 9 | 10 | &__title { 11 | margin-bottom: 10px; 12 | } 13 | 14 | &__chart { 15 | position: relative; 16 | 17 | display: flex; 18 | overflow: hidden; 19 | 20 | width: 100%; 21 | height: 100%; 22 | } 23 | 24 | &__error { 25 | position: absolute; 26 | z-index: 1; 27 | top: 10%; 28 | left: 50%; 29 | 30 | text-align: center; 31 | 32 | transform: translateX(-50%); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/components/MetricChart/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "not-supported": "Charts are not supported on current ydb version" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/MetricChart/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-metric-chart'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/MetricChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export {MetricChart} from './MetricChart'; 3 | -------------------------------------------------------------------------------- /src/components/MonacoEditor/MonacoEditor.tsx: -------------------------------------------------------------------------------- 1 | import {lazyComponent} from '../../utils/lazyComponent'; 2 | 3 | export const MonacoEditor = lazyComponent(async () => { 4 | const Editor = (await import('react-monaco-editor')).default; 5 | return {Editor}; 6 | }, 'Editor'); 7 | -------------------------------------------------------------------------------- /src/components/MultilineTableHeader/MultilineTableHeader.scss: -------------------------------------------------------------------------------- 1 | .ydb-multiline-table-header { 2 | white-space: normal; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/MultilineTableHeader/MultilineTableHeader.tsx: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | 3 | import './MultilineTableHeader.scss'; 4 | 5 | const b = cn('ydb-multiline-table-header'); 6 | 7 | interface MultilineTableHeaderProps { 8 | title?: string; 9 | } 10 | 11 | export function MultilineTableHeader({title}: MultilineTableHeaderProps) { 12 | if (!title) { 13 | return null; 14 | } 15 | return
{title}
; 16 | } 17 | -------------------------------------------------------------------------------- /src/components/PDiskInfo/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Type", 3 | "path": "Path", 4 | "guid": "GUID", 5 | "serial-number": "Serial Number", 6 | "shared-with-os": "SharedWithOs", 7 | 8 | "drive-status": "Drive Status", 9 | "state": "State", 10 | "device": "Device", 11 | "realtime": "Realtime", 12 | 13 | "space": "Space", 14 | "slots": "Slots", 15 | "log-size": "Log Size", 16 | "system-size": "System Size", 17 | 18 | "links": "Links", 19 | 20 | "developer-ui": "Developer UI", 21 | "pdisk-page": "PDisk page", 22 | 23 | "yes": "Yes" 24 | } 25 | -------------------------------------------------------------------------------- /src/components/PDiskInfo/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-pDisk-info'; 6 | 7 | export const pDiskInfoKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/PageMeta/PageMeta.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles//mixins.scss'; 2 | 3 | .ydb-page-meta { 4 | &__info { 5 | display: flex; 6 | flex-grow: 1; 7 | flex-flow: row nowrap; 8 | 9 | height: var(--g-text-body-2-line-height); 10 | 11 | text-wrap: nowrap; 12 | 13 | color: var(--g-color-text-primary); 14 | 15 | @include mixins.body-2-typography(); 16 | } 17 | 18 | &__skeleton { 19 | width: 80%; 20 | height: 80%; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/PaginatedTable/constants.ts: -------------------------------------------------------------------------------- 1 | export const LEFT = 'left'; 2 | export const CENTER = 'center'; 3 | export const RIGHT = 'right'; 4 | 5 | export const DEFAULT_ALIGN = LEFT; 6 | export const DEFAULT_RESIZEABLE = true; 7 | 8 | export const ASCENDING = 1; 9 | export const DESCENDING = -1; 10 | 11 | export const DEFAULT_SORT_ORDER = DESCENDING; 12 | 13 | // Time in ms after which request will be sent 14 | export const DEFAULT_REQUEST_TIMEOUT = 200; 15 | 16 | export const DEFAULT_TABLE_ROW_HEIGHT = 41; 17 | 18 | export const DEFAULT_INTERSECTION_OBSERVER_MARGIN = '100%'; 19 | -------------------------------------------------------------------------------- /src/components/PaginatedTable/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "empty": "No data" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/PaginatedTable/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-paginated-table'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/components/PaginatedTable/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "empty": "Нет данных" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/PaginatedTable/index.ts: -------------------------------------------------------------------------------- 1 | export * from './constants'; 2 | export * from './types'; 3 | export * from './PaginatedTable'; 4 | export * from './ResizeablePaginatedTable'; 5 | -------------------------------------------------------------------------------- /src/components/PaginatedTable/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | 3 | export const b = cn('ydb-paginated-table'); 4 | -------------------------------------------------------------------------------- /src/components/PoolsGraph/PoolsGraph.scss: -------------------------------------------------------------------------------- 1 | .ydb-pools-graph { 2 | display: flex; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/PoolsGraph/PoolsGraph.tsx: -------------------------------------------------------------------------------- 1 | import type {TPoolStats} from '../../types/api/nodes'; 2 | import {cn} from '../../utils/cn'; 3 | import {PoolBar} from '../PoolBar/PoolBar'; 4 | 5 | import './PoolsGraph.scss'; 6 | 7 | const b = cn('ydb-pools-graph'); 8 | 9 | interface PoolsGraphProps { 10 | pools?: TPoolStats[]; 11 | } 12 | 13 | export const PoolsGraph = ({pools = []}: PoolsGraphProps) => { 14 | return ( 15 |
16 | {pools.map((item, index) => ( 17 | 18 | ))} 19 |
20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /src/components/ProblemFilter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProblemFilter'; 2 | -------------------------------------------------------------------------------- /src/components/QueryExecutionStatus/QueryExecutionStatus.scss: -------------------------------------------------------------------------------- 1 | .kv-query-execution-status { 2 | display: flex; 3 | align-items: center; 4 | gap: 4px; 5 | } 6 | -------------------------------------------------------------------------------- /src/components/QueryExecutionStatus/index.ts: -------------------------------------------------------------------------------- 1 | export * from './QueryExecutionStatus'; 2 | -------------------------------------------------------------------------------- /src/components/QueryResultTable/Cell/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Cell'; 2 | -------------------------------------------------------------------------------- /src/components/QueryResultTable/QueryResultTable.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .ydb-query-result-table { 4 | &__cell { 5 | width: 100%; 6 | @include mixins.cell-container; 7 | } 8 | 9 | &__message { 10 | padding: 15px 10px; 11 | } 12 | 13 | // Must have fixed height for frequent data updates (to avoid interface shaking). 14 | // Will be fixed after migration to new @gravity-ui/table. 15 | &__table-wrapper { 16 | height: 0px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/QueryResultTable/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "empty": "Table is empty" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/QueryResultTable/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-query-result-table'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/components/QueryResultTable/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "empty": "Таблица пустая" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/QueryResultTable/index.ts: -------------------------------------------------------------------------------- 1 | export * from './QueryResultTable'; 2 | -------------------------------------------------------------------------------- /src/components/QuerySettingsDescription/QuerySettingsDescription.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-settings-description { 2 | &__message { 3 | display: flex; 4 | flex-wrap: wrap; 5 | 6 | white-space: pre; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/components/ResizeableDataTable/ResizeableDataTable.scss: -------------------------------------------------------------------------------- 1 | .ydb-resizeable-data-table { 2 | display: flex; 3 | 4 | width: max-content; 5 | 6 | // padding for easier resize of the last column 7 | padding-right: 20px; 8 | 9 | &__row-skeleton { 10 | width: 100%; 11 | height: 50%; 12 | } 13 | 14 | &__row-skeleton::after { 15 | animation: none !important; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Search/Search.scss: -------------------------------------------------------------------------------- 1 | .ydb-search { 2 | min-width: 100px; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/Search/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Search'; 2 | -------------------------------------------------------------------------------- /src/components/ShardsTable/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "tablet-id": "TabletId", 3 | "cpu-cores": "CPUCores", 4 | "data-size": "DataSize (B)", 5 | "path": "Path", 6 | "node-id": "NodeId", 7 | "peak-time": "PeakTime", 8 | "in-flight-tx-count": "InFlightTxCount", 9 | "interval-end": "IntervalEnd" 10 | } 11 | -------------------------------------------------------------------------------- /src/components/ShardsTable/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-shards-table'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/ShardsTable/types.ts: -------------------------------------------------------------------------------- 1 | import type {Column} from '@gravity-ui/react-data-table'; 2 | 3 | import type {KeyValueRow} from '../../types/api/query'; 4 | 5 | export type ShardsColumn = Column; 6 | 7 | export type GetShardsColumn = (params: {database: string; schemaPath?: string}) => ShardsColumn; 8 | -------------------------------------------------------------------------------- /src/components/ShardsTable/utils.ts: -------------------------------------------------------------------------------- 1 | import type {CellValue} from '../../types/api/query'; 2 | import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants'; 3 | import {formatDateTime} from '../../utils/dataFormatters/dataFormatters'; 4 | 5 | export function prepareDateTimeValue(value: CellValue) { 6 | if (!value) { 7 | return EMPTY_DATA_PLACEHOLDER; 8 | } 9 | return formatDateTime(new Date(value).getTime()); 10 | } 11 | -------------------------------------------------------------------------------- /src/components/ShortyString/ShortyString.scss: -------------------------------------------------------------------------------- 1 | .kv-shorty-string { 2 | &__toggle { 3 | margin-left: 1em; 4 | 5 | font-size: 0.85em; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/components/ShortyString/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "default_collapse_label": "Show less", 3 | "default_expand_label": "Show more", 4 | "chars_count": [ 5 | " ({{count}} symbol)", 6 | " ({{count}} symbols)", 7 | " ({{count}} symbols)", 8 | " ({{count}} symbols)" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/components/ShortyString/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-shorty-string'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/components/ShortyString/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "default_collapse_label": "Показать меньше", 3 | "default_expand_label": "Показать ещё", 4 | "chars_count": [ 5 | " ({{count}} символ)", 6 | " ({{count}} символа)", 7 | " ({{count}} символов)", 8 | " ({{count}} символов)" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Skeleton/Skeleton.tsx: -------------------------------------------------------------------------------- 1 | import {Skeleton as KitSkeleton} from '@gravity-ui/uikit'; 2 | 3 | import {useDelayed} from '../../utils/hooks/useDelayed'; 4 | 5 | interface SkeletonProps { 6 | delay?: number; 7 | className?: string; 8 | } 9 | 10 | export const Skeleton = ({delay = 600, className}: SkeletonProps) => { 11 | const [show] = useDelayed(delay); 12 | if (!show) { 13 | return null; 14 | } 15 | return ; 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/SpeedMultiMeter/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "averageSpeed": "Average speed", 3 | "perMinute": "per minute", 4 | "perHour": "per hour", 5 | "perDay": "per day" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/SpeedMultiMeter/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-components-speed-multimeter'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/components/SpeedMultiMeter/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "averageSpeed": "Средняя скорость", 3 | "perMinute": "за минуту", 4 | "perHour": "за час", 5 | "perDay": "за день" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/SpeedMultiMeter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SpeedMultiMeter'; 2 | -------------------------------------------------------------------------------- /src/components/SplitPane/index.ts: -------------------------------------------------------------------------------- 1 | import SplitPane from './SplitPane'; 2 | 3 | export default SplitPane; 4 | -------------------------------------------------------------------------------- /src/components/StorageGroupInfo/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'storage-group-info'; 6 | 7 | export const storageGroupInfoKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/SyntaxHighlighter/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "copy": "Copy" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/SyntaxHighlighter/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-syntax-highlighter'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/SyntaxHighlighter/lazy.ts: -------------------------------------------------------------------------------- 1 | import {lazyComponent} from '../../utils/lazyComponent'; 2 | 3 | export const YDBSyntaxHighlighterLazy = lazyComponent( 4 | () => import('./YDBSyntaxHighlighter'), 5 | 'YDBSyntaxHighlighter', 6 | ); 7 | -------------------------------------------------------------------------------- /src/components/SyntaxHighlighter/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | 3 | export const b = cn('ydb-syntax-highlighter'); 4 | -------------------------------------------------------------------------------- /src/components/SyntaxHighlighter/types.ts: -------------------------------------------------------------------------------- 1 | export type Language = 2 | | 'bash' 3 | | 'cpp' 4 | | 'csharp' 5 | | 'go' 6 | | 'java' 7 | | 'javascript' 8 | | 'php' 9 | | 'python' 10 | | 'yql'; 11 | -------------------------------------------------------------------------------- /src/components/TabletIcon/TabletIcon.scss: -------------------------------------------------------------------------------- 1 | .tablet-icon { 2 | display: flex; 3 | justify-content: center; 4 | 5 | width: 23px; 6 | height: 16px; 7 | 8 | font-size: 10px; 9 | text-transform: uppercase; 10 | 11 | border: 1px solid; 12 | border-radius: 4px; 13 | 14 | &__type { 15 | line-height: 14px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/TabletIcon/TabletIcon.tsx: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | 3 | import './TabletIcon.scss'; 4 | 5 | interface TabletIconProps { 6 | text?: string; 7 | className?: string; 8 | } 9 | 10 | const b = cn('tablet-icon'); 11 | 12 | export const TabletIcon = ({text, className}: TabletIconProps) => { 13 | return ( 14 |
15 |
{text || 'T'}
16 |
17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/TabletNameWrapper/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "field_links": "Links", 3 | "context_developer-ui": "Developer UI" 4 | } 5 | -------------------------------------------------------------------------------- /src/components/TabletNameWrapper/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-tablet-name-wrapper'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/TabletState/TabletState.tsx: -------------------------------------------------------------------------------- 1 | import {Label} from '@gravity-ui/uikit'; 2 | 3 | import type {ETabletState} from '../../types/api/tablet'; 4 | import {mapTabletStateToLabelTheme} from '../../utils/tablet'; 5 | 6 | interface TabletStateProps { 7 | state?: ETabletState; 8 | } 9 | 10 | export function TabletState({state}: TabletStateProps) { 11 | return ; 12 | } 13 | -------------------------------------------------------------------------------- /src/components/TabletsStatistic/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TabletsStatistic'; 2 | -------------------------------------------------------------------------------- /src/components/Tags/Tags.scss: -------------------------------------------------------------------------------- 1 | .tags { 2 | display: flex; 3 | flex-wrap: wrap; 4 | align-items: center; 5 | } 6 | -------------------------------------------------------------------------------- /src/components/Tags/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Tags'; 2 | -------------------------------------------------------------------------------- /src/components/TenantNameWrapper/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "field_links": "Links", 3 | "field_monitoring-link": "Monitoring", 4 | "field_logs-link": "Logs", 5 | "context_unknown": "unknown database" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/TenantNameWrapper/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-tenant-name-wrapper'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/TimeFrameSelector/TimeFrameSelector.scss: -------------------------------------------------------------------------------- 1 | .ydb-timeframe-selector { 2 | display: flex; 3 | gap: 2px; 4 | } 5 | -------------------------------------------------------------------------------- /src/components/TooltipsContent/NodeEndpointsTooltipContent/NodeEndpointsTooltipContent.scss: -------------------------------------------------------------------------------- 1 | .ydb-node-endpoints-tooltip-content { 2 | .info-viewer__value { 3 | min-width: 70px; 4 | } 5 | &__list-container { 6 | padding-right: 20px; 7 | } 8 | &__definition { 9 | text-align: right; 10 | word-break: break-word; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/TooltipsContent/NodeEndpointsTooltipContent/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "field_rack": "Rack", 3 | "field_host": "Host", 4 | "context_developer-ui": "Developer UI", 5 | "field_database": "Database", 6 | "field_roles": "Roles" 7 | } 8 | -------------------------------------------------------------------------------- /src/components/TooltipsContent/NodeEndpointsTooltipContent/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-node-name-tooltip'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/TooltipsContent/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NodeEndpointsTooltipContent/NodeEndpointsTooltipContent'; 2 | export * from './TabletTooltipContent/TabletTooltipContent'; 3 | export * from './PoolTooltipContent/PoolTooltipContent'; 4 | -------------------------------------------------------------------------------- /src/components/TruncatedQuery/TruncatedQuery.scss: -------------------------------------------------------------------------------- 1 | .kv-truncated-query { 2 | max-width: 100%; 3 | 4 | vertical-align: top; 5 | white-space: pre; 6 | word-break: break-word; 7 | 8 | &__message { 9 | white-space: pre-wrap; 10 | 11 | &_color { 12 | &_secondary { 13 | color: var(--g-color-text-secondary); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/UptimeFIlter/index.ts: -------------------------------------------------------------------------------- 1 | export * from './UptimeFilter'; 2 | -------------------------------------------------------------------------------- /src/components/UptimeViewer/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "start-time": "Start time", 3 | "disconnect-time": "Disconnect time", 4 | "change-time": "Change time" 5 | } 6 | -------------------------------------------------------------------------------- /src/components/UptimeViewer/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-uptime-viewer'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/UsageLabel/UsageLabel.scss: -------------------------------------------------------------------------------- 1 | .ydb-usage-label { 2 | &_overload { 3 | color: var(--g-color-text-light-primary); 4 | background-color: var(--ydb-color-status-red); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/components/User/StaffCard.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export interface StaffCardProps { 4 | login: string; 5 | children: React.ReactNode & { 6 | ref?: React.Ref; 7 | }; 8 | } 9 | 10 | export function StaffCard({children}: StaffCardProps) { 11 | return {children}; 12 | } 13 | -------------------------------------------------------------------------------- /src/components/User/User.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .kv-user { 4 | display: inline-block; 5 | 6 | color: var(--g-color-text-primary); 7 | @include mixins.body-2-typography(); 8 | 9 | &__name { 10 | display: inline-block; 11 | 12 | &::first-letter { 13 | color: var(--g-color-text-danger); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/User/User.tsx: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | import {useComponent} from '../ComponentsProvider/ComponentsProvider'; 3 | 4 | import './User.scss'; 5 | 6 | const b = cn('kv-user'); 7 | 8 | interface UserProps { 9 | className?: string; 10 | login: string; 11 | } 12 | export function UserCard({login, className}: UserProps) { 13 | const StaffCard = useComponent('StaffCard'); 14 | 15 | return ( 16 |
17 | 18 |
{login}
19 |
20 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/components/VDisk/VDisk.scss: -------------------------------------------------------------------------------- 1 | .ydb-vdisk-component { 2 | border-radius: 4px; // to match interactive area with disk shape 3 | 4 | &__content { 5 | display: block; 6 | 7 | border-radius: 4px; // to match interactive area with disk shape 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/components/VDiskInfo/VDiskInfo.scss: -------------------------------------------------------------------------------- 1 | .ydb-vdisk-info { 2 | &__title { 3 | display: flex; 4 | flex-direction: row; 5 | gap: var(--g-spacing-2); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/components/VDiskInfo/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-vDisk-info'; 6 | 7 | export const vDiskInfoKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/VDiskPopup/VDiskPopup.scss: -------------------------------------------------------------------------------- 1 | .vdisk-storage-popup { 2 | .info-viewer + .info-viewer { 3 | margin-top: 8px; 4 | padding-top: 8px; 5 | 6 | border-top: 1px solid var(--g-color-line-generic); 7 | } 8 | 9 | &__donor-label { 10 | margin-bottom: 8px; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/YDBDefinitionList/YDBDefinitionList.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .ydb-definition-list { 4 | @include mixins.flex-container(); 5 | 6 | &__title { 7 | @include mixins.info-viewer-title(); 8 | } 9 | 10 | &__properties-list { 11 | max-width: calc(100% - 40px); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/YDBDefinitionList/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "no-data": "No data" 3 | } 4 | -------------------------------------------------------------------------------- /src/components/YDBDefinitionList/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-definition-list'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/nodesColumns/NodesColumns.scss: -------------------------------------------------------------------------------- 1 | .ydb-nodes-columns { 2 | &__column-ram, 3 | &__column-cpu { 4 | min-width: 40px; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/components/nodesColumns/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-nodes-columns'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/components/nodesColumns/types.ts: -------------------------------------------------------------------------------- 1 | import type {GetNodeRefFunc} from '../../types/additionalProps'; 2 | 3 | export interface GetNodesColumnsParams { 4 | getNodeRef?: GetNodeRefFunc; 5 | database?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/nodesColumns/utils.ts: -------------------------------------------------------------------------------- 1 | import {formatToMs, parseUsToMs} from '../../utils/timeParsers'; 2 | 3 | export function preparePingTimeValue(value: string | number) { 4 | return formatToMs(parseUsToMs(value, 1)); 5 | } 6 | 7 | export function prepareClockSkewValue(value: string | number) { 8 | const valueMs = parseUsToMs(value, 1); 9 | // Add + sign to positive values, do not add + to values that displayed as 0 10 | const sign = Number(valueMs) <= 0 ? '' : '+'; 11 | 12 | return sign + formatToMs(valueMs); 13 | } 14 | -------------------------------------------------------------------------------- /src/components/slots/createSlot.ts: -------------------------------------------------------------------------------- 1 | import type {SlotComponent} from './types'; 2 | 3 | export function createSlot(name = 'unknown') { 4 | const Slot: SlotComponent = () => null; 5 | 6 | Slot.displayName = `Slot(${name})`; 7 | Slot.__slotName = name; 8 | 9 | return Slot; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/slots/index.ts: -------------------------------------------------------------------------------- 1 | export {createSlot} from './createSlot'; 2 | export {useSlots} from './useSlots'; 3 | -------------------------------------------------------------------------------- /src/components/slots/types.ts: -------------------------------------------------------------------------------- 1 | export interface SlotComponent 2 | extends React.FC}> { 3 | /** 4 | * @internal 5 | */ 6 | __slotName: string; 7 | } 8 | 9 | export interface SlotItem { 10 | name: string; 11 | props: Props; 12 | ref?: React.Ref; 13 | rendered: ExtractChildrenType; 14 | } 15 | 16 | type ExtractChildrenType = Props extends {children: infer Children} 17 | ? Children 18 | : Props extends {children?: infer Children} 19 | ? Children | undefined 20 | : never; 21 | -------------------------------------------------------------------------------- /src/components/slots/useSlots.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import {SlotMap} from './SlotMap'; 4 | 5 | export interface UseSlotsProps { 6 | children?: React.ReactNode; 7 | } 8 | 9 | export function useSlots(props: UseSlotsProps) { 10 | const {children} = props; 11 | 12 | const slots = React.useMemo(() => { 13 | return new SlotMap(children); 14 | }, [children]); 15 | 16 | return slots; 17 | } 18 | -------------------------------------------------------------------------------- /src/components/slots/utils.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import type {SlotComponent} from './types'; 4 | 5 | export function isSlotElement

( 6 | node: React.ReactNode, 7 | ): node is React.ReactElement> & {ref?: React.Ref} { 8 | return React.isValidElement(node) && isSlotComponent(node.type); 9 | } 10 | 11 | export function isSlotComponent( 12 | type: string | React.JSXElementConstructor, 13 | ): type is SlotComponent { 14 | return typeof type === 'function' && '__slotName' in type; 15 | } 16 | -------------------------------------------------------------------------------- /src/containers/App/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages.clusters": "All clusters" 3 | } 4 | -------------------------------------------------------------------------------- /src/containers/App/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-app-content'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/App/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages.clusters": "Все кластеры" 3 | } 4 | -------------------------------------------------------------------------------- /src/containers/App/index.ts: -------------------------------------------------------------------------------- 1 | export {default as App} from './App'; 2 | 3 | export * as AppSlots from './appSlots'; 4 | -------------------------------------------------------------------------------- /src/containers/AppWithClusters/ExtendedCluster/ExtendedCluster.scss: -------------------------------------------------------------------------------- 1 | .extended-cluster { 2 | display: flex; 3 | 4 | height: 100%; 5 | 6 | &__balancer { 7 | display: flex; 8 | flex-direction: row; 9 | align-items: center; 10 | } 11 | &__clipboard-button { 12 | margin-left: 5px; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/containers/AsideNavigation/AsideNavigation.scss: -------------------------------------------------------------------------------- 1 | .kv-navigation { 2 | &__internal-user { 3 | display: flex; 4 | justify-content: space-between; 5 | align-items: center; 6 | 7 | margin-left: 16px; 8 | 9 | line-height: var(--g-text-body-2-line-height); 10 | } 11 | &__user-info-wrapper { 12 | display: flex; 13 | flex-direction: column; 14 | } 15 | &__ydb-internal-user-title { 16 | font-weight: 500; 17 | } 18 | &__ydb-user-wrapper { 19 | width: 300px; 20 | padding: 10px; 21 | } 22 | 23 | &__hotkeys-panel-title { 24 | display: flex; 25 | gap: var(--g-spacing-2); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/containers/AsideNavigation/InformationPopup/index.ts: -------------------------------------------------------------------------------- 1 | export {InformationPopup} from './InformationPopup'; 2 | -------------------------------------------------------------------------------- /src/containers/AsideNavigation/InformationPopup/types.ts: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | 3 | export interface FooterItem { 4 | id: string; 5 | text: string; 6 | url?: string; 7 | rightContent?: React.ReactNode; 8 | onClick?: () => void; 9 | icon?: React.ReactNode; 10 | disableClickHandler?: boolean; 11 | } 12 | 13 | export type FooterItemsArray = FooterItem[]; 14 | -------------------------------------------------------------------------------- /src/containers/AsideNavigation/YdbInternalUser/YdbInternalUser.scss: -------------------------------------------------------------------------------- 1 | .kv-ydb-internal-user { 2 | display: flex; 3 | flex-grow: 1; 4 | justify-content: space-between; 5 | align-items: center; 6 | 7 | margin-left: 16px; 8 | 9 | line-height: var(--g-text-body-2-line-height); 10 | 11 | &__user-info-wrapper { 12 | display: flex; 13 | flex-direction: column; 14 | } 15 | 16 | &__ydb-internal-user-title { 17 | font-weight: 500; 18 | } 19 | 20 | &__ydb-user-wrapper { 21 | width: 300px; 22 | padding: 10px; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/containers/AsideNavigation/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-aside-navigation'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Cluster/ClusterInfo/ClusterInfo.scss: -------------------------------------------------------------------------------- 1 | @use '../../../styles/mixins'; 2 | 3 | .cluster-info { 4 | --g-definition-list-item-gap: var(--g-spacing-3); 5 | padding: var(--g-spacing-4) 0 var(--g-spacing-2); 6 | 7 | @include mixins.body-2-typography(); 8 | 9 | &__skeleton { 10 | margin-top: 5px; 11 | } 12 | 13 | &__dc { 14 | height: 20px; 15 | } 16 | 17 | &__clipboard-button { 18 | display: flex; 19 | align-items: center; 20 | 21 | margin-left: 5px; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/containers/Cluster/ClusterInfo/components/DiskGroupsStatsBars/DiskGroupsStats.scss: -------------------------------------------------------------------------------- 1 | @use '../../../../../styles/mixins.scss'; 2 | 3 | .ydb-disk-groups-stats { 4 | --g-definition-list-item-gap: var(--g-spacing-3); 5 | 6 | width: 287px; 7 | padding: var(--g-spacing-3) var(--g-spacing-4); 8 | 9 | border-radius: var(--g-border-radius-s); 10 | background-color: var(--g-color-base-generic-ultralight); 11 | 12 | @include mixins.body-2-typography(); 13 | 14 | &__progress { 15 | display: inline-block; 16 | 17 | width: 60px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/Cluster/ClusterInfo/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../utils/cn'; 2 | 3 | export const b = cn('cluster-info'); 4 | -------------------------------------------------------------------------------- /src/containers/Cluster/ClusterOverview/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../utils/cn'; 2 | export const b = cn('ydb-cluster-dashboard'); 3 | 4 | export interface ClusterMetricsBaseProps { 5 | colorizeProgress?: boolean; 6 | inverseColorize?: boolean; 7 | warningThreshold?: number; 8 | dangerThreshold?: number; 9 | collapsed?: boolean; 10 | } 11 | 12 | export interface ClusterMetricsCommonProps extends ClusterMetricsBaseProps { 13 | value: number | string; 14 | capacity: number | string; 15 | } 16 | -------------------------------------------------------------------------------- /src/containers/Cluster/VersionsBar/VersionsBar.scss: -------------------------------------------------------------------------------- 1 | .ydb-cluster-versions-bar { 2 | display: flex; 3 | flex-direction: column; 4 | 5 | min-width: 600px; 6 | 7 | & .g-progress { 8 | width: 100%; 9 | } 10 | 11 | &__versions { 12 | display: flex; 13 | flex-flow: row wrap; 14 | 15 | margin-top: 6px; 16 | } 17 | 18 | &__version-title { 19 | margin-left: 3px; 20 | 21 | white-space: nowrap; 22 | } 23 | 24 | & .g-progress__stack { 25 | cursor: pointer; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/containers/Cluster/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-cluster'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/ClusterModeGuard/ClusterModeGuard.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import {useTypedSelector} from '../../utils/hooks'; 4 | 5 | export interface ClusterModeGuardProps { 6 | children: React.ReactNode; 7 | mode: 'single' | 'multi'; 8 | } 9 | 10 | export function ClusterModeGuard({children, mode}: ClusterModeGuardProps) { 11 | const shouldRender = useTypedSelector((state) => 12 | mode === 'single' ? state.singleClusterMode : !state.singleClusterMode, 13 | ); 14 | 15 | return shouldRender ? {children} : null; 16 | } 17 | -------------------------------------------------------------------------------- /src/containers/Clusters/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "controls_status-select-label": "Status:", 3 | "controls_service-select-label": "Service:", 4 | "controls_version-select-label": "Version:", 5 | 6 | "controls_search-placeholder": "Cluster name, version, host", 7 | "controls_select-placeholder": "All", 8 | 9 | "statistics_clusters": "Clusters", 10 | "statistics_hosts": "Hosts", 11 | "statistics_tenants": "Tenants", 12 | "statistics_nodes": "Nodes", 13 | "statistics_load": "Load", 14 | "statistics_storage": "Storage", 15 | 16 | "tooltip_no-cluster-data": "No cluster data", 17 | 18 | "page_title": "Clusters" 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/Clusters/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-clusters-page'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/Clusters/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "controls_status-select-label": "Статус:", 3 | "controls_service-select-label": "Сервис:", 4 | "controls_version-select-label": "Версия:", 5 | 6 | "controls_search-placeholder": "Имя кластера, версия или хост", 7 | "controls_select-placeholder": "Все", 8 | 9 | "statistics_clusters": "Кластеры", 10 | "statistics_hosts": "Хосты", 11 | "statistics_tenants": "Базы данных", 12 | "statistics_nodes": "Узлы", 13 | "statistics_load": "Нагрузка", 14 | "statistics_storage": "Хранилище", 15 | 16 | "tooltip_no-cluster-data": "Нет данных кластера", 17 | 18 | "page_title": "Кластеры" 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/Clusters/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | 3 | export const b = cn('clusters'); 4 | -------------------------------------------------------------------------------- /src/containers/Header/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "breadcrumbs.tenant": "Tenant", 3 | "breadcrumbs.node": "Node", 4 | "breadcrumbs.pDisk": "PDisk", 5 | "breadcrumbs.vDisk": "VDisk", 6 | "breadcrumbs.tablet": "Tablet", 7 | "breadcrumbs.tablets": "Tablets", 8 | "breadcrumbs.storageGroup": "Storage Group", 9 | 10 | "connect": "Connect" 11 | } 12 | -------------------------------------------------------------------------------- /src/containers/Header/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-header'; 6 | 7 | export const headerKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Heatmap/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Heatmap'; 2 | -------------------------------------------------------------------------------- /src/containers/Node/Node.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins'; 2 | 3 | .node { 4 | position: relative; 5 | 6 | overflow: auto; 7 | 8 | height: 100%; 9 | padding: 0 20px; 10 | 11 | &__meta, 12 | &__title, 13 | &__info, 14 | &__error, 15 | &__tabs { 16 | position: sticky; 17 | left: 0; 18 | 19 | margin-bottom: 20px; 20 | } 21 | 22 | &__meta { 23 | margin-top: 20px; 24 | } 25 | 26 | &__tabs, 27 | &__error { 28 | margin-bottom: 0; 29 | } 30 | 31 | &__tabs { 32 | @include mixins.tabs-wrapper-styles(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/containers/Node/NodeStructure/PDiskTitleBadge.tsx: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../utils/cn'; 2 | 3 | const b = cn('kv-node-structure'); 4 | 5 | interface PDiskTitleBadgeProps { 6 | label?: string; 7 | value: React.ReactNode; 8 | className?: string; 9 | } 10 | 11 | export function PDiskTitleBadge({label, value, className}: PDiskTitleBadgeProps) { 12 | return ( 13 | 14 | {label && {label}:} 15 | {value} 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/containers/Node/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "pdisk.developer-ui-button-title": "PDisk Developer UI page", 3 | "vdisk.developer-ui-button-title": "VDisk Developer UI page", 4 | 5 | "tabs.storage": "Storage", 6 | "tabs.structure": "Structure", 7 | "tabs.tablets": "Tablets", 8 | 9 | "node": "Node", 10 | "fqdn": "FQDN", 11 | "dc": "DC" 12 | } 13 | -------------------------------------------------------------------------------- /src/containers/Node/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-node-page'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Nodes/Nodes.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .ydb-nodes { 4 | &__search { 5 | @include mixins.search(); 6 | } 7 | 8 | &__show-all-wrapper { 9 | position: sticky; 10 | left: 0; 11 | 12 | margin-bottom: 15px; 13 | } 14 | 15 | &__node_unavailable { 16 | opacity: 0.6; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/containers/Nodes/PaginatedNodes/index.ts: -------------------------------------------------------------------------------- 1 | export {PaginatedNodes} from './PaginatedNodes'; 2 | -------------------------------------------------------------------------------- /src/containers/Nodes/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": "Nodes", 3 | 4 | "empty.default": "No such nodes", 5 | 6 | "no-nodes-groups": "No nodes groups", 7 | 8 | "controls_search-placeholder": "Host name", 9 | "controls_group-by-placeholder": "Group by:", 10 | 11 | "controls_peer-role-label": "Peer role:", 12 | 13 | "database": "database", 14 | "static": "static", 15 | "other": "other", 16 | "any": "any" 17 | } 18 | -------------------------------------------------------------------------------- /src/containers/Nodes/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-nodes'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Nodes/shared.tsx: -------------------------------------------------------------------------------- 1 | import type {GetRowClassName} from '../../components/PaginatedTable'; 2 | import type {NodesPreparedEntity} from '../../store/reducers/nodes/types'; 3 | import {cn} from '../../utils/cn'; 4 | import {isUnavailableNode} from '../../utils/nodes'; 5 | 6 | export const b = cn('ydb-nodes'); 7 | 8 | export const getRowClassName: GetRowClassName = (row) => { 9 | return b('node', {unavailable: isUnavailableNode(row)}); 10 | }; 11 | -------------------------------------------------------------------------------- /src/containers/Operations/Operations.scss: -------------------------------------------------------------------------------- 1 | .operations { 2 | &__search { 3 | width: 220px; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Operations/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-operations'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Operations/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Operations'; 2 | -------------------------------------------------------------------------------- /src/containers/Operations/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | 3 | export const b = cn('operations'); 4 | -------------------------------------------------------------------------------- /src/containers/PDiskPage/DecommissionButton/DecommissionButton.scss: -------------------------------------------------------------------------------- 1 | .ydb-pdisk-decommission-button { 2 | &__button, 3 | &__popup { 4 | width: 160px; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/PDiskPage/PDiskSpaceDistribution/utils.ts: -------------------------------------------------------------------------------- 1 | import type {SlotItem, SlotItemType} from '../../../store/reducers/pdisk/types'; 2 | 3 | export function isVDiskSlot(slot: SlotItem): slot is SlotItem<'vDisk'> { 4 | return slot.SlotType === 'vDisk'; 5 | } 6 | 7 | export function isLogSlot(slot: SlotItem): slot is SlotItem<'log'> { 8 | return slot.SlotType === 'log'; 9 | } 10 | 11 | export function isEmptySlot(slot: SlotItem): slot is SlotItem<'empty'> { 12 | return slot.SlotType === 'empty'; 13 | } 14 | -------------------------------------------------------------------------------- /src/containers/PDiskPage/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-pDisk-page'; 6 | 7 | export const pDiskPageKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/ReduxTooltip/ReduxTooltip.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .popup2 { 4 | max-width: 300px; 5 | 6 | animation: none !important; 7 | } 8 | 9 | .node-tootltip, 10 | .histogram-tooltip { 11 | padding: 10px; 12 | 13 | &__label { 14 | padding-right: 15px; 15 | 16 | color: var(--g-color-text-secondary); 17 | } 18 | } 19 | 20 | .cell-tooltip { 21 | padding: 10px; 22 | 23 | word-break: break-word; 24 | } 25 | -------------------------------------------------------------------------------- /src/containers/Storage/EmptyFilter/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "default_message": "Everything is fine!", 3 | "default_button_label": "Show All" 4 | } 5 | -------------------------------------------------------------------------------- /src/containers/Storage/EmptyFilter/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-storage-empty-filter'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/Storage/EmptyFilter/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "default_message": "Всё в порядке!", 3 | "default_button_label": "Показать все" 4 | } 5 | -------------------------------------------------------------------------------- /src/containers/Storage/PDisk/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PDisk'; 2 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageGroups/index.ts: -------------------------------------------------------------------------------- 1 | export {PaginatedStorageGroups} from './PaginatedStorageGroups'; 2 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageGroupsTable/columns/StorageGroupsColumns.scss: -------------------------------------------------------------------------------- 1 | @use '../../../../styles/mixins.scss'; 2 | 3 | .ydb-storage-groups-columns { 4 | &__vdisks-column, 5 | &__disks-column { 6 | overflow: visible; // to enable stacked disks overflow the row 7 | } 8 | 9 | &__pool-name-wrapper { 10 | overflow: hidden; 11 | 12 | white-space: nowrap; 13 | text-overflow: ellipsis; 14 | direction: rtl; 15 | } 16 | 17 | &__pool-name { 18 | unicode-bidi: plaintext; 19 | } 20 | 21 | &__group-id { 22 | margin-right: var(--g-spacing-1); 23 | 24 | font-weight: 500; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageGroupsTable/columns/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "pool-name": "Pool Name", 3 | "type": "Type", 4 | "encryption": "Encryption", 5 | "erasure": "Erasure", 6 | "degraded": "Degraded", 7 | "missing-disks": "Missing Disks", 8 | "state": "State", 9 | "usage": "Usage", 10 | "disk-usage": "Disk usage", 11 | "group-id": "Group ID", 12 | "used": "Used", 13 | "limit": "Limit", 14 | "space": "Space", 15 | "read": "Read", 16 | "write": "Write", 17 | "latency": "Latency", 18 | "allocation-units": "Allocation Units", 19 | "vdisks": "VDisks", 20 | "vdisks-pdisks": "VDisks with PDisks" 21 | } 22 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageGroupsTable/columns/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-storage-groups-columns'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageGroupsTable/columns/types.ts: -------------------------------------------------------------------------------- 1 | import type {PreparedStorageGroup, VisibleEntities} from '../../../../store/reducers/storage/types'; 2 | import type {Column} from '../../../../utils/tableUtils/types'; 3 | import type {StorageViewContext} from '../../types'; 4 | 5 | export type StorageGroupsColumn = Column; 6 | 7 | export interface GetStorageColumnsData { 8 | viewContext?: StorageViewContext; 9 | } 10 | 11 | export interface GetStorageGroupsColumnsParams { 12 | visibleEntities?: VisibleEntities; 13 | viewContext?: StorageViewContext; 14 | } 15 | 16 | export type StorageColumnsGetter = (data?: GetStorageColumnsData) => StorageGroupsColumn[]; 17 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageGroupsTable/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "empty.default": "No such groups", 3 | "empty.out_of_space": "No groups with out of space errors", 4 | "empty.degraded": "No degraded groups", 5 | "show_all": "Show all groups", 6 | "encrypted": "Encrypted group" 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageGroupsTable/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-storage-groups'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageGroupsTable/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "empty.default": "Нет групп", 3 | "empty.out_of_space": "Нет групп, в которых кончается место", 4 | "empty.degraded": "Нет деградировавших групп", 5 | "show_all": "Показать все группы", 6 | "encrypted": "Зашифрованная группа" 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageGroupsTable/index.tsx: -------------------------------------------------------------------------------- 1 | export {PaginatedStorageGroupsTable} from './PaginatedStorageGroupsTable'; 2 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageNodes/index.ts: -------------------------------------------------------------------------------- 1 | export {PaginatedStorageNodes} from './PaginatedStorageNodes'; 2 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageNodesTable/StorageNodes.scss: -------------------------------------------------------------------------------- 1 | .ydb-storage-nodes { 2 | &__node_unavailable { 3 | opacity: 0.6; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageNodesTable/columns/StorageNodesColumns.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../styles/mixins.scss'; 2 | 3 | .ydb-storage-nodes-columns { 4 | &__pdisks-column { 5 | overflow: visible; // to enable stacked disks overflow the row 6 | } 7 | 8 | &__pdisks-wrapper { 9 | display: flex; 10 | gap: 10px; 11 | 12 | height: 40px; 13 | } 14 | 15 | &__pdisks-item { 16 | display: flex; 17 | flex-shrink: 0; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageNodesTable/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "empty.default": "No such nodes", 3 | "empty.out_of_space": "No nodes with out of space errors", 4 | "empty.degraded": "No degraded nodes", 5 | "empty.small_uptime": "No nodes with uptime < 1h", 6 | "empty.several_filters": "No nodes match current filters combination", 7 | "show_all": "Show all nodes" 8 | } 9 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageNodesTable/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-storage-nodes'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageNodesTable/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "empty.default": "Нет узлов", 3 | "empty.out_of_space": "Нет узлов, в которых кончается место", 4 | "empty.degraded": "Нет деградировавших узлов", 5 | "empty.small_uptime": "Нет узлов с uptime < 1h", 6 | "empty.several_filters": "Нет узлов, подходящих под текущие фильтры", 7 | "show_all": "Показать все узлы" 8 | } 9 | -------------------------------------------------------------------------------- /src/containers/Storage/PaginatedStorageNodesTable/index.tsx: -------------------------------------------------------------------------------- 1 | export {PaginatedStorageNodesTable} from './PaginatedStorageNodesTable'; 2 | -------------------------------------------------------------------------------- /src/containers/Storage/Storage.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .global-storage { 4 | &__search { 5 | @include mixins.search(); 6 | } 7 | 8 | &__table { 9 | .g-tooltip { 10 | // stylelint-disable-next-line declaration-no-important 11 | height: var(--g-text-body-2-line-height) !important; 12 | } 13 | } 14 | 15 | .entity-status { 16 | justify-content: center; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/containers/Storage/VDisks/VDisks.scss: -------------------------------------------------------------------------------- 1 | .ydb-storage-vdisks { 2 | &__wrapper { 3 | display: flex; 4 | } 5 | 6 | &__item { 7 | width: 90px; 8 | margin-right: 6px; 9 | 10 | &_with-dc-margin { 11 | margin-right: 12px; 12 | } 13 | 14 | &:last-child { 15 | margin-right: 0px; 16 | } 17 | 18 | .stack__layer { 19 | .data-table__row:hover & { 20 | background: var(--ydb-data-table-color-hover); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/containers/Storage/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "groups": "Groups", 3 | "nodes": "Nodes", 4 | 5 | "controls_groups-search-placeholder": "Group ID, Pool name", 6 | "controls_nodes-search-placeholder": "Node ID, FQDN", 7 | "controls_group-by-placeholder": "Group by:", 8 | 9 | "no-nodes": "No such nodes", 10 | "no-groups": "No such groups" 11 | } 12 | -------------------------------------------------------------------------------- /src/containers/Storage/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-storage'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Storage/shared.tsx: -------------------------------------------------------------------------------- 1 | import {cn} from '../../utils/cn'; 2 | 3 | export const b = cn('global-storage'); 4 | -------------------------------------------------------------------------------- /src/containers/Storage/types.ts: -------------------------------------------------------------------------------- 1 | import type {PaginatedTableData} from '../../components/PaginatedTable'; 2 | import type {PreparedStorageNode} from '../../store/reducers/storage/types'; 3 | 4 | export type StorageViewContext = { 5 | groupId?: string; 6 | nodeId?: string; 7 | pDiskId?: string; 8 | vDiskSlotId?: string; 9 | }; 10 | 11 | export type StorageNodesPaginatedTableData = PaginatedTableData & { 12 | columnsSettings?: { 13 | maxSlotsPerDisk: number; 14 | maxDisksPerNode: number; 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /src/containers/StorageGroupPage/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "storage-group": "Storage Group", 3 | "storage": "Storage", 4 | "pool-name": "Pool Name" 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/StorageGroupPage/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-storage-group-page'; 6 | 7 | export const storageGroupPageKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tablet/Tablet.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .ydb-tablet-page { 4 | $_: &; 5 | height: 100%; 6 | padding: 20px; 7 | @include mixins.body-2-typography(); 8 | 9 | &__placeholder { 10 | display: flex; 11 | flex: 1 1 auto; 12 | justify-content: center; 13 | align-items: center; 14 | } 15 | 16 | &__loader { 17 | margin-left: var(--g-spacing-2); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletControls/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TabletControls'; 2 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletInfo/TabletInfo.scss: -------------------------------------------------------------------------------- 1 | @use '../../../../styles/mixins.scss'; 2 | 3 | .ydb-tablet-info { 4 | &__link { 5 | @extend .link; 6 | } 7 | 8 | &__section-title { 9 | margin: var(--g-spacing-1) 0 var(--g-spacing-3); 10 | @include mixins.text-subheader-2(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletInfo/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "field_scheme-shard": "SchemeShard", 3 | "field_follower": "Follower", 4 | "field_generation": "Generation", 5 | "field_hive": "HiveId", 6 | "field_state": "State", 7 | "field_uptime": "Uptime", 8 | "field_node": "Node", 9 | "field_links": "Links", 10 | "field_developer-ui-app": "App", 11 | "field_developer-ui-counters": "Counters", 12 | "field_developer-ui-executor": "Executor DB internals", 13 | "field_developer-ui-state": "State Storage", 14 | "title_info": "Info", 15 | "title_links": "Links" 16 | } 17 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletInfo/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-tablet-info'; 6 | 7 | export const tabletInfoKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletInfo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TabletInfo'; 2 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletStorageInfo/TabletStorageInfo.scss: -------------------------------------------------------------------------------- 1 | @use '../../../../styles/mixins.scss'; 2 | 3 | .ydb-tablet-storage-info { 4 | $block: &; 5 | 6 | &__metrics-cell { 7 | padding: var(--g-spacing-1) var(--g-spacing-2); 8 | 9 | white-space: nowrap; 10 | } 11 | &__name-wrapper { 12 | padding: var(--g-spacing-1) var(--g-spacing-2); 13 | } 14 | &__with-padding { 15 | padding-left: calc(var(--g-spacing-2) + var(--g-spacing-6)); 16 | } 17 | &__name-content_no-control { 18 | padding-left: var(--g-spacing-6); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletStorageInfo/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "label_channel-index": "Channel", 3 | "label_storage-pool": "Storage Pool Name", 4 | "label_group-id": "Group ID", 5 | "label_generation": "From generation", 6 | "label_timestamp": "Timestamp" 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletStorageInfo/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-tablet-storage-info'; 6 | 7 | export const tabletInfoKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletStorageInfo/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../../utils/cn'; 2 | 3 | export const b = cn('ydb-tablet-storage-info'); 4 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletStorageInfo/types.ts: -------------------------------------------------------------------------------- 1 | import type {TTabletStorageInfoChannelHistory} from '../../../../types/api/tablet'; 2 | 3 | export interface TabletStorageItem extends TTabletStorageInfoChannelHistory { 4 | storagePoolName?: string; 5 | children?: TabletStorageItem[]; 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/Tablet/components/TabletTable/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TabletTable'; 2 | -------------------------------------------------------------------------------- /src/containers/Tablet/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-tablet-page'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tablet/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Tablet'; 2 | -------------------------------------------------------------------------------- /src/containers/Tablet/utils.ts: -------------------------------------------------------------------------------- 1 | export function hasHive(id?: string): id is string { 2 | return Boolean(id && id !== '0'); 3 | } 4 | -------------------------------------------------------------------------------- /src/containers/Tablets/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "noTabletsData": "No tablets data", 3 | "Type": "Type", 4 | "Tablet": "Tablet", 5 | "State": "State", 6 | "Node ID": "Node ID", 7 | "Node FQDN": "Node FQDN", 8 | "Generation": "Generation", 9 | "Uptime": "Uptime", 10 | "dialog.kill-header": "Restart tablet", 11 | "dialog.kill-text": "The tablet will be restarted. Do you want to proceed?", 12 | "controls.kill-not-allowed": "You don't have enough rights to restart tablet", 13 | "controls.search-placeholder": "Tablet ID", 14 | "controls.entities-count-label": "Tablets" 15 | } 16 | -------------------------------------------------------------------------------- /src/containers/Tablets/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-tablets'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Acl/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "title_rights": "Access Rights", 3 | "title_effective-rights": "Effective Access Rights", 4 | "title_owner": "Owner", 5 | "title_interupt-inheritance": "Interrupt inheritance", 6 | "description_empty": "No Acl data" 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Acl/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-acl'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Configs/Configs.scss: -------------------------------------------------------------------------------- 1 | .ydb-diagnostics-configs { 2 | &__icon-touched { 3 | line-height: 1; 4 | cursor: default !important; 5 | 6 | color: var(--g-color-text-secondary); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Configs/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "td-feature-flag": "Feature flag", 3 | "td-default": "Default", 4 | "td-current": "Current", 5 | 6 | "enabled": "Enabled", 7 | "disabled": "Disabled", 8 | "flag-touched": "Flag is changed", 9 | 10 | "search-placeholder": "Search by feature flag", 11 | "search-empty": "Empty search result", 12 | "no-data": "No data" 13 | } 14 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Configs/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-diagnostics-configs'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/Consumers.scss: -------------------------------------------------------------------------------- 1 | @use '../../../../styles/mixins.scss'; 2 | 3 | .ydb-diagnostics-consumers { 4 | overflow: auto; 5 | flex-grow: 1; 6 | 7 | height: 100%; 8 | 9 | @include mixins.flex-container(); 10 | 11 | &__controls { 12 | @include mixins.controls(); 13 | } 14 | 15 | &__search { 16 | @include mixins.search(); 17 | } 18 | 19 | &__table-wrapper { 20 | overflow: auto; 21 | @include mixins.flex-container(); 22 | } 23 | 24 | &__table-content { 25 | overflow: auto; 26 | 27 | height: 100%; 28 | } 29 | 30 | &__table { 31 | @include mixins.freeze-nth-column(1); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/Headers/Headers.scss: -------------------------------------------------------------------------------- 1 | .ydb-diagnostics-consumers-columns-header { 2 | &__lags { 3 | white-space: nowrap; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/Headers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Headers'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/TopicStats/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ConsumersTopicStats'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/columns/Columns.scss: -------------------------------------------------------------------------------- 1 | .ydb-diagnostics-consumers-columns { 2 | &__lags-header { 3 | text-align: center; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/columns/index.ts: -------------------------------------------------------------------------------- 1 | export * from './columns'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "noConsumersMessage.topic": "This topic has no consumers", 3 | "noConsumersMessage.stream": "This changefeed has no consumers", 4 | "lagsPopover.readLags": "Read lags statistics, maximum among all consumer partitions (time format dd hh:mm:ss)", 5 | "table.emptyDataMessage": "No consumers match the current search", 6 | "controls.search": "Consumer" 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-diagnostics-consumers'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "noConsumersMessage.topic": "У этого топика нет читателей", 3 | "noConsumersMessage.stream": "У этого стрима нет читателей", 4 | "lagsPopover.readLags": "Статистика лагов чтения, максимальное значение среди всех партиций читателя (формат времени дд чч:мм:сс)", 5 | "table.emptyDataMessage": "По заданному поиску нет читателей", 6 | "controls.search": "Consumer" 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Consumers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Consumers'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Describe/Describe.scss: -------------------------------------------------------------------------------- 1 | @use '../../../../styles/mixins.scss'; 2 | 3 | .ydb-describe { 4 | &__message-container { 5 | padding: 15px 0; 6 | } 7 | 8 | &__result { 9 | position: relative; 10 | 11 | display: flex; 12 | flex: 0 0 auto; 13 | 14 | padding: 0 20px 20px 0; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss: -------------------------------------------------------------------------------- 1 | .kv-detailed-overview { 2 | display: flex; 3 | flex-direction: column; 4 | gap: 20px; 5 | 6 | width: 100%; 7 | height: 100%; 8 | 9 | &__section { 10 | display: flex; 11 | flex: 1 0 calc(50% - 10px); 12 | flex-direction: column; 13 | 14 | min-width: 300px; 15 | } 16 | 17 | &__modal { 18 | & .g-modal__content { 19 | position: relative; 20 | } 21 | } 22 | 23 | &__close-modal-button { 24 | position: absolute; 25 | top: 23px; 26 | right: 13px; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/HotKeys/HotKeys.scss: -------------------------------------------------------------------------------- 1 | .ydb-hot-keys { 2 | &__primary-key-column { 3 | display: flex; 4 | align-items: center; 5 | gap: 5px; 6 | } 7 | 8 | &__help-card { 9 | position: sticky; 10 | left: 0; 11 | 12 | margin-bottom: 20px; 13 | padding: 20px 40px 20px 20px; 14 | 15 | &__close-button { 16 | position: absolute; 17 | top: 5px; 18 | right: 5px; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/HotKeys/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "hot-keys-collecting": "Please wait a little while we are collecting hot keys samples...", 3 | "no-data": "No information about hot keys", 4 | 5 | "help": "Hot keys contains a list of table primary key values that are accessed most often. Sample is collected upon request to the tab during 5s time interval. Samples column indicates how many requests to the particular key value were registered during collection phase." 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/HotKeys/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-hot-keys'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Network/utils.ts: -------------------------------------------------------------------------------- 1 | import type {TNetNodePeerInfo} from '../../../../types/api/netInfo'; 2 | 3 | // determine how many nodes have status Connected "true" 4 | export const getConnectedNodesCount = (peers: TNetNodePeerInfo[] | undefined) => { 5 | return peers?.reduce((acc, item) => (item.Connected ? acc + 1 : acc), 0); 6 | }; 7 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "credentials.label": "Credentials", 3 | "noData": "No data for entity:", 4 | "srcConnection.database.label": "Source Database Path", 5 | "srcConnection.endpoint.label": "Source Cluster Endpoint", 6 | "state.label": "State" 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-diagnostics-async-replication-info'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/AsyncReplicationInfo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AsyncReplicationInfo'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/AsyncReplicationPaths.scss: -------------------------------------------------------------------------------- 1 | @use '../../../../../styles/mixins.scss'; 2 | 3 | .ydb-async-replication-paths { 4 | &__title { 5 | @include mixins.info-viewer-title(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "column.dstPath.name": "Dist", 3 | "column.srcPath.name": "Source", 4 | "everythingWithPrefix": "Everything with prefix:", 5 | "noData": "No data.", 6 | "title": "Replicated Paths" 7 | } 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-diagnostics-async-replication-paths'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/AsyncReplicationPaths/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AsyncReplicationPaths'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ChangefeedInfo'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-diagnostics-overview-table-info'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TableInfo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableInfo'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TopicInfo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TopicInfo'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "writeLagPopover": "Write lag, maximum among all topic partitions", 3 | "writeIdleTimePopover": "Write idle time, maximum among all topic partitions" 4 | } 5 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-diagnostics-overview-topic-stats'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "writeLagPopover": "Лаг записи, максимальное значение среди всех партиций топика", 3 | "writeIdleTimePopover": "Время без записи, максимальное значение среди всех партиций топика" 4 | } 5 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TopicStats/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TopicStats'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TransferInfo/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "credentials.label": "Credentials", 3 | "noData": "No data for entity:", 4 | "srcConnection.database.label": "Source Database Path", 5 | "srcConnection.endpoint.label": "Source Cluster Endpoint", 6 | "state.label": "State", 7 | "state.error": "Error", 8 | "srcPath.label": "Source Topic", 9 | "dstPath.label": "Destination Table", 10 | "transformLambda.label": "Transformation Lambda" 11 | } 12 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TransferInfo/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-diagnostics-transfer-info'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/TransferInfo/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TransferInfo'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Overview/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './prepareTopicSchemaInfo'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Partitions/Headers/Headers.scss: -------------------------------------------------------------------------------- 1 | .ydb-diagnostics-partitions-columns-header { 2 | &__read-session { 3 | width: 80px; 4 | 5 | white-space: normal; 6 | } 7 | 8 | &__lags { 9 | white-space: nowrap; 10 | } 11 | 12 | &__messages { 13 | width: 90px; 14 | 15 | white-space: normal; 16 | } 17 | 18 | &__messages-popover-content { 19 | max-width: 200px; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Partitions/Headers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Headers'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Partitions/columns/Columns.scss: -------------------------------------------------------------------------------- 1 | .ydb-diagnostics-partitions-columns { 2 | &__lags-header { 3 | text-align: center; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Partitions/columns/index.ts: -------------------------------------------------------------------------------- 1 | export * from './columns'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Partitions/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-diagnostics-partitions'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/Partitions/utils/types.ts: -------------------------------------------------------------------------------- 1 | import type {PreparedPartitionData} from '../../../../../store/reducers/partitions/types'; 2 | 3 | export interface PreparedPartitionDataWithHosts extends PreparedPartitionData { 4 | partitionHost: string | undefined; 5 | connectionHost: string | undefined; 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/DefaultOverviewContent/DefaultOverviewContent.tsx: -------------------------------------------------------------------------------- 1 | import {TenantDashboard} from '../TenantDashboard/TenantDashboard'; 2 | 3 | import {defaultDashboardConfig} from './defaultDashboardConfig'; 4 | 5 | interface DefaultOverviewContentProps { 6 | database: string; 7 | } 8 | 9 | export const DefaultOverviewContent = ({database}: DefaultOverviewContentProps) => { 10 | return ; 11 | }; 12 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/IssuesViewer/IssueTreeItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IssueTreeItem'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "title.healthcheck": "Healthcheck", 3 | "label.update": "Update", 4 | "label.show-details": "Show details", 5 | "label.issues": "Issues:", 6 | "status_message.ok": "No issues", 7 | "no-data": "no healthcheck data" 8 | } 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-diagnostics-healthcheck'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "title.healthcheck": "Healthcheck", 3 | "label.update": "Обновить", 4 | "label.show-details": "Посмотреть подробности", 5 | "label.issues": "Проблемы:", 6 | "status_message.ok": "Нет проблем", 7 | "no-data": "нет данных healthcheck" 8 | } 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.scss: -------------------------------------------------------------------------------- 1 | .metrics-cards { 2 | display: flex; 3 | gap: 16px; 4 | 5 | margin-bottom: 32px; 6 | 7 | &__tab { 8 | text-decoration: none; 9 | 10 | color: inherit; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/TenantDashboard/TenantDashboard.scss: -------------------------------------------------------------------------------- 1 | .ydb-tenant-dashboard { 2 | width: var(--diagnostics-section-table-width); 3 | margin-bottom: var(--diagnostics-section-margin); 4 | 5 | &__controls { 6 | margin-bottom: 10px; 7 | } 8 | 9 | &__charts { 10 | display: flex; 11 | flex-flow: row wrap; 12 | gap: 16px; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/memoryDashboardConfig.ts: -------------------------------------------------------------------------------- 1 | import type {ChartConfig} from '../TenantDashboard/TenantDashboard'; 2 | import i18n from '../i18n'; 3 | 4 | export const memoryDashboardConfig: ChartConfig[] = [ 5 | { 6 | title: i18n('charts.memory-usage'), 7 | metrics: [ 8 | { 9 | target: 'resources.memory.used_bytes', 10 | title: i18n('charts.memory-usage'), 11 | }, 12 | ], 13 | options: { 14 | dataType: 'size', 15 | }, 16 | }, 17 | ]; 18 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/storageDashboardConfig.ts: -------------------------------------------------------------------------------- 1 | import type {ChartConfig} from '../TenantDashboard/TenantDashboard'; 2 | import i18n from '../i18n'; 3 | 4 | export const storageDashboardConfig: ChartConfig[] = [ 5 | { 6 | title: i18n('charts.storage-usage'), 7 | metrics: [ 8 | { 9 | target: 'resources.storage.used_bytes', 10 | title: i18n('charts.storage-usage'), 11 | }, 12 | ], 13 | options: { 14 | dataType: 'size', 15 | }, 16 | }, 17 | ]; 18 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-diagnostics-tenant-overview'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TenantOverview/utils.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../../utils/cn'; 2 | 3 | export const b = cn('tenant-overview'); 4 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopQueries/columns/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "cpu-time": "CPU Time", 3 | "read-rows": "Read Rows", 4 | "read-bytes": "Read Bytes", 5 | "query-hash": "Query Hash", 6 | "user": "User", 7 | "start-time": "Start time", 8 | "end-time": "End time", 9 | "duration": "Duration", 10 | "query-text": "Query text", 11 | "application": "Application", 12 | "request-units": "Request Units" 13 | } 14 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopQueries/columns/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-top-queries-columns'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopQueries/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "no-data": "No data", 3 | "filter.text.placeholder": "Search by query text or userSID...", 4 | "mode_top": "Top", 5 | "mode_running": "Running", 6 | "timeframe_hour": "Per hour", 7 | "timeframe_minute": "Per minute", 8 | "query-details.title": "Query", 9 | "query-details.open-in-editor": "Open in Editor", 10 | "query-details.close": "Close", 11 | "query-details.query.title": "Query Text", 12 | "query-details.not-found.title": "Not found", 13 | "query-details.not-found.description": "This query no longer exists" 14 | } 15 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopQueries/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-diagnostics-top-queries'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopQueries/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TopQueries'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopShards/Filters/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Filters'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopShards/TopShards.scss: -------------------------------------------------------------------------------- 1 | .top-shards { 2 | &__hint { 3 | position: sticky; 4 | left: 0; 5 | 6 | width: max-content; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopShards/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "no-data": "No data", 3 | "filters.mode.immediate": "Immediate", 4 | "filters.mode.history": "Historical", 5 | "description": "Historical data only tracks shards with CPU load over 70%" 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopShards/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-diagnostics-top-shards'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopShards/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "no-data": "Нет данных", 3 | "filters.mode.immediate": "Мгновенные", 4 | "filters.mode.history": "Исторические", 5 | "description": "Исторические данные хранятся только о шардах с загрузкой CPU выше 70%" 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopShards/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TopShards'; 2 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopicData/TopicMessageDetails/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../../../utils/cn'; 2 | 3 | export const b = cn('ydb-diagnostics-message-details'); 4 | 5 | export const MESSAGE_SIZE_LIMIT = 10_000_000; 6 | -------------------------------------------------------------------------------- /src/containers/Tenant/Diagnostics/TopicData/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-diagnostics-topic-data'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/EntityTitle/EntityTitle.tsx: -------------------------------------------------------------------------------- 1 | import {Flex, Label} from '@gravity-ui/uikit'; 2 | 3 | import type {TPathDescription} from '../../../types/api/schema'; 4 | import i18n from '../i18n'; 5 | import {getEntityName, isReadOnlyTable} from '../utils'; 6 | 7 | interface EntityTitleProps { 8 | data?: TPathDescription; 9 | } 10 | 11 | export function EntityTitle({data}: EntityTitleProps) { 12 | const entityName = getEntityName(data); 13 | 14 | if (isReadOnlyTable(data)) { 15 | return ( 16 | 17 | {entityName} 18 | 19 | ); 20 | } 21 | 22 | return entityName; 23 | } 24 | -------------------------------------------------------------------------------- /src/containers/Tenant/Info/ExternalDataSource/ExternalDataSource.scss: -------------------------------------------------------------------------------- 1 | .ydb-external-data-source-info { 2 | &__location { 3 | max-width: var(--tenant-object-info-max-value-width); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Tenant/Info/ExternalTable/ExternalTable.scss: -------------------------------------------------------------------------------- 1 | .ydb-external-table-info { 2 | &__location { 3 | max-width: var(--tenant-object-info-max-value-width); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Tenant/Info/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "external-objects.source-type": "Source Type", 3 | "external-objects.data-source": "Data Source", 4 | "external-objects.location": "Location", 5 | "external-objects.auth-method": "Auth Method", 6 | "external-objects.auth-method.none": "None", 7 | "external-objects.auth-method.service-account": "Service Account", 8 | 9 | "view.query-text": "Query Text" 10 | } 11 | -------------------------------------------------------------------------------- /src/containers/Tenant/Info/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-tenant-objects-info'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/ObjectGeneral/ObjectGeneral.scss: -------------------------------------------------------------------------------- 1 | .object-general { 2 | display: flex; 3 | flex-grow: 1; 4 | flex-direction: column; 5 | 6 | width: 100%; 7 | height: 100%; 8 | max-height: 100%; 9 | 10 | &__loader { 11 | display: flex; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/containers/Tenant/ObjectSummary/CreateDirectoryDialog/CreateDirectoryDialog.scss: -------------------------------------------------------------------------------- 1 | .ydb-schema-create-directory-dialog { 2 | &__label { 3 | display: flex; 4 | flex-direction: column; 5 | 6 | margin-bottom: 8px; 7 | } 8 | &__description { 9 | color: var(--g-color-text-secondary); 10 | } 11 | &__input-wrapper { 12 | min-height: 48px; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/containers/Tenant/ObjectSummary/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-object-summary'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/ObjectSummary/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../utils/cn'; 2 | 3 | export const b = cn('ydb-object-summary'); 4 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/Issues/models.ts: -------------------------------------------------------------------------------- 1 | const SEVERITY_LIST = ['S_FATAL', 'S_ERROR', 'S_WARNING', 'S_INFO'] as const; 2 | 3 | export type SEVERITY = (typeof SEVERITY_LIST)[number]; 4 | 5 | // Severity values from ydb/library/yql/public/issue/protos/issue_severity.proto 6 | // FATAL = 0; 7 | // ERROR = 1; 8 | // WARNING = 2; 9 | // INFO = 3; 10 | function isSeverity(value: number | undefined) { 11 | return value ? SEVERITY_LIST[value] !== undefined : false; 12 | } 13 | 14 | export function getSeverity(value: number | undefined) { 15 | return isSeverity(value) ? SEVERITY_LIST[value!] : 'S_INFO'; 16 | } 17 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/NewSQL/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-new-sql'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/Preview/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "label_partition-id": "Partition ID: {{id}}", 3 | "label_offsets-range": "offsets: {{start}} - {{end}}" 4 | } 5 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/Preview/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-preview'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/Preview/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../../utils/cn'; 2 | 3 | export const b = cn('ydb-preview'); 4 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/Preview/types.ts: -------------------------------------------------------------------------------- 1 | import type {EPathSubType, EPathType} from '../../../../types/api/schema'; 2 | 3 | export interface PreviewContainerProps { 4 | database: string; 5 | path: string; 6 | type?: EPathType; 7 | subType?: EPathSubType; 8 | } 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/Query.scss: -------------------------------------------------------------------------------- 1 | @use '../../../styles/mixins.scss'; 2 | 3 | .ydb-query { 4 | max-height: calc(100% - 56px); // 56px - height of TenantNavigation 5 | @include mixins.flex-container(); 6 | 7 | &__tabs { 8 | padding: 0 20px 16px; 9 | } 10 | 11 | &__content { 12 | overflow: hidden; 13 | 14 | height: 100%; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryEditorControls/EditorButton.scss: -------------------------------------------------------------------------------- 1 | @use '../../../../styles/mixins.scss'; 2 | 3 | .ydb-query-editor-button { 4 | &__explain-button, 5 | &__stop-button, 6 | &__run-button { 7 | width: 92px; 8 | } 9 | 10 | &__stop-button { 11 | &_error { 12 | @include mixins.query-buttons-animations(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/Ast/Ast.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-ast { 2 | overflow: hidden; 3 | 4 | width: 100%; 5 | height: 100%; 6 | 7 | white-space: pre-wrap; 8 | } 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/Graph/Graph.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-explain-graph { 2 | &__canvas-container { 3 | overflow-y: auto; 4 | 5 | width: 100%; 6 | height: 100%; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/QueryInfoDropdown/QueryInfoDropdown.scss: -------------------------------------------------------------------------------- 1 | .query-info-dropdown { 2 | &__menu-item { 3 | align-items: start; 4 | } 5 | 6 | &__menu-item-content { 7 | display: flex; 8 | flex-direction: column; 9 | 10 | padding: var(--g-spacing-1) 0; 11 | } 12 | 13 | &__icon { 14 | margin-top: var(--g-spacing-2); 15 | margin-right: var(--g-spacing-2); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/QueryInfoDropdown/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../../../../utils/cn'; 2 | export const b = cn('query-info-dropdown'); 3 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/QueryJSONViewer/QueryJSONViewer.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-json-viewer { 2 | width: 100%; 3 | height: 100%; 4 | padding: 15px 0; 5 | &__tree { 6 | overflow-y: auto; 7 | 8 | width: 100%; 9 | height: 100%; 10 | padding: 0 10px; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/QueryResultError/QueryResultError.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-result-error { 2 | &__message { 3 | padding-top: var(--g-spacing-4); 4 | padding-left: var(--g-spacing-4); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/SimplifiedPlan/MetricsCell.tsx: -------------------------------------------------------------------------------- 1 | import {isNumeric} from '../../../../../../utils/utils'; 2 | 3 | import {block} from './utils'; 4 | 5 | interface MetricsCellProps { 6 | value: unknown; 7 | formatter: (value: number) => string; 8 | } 9 | 10 | export function MetricsCell({value, formatter}: MetricsCellProps) { 11 | if (!isNumeric(value)) { 12 | return undefined; 13 | } 14 | 15 | const numberValue = Number(value); 16 | const content = formatter(numberValue); 17 | 18 | return

{content}
; 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/SimplifiedPlan/types.ts: -------------------------------------------------------------------------------- 1 | import type {SimplifiedPlanItem} from '../../../../../../store/reducers/query/types'; 2 | 3 | export interface ExtendedSimplifiesPlanItem extends Omit { 4 | lines?: string; 5 | children?: ExtendedSimplifiesPlanItem[]; 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/Stub/Stub.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-result-stub-message { 2 | padding: 15px 20px; 3 | } 4 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/components/Stub/Stub.tsx: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../../../../utils/cn'; 2 | 3 | import './Stub.scss'; 4 | 5 | const b = cn('ydb-query-result-stub-message'); 6 | 7 | interface StubMessageProps { 8 | message: string; 9 | } 10 | 11 | export function StubMessage({message}: StubMessageProps) { 12 | return
{message}
; 13 | } 14 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryResult/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-execute-result'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QuerySettingsBanner/QuerySettingsBanner.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-settings-banner { 2 | margin-top: var(--g-spacing-4); 3 | margin-right: var(--g-spacing-4); 4 | margin-left: var(--g-spacing-4); 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsSelect.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-settings-select { 2 | &__selector { 3 | width: 100%; 4 | } 5 | 6 | &__popup { 7 | max-width: 320px; 8 | } 9 | 10 | &__item-description { 11 | white-space: pre-wrap; 12 | 13 | color: var(--g-color-text-secondary); 14 | } 15 | 16 | &__item { 17 | padding: var(--g-spacing-1) 0; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsTimeout.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-settings-timeout { 2 | &__control-wrapper { 3 | display: flex; 4 | flex: 6; 5 | align-items: center; 6 | } 7 | 8 | &__input { 9 | width: 50%; 10 | } 11 | 12 | &__postfix { 13 | margin-right: var(--g-spacing-2); 14 | 15 | color: var(--g-color-text-secondary); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QuerySettingsDialog/TimeoutLabel.scss: -------------------------------------------------------------------------------- 1 | .ydb-timeout-label { 2 | &__switch { 3 | align-items: center; 4 | 5 | height: var(--g-text-header-2-line-height); 6 | margin-right: var(--g-spacing-1); 7 | } 8 | 9 | &__label-title, 10 | &__switch-title { 11 | flex: 4; 12 | align-items: center; 13 | 14 | margin-right: var(--g-spacing-3); 15 | 16 | font-weight: 500; 17 | white-space: nowrap; 18 | } 19 | 20 | &__label-title { 21 | line-height: var(--g-text-header-2-line-height); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QuerySettingsDialog/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-query-settings-dialog'; 7 | 8 | export default registerKeysets(COMPONENT, {en, ru}); 9 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/QueryStoppedBanner/QueryStoppedBanner.scss: -------------------------------------------------------------------------------- 1 | .ydb-query-stopped-banner { 2 | margin-top: var(--g-spacing-4); 3 | margin-right: var(--g-spacing-4); 4 | margin-left: var(--g-spacing-4); 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/SaveQuery/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "action.save": "Save query", 3 | "action.edit": "Edit query", 4 | "action.save-as-new": "Save as new", 5 | "action.edit-existing": "Edit existing", 6 | "description": "The query will be saved in your browser", 7 | "input-label": "Query name", 8 | "input-placeholder": "Enter query name", 9 | "button-apply": "Save", 10 | "button-cancel": "Cancel", 11 | "error.name-exists": "This name already exists", 12 | "error.name-not-empty": "Name should not be empty" 13 | } 14 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/SaveQuery/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-save-query-dialog'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-query-editor'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/utils/replaceParams.ts: -------------------------------------------------------------------------------- 1 | // Takes a template string and an object of parameters, and replaces placeholders in the template with corresponding values 2 | // from the parameters object. 3 | export function replaceParams(template: string, params: Record) { 4 | return template.replace(/\${(\w+)}/g, (_, key) => params[key] || _); 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Tenant/Query/utils/useSavedQueries.tsx: -------------------------------------------------------------------------------- 1 | import {selectSavedQueriesFilter} from '../../../../store/reducers/queryActions/queryActions'; 2 | import type {SavedQuery} from '../../../../types/store/query'; 3 | import {SAVED_QUERIES_KEY} from '../../../../utils/constants'; 4 | import {useSetting, useTypedSelector} from '../../../../utils/hooks'; 5 | 6 | export function useSavedQueries() { 7 | const [savedQueries] = useSetting(SAVED_QUERIES_KEY, []); 8 | const filter = useTypedSelector(selectSavedQueriesFilter).toLowerCase(); 9 | 10 | return filter 11 | ? savedQueries.filter((item) => item.body.toLowerCase().includes(filter)) 12 | : savedQueries; 13 | } 14 | -------------------------------------------------------------------------------- /src/containers/Tenant/Schema/SchemaViewer/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "column-title.id": "Id", 3 | "column-title.name": "Name", 4 | "column-title.type": "Type", 5 | "column-title.notNull": "NotNull", 6 | "column-title.autoIncrement": "AutoIncrement", 7 | "column-title.defaultValue": "Default", 8 | "column-title.family": "Family", 9 | "column-title.media": "Media", 10 | "column-title.compression": "Compression", 11 | "primary-key.title": "Primary key:", 12 | "partitioning-key.title": "Partitioning key:" 13 | } 14 | -------------------------------------------------------------------------------- /src/containers/Tenant/Schema/SchemaViewer/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-schema-viewer'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/Schema/SchemaViewer/shared.ts: -------------------------------------------------------------------------------- 1 | import {cn} from '../../../../utils/cn'; 2 | 3 | export const b = cn('schema-viewer'); 4 | -------------------------------------------------------------------------------- /src/containers/Tenant/Schema/SchemaViewer/types.ts: -------------------------------------------------------------------------------- 1 | import type {Column} from '@gravity-ui/react-data-table'; 2 | 3 | export type SchemaData = { 4 | id?: number; 5 | name?: string; 6 | keyColumnIndex?: number; 7 | partitioningColumnIndex?: number; 8 | type?: string; 9 | notNull?: boolean; 10 | autoIncrement?: boolean; 11 | familyName?: string; 12 | prefferedPoolKind?: string; 13 | columnCodec?: string; 14 | defaultValue?: string | number | boolean; 15 | }; 16 | 17 | export interface SchemaColumn extends Column { 18 | name: keyof SchemaData; 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/Tenant/Tenant.scss: -------------------------------------------------------------------------------- 1 | @use '../../styles/mixins.scss'; 2 | 3 | .tenant-page { 4 | overflow: hidden; 5 | 6 | @include mixins.body-2-typography(); 7 | @include mixins.flex-container(); 8 | 9 | &__main { 10 | flex-grow: 1; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/containers/Tenant/TenantNavigation/TenantNavigation.scss: -------------------------------------------------------------------------------- 1 | .ydb-tenant-navigation { 2 | padding: 12px 16px 8px; 3 | 4 | &__item { 5 | display: flex; 6 | align-items: center; 7 | gap: 5px; 8 | } 9 | 10 | &__icon { 11 | flex-shrink: 0; 12 | } 13 | &__text { 14 | overflow: hidden; 15 | 16 | text-overflow: ellipsis; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/containers/Tenant/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-tenant'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Tenant/utils/ToggleButton.scss: -------------------------------------------------------------------------------- 1 | .kv-pane-visibility-button { 2 | &_hidden { 3 | display: none; 4 | } 5 | 6 | &_bottom { 7 | transform: rotate(180deg); 8 | } 9 | 10 | &_bottom.rotate { 11 | transform: rotate(0); 12 | } 13 | &_left { 14 | transform: rotate(-90deg); 15 | } 16 | 17 | &_left.rotate { 18 | transform: rotate(90deg); 19 | } 20 | 21 | &_top.rotate { 22 | transform: rotate(180deg); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/containers/Tenant/utils/constants.ts: -------------------------------------------------------------------------------- 1 | import type {Settings} from '@gravity-ui/react-data-table'; 2 | 3 | import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants'; 4 | 5 | export const MAX_QUERY_HEIGHT = 6; 6 | 7 | export const QUERY_TABLE_SETTINGS: Settings = { 8 | ...DEFAULT_TABLE_SETTINGS, 9 | dynamicRenderType: 'variable', 10 | }; 11 | -------------------------------------------------------------------------------- /src/containers/Tenant/utils/index.ts: -------------------------------------------------------------------------------- 1 | import type {TPathDescription} from '../../../types/api/schema'; 2 | 3 | import {mapPathTypeToEntityName} from './schema'; 4 | 5 | export const getEntityName = (pathDescription?: TPathDescription) => { 6 | const {PathType, PathSubType} = pathDescription?.Self || {}; 7 | 8 | return mapPathTypeToEntityName(PathType, PathSubType); 9 | }; 10 | 11 | export const isReadOnlyTable = (pathDescription?: TPathDescription) => { 12 | return pathDescription?.UserAttributes?.some(({Key, Value}) => { 13 | return Key === '__async_replica' && Value === 'true'; 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /src/containers/Tenant/utils/types.ts: -------------------------------------------------------------------------------- 1 | import type {NavigationTreeProps} from 'ydb-ui-components'; 2 | 3 | export type DropdownItem = { 4 | text: string; 5 | action: () => void; 6 | iconEnd?: React.ReactNode; 7 | }; 8 | 9 | export type TreeNodeMeta = { 10 | subType?: string; 11 | }; 12 | 13 | export type YdbNavigationTreeProps = NavigationTreeProps; 14 | -------------------------------------------------------------------------------- /src/containers/Tenants/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "create-database": "Create database", 3 | "remove": "Remove", 4 | "edit": "Edit" 5 | } 6 | -------------------------------------------------------------------------------- /src/containers/Tenants/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-tenants-table'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/UserSettings/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | export default registerKeysets('ydb-user-settings', {en}); 6 | -------------------------------------------------------------------------------- /src/containers/VDiskPage/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "fqdn": "FQDN", 3 | "node": "Node", 4 | "pdisk": "PDisk", 5 | "vdisk": "VDisk", 6 | "storage": "Storage", 7 | 8 | "evict-vdisk-button": "Evict VDisk", 9 | "force-evict-vdisk-button": "Evict anyway", 10 | "evict-vdisk-dialog-header": "Evict VDisk", 11 | "evict-vdisk-dialog-text": "VDisk will be evicted. Do you want to proceed?", 12 | "evict-vdisk-not-allowed": "You don't have enough rights to evict VDisk" 13 | } 14 | -------------------------------------------------------------------------------- /src/containers/VDiskPage/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-vDisk-page'; 6 | 7 | export const vDiskPageKeyset = registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Versions/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "title_overall": "Overall", 3 | "title_storage": "Storage nodes", 4 | "title_database": "Database nodes", 5 | "title_other": "Other nodes" 6 | } 7 | -------------------------------------------------------------------------------- /src/containers/Versions/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../utils/i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-versions'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/containers/Versions/types.ts: -------------------------------------------------------------------------------- 1 | import type {NodesPreparedEntity} from '../../store/reducers/nodes/types'; 2 | import type {VersionValue} from '../../types/versions'; 3 | 4 | export interface GroupedNodesItem { 5 | title?: string; 6 | nodes?: NodesPreparedEntity[]; 7 | items?: GroupedNodesItem[]; 8 | versionColor?: string; 9 | versionsValues?: VersionValue[]; 10 | } 11 | 12 | export enum GroupByValue { 13 | VERSION = 'Version', 14 | TENANT = 'Database', 15 | STORAGE = 'Storage', 16 | } 17 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import type {ReportHandler} from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({getCLS, getFID, getFCP, getLCP, getTTFB}) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /src/services/api/auth.ts: -------------------------------------------------------------------------------- 1 | import {BaseYdbAPI} from './base'; 2 | 3 | export class AuthAPI extends BaseYdbAPI { 4 | authenticate(params: {user: string; password: string; database?: string}) { 5 | return this.post(this.getPath('/login'), params, {}); 6 | } 7 | 8 | logout() { 9 | return this.post(this.getPath('/logout'), {}, {}); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/services/api/scheme.ts: -------------------------------------------------------------------------------- 1 | import {BaseYdbAPI} from './base'; 2 | 3 | export class SchemeAPI extends BaseYdbAPI { 4 | createSchemaDirectory( 5 | {database, path}: {database: string; path: string}, 6 | {signal}: {signal?: AbortSignal} = {}, 7 | ) { 8 | return this.post<{test: string}>( 9 | this.getPath('/scheme/directory'), 10 | {}, 11 | { 12 | database, 13 | path, 14 | }, 15 | { 16 | requestConfig: {signal}, 17 | }, 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/services/parsers/parseMetaCluster.ts: -------------------------------------------------------------------------------- 1 | import {traceViewSchema} from '../../types/api/trace'; 2 | 3 | export function parseTraceFields({traceView}: {traceView?: string}) { 4 | try { 5 | return { 6 | traceView: traceView ? traceViewSchema.parse(JSON.parse(traceView)) : undefined, 7 | }; 8 | } catch (e) { 9 | console.error('Error parsing trace fields:', e); 10 | } 11 | 12 | return {}; 13 | } 14 | -------------------------------------------------------------------------------- /src/services/parsers/parseMetaTenants.ts: -------------------------------------------------------------------------------- 1 | import type {MetaTenants} from '../../types/api/meta'; 2 | import type {TTenantInfo} from '../../types/api/tenant'; 3 | 4 | export const parseMetaTenants = (data: MetaTenants): TTenantInfo => { 5 | return { 6 | TenantInfo: data?.databases, 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /src/setupProxy.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | const {createProxyMiddleware} = require('http-proxy-middleware'); 3 | 4 | module.exports = function (app) { 5 | const metaYdbBackend = process.env.META_YDB_BACKEND; 6 | if (metaYdbBackend && metaYdbBackend !== 'undefined') { 7 | app.use( 8 | '/meta', 9 | createProxyMiddleware({ 10 | target: metaYdbBackend, 11 | changeOrigin: true, 12 | }), 13 | ); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/store/defaultStore.ts: -------------------------------------------------------------------------------- 1 | import {configureStore} from './configureStore'; 2 | 3 | export const {store, history} = configureStore(); 4 | 5 | export type GetState = typeof store.getState; 6 | export type RootState = ReturnType; 7 | export type AppDispatch = typeof store.dispatch; 8 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | backend, 3 | basename, 4 | clusterName, 5 | configureStore, 6 | customBackend, 7 | metaBackend, 8 | codeAssistBackend, 9 | webVersion, 10 | } from './configureStore'; 11 | export {rootReducer} from './reducers'; 12 | 13 | export type {AppDispatch, GetState, RootState} from './defaultStore'; 14 | -------------------------------------------------------------------------------- /src/store/reducers/authentication/types.ts: -------------------------------------------------------------------------------- 1 | export interface AuthenticationState { 2 | isAuthenticated: boolean; 3 | isUserAllowedToMakeChanges?: boolean; 4 | user: string | undefined; 5 | } 6 | -------------------------------------------------------------------------------- /src/store/reducers/cluster/types.ts: -------------------------------------------------------------------------------- 1 | import type {ClusterTab} from '../../../containers/Cluster/utils'; 2 | 3 | export interface DiskErasureGroupsStats { 4 | diskType: string; 5 | erasure: string; 6 | createdGroups: number; 7 | totalGroups: number; 8 | allocatedSize: number; 9 | availableSize: number; 10 | } 11 | 12 | /** Keys - erasure types */ 13 | type DiskGroupsStats = Record; 14 | 15 | /** Keys - PDisks types */ 16 | export type ClusterGroupsStats = Record; 17 | 18 | export interface ClusterState { 19 | defaultClusterTab: ClusterTab; 20 | } 21 | -------------------------------------------------------------------------------- /src/store/reducers/executeTopQueries/types.ts: -------------------------------------------------------------------------------- 1 | export type TimeFrame = 'minute' | 'hour'; 2 | 3 | export interface TopQueriesFilters { 4 | /** ms from epoch */ 5 | from?: string; 6 | /** ms from epoch */ 7 | to?: string; 8 | text?: string; 9 | } 10 | -------------------------------------------------------------------------------- /src/store/reducers/healthcheckInfo/types.ts: -------------------------------------------------------------------------------- 1 | import type {IssueLog} from '../../../types/api/healthcheck'; 2 | 3 | export interface IssuesTree extends IssueLog { 4 | reasonsItems?: IssuesTree[]; 5 | } 6 | -------------------------------------------------------------------------------- /src/store/reducers/healthcheckInfo/utils.ts: -------------------------------------------------------------------------------- 1 | import {EFlag} from '../../../types/api/enums'; 2 | import {StatusFlag} from '../../../types/api/healthcheck'; 3 | 4 | export const hcStatusToColorFlag: Record = { 5 | [StatusFlag.UNSPECIFIED]: EFlag.Grey, 6 | [StatusFlag.GREY]: EFlag.Grey, 7 | [StatusFlag.GREEN]: EFlag.Green, 8 | [StatusFlag.BLUE]: EFlag.Blue, 9 | [StatusFlag.YELLOW]: EFlag.Yellow, 10 | [StatusFlag.ORANGE]: EFlag.Orange, 11 | [StatusFlag.RED]: EFlag.Red, 12 | }; 13 | -------------------------------------------------------------------------------- /src/store/reducers/node/utils.ts: -------------------------------------------------------------------------------- 1 | import type {TEvSystemStateResponse} from '../../../types/api/systemState'; 2 | import {prepareNodeSystemState} from '../../../utils/nodes'; 3 | 4 | import type {PreparedNode} from './types'; 5 | 6 | export const prepareNodeData = (data: TEvSystemStateResponse): PreparedNode => { 7 | if (!data.SystemStateInfo?.length) { 8 | return {}; 9 | } 10 | 11 | const nodeData = data.SystemStateInfo[0]; 12 | 13 | return prepareNodeSystemState(nodeData); 14 | }; 15 | -------------------------------------------------------------------------------- /src/store/reducers/queryActions/types.ts: -------------------------------------------------------------------------------- 1 | export type QueryActions = 'idle' | 'settings'; 2 | 3 | export interface QueryActionsState { 4 | queryName: string | null; 5 | queryAction: QueryActions; 6 | savedQueriesFilter: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/store/reducers/settings/hooks.ts: -------------------------------------------------------------------------------- 1 | import {useTypedDispatch, useTypedSelector} from '../../../utils/hooks'; 2 | 3 | import {changeFilter, selectProblemFilter} from './settings'; 4 | import type {ProblemFilterValue} from './types'; 5 | 6 | export function useProblemFilter() { 7 | const dispatch = useTypedDispatch(); 8 | 9 | const problemFilter = useTypedSelector(selectProblemFilter); 10 | 11 | const handleProblemFilterChange = (value: ProblemFilterValue) => { 12 | dispatch(changeFilter(value)); 13 | }; 14 | 15 | return { 16 | problemFilter, 17 | handleProblemFilterChange, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/store/reducers/settings/types.ts: -------------------------------------------------------------------------------- 1 | import type {SettingsObject} from '../../../services/settings'; 2 | import type {ValueOf} from '../../../types/common'; 3 | 4 | import type {ProblemFilterValues} from './settings'; 5 | 6 | export type ProblemFilterValue = ValueOf; 7 | 8 | export interface SettingsState { 9 | problemFilter: ProblemFilterValue; 10 | userSettings: SettingsObject; 11 | systemSettings: SettingsObject; 12 | } 13 | -------------------------------------------------------------------------------- /src/store/reducers/shardsWorkload/types.ts: -------------------------------------------------------------------------------- 1 | export enum EShardsWorkloadMode { 2 | Immediate = 'immediate', 3 | History = 'history', 4 | } 5 | 6 | export interface ShardsWorkloadFilters { 7 | /** ms from epoch */ 8 | from?: string; 9 | /** ms from epoch */ 10 | to?: string; 11 | mode?: EShardsWorkloadMode; 12 | } 13 | -------------------------------------------------------------------------------- /src/store/reducers/singleClusterMode.ts: -------------------------------------------------------------------------------- 1 | function singleClusterMode(state = true) { 2 | return state; 3 | } 4 | 5 | export default singleClusterMode; 6 | -------------------------------------------------------------------------------- /src/store/reducers/storage/constants.ts: -------------------------------------------------------------------------------- 1 | export const VISIBLE_ENTITIES = { 2 | all: 'all', 3 | missing: 'missing', 4 | space: 'space', 5 | } as const; 6 | 7 | export const STORAGE_TYPES = { 8 | groups: 'groups', 9 | nodes: 'nodes', 10 | } as const; 11 | -------------------------------------------------------------------------------- /src/store/reducers/tenants/contants.ts: -------------------------------------------------------------------------------- 1 | export const METRIC_STATUS = { 2 | Unspecified: 'Unspecified', 3 | Good: 'Good', 4 | Warning: 'Warning', 5 | Danger: 'Danger', 6 | } as const; 7 | 8 | export const MetricStatusToSeverity = { 9 | [METRIC_STATUS.Unspecified]: 0, 10 | [METRIC_STATUS.Good]: 1, 11 | [METRIC_STATUS.Warning]: 2, 12 | [METRIC_STATUS.Danger]: 3, 13 | }; 14 | -------------------------------------------------------------------------------- /src/store/reducers/vdisk/types.ts: -------------------------------------------------------------------------------- 1 | import type {PreparedVDisk} from '../../../utils/disks/types'; 2 | 3 | export interface VDiskData extends PreparedVDisk { 4 | NodeId?: number; 5 | NodeHost?: string; 6 | NodeType?: string; 7 | NodeDC?: string; 8 | 9 | PDiskId?: number; 10 | PDiskType?: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/styles/index.scss: -------------------------------------------------------------------------------- 1 | @forward '@gravity-ui/uikit/styles/styles.scss'; 2 | @forward './themes.scss'; 3 | @forward './unipika.scss'; 4 | @forward './illustrations.scss'; 5 | 6 | body { 7 | margin: 0; 8 | 9 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 10 | 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | } 14 | 15 | code { 16 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; 17 | } 18 | -------------------------------------------------------------------------------- /src/styles/unipika.scss: -------------------------------------------------------------------------------- 1 | @use '~@gravity-ui/unipika/styles/unipika.scss'; 2 | 3 | .g-root { 4 | .unipika { 5 | font-family: var(--g-font-family-monospace); 6 | 7 | &-wrapper & { 8 | margin: 0; 9 | padding: 0; 10 | 11 | border: 0; 12 | } 13 | } 14 | 15 | &_theme_dark, 16 | &_theme_dark-hc { 17 | @include unipika.unipika-dark; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/types/api/common.ts: -------------------------------------------------------------------------------- 1 | export interface IProtobufTimeObject { 2 | /** int64 */ 3 | seconds?: string; 4 | nanos?: number; 5 | } 6 | 7 | export type BackendSortParam = `-${T}` | `+${T}` | T; 8 | -------------------------------------------------------------------------------- /src/types/api/enums.ts: -------------------------------------------------------------------------------- 1 | // Shows system status 2 | // Currently is used in response types viewer/json/ storage, nodes, compute 3 | // pdiskinfo, vdiskinfo, tabletinfo, tenantinfo 4 | export enum EFlag { 5 | Grey = 'Grey', 6 | Green = 'Green', 7 | Blue = 'Blue', 8 | Yellow = 'Yellow', 9 | Orange = 'Orange', 10 | Red = 'Red', 11 | } 12 | -------------------------------------------------------------------------------- /src/types/api/error.ts: -------------------------------------------------------------------------------- 1 | export interface IResponseError { 2 | data?: T; 3 | status?: number; 4 | statusText?: string; 5 | isCancelled?: boolean; 6 | } 7 | 8 | // Error on offline backend or requests blocked by CORS 9 | export interface NetworkError { 10 | code?: unknown; 11 | columnNumber?: unknown; 12 | config?: Record; 13 | description?: unknown; 14 | fileName?: unknown; 15 | lineNumber?: unknown; 16 | message: 'Network Error'; 17 | name?: string; 18 | number?: unknown; 19 | stack?: string; 20 | } 21 | 22 | export type AuthErrorResponse = IResponseError<{ 23 | error?: string; 24 | }>; 25 | -------------------------------------------------------------------------------- /src/types/api/featureFlags.ts: -------------------------------------------------------------------------------- 1 | export interface FeatureFlagConfig { 2 | Name: string; 3 | Current?: boolean; 4 | Default?: boolean; 5 | } 6 | 7 | interface ConfigDb { 8 | Name: string; 9 | FeatureFlags: FeatureFlagConfig[]; 10 | } 11 | 12 | export interface FeatureFlagConfigs { 13 | Databases: ConfigDb[]; 14 | } 15 | -------------------------------------------------------------------------------- /src/types/api/hotkeys.ts: -------------------------------------------------------------------------------- 1 | export interface JsonHotKeysResponse { 2 | hotkeys: HotKey[] | null; 3 | } 4 | 5 | export interface HotKey { 6 | accessSample: number; 7 | keyValues: string[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/types/api/modifyDisk.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * endpoints: pdisk/restart and vdiks/evict 3 | */ 4 | export interface ModifyDiskResponse { 5 | debugMessage?: string; 6 | // true if successful, false if not 7 | result?: boolean; 8 | // Error message 9 | error?: string; 10 | forceRetryPossible?: boolean; 11 | } 12 | -------------------------------------------------------------------------------- /src/types/api/nodesList.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * endpoint: /viewer/json/nodesList 3 | * 4 | * source: https://github.com/ydb-platform/ydb/blob/main/library/cpp/actors/core/interconnect.h 5 | */ 6 | export type TEvNodesInfo = TNodeInfo[]; 7 | 8 | export interface TNodeInfo { 9 | Id?: number; 10 | Host?: string; 11 | ResolveHost?: string; 12 | Address?: string; 13 | Port?: number; 14 | PhysicalLocation?: TNodeLocation; 15 | } 16 | 17 | interface TNodeLocation { 18 | DataCenter?: number; 19 | Room?: number; 20 | Rack?: number; 21 | Body?: number; 22 | DataCenterId?: string; 23 | /** String with DC, Module, Rack and Unit ids */ 24 | Location?: string; 25 | } 26 | -------------------------------------------------------------------------------- /src/types/api/schema/externalDataSource.ts: -------------------------------------------------------------------------------- 1 | import type {TPathID} from './shared'; 2 | 3 | export interface TExternalDataSourceDescription { 4 | Name?: string; 5 | PathId?: TPathID; 6 | /** uint64 */ 7 | Version?: string; 8 | SourceType?: string; 9 | Location?: string; 10 | Installation?: string; 11 | Auth?: TAuth; 12 | } 13 | 14 | interface TAuth { 15 | None?: NoneAuth; 16 | ServiceAccount?: ServiceAccountAuth; 17 | } 18 | 19 | interface NoneAuth {} 20 | 21 | interface ServiceAccountAuth { 22 | Id?: string; 23 | SecretName?: string; 24 | } 25 | -------------------------------------------------------------------------------- /src/types/api/schema/externalTable.ts: -------------------------------------------------------------------------------- 1 | import type {TColumnDescription, TPathID} from './shared'; 2 | 3 | export interface TExternalTableDescription { 4 | Name?: string; 5 | PathId?: TPathID; 6 | /** uint64 */ 7 | Version?: string; 8 | SourceType?: string; 9 | DataSourcePath?: string; 10 | Location?: string; 11 | Columns?: TColumnDescription[]; 12 | /** bytes */ 13 | Content?: unknown; 14 | } 15 | -------------------------------------------------------------------------------- /src/types/api/schema/index.ts: -------------------------------------------------------------------------------- 1 | export * from './schema'; 2 | export * from './shared'; 3 | 4 | export * from './cdcStream'; 5 | export * from './columnEntity'; 6 | export * from './externalDataSource'; 7 | export * from './externalTable'; 8 | export * from './persQueueGroup'; 9 | export * from './table'; 10 | export * from './tableIndex'; 11 | -------------------------------------------------------------------------------- /src/types/api/schema/view.ts: -------------------------------------------------------------------------------- 1 | import type {TPathID} from './shared'; 2 | 3 | export interface TViewDescription { 4 | Name?: string; 5 | PathId?: TPathID; 6 | /** uint64 */ 7 | Version?: string; 8 | QueryText?: string; 9 | } 10 | -------------------------------------------------------------------------------- /src/types/api/systemState.ts: -------------------------------------------------------------------------------- 1 | import type {TSystemStateInfo} from './nodes'; 2 | 3 | /** 4 | * endpoint: /viewer/json/sysinfo 5 | * 6 | * source: https://github.com/ydb-platform/ydb/blob/main/ydb/core/protos/node_whiteboard.proto 7 | */ 8 | export interface TEvSystemStateResponse { 9 | SystemStateInfo?: TSystemStateInfo[]; 10 | /** uint64 */ 11 | ResponseTime?: string; 12 | ResponseDuration?: number; 13 | } 14 | -------------------------------------------------------------------------------- /src/types/api/trace.ts: -------------------------------------------------------------------------------- 1 | import {z} from 'zod'; 2 | 3 | export const traceViewSchema = z.object({ 4 | url: z.string().url(), 5 | }); 6 | 7 | export type TTraceView = z.infer; 8 | -------------------------------------------------------------------------------- /src/types/assets.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | // eslint-disable-next-line @typescript-eslint/consistent-type-imports 3 | const content: import('@gravity-ui/uikit').IconData; 4 | export default content; 5 | } 6 | 7 | declare module '*.png'; 8 | declare module '*.jpg'; 9 | declare module '*.jpeg'; 10 | declare module '*.ico'; 11 | -------------------------------------------------------------------------------- /src/types/common.ts: -------------------------------------------------------------------------------- 1 | export type ValueOf = T[keyof T]; 2 | export type ExtractType = T extends {type: infer U} ? U : string; 3 | export type WithRequiredFields = Exclude & Required>; 4 | -------------------------------------------------------------------------------- /src/types/components.ts: -------------------------------------------------------------------------------- 1 | import type React from 'react'; 2 | 3 | export interface InfoItem { 4 | label: string; 5 | value: React.ReactNode; 6 | } 7 | -------------------------------------------------------------------------------- /src/types/global.d.ts: -------------------------------------------------------------------------------- 1 | declare type AnyRecord = Record; 2 | -------------------------------------------------------------------------------- /src/types/react-table.d.ts: -------------------------------------------------------------------------------- 1 | import '@tanstack/react-table'; 2 | 3 | declare module '@tanstack/react-table' { 4 | interface ColumnMeta { 5 | align?: 'left' | 'right'; 6 | verticalAlign?: 'top' | 'middle'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/types/store/describe.ts: -------------------------------------------------------------------------------- 1 | import type {TEvDescribeSchemeResult} from '../api/schema'; 2 | 3 | export type IDescribeData = Record; 4 | -------------------------------------------------------------------------------- /src/types/store/heatmap.ts: -------------------------------------------------------------------------------- 1 | import type {TTableStats} from '../api/schema'; 2 | import type {TTabletStateInfo} from '../api/tablet'; 3 | import type {TMetrics} from '../api/tenant'; 4 | 5 | export interface IHeatmapTabletData extends TTabletStateInfo { 6 | metrics?: TTableStats & TMetrics; 7 | } 8 | 9 | export type IHeatmapMetricValue = keyof TTableStats | keyof TMetrics; 10 | 11 | export interface IHeatmapState { 12 | currentMetric?: IHeatmapMetricValue; 13 | sort: boolean; 14 | heatmap: boolean; 15 | } 16 | 17 | export interface IHeatmapApiRequestParams { 18 | path: string; 19 | database: string; 20 | } 21 | -------------------------------------------------------------------------------- /src/types/store/nodesList.ts: -------------------------------------------------------------------------------- 1 | export type NodesMap = Map< 2 | number, 3 | { 4 | Host?: string; 5 | DC?: string; 6 | } 7 | >; 8 | -------------------------------------------------------------------------------- /src/types/store/tablet.ts: -------------------------------------------------------------------------------- 1 | import type {ETabletState} from '../api/tablet'; 2 | 3 | export interface ITabletPreparedHistoryItem { 4 | nodeId: string; 5 | generation: number | undefined; 6 | changeTime: string | undefined; 7 | state: ETabletState | undefined; 8 | leader: boolean | undefined; 9 | followerId: number | undefined; 10 | fqdn: string | undefined; 11 | } 12 | -------------------------------------------------------------------------------- /src/types/store/tablets.ts: -------------------------------------------------------------------------------- 1 | export interface TabletsApiRequestParams { 2 | nodeId?: string | number; 3 | path?: string; 4 | database?: string; 5 | filter?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/types/store/topic.ts: -------------------------------------------------------------------------------- 1 | import type {ProcessSpeedStats} from '../../utils/bytesParsers'; 2 | 3 | export interface IPreparedConsumerData { 4 | name: string | undefined; 5 | readSpeed: ProcessSpeedStats; 6 | 7 | writeLag: number; 8 | readLag: number; 9 | readIdleTime: number; 10 | } 11 | 12 | export interface IPreparedTopicStats { 13 | storeSize: string; 14 | 15 | partitionsWriteLag: number; 16 | partitionsIdleTime: number; 17 | 18 | writeSpeed: ProcessSpeedStats; 19 | } 20 | -------------------------------------------------------------------------------- /src/types/unipika.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@gravity-ui/unipika'; 2 | -------------------------------------------------------------------------------- /src/types/versions.ts: -------------------------------------------------------------------------------- 1 | export type VersionsMap = Map>; 2 | export type VersionToColorMap = Map; 3 | 4 | export interface VersionValue { 5 | value: number; 6 | color: string | undefined; 7 | version: string; 8 | title: string; 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/additionalProps.ts: -------------------------------------------------------------------------------- 1 | import {backend} from '../store'; 2 | import type {AdditionalNodesProps} from '../types/additionalProps'; 3 | 4 | import {getBackendFromBalancerAndNodeId} from './prepareBackend'; 5 | 6 | export const getAdditionalNodesProps = (balancer = backend): AdditionalNodesProps => { 7 | return { 8 | getNodeRef: (node) => getBackendFromBalancerAndNodeId(node?.NodeId, balancer ?? ''), 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /src/utils/bytesParsers/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "b": "B", 3 | "kb": "KB", 4 | "mb": "MB", 5 | "gb": "GB", 6 | "tb": "TB", 7 | "label_thousand": "k", 8 | "label_million": "m", 9 | "label_billion": "b", 10 | "label_trillion": "t", 11 | "perSecond": "/s" 12 | } 13 | -------------------------------------------------------------------------------- /src/utils/bytesParsers/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-bytes-parsers'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/utils/bytesParsers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './formatBytes'; 2 | export * from './convertBytesObjectToSpeed'; 3 | -------------------------------------------------------------------------------- /src/utils/cn.ts: -------------------------------------------------------------------------------- 1 | import {withNaming} from '@bem-react/classname'; 2 | 3 | export const cn = withNaming({ 4 | e: '__', 5 | m: '_', 6 | }); 7 | -------------------------------------------------------------------------------- /src/utils/dataFormatters/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "format-cpu.cores": ["core", "cores", "cores", "cores"], 3 | 4 | "d": "d", 5 | "s": "s" 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/dataFormatters/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-format-cpu'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/utils/errors/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "unknown-error": "An unknown error occurred" 3 | } 4 | -------------------------------------------------------------------------------- /src/utils/errors/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-errors'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/utils/filters.ts: -------------------------------------------------------------------------------- 1 | import type {OrderType} from '@gravity-ui/react-data-table'; 2 | import {DESCENDING} from '@gravity-ui/react-data-table/build/esm/lib/constants'; 3 | import escapeRegExp from 'lodash/escapeRegExp'; 4 | 5 | import type {BackendSortParam} from '../types/api/common'; 6 | 7 | export const prepareSortValue = ( 8 | sortValue: T, 9 | sortOrder: OrderType = DESCENDING, 10 | ): BackendSortParam => { 11 | if (sortOrder === DESCENDING) { 12 | return `-${sortValue}`; 13 | } 14 | 15 | return sortValue; 16 | }; 17 | 18 | export const prepareSearchValue = (searchValue = '') => { 19 | return new RegExp(escapeRegExp(searchValue), 'i'); 20 | }; 21 | -------------------------------------------------------------------------------- /src/utils/generateHash.ts: -------------------------------------------------------------------------------- 1 | import crc32 from 'crc-32'; 2 | 3 | export const generateHash = (value: string) => { 4 | // 1. crc32.str(value) - generate crc32 hash 5 | // 2. (>>>) - use unsigned right shift operator (>>>) to avoid negative values 6 | // 3. toString(16) - convert hash to hex format 7 | // 4. toUpperCase() - convert hash to uppercase 8 | // 5. padStart(8, '0') - fill hash with leading zeros if hash length < 8 9 | // eslint-disable-next-line no-bitwise 10 | return (crc32.str(value) >>> 0).toString(16).toUpperCase().padStart(8, '0'); 11 | }; 12 | -------------------------------------------------------------------------------- /src/utils/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useTypedSelector'; 2 | export * from './useTypedDispatch'; 3 | export * from './useSetting'; 4 | export * from './useQueryExecutionSettings'; 5 | export * from './useTableSort'; 6 | export * from './useSearchQuery'; 7 | export * from './useAutoRefreshInterval'; 8 | export * from './useEventHandler'; 9 | -------------------------------------------------------------------------------- /src/utils/hooks/useAdditionalNodesProps.ts: -------------------------------------------------------------------------------- 1 | import {useClusterBaseInfo} from '../../store/reducers/cluster/cluster'; 2 | import {getAdditionalNodesProps} from '../additionalProps'; 3 | 4 | import {useTypedSelector} from './useTypedSelector'; 5 | 6 | /** For multi-cluster version */ 7 | export function useAdditionalNodesProps() { 8 | const {balancer} = useClusterBaseInfo(); 9 | const singleClusterMode = useTypedSelector((state) => state.singleClusterMode); 10 | 11 | const additionalNodesProps = getAdditionalNodesProps(balancer); 12 | 13 | return singleClusterMode ? undefined : additionalNodesProps; 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/hooks/useCancellable.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function useCancellableFunction void}>(cancellable: T) { 4 | React.useEffect(() => { 5 | return () => { 6 | cancellable.cancel(); 7 | }; 8 | }, [cancellable]); 9 | return cancellable; 10 | } 11 | -------------------------------------------------------------------------------- /src/utils/hooks/useDatabaseFromQuery.ts: -------------------------------------------------------------------------------- 1 | import {StringParam, useQueryParam} from 'use-query-params'; 2 | 3 | export function useDatabaseFromQuery() { 4 | const [database] = useQueryParam('database', StringParam); 5 | 6 | // Remove null from type 7 | return database ?? undefined; 8 | } 9 | 10 | export function useClusterNameFromQuery() { 11 | const [clusterName] = useQueryParam('clusterName', StringParam); 12 | 13 | // Remove null from type 14 | return clusterName ?? undefined; 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/hooks/useDelayed.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function useDelayed(delay = 600) { 4 | const [show, setShow] = React.useState(false); 5 | const [key, setKey] = React.useState(0); 6 | 7 | React.useEffect(() => { 8 | setShow(false); 9 | const timerId = setTimeout(() => { 10 | setShow(true); 11 | }, delay); 12 | 13 | return () => { 14 | clearTimeout(timerId); 15 | }; 16 | }, [delay, key]); 17 | 18 | const resetDelay = React.useCallback(() => { 19 | setKey((prevKey) => prevKey + 1); 20 | }, []); 21 | 22 | return [show, resetDelay] as const; 23 | } 24 | -------------------------------------------------------------------------------- /src/utils/hooks/useEventHandler.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | /** 4 | * The hook returns a stable function (an empty list of dependencies), 5 | * but this function always calls the actual function associated with the last render. 6 | * The returned function should be used as an event handler or inside a useEffect. 7 | */ 8 | export function useEventHandler(handler?: T) { 9 | const ref = React.useRef(handler); 10 | React.useLayoutEffect(() => { 11 | ref.current = handler; 12 | }, [handler]); 13 | // @ts-expect-error 14 | return React.useCallback((...args) => { 15 | return ref.current?.(...args); 16 | }, []); 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/hooks/useIsUserAllowedToMakeChanges.ts: -------------------------------------------------------------------------------- 1 | import {selectIsUserAllowedToMakeChanges} from '../../store/reducers/authentication/authentication'; 2 | 3 | import {useTypedSelector} from './useTypedSelector'; 4 | 5 | export function useIsUserAllowedToMakeChanges() { 6 | return useTypedSelector(selectIsUserAllowedToMakeChanges); 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/hooks/useSearchQuery.ts: -------------------------------------------------------------------------------- 1 | import {useLocation} from 'react-router-dom'; 2 | 3 | import {parseQuery} from '../../routes'; 4 | 5 | export const useSearchQuery = () => { 6 | const location = useLocation(); 7 | 8 | return parseQuery(location); 9 | }; 10 | -------------------------------------------------------------------------------- /src/utils/hooks/useTypedDispatch.ts: -------------------------------------------------------------------------------- 1 | import {useDispatch} from 'react-redux'; 2 | 3 | import type {AppDispatch} from '../../store'; 4 | 5 | export const useTypedDispatch: () => AppDispatch = useDispatch; 6 | -------------------------------------------------------------------------------- /src/utils/hooks/useTypedSelector.ts: -------------------------------------------------------------------------------- 1 | import type {TypedUseSelectorHook} from 'react-redux'; 2 | import {useSelector} from 'react-redux'; 3 | 4 | import type {RootState} from '../../store'; 5 | 6 | export const useTypedSelector: TypedUseSelectorHook = useSelector; 7 | -------------------------------------------------------------------------------- /src/utils/hooks/withConfirmation/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "action_apply": "Don't save", 3 | "context_unsaved-changes-warning": "You have unsaved changes in query editor.\nDo you want to proceed?" 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/hooks/withConfirmation/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../../i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-change-input-confirmation'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/utils/i18n/index.ts: -------------------------------------------------------------------------------- 1 | export * from './i18n'; 2 | -------------------------------------------------------------------------------- /src/utils/logs.ts: -------------------------------------------------------------------------------- 1 | export interface GetLogsLinkProps { 2 | dbName: string; 3 | logging: string; 4 | } 5 | 6 | export type GetLogsLink = (props: GetLogsLinkProps) => string; 7 | -------------------------------------------------------------------------------- /src/utils/monaco/constats.ts: -------------------------------------------------------------------------------- 1 | export const S_EXPRESSION_LANGUAGE_ID = 's-expression'; 2 | export const YQL_LANGUAGE_ID = 'yql'; 3 | -------------------------------------------------------------------------------- /src/utils/monaco/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "context_syntax-error": "Syntax error" 3 | } 4 | -------------------------------------------------------------------------------- /src/utils/monaco/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../i18n'; 2 | 3 | import en from './en.json'; 4 | 5 | const COMPONENT = 'ydb-monaco'; 6 | 7 | export default registerKeysets(COMPONENT, {en}); 8 | -------------------------------------------------------------------------------- /src/utils/numeral.ts: -------------------------------------------------------------------------------- 1 | import numeral from 'numeral'; 2 | import 'numeral/locales'; // Without this numeral will throw an error when using not 'en' locale 3 | 4 | import {Lang, i18n} from './i18n'; 5 | import {UNBREAKABLE_GAP} from './utils'; 6 | 7 | // Set space delimiter for all locales possible in project 8 | Object.values(Lang).forEach((value) => { 9 | if (numeral.locales[value]) { 10 | numeral.locales[value].delimiters.thousands = UNBREAKABLE_GAP; 11 | } 12 | }); 13 | 14 | numeral.locale(i18n.lang); 15 | 16 | export const configuredNumeral = numeral; 17 | -------------------------------------------------------------------------------- /src/utils/prepareBackend.ts: -------------------------------------------------------------------------------- 1 | import {prepareBackendFromBalancer} from './parseBalancer'; 2 | 3 | import {valueIsDefined} from '.'; 4 | 5 | export const prepareHost = (host?: string) => { 6 | // add "u-" prefix to cloud din nodes 7 | return host?.startsWith('vm-') ? `u-${host}` : host; 8 | }; 9 | 10 | /** For multi-cluster version */ 11 | export const getBackendFromBalancerAndNodeId = (nodeId?: string | number, balancer?: string) => { 12 | if (valueIsDefined(nodeId) && valueIsDefined(balancer)) { 13 | const preparedBalancer = prepareBackendFromBalancer(balancer); 14 | return `${preparedBalancer}/node/${nodeId}`; 15 | } 16 | 17 | return undefined; 18 | }; 19 | -------------------------------------------------------------------------------- /src/utils/prepareErrorMessage.ts: -------------------------------------------------------------------------------- 1 | export function prepareErrorMessage(error: unknown) { 2 | if (error && typeof error === 'string') { 3 | return error; 4 | } 5 | 6 | if (error && typeof error === 'object') { 7 | if ('data' in error && typeof error.data === 'string') { 8 | return error.data; 9 | } else if ('statusText' in error && typeof error.statusText === 'string') { 10 | return error.statusText; 11 | } else if ('message' in error && typeof error.message === 'string') { 12 | return error.message; 13 | } 14 | } 15 | 16 | return ''; 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/registerError.ts: -------------------------------------------------------------------------------- 1 | export function registerError(error: Error, message?: string, type = 'error') { 2 | if (typeof window !== 'undefined' && window.Ya?.Rum) { 3 | window.Ya.Rum.logError( 4 | { 5 | additional: { 6 | url: window.location.href, 7 | }, 8 | type, 9 | message, 10 | level: window.Ya.Rum.ERROR_LEVEL.ERROR, 11 | }, 12 | error, 13 | ); 14 | } else { 15 | // eslint-disable-next-line no-console 16 | console.error(error); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/renderPaginatedTableErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | import {AccessDenied} from '../components/Errors/403'; 2 | import {ResponseError} from '../components/Errors/ResponseError'; 3 | import type {RenderErrorMessage} from '../components/PaginatedTable'; 4 | 5 | export const renderPaginatedTableErrorMessage: RenderErrorMessage = (error) => { 6 | if (error.status === 403) { 7 | return ; 8 | } 9 | 10 | return ; 11 | }; 12 | -------------------------------------------------------------------------------- /src/utils/storage.ts: -------------------------------------------------------------------------------- 1 | interface EntityWithUsage { 2 | Used: number; 3 | Limit: number; 4 | } 5 | 6 | export const getUsage = (data: T, step = 1) => { 7 | // if limit is 0, display 0 8 | const usage = data.Limit ? (data.Used * 100) / data.Limit : 0; 9 | 10 | return Math.floor(usage / step) * step; 11 | }; 12 | -------------------------------------------------------------------------------- /src/utils/tableUtils/getRequiredDataFields.ts: -------------------------------------------------------------------------------- 1 | export function getRequiredDataFields( 2 | columns: string[], 3 | columnsToFields: Record, 4 | ) { 5 | const requiredFieldsSet = columns.reduce((fields, column) => { 6 | const columnFields = columnsToFields[column as ColumnId]; 7 | columnFields.forEach((field) => { 8 | fields.add(field); 9 | }); 10 | 11 | return fields; 12 | }, new Set()); 13 | 14 | return Array.from(requiredFieldsSet).sort(); 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/tableUtils/types.ts: -------------------------------------------------------------------------------- 1 | import type {Column as DataTableColumn} from '@gravity-ui/react-data-table'; 2 | 3 | import type {Column as PaginatedTableColumn} from '../../components/PaginatedTable'; 4 | 5 | export type Column = PaginatedTableColumn & DataTableColumn; 6 | -------------------------------------------------------------------------------- /src/utils/timeParsers/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "daysHours": "{{days}}\u00a0d\u00a0{{hours}}\u00a0h", 3 | "hoursMin": "{{hours}}\u00a0h\u00a0{{minutes}}\u00a0m", 4 | "minSec": "{{minutes}}\u00a0m\u00a0{{seconds}}\u00a0s", 5 | "secMs": "{{seconds}}\u00a0s\u00a0{{ms}}\u00a0ms", 6 | "days": "{{days}}\u00a0d", 7 | "hours": "{{hours}}\u00a0h", 8 | "min": "{{minutes}}\u00a0m", 9 | "sec": "{{seconds}}\u00a0s", 10 | "ms": "{{ms}}\u00a0ms" 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/timeParsers/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import {registerKeysets} from '../../i18n'; 2 | 3 | import en from './en.json'; 4 | import ru from './ru.json'; 5 | 6 | const COMPONENT = 'ydb-time-parsers'; 7 | 8 | export default registerKeysets(COMPONENT, {ru, en}); 9 | -------------------------------------------------------------------------------- /src/utils/timeParsers/i18n/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "daysHours": "{{days}}\u00a0д\u00a0{{hours}}\u00a0ч", 3 | "hoursMin": "{{hours}}\u00a0ч\u00a0{{minutes}}\u00a0м", 4 | "minSec": "{{minutes}}\u00a0м\u00a0{{seconds}}\u00a0с", 5 | "secMs": "{{seconds}}\u00a0с\u00a0{{ms}}\u00a0мс", 6 | "days": "{{days}}\u00a0д", 7 | "hours": "{{hours}}\u00a0ч", 8 | "min": "{{minutes}}\u00a0м", 9 | "sec": "{{seconds}}\u00a0с", 10 | "ms": "{{ms}}\u00a0мс" 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/timeParsers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './formatDuration'; 2 | export * from './protobufParsers'; 3 | export * from './parsers'; 4 | -------------------------------------------------------------------------------- /src/utils/timeframes.ts: -------------------------------------------------------------------------------- 1 | import {DAY_IN_SECONDS, HOUR_IN_SECONDS, MINUTE_IN_SECONDS} from './constants'; 2 | 3 | export const TIMEFRAMES = { 4 | '30m': 30 * MINUTE_IN_SECONDS, 5 | '1h': HOUR_IN_SECONDS, 6 | '1d': DAY_IN_SECONDS, 7 | '1w': 7 * DAY_IN_SECONDS, 8 | } as const; 9 | 10 | export type TimeFrame = keyof typeof TIMEFRAMES; 11 | -------------------------------------------------------------------------------- /src/utils/typecheckers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Intended to typecheck enums, but also checks if the value is any of the arbitrary object values 3 | */ 4 | export const isEnumMember = (object: T, value: any): value is T[keyof T] => 5 | Object.values(object).includes(value); 6 | 7 | export type Nullable = T | null; 8 | -------------------------------------------------------------------------------- /src/utils/versions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getVersionsColors'; 2 | export * from './parseVersion'; 3 | export * from './parseNodesToVersionsValues'; 4 | -------------------------------------------------------------------------------- /tests/models/BaseModel.ts: -------------------------------------------------------------------------------- 1 | import type {Locator, Page} from '@playwright/test'; 2 | 3 | export class BaseModel { 4 | readonly page: Page; 5 | readonly selector: Locator; 6 | 7 | constructor(page: Page, selector: Locator) { 8 | this.page = page; 9 | this.selector = selector; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/suites/internalViewer/internalViewer.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, test} from '@playwright/test'; 2 | 3 | test.describe('Test InternalViewer', async () => { 4 | test('Test internalViewer header link', async ({page}) => { 5 | page.goto(''); 6 | const link = page.locator('header').locator('a').filter({hasText: 'Developer UI'}); 7 | const href = await link.getAttribute('href'); 8 | 9 | expect(href).not.toBeNull(); 10 | 11 | const response = await page.goto(href as string); 12 | expect(response?.ok()).toBe(true); 13 | 14 | expect(await page.title()).toContain('YDB Developer UI'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tests/suites/tenant/summary/types.ts: -------------------------------------------------------------------------------- 1 | export enum RowTableAction { 2 | CopyPath = 'Copy path', 3 | AlterTable = 'Alter table...', 4 | DropTable = 'Drop table...', 5 | SelectQuery = 'Select query...', 6 | UpsertQuery = 'Upsert query...', 7 | AddIndex = 'Add index...', 8 | CreateChangefeed = 'Create changefeed...', 9 | CreateDirectory = 'Create directory', 10 | } 11 | -------------------------------------------------------------------------------- /tests/suites/tenants/TenantsPage.ts: -------------------------------------------------------------------------------- 1 | import type {Locator, Page} from '@playwright/test'; 2 | 3 | import {PageModel} from '../../models/PageModel'; 4 | import {tenantsPage} from '../../utils/constants'; 5 | import {selectContentTable} from '../../utils/selectContentTable'; 6 | 7 | export class TenantsPage extends PageModel { 8 | readonly table: Locator; 9 | 10 | constructor(page: Page) { 11 | super(page, tenantsPage); 12 | 13 | this.table = selectContentTable(this.selector); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/utils/constants.ts: -------------------------------------------------------------------------------- 1 | // Pages 2 | export const tenantsPage = 'cluster/tenants'; 3 | export const nodesPage = 'cluster/nodes'; 4 | export const storagePage = 'cluster/storage'; 5 | export const clusterPage = 'cluster/cluster'; 6 | export const authPage = 'auth'; 7 | export const tenantPage = 'tenant'; 8 | 9 | // Entities 10 | export const tenantName = '/local'; 11 | export const dsVslotsSchema = '/local/.sys/ds_vslots'; 12 | export const dsVslotsTableName = 'ds_vslots'; 13 | export const dsStorageStatsTableName = 'ds_storage_stats'; 14 | export const dsStoragePoolsTableName = 'ds_storage_pools'; 15 | 16 | // URLs 17 | export const backend = process.env.PLAYWRIGHT_APP_BACKEND || 'http://localhost:8765'; 18 | -------------------------------------------------------------------------------- /tests/utils/retryAction.ts: -------------------------------------------------------------------------------- 1 | export const retryAction = async ( 2 | action: () => Promise, 3 | maxAttempts = 3, 4 | delay = 1000, 5 | ): Promise => { 6 | for (let attempt = 1; attempt <= maxAttempts; attempt++) { 7 | try { 8 | return await action(); 9 | } catch (error) { 10 | if (attempt === maxAttempts) { 11 | throw error; 12 | } 13 | await new Promise((resolve) => setTimeout(resolve, delay)); 14 | } 15 | } 16 | throw new Error('Max attempts reached'); 17 | }; 18 | -------------------------------------------------------------------------------- /tests/utils/selectContentTable.ts: -------------------------------------------------------------------------------- 1 | import type {Locator} from '@playwright/test'; 2 | 3 | // react-data-table has 2 table elements - for header and for the content 4 | // so we select content table that is wrapped with .data-table__box 5 | export const selectContentTable = (selector: Locator) => { 6 | return selector.locator('.data-table__box').getByRole('table'); 7 | }; 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@gravity-ui/tsconfig/tsconfig", 3 | "compilerOptions": { 4 | "outDir": "build/esm", 5 | "target": "ES2018", 6 | "module": "ESNext", 7 | "moduleResolution": "Bundler", 8 | "jsx": "react-jsx", 9 | "lib": ["dom", "dom.iterable", "esnext"], 10 | "allowSyntheticDefaultImports": true, 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "noEmit": true 14 | }, 15 | "exclude": ["build", "dist"] 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.package.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src", 6 | "declaration": true, 7 | "sourceMap": true, 8 | "noEmit": false, 9 | "importHelpers": true 10 | }, 11 | "include": ["src/**/*"], 12 | "exclude": ["src/setup*", "src/index.tsx", "**/__tests__", "**/tests"] 13 | } 14 | --------------------------------------------------------------------------------