Skip to content

Commit 2a05ad5

Browse files
feat: show streaming query stats in Info tab (#3060)
1 parent c9733a7 commit 2a05ad5

File tree

16 files changed

+428
-71
lines changed

16 files changed

+428
-71
lines changed

src/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,9 @@
2525
top: 23px;
2626
right: 13px;
2727
}
28+
29+
// Delete padding for all query text on Diagnostics -> Info tab
30+
pre {
31+
padding: 0;
32+
}
2833
}

src/containers/Tenant/Diagnostics/Overview/Overview.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {ViewInfo} from '../../Info/View/View';
1313

1414
import {AsyncReplicationInfo} from './AsyncReplicationInfo';
1515
import {ChangefeedInfo} from './ChangefeedInfo';
16+
import {StreamingQueryInfo} from './StreamingQueryInfo';
1617
import {TableInfo} from './TableInfo';
1718
import {TopicInfo} from './TopicInfo';
1819
import {TransferInfo} from './TransferInfo';
@@ -77,7 +78,9 @@ function Overview({type, path, database, databaseFullPath}: OverviewProps) {
7778
data={data}
7879
/>
7980
),
80-
[EPathType.EPathTypeStreamingQuery]: undefined,
81+
[EPathType.EPathTypeStreamingQuery]: () => (
82+
<StreamingQueryInfo data={data} path={path} database={database} />
83+
),
8184
};
8285

8386
return (type && pathTypeToComponent[type]?.()) || <TableInfo data={data} type={type} />;
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import React from 'react';
2+
3+
import {Label} from '@gravity-ui/uikit';
4+
5+
import {YDBSyntaxHighlighter} from '../../../../../components/SyntaxHighlighter/YDBSyntaxHighlighter';
6+
import {YDBDefinitionList} from '../../../../../components/YDBDefinitionList/YDBDefinitionList';
7+
import type {YDBDefinitionListItem} from '../../../../../components/YDBDefinitionList/YDBDefinitionList';
8+
import {streamingQueriesApi} from '../../../../../store/reducers/streamingQuery/streamingQuery';
9+
import type {ErrorResponse} from '../../../../../types/api/query';
10+
import type {TEvDescribeSchemeResult} from '../../../../../types/api/schema';
11+
import type {IQueryResult} from '../../../../../types/store/query';
12+
import {
13+
getStringifiedData,
14+
stripIndentByFirstLine,
15+
trimOuterEmptyLines,
16+
} from '../../../../../utils/dataFormatters/dataFormatters';
17+
import {isErrorResponse} from '../../../../../utils/query';
18+
import {ResultIssuesModal} from '../../../Query/Issues/Issues';
19+
import {getEntityName} from '../../../utils';
20+
21+
import i18n from './i18n';
22+
23+
interface StreamingQueryProps {
24+
data?: TEvDescribeSchemeResult;
25+
database: string;
26+
path: string;
27+
}
28+
29+
/** Displays overview for StreamingQuery EPathType */
30+
export function StreamingQueryInfo({data, database, path}: StreamingQueryProps) {
31+
const entityName = getEntityName(data?.PathDescription);
32+
33+
if (!data) {
34+
return (
35+
<div className="error">
36+
{i18n('alert_no-data')} {entityName}
37+
</div>
38+
);
39+
}
40+
41+
const {data: sysData} = streamingQueriesApi.useGetStreamingQueryInfoQuery(
42+
{database, path},
43+
{skip: !database || !path},
44+
);
45+
46+
const items = prepareStreamingQueryItems(sysData);
47+
48+
return <YDBDefinitionList title={entityName} items={items} />;
49+
}
50+
51+
const STATE_THEME_MAP: Record<string, React.ComponentProps<typeof Label>['theme']> = {
52+
CREATING: 'info',
53+
CREATED: 'normal',
54+
STARTING: 'info',
55+
RUNNING: 'success',
56+
STOPPING: 'info',
57+
STOPPED: 'normal',
58+
COMPLETED: 'success',
59+
SUSPENDED: 'warning',
60+
FAILED: 'danger',
61+
};
62+
63+
function StateLabel({state}: {state?: string}) {
64+
if (!state) {
65+
return null;
66+
}
67+
68+
const theme = STATE_THEME_MAP[state] ?? 'normal';
69+
70+
return <Label theme={theme}>{state}</Label>;
71+
}
72+
73+
function prepareStreamingQueryItems(sysData?: IQueryResult): YDBDefinitionListItem[] {
74+
if (!sysData) {
75+
return [];
76+
}
77+
78+
const info: YDBDefinitionListItem[] = [];
79+
const state = getStringifiedData(sysData.resultSets?.[0]?.result?.[0]?.State);
80+
81+
const queryText = getStringifiedData(sysData.resultSets?.[0]?.result?.[0]?.Text);
82+
let normalizedQueryText = trimOuterEmptyLines(queryText);
83+
normalizedQueryText = stripIndentByFirstLine(normalizedQueryText);
84+
85+
const errorRaw = sysData.resultSets?.[0]?.result?.[0]?.Error;
86+
87+
// We use custom error check, because error type can be non-standard
88+
const errorData = parseErrorData(errorRaw);
89+
90+
info.push({
91+
name: i18n('field_query-state'),
92+
content: <StateLabel state={state} />,
93+
});
94+
95+
if (errorData) {
96+
info.push({
97+
name: i18n('field_query-error'),
98+
content: <ResultIssuesModal data={errorData} />,
99+
});
100+
}
101+
102+
info.push({
103+
name: i18n('field_query-text'),
104+
copyText: normalizedQueryText,
105+
content: normalizedQueryText ? (
106+
<YDBSyntaxHighlighter language="yql" text={normalizedQueryText} />
107+
) : null,
108+
});
109+
110+
return info;
111+
}
112+
113+
function parseErrorData(raw: unknown): ErrorResponse | string | undefined {
114+
if (typeof raw === 'string') {
115+
try {
116+
const parsed = JSON.parse(raw);
117+
return isErrorResponse(parsed) ? parsed : undefined;
118+
} catch {
119+
return raw;
120+
}
121+
}
122+
123+
if (isErrorResponse(raw)) {
124+
return raw;
125+
}
126+
127+
return undefined;
128+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"alert_no-data": "No data for entity:",
3+
"field_query-state": "State",
4+
"field_query-error": "Error",
5+
"field_query-text": "Text"
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {registerKeysets} from '../../../../../../utils/i18n';
2+
3+
import en from './en.json';
4+
5+
const COMPONENT = 'ydb-diagnostics-streaming-query-info';
6+
7+
export default registerKeysets(COMPONENT, {en});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './StreamingQueryInfo';

src/containers/Tenant/Query/Issues/Issues.scss

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
.kv-result-issues {
2-
padding: 0 10px;
3-
42
&__error-message {
53
position: sticky;
64
z-index: 2;
@@ -10,8 +8,6 @@
108
display: flex;
119
align-items: center;
1210

13-
padding: 10px 0;
14-
1511
background-color: var(--g-color-base-background);
1612
}
1713

0 commit comments

Comments
 (0)