ydb-embedded-ui 4.29.0 → 4.30.0

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.30.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.29.0...v4.30.0) (2024-01-16)
4
+
5
+
6
+ ### Features
7
+
8
+ * add clipboard button to nodes tree titles ([#648](https://github.com/ydb-platform/ydb-embedded-ui/issues/648)) ([1411651](https://github.com/ydb-platform/ydb-embedded-ui/commit/141165173189be064e9e9314b42aa3eb7fce9c69))
9
+
3
10
  ## [4.29.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.28.0...v4.29.0) (2024-01-12)
4
11
 
5
12
 
package/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  Local viewer for YDB clusters
4
4
 
5
- [Docs for users](https://ydb.tech/en/docs/maintenance/embedded_monitoring/ydb_monitoring)
5
+ * [Docs for users](https://ydb.tech/en/docs/maintenance/embedded_monitoring/ydb_monitoring)
6
+ * [Project Roadmap](ROADMAP.md)
6
7
 
7
8
  ## Preview
8
9
 
@@ -0,0 +1,52 @@
1
+ import {
2
+ Button,
3
+ ButtonProps,
4
+ ClipboardIcon,
5
+ CopyToClipboard as CopyToClipboardUiKit,
6
+ CopyToClipboardStatus,
7
+ Tooltip,
8
+ } from '@gravity-ui/uikit';
9
+ import cn from 'bem-cn-lite';
10
+
11
+ const b = cn('clipboard-button');
12
+
13
+ interface ClipboardButtonProps extends Pick<ButtonProps, 'disabled' | 'size' | 'title' | 'view'> {
14
+ className?: string;
15
+ text: string;
16
+ }
17
+
18
+ /**
19
+ * An inner component required
20
+ * because `react-copy-to-clipboard` doesn't work with `Tooltip` otherwise.
21
+ */
22
+ function InnerButton({
23
+ className,
24
+ status,
25
+ title,
26
+ ...props
27
+ }: Omit<ClipboardButtonProps, 'text'> & {status: CopyToClipboardStatus}) {
28
+ return (
29
+ <Tooltip
30
+ content={status === CopyToClipboardStatus.Success ? 'Copied!' : title || 'Copy'}
31
+ /**
32
+ * Auto-placement has a bug with text changing.
33
+ * @link https://github.com/ydb-platform/ydb-embedded-ui/pull/648#discussion_r1453530092
34
+ */
35
+ placement="bottom-start"
36
+ >
37
+ <Button {...props} className={b(null, className)}>
38
+ <Button.Icon>
39
+ <ClipboardIcon status={status} size={16} />
40
+ </Button.Icon>
41
+ </Button>
42
+ </Tooltip>
43
+ );
44
+ }
45
+
46
+ export function ClipboardButton({text, ...props}: ClipboardButtonProps) {
47
+ return (
48
+ <CopyToClipboardUiKit text={text} timeout={1000}>
49
+ {(status) => <InnerButton {...props} status={status} />}
50
+ </CopyToClipboardUiKit>
51
+ );
52
+ }
@@ -0,0 +1 @@
1
+ export * from './ClipboardButton';
@@ -1,14 +1,13 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
1
+ import {Icon, Link as UIKitLink} from '@gravity-ui/uikit';
3
2
  import cn from 'bem-cn-lite';
3
+ import PropTypes from 'prop-types';
4
+ import React from 'react';
4
5
  import {Link} from 'react-router-dom';
5
- import {ClipboardButton, Link as UIKitLink, Button, Icon} from '@gravity-ui/uikit';
6
-
7
- import circleInfoIcon from '../../assets/icons/circle-info.svg';
8
6
  import circleExclamationIcon from '../../assets/icons/circle-exclamation.svg';
9
- import triangleExclamationIcon from '../../assets/icons/triangle-exclamation.svg';
7
+ import circleInfoIcon from '../../assets/icons/circle-info.svg';
10
8
  import circleTimesIcon from '../../assets/icons/circle-xmark.svg';
11
-
9
+ import triangleExclamationIcon from '../../assets/icons/triangle-exclamation.svg';
10
+ import {ClipboardButton} from '../ClipboardButton';
12
11
  import './EntityStatus.scss';
13
12
 
14
13
  const icons = {
@@ -121,15 +120,13 @@ class EntityStatus extends React.Component {
121
120
  {this.renderLink()}
122
121
  </span>
123
122
  {hasClipboardButton && (
124
- <Button
125
- component="span"
123
+ <ClipboardButton
124
+ text={name}
126
125
  size="s"
127
126
  className={b('clipboard-button', {
128
127
  visible: this.props.clipboardButtonAlwaysVisible,
129
128
  })}
130
- >
131
- <ClipboardButton text={name} size={16} />
132
- </Button>
129
+ />
133
130
  )}
134
131
  </div>
135
132
  );
@@ -10,25 +10,14 @@
10
10
  @include body-2-typography();
11
11
 
12
12
  &__clipboard-button {
13
- display: none;
14
- justify-content: center;
15
- align-items: center;
13
+ visibility: hidden;
16
14
 
17
15
  margin-left: 8px;
18
16
 
19
17
  color: var(--yc-color-text-secondary);
20
18
 
21
- .yc-button__text {
22
- margin: 0;
23
- }
24
-
25
- .yc-clipboard-button {
26
- width: 24px;
27
- height: 24px;
28
- }
29
-
30
19
  &_visible {
31
- display: inline-flex;
20
+ visibility: visible;
32
21
  }
33
22
  }
34
23
 
@@ -107,21 +107,21 @@ body,
107
107
  border-right: unset;
108
108
  border-left: unset;
109
109
  }
110
-
111
- .yc-clipboard-button {
112
- display: inline-flex;
113
- justify-content: center;
114
- align-items: center;
115
- }
116
110
  }
117
111
 
118
112
  .error {
119
113
  color: var(--g-color-text-danger);
120
114
  }
121
115
 
122
- .data-table__row:hover .entity-status__clipboard-button,
123
- .ydb-virtual-table__row:hover .entity-status__clipboard-button {
124
- display: flex;
116
+ .data-table__row,
117
+ .ydb-virtual-table__row,
118
+ .ydb-tree-view__item {
119
+ &:hover,
120
+ &:focus-within {
121
+ & .clipboard-button {
122
+ visibility: visible;
123
+ }
124
+ }
125
125
  }
126
126
 
127
127
  .g-root .data-table_highlight-rows .data-table__row:hover {
@@ -1,60 +1,53 @@
1
+ import {HelpPopover} from '@gravity-ui/components';
2
+ import {Button, Tabs} from '@gravity-ui/uikit';
3
+ import cn from 'bem-cn-lite';
4
+ import qs from 'qs';
1
5
  import React, {ReactNode, useEffect, useReducer} from 'react';
2
6
  import {useDispatch} from 'react-redux';
3
7
  import {useLocation} from 'react-router';
4
8
  import {Link} from 'react-router-dom';
5
- import qs from 'qs';
6
- import cn from 'bem-cn-lite';
7
-
8
- import {Button, Tabs} from '@gravity-ui/uikit';
9
- import {HelpPopover} from '@gravity-ui/components';
10
-
11
- import SplitPane from '../../../components/SplitPane';
12
- import CopyToClipboard from '../../../components/CopyToClipboard/CopyToClipboard';
9
+ import {ClipboardButton} from '../../../components/ClipboardButton';
10
+ import {Icon} from '../../../components/Icon';
13
11
  import InfoViewer from '../../../components/InfoViewer/InfoViewer';
14
12
  import {
15
13
  CDCStreamOverview,
16
14
  PersQueueGroupOverview,
17
15
  } from '../../../components/InfoViewer/schemaOverview';
18
- import {Icon} from '../../../components/Icon';
19
16
  import {Loader} from '../../../components/Loader';
20
-
17
+ import SplitPane from '../../../components/SplitPane';
18
+ import routes, {createHref} from '../../../routes';
19
+ import {setShowPreview} from '../../../store/reducers/schema/schema';
20
+ import {
21
+ TENANT_PAGES_IDS,
22
+ TENANT_QUERY_TABS_ID,
23
+ TENANT_SUMMARY_TABS_IDS,
24
+ } from '../../../store/reducers/tenant/constants';
25
+ import {setQueryTab, setSummaryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
21
26
  import {
22
27
  EPathSubType,
23
28
  EPathType,
24
29
  TColumnDescription,
25
30
  TColumnTableDescription,
26
31
  } from '../../../types/api/schema';
27
- import routes, {createHref} from '../../../routes';
28
- import {formatDateTime} from '../../../utils/dataFormatters/dataFormatters';
29
- import {useTypedSelector} from '../../../utils/hooks';
30
32
  import {
31
33
  DEFAULT_IS_TENANT_COMMON_INFO_COLLAPSED,
32
34
  DEFAULT_SIZE_TENANT_SUMMARY_KEY,
33
35
  } from '../../../utils/constants';
34
- import {setShowPreview} from '../../../store/reducers/schema/schema';
35
- import {setQueryTab, setSummaryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
36
- import {
37
- TENANT_PAGES_IDS,
38
- TENANT_QUERY_TABS_ID,
39
- TENANT_SUMMARY_TABS_IDS,
40
- } from '../../../store/reducers/tenant/constants';
41
-
42
- import {SchemaTree} from '../Schema/SchemaTree/SchemaTree';
43
- import {SchemaViewer} from '../Schema/SchemaViewer/SchemaViewer';
36
+ import {formatDateTime} from '../../../utils/dataFormatters/dataFormatters';
37
+ import {useTypedSelector} from '../../../utils/hooks';
44
38
  import {Acl} from '../Acl/Acl';
45
- import {ExternalTableSummary} from '../Info/ExternalTable/ExternalTable';
39
+ import i18n from '../i18n';
46
40
  import {ExternalDataSourceSummary} from '../Info/ExternalDataSource/ExternalDataSource';
47
-
41
+ import {ExternalTableSummary} from '../Info/ExternalTable/ExternalTable';
42
+ import {SchemaTree} from '../Schema/SchemaTree/SchemaTree';
43
+ import {SchemaViewer} from '../Schema/SchemaViewer/SchemaViewer';
48
44
  import {TenantTabsGroups, TENANT_INFO_TABS, TENANT_SCHEMA_TAB} from '../TenantPages';
49
45
  import {
50
46
  PaneVisibilityActionTypes,
51
- paneVisibilityToggleReducerCreator,
52
47
  PaneVisibilityToggleButtons,
48
+ paneVisibilityToggleReducerCreator,
53
49
  } from '../utils/paneVisibilityToggleHelpers';
54
50
  import {isColumnEntityType, isExternalTable, isIndexTable, isTableType} from '../utils/schema';
55
-
56
- import i18n from '../i18n';
57
-
58
51
  import './ObjectSummary.scss';
59
52
 
60
53
  const b = cn('object-summary');
@@ -306,8 +299,9 @@ export function ObjectSummary({
306
299
  </Button>
307
300
  )}
308
301
  {currentSchemaPath && (
309
- <CopyToClipboard
302
+ <ClipboardButton
310
303
  text={currentSchemaPath}
304
+ view="flat-secondary"
311
305
  title={i18n('summary.copySchemaPath')}
312
306
  />
313
307
  )}
@@ -1,31 +1,25 @@
1
- import React, {useEffect, useState} from 'react';
2
- import {useDispatch} from 'react-redux';
1
+ import {RadioButton, Tabs} from '@gravity-ui/uikit';
3
2
  import cn from 'bem-cn-lite';
3
+ import React, {useEffect, useState} from 'react';
4
4
  import JSONTree from 'react-json-inspector';
5
-
6
- import {RadioButton, Tabs} from '@gravity-ui/uikit';
7
-
8
- import CopyToClipboard from '../../../../components/CopyToClipboard/CopyToClipboard';
5
+ import {useDispatch} from 'react-redux';
6
+ import {ClipboardButton} from '../../../../components/ClipboardButton';
9
7
  import Divider from '../../../../components/Divider/Divider';
10
8
  import EnableFullscreenButton from '../../../../components/EnableFullscreenButton/EnableFullscreenButton';
11
9
  import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
12
10
  import {QueryExecutionStatus} from '../../../../components/QueryExecutionStatus';
13
11
  import {QueryResultTable} from '../../../../components/QueryResultTable/QueryResultTable';
14
-
12
+ import {disableFullscreen} from '../../../../store/reducers/fullscreen';
13
+ import type {ColumnType, KeyValueRow} from '../../../../types/api/query';
15
14
  import type {ValueOf} from '../../../../types/common';
16
15
  import type {IQueryResult, QueryErrorResponse} from '../../../../types/store/query';
17
- import type {ColumnType, KeyValueRow} from '../../../../types/api/query';
18
- import {disableFullscreen} from '../../../../store/reducers/fullscreen';
19
- import {prepareQueryError} from '../../../../utils/query';
20
- import {useTypedSelector} from '../../../../utils/hooks';
21
16
  import {getArray} from '../../../../utils';
22
-
17
+ import {useTypedSelector} from '../../../../utils/hooks';
18
+ import {prepareQueryError} from '../../../../utils/query';
23
19
  import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';
24
-
25
20
  import {ResultIssues} from '../Issues/Issues';
26
21
  import {QueryDuration} from '../QueryDuration/QueryDuration';
27
22
  import {getPreparedResult} from '../utils/getPreparedResult';
28
-
29
23
  import './ExecuteResult.scss';
30
24
 
31
25
  const b = cn('ydb-query-execute-result');
@@ -115,10 +109,10 @@ export function ExecuteResult({
115
109
 
116
110
  const renderClipboardButton = () => {
117
111
  return (
118
- <CopyToClipboard
112
+ <ClipboardButton
119
113
  text={textResults}
114
+ view="flat-secondary"
120
115
  title="Copy results"
121
- toastText="Results were copied to clipboard successfully"
122
116
  disabled={copyDisabled}
123
117
  />
124
118
  );
@@ -17,10 +17,12 @@
17
17
  margin-left: 30px;
18
18
  }
19
19
  }
20
+
20
21
  &__overview-container {
21
22
  display: flex;
22
23
  align-items: center;
23
24
  }
25
+
24
26
  &__info-label {
25
27
  font-weight: 200;
26
28
 
@@ -52,4 +54,17 @@
52
54
  width: 200px;
53
55
  }
54
56
  }
57
+
58
+ &__overview-title {
59
+ display: flex;
60
+ align-items: center;
61
+ }
62
+
63
+ &__clipboard-button {
64
+ visibility: hidden;
65
+
66
+ margin-left: 8px;
67
+
68
+ color: var(--yc-color-text-secondary);
69
+ }
55
70
  }
@@ -1,11 +1,9 @@
1
- import block from 'bem-cn-lite';
2
-
3
1
  import {Progress} from '@gravity-ui/uikit';
4
-
5
- import type {VersionValue} from '../../../types/versions';
2
+ import block from 'bem-cn-lite';
3
+ import {ClipboardButton} from '../../../components/ClipboardButton';
6
4
  import type {PreparedClusterNode} from '../../../store/reducers/clusterNodes/types';
5
+ import type {VersionValue} from '../../../types/versions';
7
6
  import type {GroupedNodesItem} from '../types';
8
-
9
7
  import './NodesTreeTitle.scss';
10
8
 
11
9
  const b = block('ydb-versions-nodes-tree-title');
@@ -43,7 +41,12 @@ export const NodesTreeTitle = ({
43
41
  {versionColor ? (
44
42
  <div className={b('version-color')} style={{background: versionColor}} />
45
43
  ) : null}
46
- <span className={b('overview-title')}>{title}</span>
44
+ {title ? (
45
+ <span className={b('overview-title')}>
46
+ {title}
47
+ <ClipboardButton text={title} size="s" className={b('clipboard-button')} />
48
+ </span>
49
+ ) : null}
47
50
  </div>
48
51
  <div className={b('overview-info')}>
49
52
  <div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.29.0",
3
+ "version": "4.30.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -46,7 +46,7 @@
46
46
  "sass": "1.32.8",
47
47
  "url": "^0.11.0",
48
48
  "web-vitals": "1.1.2",
49
- "ydb-ui-components": "^3.5.0"
49
+ "ydb-ui-components": "^3.6.0"
50
50
  },
51
51
  "scripts": {
52
52
  "start": "react-app-rewired start",
@@ -1,38 +0,0 @@
1
- import {Button, CopyToClipboard as CopyToClipboardUiKit} from '@gravity-ui/uikit';
2
- import createToast from '../../utils/createToast';
3
- import {Icon} from '../Icon';
4
-
5
- interface CopyToClipboardProps {
6
- text: string;
7
- title?: string;
8
- disabled?: boolean;
9
- toastText?: string;
10
- }
11
-
12
- function CopyToClipboard(props: CopyToClipboardProps) {
13
- return (
14
- <CopyToClipboardUiKit text={props.text} timeout={1000}>
15
- {(state) => {
16
- if (state === 'success') {
17
- createToast({
18
- name: 'Copied',
19
- title: props.toastText ?? 'Data was copied to clipboard successfully',
20
- type: state,
21
- });
22
- }
23
-
24
- return (
25
- <Button
26
- disabled={props.disabled}
27
- title={props.title ?? 'Copy'}
28
- view="flat-secondary"
29
- >
30
- <Icon name="copy" viewBox={'0 0 16 16'} width={16} height={16} />
31
- </Button>
32
- );
33
- }}
34
- </CopyToClipboardUiKit>
35
- );
36
- }
37
-
38
- export default CopyToClipboard;