Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/components/Errors/ResponseError/ResponseError.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export const ResponseError = ({
defaultMessage = i18n('responseError.defaultMessage'),
}: ResponseErrorProps) => {
let statusText = '';

if (error && typeof error === 'string') {
statusText = error;
}
if (error && typeof error === 'object') {
if ('statusText' in error && typeof error.statusText === 'string') {
statusText = error.statusText;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {CircleCheck, CircleQuestionFill, CircleXmark} from '@gravity-ui/icons';
import {Icon} from '@gravity-ui/uikit';
import type {AxiosError} from 'axios';
import {isAxiosError} from 'axios';

import {cn} from '../../utils/cn';

Expand All @@ -10,15 +10,14 @@ const b = cn('kv-query-execution-status');

interface QueryExecutionStatusProps {
className?: string;
// TODO: Remove Record<string, any> when ECONNABORTED error case is fully typed
error?: AxiosError | Record<string, any> | string;
error?: unknown;
}

export const QueryExecutionStatus = ({className, error}: QueryExecutionStatusProps) => {
let icon: React.ReactNode;
let label: string;

if (typeof error === 'object' && error?.code === 'ECONNABORTED') {
if (isAxiosError(error) && error.code === 'ECONNABORTED') {
icon = <Icon data={CircleQuestionFill} />;
label = 'Connection aborted';
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '../../../../../store/reducers/tenant/constants';
import {topQueriesApi} from '../../../../../store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries';
import {useTypedDispatch, useTypedSelector} from '../../../../../utils/hooks';
import {parseQueryErrorToString} from '../../../../../utils/query';
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
import {
TOP_QUERIES_COLUMNS_WIDTH_LS_KEY,
Expand Down Expand Up @@ -80,7 +81,7 @@ export function TopQueries({path}: TopQueriesProps) {
onRowClick={handleRowClick}
title={title}
loading={loading}
error={error}
error={parseQueryErrorToString(error)}
rowClassName={() => b('top-queries-row')}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {parseQuery} from '../../../../../routes';
import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
import {topShardsApi} from '../../../../../store/reducers/tenantOverview/topShards/tenantOverviewTopShards';
import {useTypedSelector} from '../../../../../utils/hooks';
import {parseQueryErrorToString} from '../../../../../utils/query';
import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
import {
TOP_SHARDS_COLUMNS_WIDTH_LS_KEY,
Expand Down Expand Up @@ -50,7 +51,7 @@ export const TopShards = ({path}: TopShardsProps) => {
columns={columns}
title={title}
loading={loading}
error={error}
error={parseQueryErrorToString(error)}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {topTablesApi} from '../../../../../store/reducers/tenantOverview/execute
import type {KeyValueRow} from '../../../../../types/api/query';
import {formatBytes, getSizeWithSignificantDigits} from '../../../../../utils/bytesParsers';
import {useTypedSelector} from '../../../../../utils/hooks';
import {parseQueryErrorToString} from '../../../../../utils/query';
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
import {getSectionTitle} from '../getSectionTitle';
import i18n from '../i18n';
Expand Down Expand Up @@ -73,7 +74,7 @@ export function TopTables({path}: TopTablesProps) {
columns={columns}
title={title}
loading={loading}
error={error}
error={parseQueryErrorToString(error)}
/>
);
}
6 changes: 3 additions & 3 deletions src/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import type {EPathType} from '../../../../types/api/schema';
import {cn} from '../../../../utils/cn';
import {isSortableTopQueriesProperty} from '../../../../utils/diagnostics';
import {useTypedDispatch, useTypedSelector} from '../../../../utils/hooks';
import {prepareQueryError} from '../../../../utils/query';
import {parseQueryErrorToString} from '../../../../utils/query';
import {TenantTabsGroups, getTenantPath} from '../../TenantPages';
import {QUERY_TABLE_SETTINGS} from '../../utils/constants';
import {isColumnEntityType} from '../../utils/schema';
Expand Down Expand Up @@ -91,8 +91,8 @@ export const TopQueries = ({path, type}: TopQueriesProps) => {
};

const renderContent = () => {
if (error && typeof error === 'object' && !(error as any).isCancelled) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With rtk query requests are not cancelled as they were previously

return <div className="error">{prepareQueryError(error)}</div>;
if (error) {
return <div className="error">{parseQueryErrorToString(error)}</div>;
}

if (!data || isColumnEntityType(type)) {
Expand Down
6 changes: 3 additions & 3 deletions src/containers/Tenant/Diagnostics/TopShards/TopShards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constan
import {formatDateTime} from '../../../../utils/dataFormatters/dataFormatters';
import {isSortableTopShardsProperty} from '../../../../utils/diagnostics';
import {useTypedDispatch, useTypedSelector} from '../../../../utils/hooks';
import {prepareQueryError} from '../../../../utils/query';
import {parseQueryErrorToString} from '../../../../utils/query';
import {isColumnEntityType} from '../../utils/schema';

import {Filters} from './Filters';
Expand Down Expand Up @@ -192,8 +192,8 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
};

const renderContent = () => {
if (error && typeof error === 'object' && !(error as any).isCancelled) {
return <div className="error">{prepareQueryError(error)}</div>;
if (error) {
return <div className="error">{parseQueryErrorToString(error)}</div>;
}

if (!data || isColumnEntityType(type)) {
Expand Down
16 changes: 8 additions & 8 deletions src/containers/Tenant/Query/ExecuteResult/ExecuteResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import {QueryResultTable} from '../../../../components/QueryResultTable/QueryRes
import {disableFullscreen} from '../../../../store/reducers/fullscreen';
import type {ColumnType, KeyValueRow} from '../../../../types/api/query';
import type {ValueOf} from '../../../../types/common';
import type {IQueryResult, QueryErrorResponse} from '../../../../types/store/query';
import type {IQueryResult} from '../../../../types/store/query';
import {getArray} from '../../../../utils';
import {cn} from '../../../../utils/cn';
import {useTypedDispatch, useTypedSelector} from '../../../../utils/hooks';
import {prepareQueryError} from '../../../../utils/query';
import {parseQueryError} from '../../../../utils/query';
import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';
import {ResultIssues} from '../Issues/Issues';
import {QueryDuration} from '../QueryDuration/QueryDuration';
Expand All @@ -41,7 +41,7 @@ const resultOptions = [
interface ExecuteResultProps {
data: IQueryResult | undefined;
stats: IQueryResult['stats'] | undefined;
error: string | QueryErrorResponse | undefined;
error: unknown;
isResultsCollapsed?: boolean;
onCollapseResults: VoidFunction;
onExpandResults: VoidFunction;
Expand All @@ -68,6 +68,8 @@ export function ExecuteResult({
const textResults = getPreparedResult(currentResult);
const copyDisabled = !textResults.length;

const parsedError = parseQueryError(error);

React.useEffect(() => {
return () => {
dispatch(disableFullscreen());
Expand Down Expand Up @@ -159,12 +161,12 @@ export function ExecuteResult({
};

const renderIssues = () => {
if (!error) {
if (!parsedError) {
return null;
}

if (typeof error === 'object' && error.data?.issues && Array.isArray(error.data.issues)) {
const content = <ResultIssues data={error.data} />;
if (typeof parsedError === 'object') {
const content = <ResultIssues data={parsedError} />;

return (
<React.Fragment>
Expand All @@ -180,8 +182,6 @@ export function ExecuteResult({
);
}

const parsedError = typeof error === 'string' ? error : prepareQueryError(error);

return <div className={b('error')}>{parsedError}</div>;
};

Expand Down
19 changes: 5 additions & 14 deletions src/containers/Tenant/Query/ExplainResult/ExplainResult.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import EnableFullscreenButton from '../../../../components/EnableFullscreenButto
import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
import {MonacoEditor} from '../../../../components/MonacoEditor/MonacoEditor';
import {QueryExecutionStatus} from '../../../../components/QueryExecutionStatus';
import {explainVersions} from '../../../../store/reducers/explainQuery';
import {explainVersions} from '../../../../store/reducers/explainQuery/utils';
import {disableFullscreen} from '../../../../store/reducers/fullscreen';
import {cn} from '../../../../utils/cn';
import {useTypedDispatch, useTypedSelector} from '../../../../utils/hooks';
import {LANGUAGE_S_EXPRESSION_ID} from '../../../../utils/monaco/s-expression/constants';
import {parseQueryErrorToString} from '../../../../utils/query';
import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';

import {renderExplainNode} from './utils';
Expand Down Expand Up @@ -193,22 +194,12 @@ export function ExplainResult(props) {
};

const renderError = () => {
const {error} = props;

let message;

if (error.data) {
message = typeof error.data === 'string' ? error.data : error.data.error?.message;
} else {
message = error;
}

return <div className={b('text-message')}>{message}</div>;
return <div className={b('text-message')}>{parseQueryErrorToString(props.error)}</div>;
};

const renderContent = () => {
const {error, loading, loadingAst} = props;
if (loading || loadingAst) {
const {error, loading} = props;
if (loading) {
return renderLoader();
}

Expand Down
6 changes: 4 additions & 2 deletions src/containers/Tenant/Query/Preview/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {setShowPreview} from '../../../../store/reducers/schema/schema';
import type {EPathType} from '../../../../types/api/schema';
import {cn} from '../../../../utils/cn';
import {useTypedDispatch, useTypedSelector} from '../../../../utils/hooks';
import {prepareQueryError} from '../../../../utils/query';
import {parseQueryErrorToString} from '../../../../utils/query';
import {isExternalTableType, isTableType} from '../../utils/schema';
import i18n from '../i18n';

Expand Down Expand Up @@ -76,7 +76,9 @@ export const Preview = ({database, type}: PreviewProps) => {
if (!isPreviewAvailable) {
message = <div className={b('message-container')}>{i18n('preview.not-available')}</div>;
} else if (error) {
message = <div className={b('message-container', 'error')}>{prepareQueryError(error)}</div>;
message = (
<div className={b('message-container', 'error')}>{parseQueryErrorToString(error)}</div>
);
}

const content = message ?? (
Expand Down
Loading