import React from 'react';
import {
CircleExclamationFill,
CircleInfoFill,
CircleXmarkFill,
TriangleExclamationFill,
} from '@gravity-ui/icons';
import type {IconData} from '@gravity-ui/uikit';
import {ArrowToggle, Button, Flex, Icon, Link} from '@gravity-ui/uikit';
import ShortyString from '../../../../components/ShortyString/ShortyString';
import type {ErrorResponse, IssueMessage} from '../../../../types/api/query';
import {cn} from '../../../../utils/cn';
import {isNumeric} from '../../../../utils/utils';
import {IssuesDialog} from './IssuesDialog';
import {
QUERY_SETTINGS_PRAGMAS_SOURCE,
getIssuePosition,
getMostSevere,
hasRootIssues,
normalizeRoots,
} from './helpers';
import i18n from './i18n';
import type {SEVERITY} from './models';
import {getSeverity} from './models';
import './Issues.scss';
const blockWrapper = cn('kv-result-issues');
const blockIssues = cn('kv-issues');
const blockIssue = cn('kv-issue');
interface ResultIssuesProps {
data: ErrorResponse | string;
hideSeverity?: boolean;
}
function ErrorStringMessage({message}: {message: string}) {
return
{message}
;
}
export function ResultIssues({data, hideSeverity}: ResultIssuesProps) {
const roots = normalizeRoots(data);
const [expanded, setExpanded] = React.useState>({});
const onToggleInline = (idx: number) => setExpanded((p) => ({...p, [idx]: !p[idx]}));
if (typeof data === 'string') {
return ;
}
return (
{roots.map((root, idx) => {
const hasIssues = hasRootIssues(root.issues);
return (
onToggleInline(idx)}
/>
{expanded[idx] && hasIssues && (
)}
);
})}
);
}
export function ResultIssuesModal({data, hideSeverity}: ResultIssuesProps) {
const roots = normalizeRoots(data);
const [open, setOpen] = React.useState(false);
const [currentIssues, setCurrentIssues] = React.useState(null);
const openDialog = (issues?: IssueMessage[]) => {
setCurrentIssues(issues ?? []);
setOpen(true);
};
const closeDialog = () => setOpen(false);
if (typeof data === 'string') {
return ;
}
return (
{roots.map((root, idx) => {
const hasIssues = hasRootIssues(root.issues);
return (
openDialog(root.issues)}
/>
);
})}
);
}
interface ErrorPreviewItemProps {
severity: SEVERITY;
message?: string;
hideSeverity?: boolean;
hasIssues?: boolean;
expanded?: boolean;
onClick: () => void;
}
export function ErrorPreviewItem({
severity,
message,
hideSeverity,
hasIssues,
expanded,
onClick,
}: ErrorPreviewItemProps) {
const buttonLabel = expanded ? i18n('action_hide-details') : i18n('action_show-details');
return (
{hideSeverity ? null : }
{message}
{hasIssues && (
)}
);
}
interface IssuesProps {
issues: IssueMessage[] | null | undefined;
hideSeverity?: boolean;
}
export function Issues({issues, hideSeverity}: IssuesProps) {
const mostSevereIssue = getMostSevere(issues);
return (
{issues?.map((issue, index) => (
))}
);
}
function Issue({
issue,
hideSeverity,
level = 0,
}: {
issue: IssueMessage;
expanded?: boolean;
hideSeverity?: boolean;
level?: number;
}) {
const [isExpand, setIsExpand] = React.useState(true);
const severity = getSeverity(issue.severity);
const issues = issue.issues;
const hasIssues = hasRootIssues(issues);
const arrowDirection = isExpand ? 'bottom' : 'right';
return (
{hasIssues && (
)}
{hideSeverity ? null :
}
{issue.issue_code ? (
{i18n('field_code')}: {issue.issue_code}
) : null}
{hasIssues && isExpand && (
)}
);
}
interface IssueTextProps {
issue: IssueMessage;
}
function IssueText({issue}: IssueTextProps) {
const position = getIssuePosition(issue);
const ydbEditor = window.ydbEditor;
const getIssue = () => {
return (
{position && (
{position}
)}
);
};
const {row, column} = issue.position ?? {};
const isIssueClickable =
isNumeric(row) && issue.position?.file !== QUERY_SETTINGS_PRAGMAS_SOURCE && ydbEditor;
if (!isIssueClickable) {
return getIssue();
}
const onIssueClickHandler = () => {
const monacoPosition = {lineNumber: row, column: column ?? 0};
ydbEditor.setPosition(monacoPosition);
ydbEditor.revealPositionInCenterIfOutsideViewport(monacoPosition);
ydbEditor.focus();
};
return (
{getIssue()}
);
}
function IssueList(props: {issues: IssueMessage[]; expanded: boolean; level: number}) {
const {issues, level, expanded} = props;
return (
{issues.map((issue, index) => (
))}
);
}
const severityIcons: Record = {
S_INFO: CircleInfoFill,
S_WARNING: CircleExclamationFill,
S_ERROR: TriangleExclamationFill,
S_FATAL: CircleXmarkFill,
};
const blockIssueSeverity = cn('yql-issue-severity');
function IssueSeverity({severity}: {severity: SEVERITY}) {
const shortenSeverity = severity.slice(2).toLowerCase();
return (
{shortenSeverity}
);
}