From 9efef4c02ea4e2faf170d59d459c49e0fc172910 Mon Sep 17 00:00:00 2001 From: Kanstantsin Autushka Date: Wed, 22 Jan 2025 16:59:05 +0300 Subject: [PATCH] feat(Navigation/NavigationError): add copy button and impove error details [YTFRONT-4049] --- packages/ui/package-lock.json | 24 +++++++------ packages/ui/package.json | 2 +- .../components/ErrorDetails/ErrorDetails.js | 4 +++ .../components/ErrorDetails/ErrorDetails.scss | 5 +++ .../pages/navigation/Navigation/Navigation.js | 5 ++- .../NavigationError/NavigationError.tsx | 15 +++++--- .../NavigationError/helpers/helpers.ts | 35 +++++++++++++++++++ 7 files changed, 73 insertions(+), 17 deletions(-) diff --git a/packages/ui/package-lock.json b/packages/ui/package-lock.json index 024c1d8b1..aab3fc3f2 100644 --- a/packages/ui/package-lock.json +++ b/packages/ui/package-lock.json @@ -44,7 +44,7 @@ "@gravity-ui/react-data-table": "^2.1.1", "@gravity-ui/stylelint-config": "^4.0.1", "@gravity-ui/tsconfig": "^1.0.0", - "@gravity-ui/uikit": "^6.19.0", + "@gravity-ui/uikit": "^6.37.0", "@gravity-ui/unipika": "^5.1.0", "@gravity-ui/websql-autocomplete": "^12.3.0", "@gravity-ui/yagr": "^4.3.1", @@ -4614,9 +4614,10 @@ } }, "node_modules/@gravity-ui/i18n": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@gravity-ui/i18n/-/i18n-1.5.1.tgz", - "integrity": "sha512-ZvaQtRUf4Yl9zi0+SMzjlDeHp9+p5IXkNu2k6RtW04c+RYKA1jX+umeKNwzft4iR3+KxDlpLX2trTFEW6W7HKQ==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@gravity-ui/i18n/-/i18n-1.7.0.tgz", + "integrity": "sha512-jZotOX73lMVARsNZ5L8rquDhyCIcHnX7GwT32m6vrnqy6iKBfBdOuAnAalUbnoVJoasfvYiSyX3kwusetyZgfQ==", + "license": "MIT" }, "node_modules/@gravity-ui/icons": { "version": "2.10.0", @@ -4741,19 +4742,20 @@ "dev": true }, "node_modules/@gravity-ui/uikit": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@gravity-ui/uikit/-/uikit-6.19.0.tgz", - "integrity": "sha512-riIgdot10rawRvp14zlrei8QIfCBGJlCLCuRpQSHbWMclc4cReRC86170NVXwA0dpXBlUt7bnV5tK140LEZDDA==", + "version": "6.42.0", + "resolved": "https://registry.npmjs.org/@gravity-ui/uikit/-/uikit-6.42.0.tgz", + "integrity": "sha512-PVe2mCXdQ15oAFZ10MxLo5iLdDCdOZ8TKLjRTRaAdROK52MKme04vv3TciOtO7gF0G6QG2SRX04x61nq/IFxAQ==", "dev": true, + "license": "MIT", "dependencies": { "@bem-react/classname": "^1.6.0", - "@gravity-ui/i18n": "^1.3.0", + "@gravity-ui/i18n": "^1.6.0", "@gravity-ui/icons": "^2.8.1", "@popperjs/core": "^2.11.8", "blueimp-md5": "^2.19.0", "focus-trap": "^7.5.4", "lodash": "^4.17.21", - "rc-slider": "^10.5.0", + "rc-slider": "^10.6.2", "react-beautiful-dnd": "^13.1.1", "react-copy-to-clipboard": "^5.1.0", "react-popper": "^2.3.0", @@ -4764,8 +4766,8 @@ "tslib": "^2.6.2" }, "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@gravity-ui/unipika": { diff --git a/packages/ui/package.json b/packages/ui/package.json index 89eb8aa0c..bd5f11a80 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -100,7 +100,7 @@ "@gravity-ui/react-data-table": "^2.1.1", "@gravity-ui/stylelint-config": "^4.0.1", "@gravity-ui/tsconfig": "^1.0.0", - "@gravity-ui/uikit": "^6.19.0", + "@gravity-ui/uikit": "^6.37.0", "@gravity-ui/unipika": "^5.1.0", "@gravity-ui/websql-autocomplete": "^12.3.0", "@gravity-ui/yagr": "^4.3.1", diff --git a/packages/ui/src/ui/components/ErrorDetails/ErrorDetails.js b/packages/ui/src/ui/components/ErrorDetails/ErrorDetails.js index e91d18656..a834883c4 100644 --- a/packages/ui/src/ui/components/ErrorDetails/ErrorDetails.js +++ b/packages/ui/src/ui/components/ErrorDetails/ErrorDetails.js @@ -1,5 +1,6 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; +import {ClipboardButton} from '@gravity-ui/uikit'; import Link from '../../components/Link/Link'; import block from 'bem-cn-lite'; import ypath from '../../common/thor/ypath'; @@ -107,13 +108,16 @@ export default class ErrorDetails extends Component { } renderTabs() { + const {error} = this.props; const {currentTab} = this.state; const items = this.prepareTabs(); + const text = unipika.formatFromYSON(error.attributes, {asHTML: false}); return (
+
); } diff --git a/packages/ui/src/ui/components/ErrorDetails/ErrorDetails.scss b/packages/ui/src/ui/components/ErrorDetails/ErrorDetails.scss index 7229c8d36..3dc801570 100644 --- a/packages/ui/src/ui/components/ErrorDetails/ErrorDetails.scss +++ b/packages/ui/src/ui/components/ErrorDetails/ErrorDetails.scss @@ -30,6 +30,11 @@ } &__tabs { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + span { color: var(--g-color-text-complementary); font-weight: 700; diff --git a/packages/ui/src/ui/pages/navigation/Navigation/Navigation.js b/packages/ui/src/ui/pages/navigation/Navigation/Navigation.js index 754b612b0..e1001b258 100644 --- a/packages/ui/src/ui/pages/navigation/Navigation/Navigation.js +++ b/packages/ui/src/ui/pages/navigation/Navigation/Navigation.js @@ -22,6 +22,10 @@ import ContentViewer from './ContentViewer/ContentViewer'; import {checkContentIsSupported} from './ContentViewer/helpers'; import Tabs from '../../../components/Tabs/Tabs'; import {NavigationError} from './NavigationError'; +import { + getEffectiveMode, + getTabs, +} from '../../../store/selectors/navigation/navigation'; import {Tab} from '../../../constants/navigation'; import {LOADING_STATUS} from '../../../constants/index'; @@ -38,7 +42,6 @@ import { getType, isNavigationFinalLoadState, } from '../../../store/selectors/navigation'; -import {getEffectiveMode, getTabs} from '../../../store/selectors/navigation/navigation'; import {NavigationPermissionsNotice} from './NavigationPermissionsNotice'; import {useRumMeasureStop} from '../../../rum/RumUiContext'; import {useAppRumMeasureStart} from '../../../rum/rum-app-measures'; diff --git a/packages/ui/src/ui/pages/navigation/Navigation/NavigationError/NavigationError.tsx b/packages/ui/src/ui/pages/navigation/Navigation/NavigationError/NavigationError.tsx index 9314a2e84..3a5310853 100644 --- a/packages/ui/src/ui/pages/navigation/Navigation/NavigationError/NavigationError.tsx +++ b/packages/ui/src/ui/pages/navigation/Navigation/NavigationError/NavigationError.tsx @@ -1,6 +1,6 @@ import React from 'react'; import cn from 'bem-cn-lite'; -import {Flex, Text} from '@gravity-ui/uikit'; +import {ClipboardButton, Flex, Text} from '@gravity-ui/uikit'; import Error from '../../../../components/Error/Error'; import {NavigationErrorImage} from './NavigationErrorImage'; @@ -8,7 +8,7 @@ import ErrorDetails from '../../../../components/ErrorDetails/ErrorDetails'; import {RequestPermission} from './RequestPermission'; import {getPermissionDeniedError} from '../../../../utils/errors'; import {YTError} from '../../../../../@types/types'; -import {getErrorTitle, getLeadingErrorCode} from './helpers'; +import {formatForCopy, getErrorTitle, getLeadingErrorCode} from './helpers'; import './NavigationError.scss'; @@ -26,8 +26,8 @@ function PrettyError(props: Props) { const code = getLeadingErrorCode(details); const error = code == 901 ? getPermissionDeniedError(details)! : details; - const title = getErrorTitle(error, path); + const errorInfo = formatForCopy(details); return ( @@ -37,7 +37,14 @@ function PrettyError(props: Props) { {title} - {code === 901 && } + + {code === 901 && ( + + )} + + Copy error details + + ); diff --git a/packages/ui/src/ui/pages/navigation/Navigation/NavigationError/helpers/helpers.ts b/packages/ui/src/ui/pages/navigation/Navigation/NavigationError/helpers/helpers.ts index c470d5338..ea9415ea4 100644 --- a/packages/ui/src/ui/pages/navigation/Navigation/NavigationError/helpers/helpers.ts +++ b/packages/ui/src/ui/pages/navigation/Navigation/NavigationError/helpers/helpers.ts @@ -1,3 +1,5 @@ +import unipika from '../../../../../common/thor/unipika'; + import {getYtErrorCode} from '../../../../../utils/errors'; import {YTError} from '../../../../../../@types/types'; import {UnipikaValue} from '../../../../../components/Yson/StructuredYson/StructuredYsonTypes'; @@ -85,3 +87,36 @@ export function getLeadingErrorCode(error: YTError): ErrorCode | undefined { return; } + +export function formatForCopy(error: YTError) { + const formatSettings = {asHTML: false}; + let res = ''; + + const errorTraversal = (e: YTError) => { + if (e.message) { + // replace needed to truncate extra \ + // for situations like: Access denied for user \"username\": \"role\" + res += `${unipika.formatFromYSON(e.message, formatSettings)}`.replace(/\\"/g, '"'); + } + + if (e.code) { + res += `[${unipika.formatFromYSON(e.code, formatSettings)}]`; + } + + res += '\n'; + + if (e.attributes) { + res += `${unipika.formatFromYSON(e.attributes, formatSettings)}\n`; + } + + if (e.inner_errors) { + for (const err of e.inner_errors) { + errorTraversal(err); + } + } + }; + + errorTraversal(error); + + return res; +}