Skip to content

Commit 113aad8

Browse files
Copilotastandrik
andcommitted
feat: add monitoring tab to database diagnostics page
Co-authored-by: astandrik <[email protected]>
1 parent e5540ee commit 113aad8

File tree

10 files changed

+194
-17
lines changed

10 files changed

+194
-17
lines changed

src/containers/Tenant/Diagnostics/Diagnostics.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,8 @@
4545
// This prevents inheritance issues with percentage-based calculations
4646
container-type: size;
4747
}
48+
49+
&__new-label {
50+
margin-left: 8px;
51+
}
4852
}

src/containers/Tenant/Diagnostics/Diagnostics.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22

3-
import {Tab, TabList, TabProvider} from '@gravity-ui/uikit';
3+
import {Label, Tab, TabList, TabProvider} from '@gravity-ui/uikit';
44
import {Helmet} from 'react-helmet-async';
55

66
import {AutoRefreshControl} from '../../../components/AutoRefreshControl/AutoRefreshControl';
@@ -33,6 +33,7 @@ import Describe from './Describe/Describe';
3333
import DetailedOverview from './DetailedOverview/DetailedOverview';
3434
import {getPagesByType, useDiagnosticsPageLinkGetter} from './DiagnosticsPages';
3535
import {HotKeys} from './HotKeys/HotKeys';
36+
import {Monitoring} from './Monitoring/Monitoring';
3637
import {NetworkWrapper} from './Network/NetworkWrapper';
3738
import {Partitions} from './Partitions/Partitions';
3839
import {TopQueries} from './TopQueries';
@@ -98,6 +99,15 @@ function Diagnostics({additionalTenantProps}: DiagnosticsProps) {
9899
/>
99100
);
100101
}
102+
case TENANT_DIAGNOSTICS_TABS_IDS.monitoring: {
103+
const monitoringUrl = additionalTenantProps?.getMonitoringLink?.(
104+
database,
105+
databaseType,
106+
);
107+
return (
108+
<Monitoring database={database} monitoringUrl={monitoringUrl || undefined} />
109+
);
110+
}
101111
case TENANT_DIAGNOSTICS_TABS_IDS.schema: {
102112
return (
103113
<SchemaViewer
@@ -220,17 +230,35 @@ function Diagnostics({additionalTenantProps}: DiagnosticsProps) {
220230
}
221231
};
222232
const renderTabs = () => {
233+
// Date when the Monitoring tab was added (Oct 22, 2025)
234+
const MONITORING_TAB_LAUNCH_DATE = new Date('2025-10-22');
235+
const FOURTEEN_DAYS_MS = 14 * 24 * 60 * 60 * 1000;
236+
const now = new Date();
237+
const showNewLabel =
238+
now.getTime() - MONITORING_TAB_LAUNCH_DATE.getTime() < FOURTEEN_DAYS_MS;
239+
223240
return (
224241
<div className={b('header-wrapper')}>
225242
<div className={b('tabs')}>
226243
<TabProvider value={activeTab?.id}>
227244
<TabList size="l">
228245
{pages.map(({id, title}) => {
229246
const linkPath = getDiagnosticsPageLink(id);
247+
const isMonitoringTab =
248+
id === TENANT_DIAGNOSTICS_TABS_IDS.monitoring;
230249
return (
231250
<Tab key={id} value={id}>
232251
<InternalLink to={linkPath} as="tab">
233252
{title}
253+
{isMonitoringTab && showNewLabel && (
254+
<Label
255+
theme="info"
256+
size="xs"
257+
className={b('new-label')}
258+
>
259+
New
260+
</Label>
261+
)}
234262
</InternalLink>
235263
</Tab>
236264
);

src/containers/Tenant/Diagnostics/DiagnosticsPages.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ const overview = {
2929
title: 'Info',
3030
};
3131

32+
const monitoring = {
33+
id: TENANT_DIAGNOSTICS_TABS_IDS.monitoring,
34+
title: 'Monitoring',
35+
};
36+
3237
const schema = {
3338
id: TENANT_DIAGNOSTICS_TABS_IDS.schema,
3439
title: 'Schema',
@@ -115,6 +120,7 @@ const TRANSFER_PAGES = [overview, tablets, describe, access];
115120

116121
const DATABASE_PAGES = [
117122
overview,
123+
monitoring,
118124
topQueries,
119125
topShards,
120126
nodes,
@@ -130,6 +136,7 @@ const DATABASE_PAGES = [
130136

131137
const SERVERLESS_DATABASE_PAGES = [
132138
overview,
139+
monitoring,
133140
topQueries,
134141
topShards,
135142
tablets,
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
@use '../../../../styles/mixins';
2+
3+
.ydb-monitoring {
4+
display: flex;
5+
flex-direction: column;
6+
7+
width: 100%;
8+
height: 100%;
9+
10+
&__controls {
11+
padding: 16px 20px;
12+
13+
border-bottom: 1px solid var(--g-color-line-generic);
14+
}
15+
16+
&__content {
17+
position: relative;
18+
19+
overflow: hidden;
20+
flex: 1;
21+
}
22+
23+
&__iframe {
24+
width: 100%;
25+
height: 100%;
26+
27+
border: none;
28+
}
29+
30+
&__empty {
31+
display: flex;
32+
justify-content: center;
33+
align-items: center;
34+
35+
width: 100%;
36+
height: 100%;
37+
}
38+
39+
&__empty-text {
40+
font-size: 16px;
41+
42+
color: var(--g-color-text-secondary);
43+
}
44+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import React from 'react';
2+
3+
import {SegmentedRadioGroup} from '@gravity-ui/uikit';
4+
5+
import {cn} from '../../../../utils/cn';
6+
7+
import './Monitoring.scss';
8+
9+
const b = cn('ydb-monitoring');
10+
11+
interface MonitoringProps {
12+
database: string;
13+
monitoringUrl?: string;
14+
}
15+
16+
const MONITORING_TABS = [
17+
{value: 'diagnostics', content: 'Diagnostics'},
18+
{value: 'transactions', content: 'Transactions'},
19+
{value: 'calling-api', content: 'Calling API'},
20+
{value: 'yql-queries', content: 'YQL Queries'},
21+
{value: 'tables-rw', content: 'Tables R/W'},
22+
{value: 'topics-rw', content: 'Topics R/W'},
23+
];
24+
25+
export function Monitoring({monitoringUrl}: MonitoringProps) {
26+
const [activeTab, setActiveTab] = React.useState('diagnostics');
27+
28+
if (!monitoringUrl) {
29+
return (
30+
<div className={b('empty')}>
31+
<div className={b('empty-text')}>Monitoring is not available</div>
32+
</div>
33+
);
34+
}
35+
36+
return (
37+
<div className={b()}>
38+
<div className={b('controls')}>
39+
<SegmentedRadioGroup
40+
size="l"
41+
value={activeTab}
42+
onUpdate={setActiveTab}
43+
options={MONITORING_TABS}
44+
/>
45+
</div>
46+
<div className={b('content')}>
47+
<iframe
48+
className={b('iframe')}
49+
src={monitoringUrl}
50+
title="YDB Monitoring Dashboard"
51+
frameBorder="0"
52+
/>
53+
</div>
54+
</div>
55+
);
56+
}

src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Button, Flex, HelpMark, Icon, Label} from '@gravity-ui/uikit';
1+
import {Button, Flex, HelpMark, Icon, Label, Tooltip} from '@gravity-ui/uikit';
22

33
import {EntityStatus} from '../../../../components/EntityStatus/EntityStatus';
44
import {LoaderWrapper} from '../../../../components/LoaderWrapper/LoaderWrapper';
@@ -186,17 +186,37 @@ export function TenantOverview({
186186
<Flex alignItems="center" gap="1" className={b('top')}>
187187
{renderName()}
188188
<Flex gap="2">
189-
{links.map(({title, url, icon}) => (
190-
<Button
191-
key={title}
192-
href={url}
193-
target="_blank"
194-
size="xs"
195-
title={title}
196-
>
189+
{links.map(({title, url, icon}) => {
190+
const isMonitoring = title === i18n('field_monitoring-link');
191+
const buttonContent = isMonitoring ? (
192+
<>
193+
<Icon data={icon} />
194+
Monium
195+
</>
196+
) : (
197197
<Icon data={icon} />
198-
</Button>
199-
))}
198+
);
199+
200+
const button = (
201+
<Button
202+
key={title}
203+
href={url}
204+
target="_blank"
205+
size="xs"
206+
title={isMonitoring ? undefined : title}
207+
>
208+
{buttonContent}
209+
</Button>
210+
);
211+
212+
return isMonitoring ? (
213+
<Tooltip key={title} content={i18n('tooltip_monium')}>
214+
{button}
215+
</Tooltip>
216+
) : (
217+
button
218+
);
219+
})}
200220
</Flex>
201221
</Flex>
202222
<Flex direction="column" gap={4}>

src/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,7 @@
4141
"value_serverless": "Serverless",
4242
"context_serverless-tooltip": "Some metrics are hidden in Serverless mode — resources scale automatically based on workload",
4343
"context_serverless-autoscaled": "Auto-Scaled Resources",
44-
"context_serverless-storage-subtitle": "{{legend}} | {{groups}} groups"
44+
"context_serverless-storage-subtitle": "{{legend}} | {{groups}} groups",
45+
"field_monitoring-link": "Monitoring",
46+
"tooltip_monium": "Full monitoring in Monium"
4547
}

src/containers/Tenant/i18n/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"actions.notCopied": "Couldn’t copy the path",
2727
"actions.copyPath": "Copy path",
2828
"actions.connectToDB": "Connect to DB",
29+
"actions.monitoring": "Monitoring",
2930
"actions.dropIndex": "Drop index",
3031
"actions.openPreview": "Open preview",
3132
"actions.createTable": "Create table...",

src/containers/Tenant/utils/schemaActions.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
import {CirclePlus, Copy, PlugConnection} from '@gravity-ui/icons';
1+
import {CirclePlus, Copy, PlugConnection, Pulse} from '@gravity-ui/icons';
22
import {Flex, Spin} from '@gravity-ui/uikit';
33
import copy from 'copy-to-clipboard';
44
import type {NavigationTreeNodeType} from 'ydb-ui-components';
55

66
import type {SnippetParams} from '../../../components/ConnectToDB/types';
77
import type {AppDispatch} from '../../../store';
8-
import {TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../store/reducers/tenant/constants';
9-
import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
8+
import {
9+
TENANT_DIAGNOSTICS_TABS_IDS,
10+
TENANT_PAGES_IDS,
11+
TENANT_QUERY_TABS_ID,
12+
} from '../../../store/reducers/tenant/constants';
13+
import {setDiagnosticsTab, setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
1014
import createToast from '../../../utils/createToast';
1115
import {insertSnippetToEditor} from '../../../utils/monaco/insertSnippet';
1216
import {transformPath} from '../ObjectSummary/transformPath';
@@ -98,6 +102,11 @@ const bindActions = (
98102
}
99103
: undefined,
100104
getConnectToDBDialog: () => getConnectToDBDialog?.({database: params.database}),
105+
goToMonitoring: () => {
106+
dispatch(setTenantPage(TENANT_PAGES_IDS.diagnostics));
107+
dispatch(setDiagnosticsTab(TENANT_DIAGNOSTICS_TABS_IDS.monitoring));
108+
setActivePath(params.path);
109+
},
101110
createTable: inputQuery(createTableTemplate),
102111
createColumnTable: inputQuery(createColumnTableTemplate),
103112
createAsyncReplication: inputQuery(createAsyncReplicationTemplate),
@@ -190,6 +199,11 @@ export const getActions =
190199
action: actions.getConnectToDBDialog,
191200
iconStart: <PlugConnection />,
192201
};
202+
const monitoringItem = {
203+
text: i18n('actions.monitoring'),
204+
action: actions.goToMonitoring,
205+
iconStart: <Pulse />,
206+
};
193207

194208
const createEntitiesSet = [
195209
{text: i18n('actions.createTable'), action: actions.createTable},
@@ -216,7 +230,7 @@ export const getActions =
216230
},
217231
],
218232
};
219-
const DB_SET: ActionsSet = [[copyItem, connectToDBItem], createEntitiesSet];
233+
const DB_SET: ActionsSet = [[copyItem, connectToDBItem, monitoringItem], createEntitiesSet];
220234

221235
const DIR_SET: ActionsSet = [[copyItem], createEntitiesSet];
222236

src/store/reducers/tenant/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const TENANT_QUERY_TABS_ID = {
1313

1414
export const TENANT_DIAGNOSTICS_TABS_IDS = {
1515
overview: 'overview',
16+
monitoring: 'monitoring',
1617
schema: 'schema',
1718
topQueries: 'topQueries',
1819
topShards: 'topShards',

0 commit comments

Comments
 (0)