Skip to content

Commit

Permalink
refactor: migrate ExecuteResult to ts (#561)
Browse files Browse the repository at this point in the history
  • Loading branch information
artemmufazalov authored Oct 19, 2023
1 parent a65cfa1 commit ca23c14
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 45 deletions.
5 changes: 3 additions & 2 deletions src/components/QueryExecutionStatus/QueryExecutionStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ const b = cn('kv-query-execution-status');

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

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

if (error?.code === 'ECONNABORTED') {
if (typeof error === 'object' && error?.code === 'ECONNABORTED') {
icon = <UiKitIcon data={questionIcon} size={16} />;
label = 'Connection aborted';
} else {
Expand Down
5 changes: 2 additions & 3 deletions src/containers/Tenant/Diagnostics/Describe/Describe.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {useCallback, useEffect, useState} from 'react';
import {shallowEqual, useDispatch} from 'react-redux';
import cn from 'bem-cn-lite';
// @ts-ignore
import JSONTree from 'react-json-inspector';
import 'react-json-inspector/json-inspector.css';

Expand Down Expand Up @@ -99,14 +98,14 @@ const Describe = ({tenant, type}: IDescribeProps) => {
<JSONTree
data={preparedDescribeData}
className={b('tree')}
onClick={({path}: {path: string}) => {
onClick={({path}) => {
const newValue = !(expandMap.get(path) || false);
expandMap.set(path, newValue);
}}
searchOptions={{
debounceTime: 300,
}}
isExpanded={(keypath: string) => {
isExpanded={(keypath) => {
return expandMap.get(keypath) || false;
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {useCallback, useState} from 'react';
import cn from 'bem-cn-lite';
import _omit from 'lodash/omit';

// @ts-ignore
import JSONTree from 'react-json-inspector';

import {TreeView} from 'ydb-ui-components';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useEffect, useState} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import React, {type ReactNode, useEffect, useState} from 'react';
import {useDispatch} from 'react-redux';
import cn from 'bem-cn-lite';
import JSONTree from 'react-json-inspector';

Expand All @@ -11,13 +11,15 @@ import EnableFullscreenButton from '../../../../components/EnableFullscreenButto
import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
import {QueryExecutionStatus} from '../../../../components/QueryExecutionStatus';

import type {ValueOf} from '../../../../types/common';
import type {IQueryResult, QueryErrorResponse} from '../../../../types/store/query';
import {disableFullscreen} from '../../../../store/reducers/fullscreen';

import {prepareQueryError} from '../../../../utils/query';
import {useTypedSelector} from '../../../../utils/hooks';

import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';

import ResultIssues from '../Issues/Issues';
import {ResultIssues} from '../Issues/Issues';
import {QueryDuration} from '../QueryDuration/QueryDuration';

import './ExecuteResult.scss';
Expand All @@ -27,31 +29,51 @@ const b = cn('ydb-query-execute-result');
const resultOptionsIds = {
result: 'result',
stats: 'stats',
};
} as const;

type SectionID = ValueOf<typeof resultOptionsIds>;

const resultOptions = [
{value: resultOptionsIds.result, content: 'Result'},
{value: resultOptionsIds.stats, content: 'Stats'},
];

export function ExecuteResult(props) {
const [activeSection, setActiveSection] = useState(resultOptionsIds.result);
const isFullscreen = useSelector((state) => state.fullscreen);
interface ExecuteResultProps {
textResults: string;
result: ReactNode;
stats: IQueryResult['stats'] | undefined;
error: string | QueryErrorResponse | undefined;
copyDisabled?: boolean;
isResultsCollapsed?: boolean;
onCollapseResults: VoidFunction;
onExpandResults: VoidFunction;
}

export function ExecuteResult({
textResults,
result,
stats,
error,
copyDisabled,
isResultsCollapsed,
onCollapseResults,
onExpandResults,
}: ExecuteResultProps) {
const [activeSection, setActiveSection] = useState<SectionID>(resultOptionsIds.result);
const isFullscreen = useTypedSelector((state) => state.fullscreen);
const dispatch = useDispatch();

useEffect(() => {
return () => {
dispatch(disableFullscreen());
};
}, []);
}, [dispatch]);

const onSelectSection = (value) => {
setActiveSection(value);
const onSelectSection = (value: string) => {
setActiveSection(value as SectionID);
};

const renderClipboardButton = () => {
const {textResults, copyDisabled} = props;

return (
<CopyToClipboard
text={textResults}
Expand All @@ -65,7 +87,7 @@ export function ExecuteResult(props) {
const renderStats = () => {
const content = (
<JSONTree
data={props.stats}
data={stats}
isExpanded={() => true}
className={b('inspector')}
searchOptions={{
Expand All @@ -86,8 +108,6 @@ export function ExecuteResult(props) {
};

const renderResult = () => {
const {result} = props;

return (
<React.Fragment>
{result}
Expand All @@ -101,11 +121,11 @@ export function ExecuteResult(props) {
};

const renderIssues = () => {
const error = props.error;

const hasIssues = error?.data?.issues && Array.isArray(error.data.issues);
if (!error) {
return null;
}

if (hasIssues) {
if (typeof error === 'object' && error.data?.issues && Array.isArray(error.data.issues)) {
return (
<React.Fragment>
<ResultIssues data={error.data} />
Expand All @@ -120,20 +140,20 @@ export function ExecuteResult(props) {
);
}

if (error) {
return <div className={b('error')}>{prepareQueryError(error)}</div>;
}
const parsedError = typeof error === 'string' ? error : prepareQueryError(error);

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

return (
<React.Fragment>
<div className={b('controls')}>
<div className={b('controls-right')}>
<QueryExecutionStatus error={props.error} />
<QueryExecutionStatus error={error} />

{props.stats && !props.error && (
{stats && !error && (
<React.Fragment>
<QueryDuration duration={props.stats?.DurationUs} />
<QueryDuration duration={stats?.DurationUs} />
<Divider />
<RadioButton
options={resultOptions}
Expand All @@ -147,16 +167,16 @@ export function ExecuteResult(props) {
{renderClipboardButton()}
<EnableFullscreenButton />
<PaneVisibilityToggleButtons
onCollapse={props.onCollapseResults}
onExpand={props.onExpandResults}
isCollapsed={props.isResultsCollapsed}
onCollapse={onCollapseResults}
onExpand={onExpandResults}
isCollapsed={isResultsCollapsed}
initialDirection="bottom"
/>
</div>
</div>
<div className={b('result')}>
{activeSection === resultOptionsIds.result && !props.error && renderResult()}
{activeSection === resultOptionsIds.stats && !props.error && renderStats()}
{activeSection === resultOptionsIds.result && !error && renderResult()}
{activeSection === resultOptionsIds.stats && !error && renderStats()}
{renderIssues()}
</div>
</React.Fragment>
Expand Down
10 changes: 4 additions & 6 deletions src/containers/Tenant/Query/Issues/Issues.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ const blockIssue = cn('kv-issue');

interface ResultIssuesProps {
data: ErrorResponse | string;
className: string;
}

export default function ResultIssues({data, className}: ResultIssuesProps) {
export function ResultIssues({data}: ResultIssuesProps) {
const [showIssues, setShowIssues] = React.useState(false);

const issues = typeof data === 'string' ? undefined : data?.issues;
Expand Down Expand Up @@ -59,22 +58,21 @@ export default function ResultIssues({data, className}: ResultIssuesProps) {
</Button>
)}
</div>
{hasIssues && showIssues && <Issues issues={issues} className={className} />}
{hasIssues && showIssues && <Issues issues={issues} />}
</div>
);
}

interface IssuesProps {
className?: string;
issues: IssueMessage[] | null | undefined;
}
export function Issues({issues, className}: IssuesProps) {
export function Issues({issues}: IssuesProps) {
const mostSevereIssue = issues?.reduce((result, issue) => {
const severity = issue.severity ?? 10;
return Math.min(result, severity);
}, 10);
return (
<div className={blockIssues(null, className)}>
<div className={blockIssues(null)}>
{issues?.map((issue, index) => (
<Issue key={index} issue={issue} expanded={issue === mostSevereIssue} />
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import i18n from '../i18n';
import './QueryDuration.scss';

interface QueryDurationProps {
duration?: string;
duration?: string | number;
}

const b = block('ydb-query-duration');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export function paneVisibilityToggleReducerCreator(isPaneCollapsedKey: string) {
interface ToggleButtonProps {
onCollapse: VoidFunction;
onExpand: VoidFunction;
isCollapsed: boolean;
isCollapsed?: boolean;
initialDirection?: 'right' | 'left' | 'top' | 'bottom';
className?: string;
}
Expand Down
21 changes: 21 additions & 0 deletions src/types/react-json-inspector.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
declare module 'react-json-inspector' {
// This typing is sufficient for current use cases, but some types are incompelete
class JSONTree extends React.Component<{
data?: object;
search?: boolean;
searchOptions?: {
debounceTime?: number;
};
onClick?: ({path: string, key: string, value: object}) => void;
validateQuery?: (query: string) => boolean;
isExpanded?: (keypath: string) => boolean;
filterOptions?: {
cacheResults?: bool;
ignoreCase?: bool;
};
query?: string;
verboseShowOriginal?: boolean;
className?: string;
}> {}
export default JSONTree;
}

0 comments on commit ca23c14

Please sign in to comment.