Skip to content

Commit 017fb56

Browse files
committed
fix: review fixes
1 parent 9bb5f0b commit 017fb56

File tree

5 files changed

+133
-94
lines changed

5 files changed

+133
-94
lines changed

src/containers/Tenant/Query/QueryResult/QueryResultViewer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,9 @@ export function QueryResultViewer({
190190
return (
191191
<QueryInfoDropdown
192192
queryResultsInfo={{
193+
queryText,
193194
ast: data.ast,
194195
stats: data.stats,
195-
queryText,
196196
plan: data.plan,
197197
}}
198198
error={error}

src/containers/Tenant/Query/QueryResult/components/QueryInfoDropdown/QueryInfoDropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import {Ellipsis} from '@gravity-ui/icons';
22
import type {ButtonProps} from '@gravity-ui/uikit';
33
import {Button, DropdownMenu} from '@gravity-ui/uikit';
44

5-
import type {QueryResultsInfo} from './useQueryInfoMenuItems';
65
import {useQueryInfoMenuItems} from './useQueryInfoMenuItems';
6+
import type {QueryResultsInfo} from './utils';
77

88
import './QueryInfoDropdown.scss';
99

src/containers/Tenant/Query/QueryResult/components/QueryInfoDropdown/useQueryInfoMenuItems.tsx

Lines changed: 19 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ import type {DropdownMenuItem} from '@gravity-ui/uikit';
55
import {Text} from '@gravity-ui/uikit';
66

77
import {planToSvgApi} from '../../../../../../store/reducers/planToSvg';
8-
import type {QueryPlan, ScriptPlan, TKqpStatsQuery} from '../../../../../../types/api/query';
98
import {cn} from '../../../../../../utils/cn';
10-
import createToast from '../../../../../../utils/createToast';
11-
import {prepareCommonErrorMessage} from '../../../../../../utils/errors';
12-
import {parseQueryError} from '../../../../../../utils/query';
139
import i18n from '../../i18n';
10+
11+
import {
12+
createHandleDiagnosticsDownload,
13+
createHandleDownload,
14+
createHandleOpenInNewTab,
15+
} from './utils';
16+
import type {QueryResultsInfo} from './utils';
1417
const b = cn('query-info-dropdown');
1518

1619
export interface MenuItemContentProps {
@@ -29,19 +32,6 @@ export function MenuItemContent({title, description}: MenuItemContentProps) {
2932
);
3033
}
3134

32-
export interface QueryResultsInfo {
33-
ast?: string;
34-
stats?: TKqpStatsQuery;
35-
queryText?: string;
36-
plan?: QueryPlan | ScriptPlan;
37-
}
38-
39-
export interface DiagnosticsData extends QueryResultsInfo {
40-
database: string;
41-
timestamp: string;
42-
error?: ReturnType<typeof parseQueryError>;
43-
}
44-
4535
export interface UseQueryInfoMenuItemsProps {
4636
queryResultsInfo: QueryResultsInfo;
4737
database: string;
@@ -71,61 +61,24 @@ export function useQueryInfoMenuItems({
7161

7262
const plan = queryResultsInfo.plan;
7363
if (plan && hasPlanToSvg) {
74-
const handleGetSvg = () => {
75-
if (blobUrl) {
76-
return Promise.resolve(blobUrl);
77-
}
78-
79-
return getPlanToSvg({plan, database})
80-
.unwrap()
81-
.then((result) => {
82-
const blob = new Blob([result], {type: 'image/svg+xml'});
83-
const url = URL.createObjectURL(blob);
84-
setBlobUrl(url);
85-
return url;
86-
})
87-
.catch((err) => {
88-
const errorMessage = prepareCommonErrorMessage(err);
89-
createToast({
90-
title: i18n('text_error-plan-svg', {error: errorMessage}),
91-
name: 'plan-svg-error',
92-
type: 'error',
93-
});
94-
return null;
95-
});
96-
};
97-
98-
const handleOpenInNewTab = () => {
99-
handleGetSvg().then((url) => {
100-
if (url) {
101-
window.open(url, '_blank');
102-
}
103-
});
104-
};
105-
106-
const handleDownload = () => {
107-
handleGetSvg().then((url) => {
108-
const link = document.createElement('a');
109-
if (url) {
110-
link.href = url;
111-
link.download = 'query-plan.svg';
112-
document.body.appendChild(link);
113-
link.click();
114-
document.body.removeChild(link);
115-
}
116-
});
64+
const handlersParams = {
65+
plan,
66+
database,
67+
blobUrl,
68+
getPlanToSvg,
69+
setBlobUrl,
11770
};
11871

11972
menuItems.push([
12073
{
12174
text: (
12275
<MenuItemContent
123-
title={i18n('text_open-new-tab')}
124-
description={i18n('text_open-new-tab_description')}
76+
title={i18n('text_open-execution-plan')}
77+
description={i18n('text_open-execution-plan_description')}
12578
/>
12679
),
12780
icon: <ArrowUpRightFromSquare className={b('icon')} />,
128-
action: handleOpenInNewTab,
81+
action: createHandleOpenInNewTab(handlersParams),
12982
className: b('menu-item'),
13083
},
13184
{
@@ -136,35 +89,13 @@ export function useQueryInfoMenuItems({
13689
/>
13790
),
13891
icon: <ArrowDownToLine className={b('icon')} />,
139-
action: handleDownload,
92+
action: createHandleDownload(handlersParams),
14093
className: b('menu-item'),
14194
},
14295
]);
14396
}
14497

14598
if (queryResultsInfo) {
146-
const handleDiagnosticsDownload = () => {
147-
const parsedError = error ? parseQueryError(error) : undefined;
148-
const diagnosticsData: DiagnosticsData = {
149-
...queryResultsInfo,
150-
database,
151-
timestamp: new Date().toISOString(),
152-
...(parsedError && {error: parsedError}),
153-
};
154-
155-
const blob = new Blob([JSON.stringify(diagnosticsData, null, 2)], {
156-
type: 'application/json',
157-
});
158-
const url = URL.createObjectURL(blob);
159-
const link = document.createElement('a');
160-
link.href = url;
161-
link.download = `query-diagnostics-${new Date().getTime()}.json`;
162-
document.body.appendChild(link);
163-
link.click();
164-
document.body.removeChild(link);
165-
URL.revokeObjectURL(url);
166-
};
167-
16899
menuItems.push([
169100
{
170101
text: (
@@ -174,14 +105,14 @@ export function useQueryInfoMenuItems({
174105
/>
175106
),
176107
icon: <ArrowDownToLine className={b('icon')} />,
177-
action: handleDiagnosticsDownload,
108+
action: createHandleDiagnosticsDownload({queryResultsInfo, database, error}),
178109
className: b('menu-item'),
179110
},
180111
]);
181112
}
182113

183114
return menuItems;
184-
}, [queryResultsInfo, hasPlanToSvg, blobUrl, getPlanToSvg, database]);
115+
}, [queryResultsInfo, hasPlanToSvg, database, blobUrl, getPlanToSvg, error]);
185116

186117
return {
187118
isLoading,
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import type {planToSvgApi} from '../../../../../../store/reducers/planToSvg';
2+
import type {QueryPlan, ScriptPlan, TKqpStatsQuery} from '../../../../../../types/api/query';
3+
import createToast from '../../../../../../utils/createToast';
4+
import {prepareCommonErrorMessage} from '../../../../../../utils/errors';
5+
import {parseQueryError} from '../../../../../../utils/query';
6+
import i18n from '../../i18n';
7+
8+
export interface QueryResultsInfo {
9+
ast?: string;
10+
stats?: TKqpStatsQuery;
11+
queryText?: string;
12+
plan?: QueryPlan | ScriptPlan;
13+
}
14+
15+
export interface DiagnosticsData extends QueryResultsInfo {
16+
database: string;
17+
error?: ReturnType<typeof parseQueryError>;
18+
}
19+
20+
interface GetSvgParams {
21+
plan: QueryPlan | ScriptPlan;
22+
database: string;
23+
blobUrl: string | null;
24+
getPlanToSvg: ReturnType<typeof planToSvgApi.useLazyPlanToSvgQueryQuery>[0];
25+
setBlobUrl: (url: string) => void;
26+
}
27+
28+
export const handleGetSvg = async ({
29+
plan,
30+
database,
31+
blobUrl,
32+
getPlanToSvg,
33+
setBlobUrl,
34+
}: GetSvgParams): Promise<string | null> => {
35+
if (blobUrl) {
36+
return Promise.resolve(blobUrl);
37+
}
38+
39+
try {
40+
const {data: result} = await getPlanToSvg({plan, database});
41+
if (!result) {
42+
throw new Error('No result from planToSvg');
43+
}
44+
const blob = new Blob([result], {type: 'image/svg+xml'});
45+
const url = URL.createObjectURL(blob);
46+
setBlobUrl(url);
47+
return url;
48+
} catch (err) {
49+
const errorMessage = prepareCommonErrorMessage(err);
50+
createToast({
51+
title: i18n('text_error-plan-svg', {error: errorMessage}),
52+
name: 'plan-svg-error',
53+
type: 'error',
54+
});
55+
return null;
56+
}
57+
};
58+
59+
interface HandlersParams extends GetSvgParams {}
60+
61+
export const createHandleOpenInNewTab = (params: HandlersParams) => () => {
62+
handleGetSvg(params).then((url) => {
63+
if (url) {
64+
window.open(url, '_blank');
65+
}
66+
});
67+
};
68+
69+
export const createHandleDownload = (params: HandlersParams) => () => {
70+
handleGetSvg(params).then((url) => {
71+
const link = document.createElement('a');
72+
if (url) {
73+
link.href = url;
74+
link.download = 'query-plan.svg';
75+
document.body.appendChild(link);
76+
link.click();
77+
document.body.removeChild(link);
78+
}
79+
});
80+
};
81+
82+
interface DiagnosticsDownloadParams {
83+
queryResultsInfo: QueryResultsInfo;
84+
database: string;
85+
error?: unknown;
86+
}
87+
88+
export const createHandleDiagnosticsDownload =
89+
({queryResultsInfo, database, error}: DiagnosticsDownloadParams) =>
90+
() => {
91+
const parsedError = error ? parseQueryError(error) : undefined;
92+
const diagnosticsData: DiagnosticsData = {
93+
...queryResultsInfo,
94+
database,
95+
...(parsedError && {error: parsedError}),
96+
};
97+
98+
const blob = new Blob([JSON.stringify(diagnosticsData, null, 2)], {
99+
type: 'application/json',
100+
});
101+
const url = URL.createObjectURL(blob);
102+
const link = document.createElement('a');
103+
link.href = url;
104+
link.download = `query-diagnostics-${new Date().getTime()}.json`;
105+
document.body.appendChild(link);
106+
link.click();
107+
document.body.removeChild(link);
108+
URL.revokeObjectURL(url);
109+
};

src/containers/Tenant/Query/QueryResult/i18n/en.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
"trace": "Trace",
1212
"title.truncated": "Truncated",
1313
"title.result": "Result",
14-
"text_plan-svg": "Execution plan",
15-
"text_open-new-tab": "Open in new tab",
16-
"text_open-new-tab_description": "New tab",
17-
"text_download": "Download",
14+
"text_open-execution-plan": "Open Execution Plan",
15+
"text_open-execution-plan_description": "New tab",
16+
"text_download": "Download Execution Plan",
1817
"text_download_description": "SVG",
1918
"text_diagnostics": "Download Diagnostics",
2019
"text_diagnostics_description": "JSON",

0 commit comments

Comments
 (0)