ydb-embedded-ui 3.1.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +2 -0
  3. package/dist/components/DateRange/DateRange.scss +11 -0
  4. package/dist/{containers/Tenant/Diagnostics/TopShards → components}/DateRange/DateRange.tsx +7 -7
  5. package/dist/{containers/Tenant/Diagnostics/TopShards → components}/DateRange/index.ts +0 -0
  6. package/dist/components/EntitiesCount/EntitiesCount.tsx +34 -0
  7. package/dist/components/EntitiesCount/i18n/en.json +3 -0
  8. package/dist/components/{AsideNavigation/Settings → EntitiesCount}/i18n/index.ts +2 -2
  9. package/dist/components/EntitiesCount/i18n/ru.json +3 -0
  10. package/dist/components/EntitiesCount/index.ts +1 -0
  11. package/dist/components/Fullscreen/Fullscreen.scss +7 -5
  12. package/dist/components/Illustration/Illustration.tsx +4 -11
  13. package/dist/components/InfoViewer/InfoViewer.scss +2 -0
  14. package/dist/components/TabletsOverall/TabletsOverall.tsx +4 -4
  15. package/dist/components/TabletsStatistic/TabletsStatistic.tsx +56 -0
  16. package/dist/components/TabletsStatistic/index.ts +1 -0
  17. package/dist/containers/App/App.scss +4 -12
  18. package/dist/containers/AsideNavigation/AsideNavigation.scss +0 -18
  19. package/dist/containers/AsideNavigation/AsideNavigation.tsx +95 -33
  20. package/dist/containers/Heatmap/Heatmap.scss +0 -7
  21. package/dist/containers/Heatmap/Heatmap.tsx +203 -0
  22. package/dist/containers/Heatmap/HeatmapCanvas/HeatmapCanvas.js +2 -1
  23. package/dist/containers/Heatmap/index.ts +1 -0
  24. package/dist/containers/Node/Node.tsx +1 -1
  25. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -1
  26. package/dist/containers/Storage/Storage.js +12 -19
  27. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +16 -0
  28. package/dist/containers/Tablets/Tablets.scss +0 -5
  29. package/dist/containers/Tablets/Tablets.tsx +172 -0
  30. package/dist/containers/Tablets/i18n/en.json +6 -0
  31. package/dist/{components/AsideNavigation → containers/Tablets}/i18n/index.ts +1 -1
  32. package/dist/containers/Tablets/i18n/ru.json +6 -0
  33. package/dist/containers/Tablets/index.ts +1 -0
  34. package/dist/containers/TabletsFilters/TabletsFilters.js +4 -8
  35. package/dist/containers/TabletsFilters/TabletsFilters.scss +6 -2
  36. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +8 -13
  37. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +7 -7
  38. package/dist/containers/Tenant/Diagnostics/{TopShards/TopShards.scss → OverloadedShards/OverloadedShards.scss} +1 -1
  39. package/dist/containers/Tenant/Diagnostics/{TopShards/TopShards.tsx → OverloadedShards/OverloadedShards.tsx} +10 -11
  40. package/dist/containers/Tenant/Diagnostics/{TopShards → OverloadedShards}/i18n/en.json +0 -0
  41. package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/index.ts +11 -0
  42. package/dist/containers/Tenant/Diagnostics/{TopShards → OverloadedShards}/i18n/ru.json +0 -0
  43. package/dist/containers/Tenant/Diagnostics/OverloadedShards/index.ts +1 -0
  44. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -7
  45. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +16 -19
  46. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +202 -0
  47. package/dist/containers/Tenant/Diagnostics/TopQueries/i18n/en.json +4 -0
  48. package/dist/containers/Tenant/Diagnostics/{TopShards → TopQueries}/i18n/index.ts +1 -1
  49. package/dist/containers/Tenant/Diagnostics/TopQueries/i18n/ru.json +4 -0
  50. package/dist/containers/Tenant/Diagnostics/TopQueries/index.ts +1 -0
  51. package/dist/containers/Tenants/Tenants.js +1 -1
  52. package/dist/containers/UserSettings/UserSettings.tsx +5 -4
  53. package/dist/routes.ts +1 -1
  54. package/dist/services/api.d.ts +7 -0
  55. package/dist/store/reducers/describe.ts +4 -1
  56. package/dist/store/reducers/executeTopQueries.ts +170 -0
  57. package/dist/store/reducers/{heatmap.js → heatmap.ts} +33 -18
  58. package/dist/store/reducers/settings.js +13 -3
  59. package/dist/store/reducers/shardsWorkload.ts +9 -9
  60. package/dist/store/reducers/storage.js +2 -0
  61. package/dist/store/reducers/{tablets.js → tablets.ts} +30 -17
  62. package/dist/store/state-url-mapping.js +10 -2
  63. package/dist/types/api/compute.ts +52 -0
  64. package/dist/types/api/consumer.ts +257 -0
  65. package/dist/types/api/enums.ts +2 -2
  66. package/dist/types/api/nodes.ts +5 -2
  67. package/dist/types/api/pdisk.ts +3 -0
  68. package/dist/types/api/schema.ts +17 -3
  69. package/dist/types/api/storage.ts +31 -28
  70. package/dist/types/api/tablet.ts +18 -2
  71. package/dist/types/api/tenant.ts +4 -1
  72. package/dist/types/api/topic.ts +157 -0
  73. package/dist/types/api/vdisk.ts +3 -0
  74. package/dist/types/store/executeTopQueries.ts +29 -0
  75. package/dist/types/store/heatmap.ts +51 -0
  76. package/dist/types/store/schema.ts +3 -3
  77. package/dist/types/store/shardsWorkload.ts +3 -3
  78. package/dist/types/store/tablets.ts +42 -0
  79. package/dist/utils/constants.ts +1 -37
  80. package/dist/utils/getNodesColumns.js +14 -2
  81. package/dist/utils/tablet.ts +53 -0
  82. package/package.json +4 -3
  83. package/dist/components/AsideNavigation/AsideHeader.scss +0 -147
  84. package/dist/components/AsideNavigation/AsideHeader.tsx +0 -389
  85. package/dist/components/AsideNavigation/AsideHeaderFooterItem/AsideHeaderFooterItem.scss +0 -82
  86. package/dist/components/AsideNavigation/AsideHeaderFooterItem/AsideHeaderFooterItem.tsx +0 -138
  87. package/dist/components/AsideNavigation/AsideHeaderFooterSlot/AsideHeaderFooterSlot.tsx +0 -33
  88. package/dist/components/AsideNavigation/AsideHeaderFooterSlot/SlotsContext.tsx +0 -49
  89. package/dist/components/AsideNavigation/AsideHeaderTooltip/AsideHeaderTooltip.scss +0 -16
  90. package/dist/components/AsideNavigation/AsideHeaderTooltip/AsideHeaderTooltip.tsx +0 -37
  91. package/dist/components/AsideNavigation/CompositeBar/CompositeBar.scss +0 -108
  92. package/dist/components/AsideNavigation/CompositeBar/CompositeBar.tsx +0 -282
  93. package/dist/components/AsideNavigation/Content/Content.tsx +0 -35
  94. package/dist/components/AsideNavigation/Drawer/Drawer.scss +0 -76
  95. package/dist/components/AsideNavigation/Drawer/Drawer.tsx +0 -134
  96. package/dist/components/AsideNavigation/Drawer/index.ts +0 -1
  97. package/dist/components/AsideNavigation/Logo/Logo.scss +0 -43
  98. package/dist/components/AsideNavigation/Logo/Logo.tsx +0 -82
  99. package/dist/components/AsideNavigation/Settings/README.md +0 -92
  100. package/dist/components/AsideNavigation/Settings/Settings.scss +0 -128
  101. package/dist/components/AsideNavigation/Settings/Settings.tsx +0 -270
  102. package/dist/components/AsideNavigation/Settings/SettingsMenu/SettingsMenu.scss +0 -78
  103. package/dist/components/AsideNavigation/Settings/SettingsMenu/SettingsMenu.tsx +0 -141
  104. package/dist/components/AsideNavigation/Settings/SettingsSearch/SettingsSearch.tsx +0 -57
  105. package/dist/components/AsideNavigation/Settings/collect-settings.ts +0 -156
  106. package/dist/components/AsideNavigation/Settings/filter-settings.ts +0 -38
  107. package/dist/components/AsideNavigation/Settings/helpers.ts +0 -39
  108. package/dist/components/AsideNavigation/Settings/i18n/en.json +0 -5
  109. package/dist/components/AsideNavigation/Settings/i18n/ru.json +0 -5
  110. package/dist/components/AsideNavigation/Settings/index.ts +0 -1
  111. package/dist/components/AsideNavigation/constants.ts +0 -28
  112. package/dist/components/AsideNavigation/helpers.ts +0 -34
  113. package/dist/components/AsideNavigation/i18n/en.json +0 -4
  114. package/dist/components/AsideNavigation/i18n/ru.json +0 -4
  115. package/dist/components/AsideNavigation/icons.ts +0 -32
  116. package/dist/components/AsideNavigation/types.ts +0 -23
  117. package/dist/components/TabletsStatistic/TabletsStatistic.js +0 -58
  118. package/dist/containers/Heatmap/Heatmap.js +0 -244
  119. package/dist/containers/Tablets/Tablets.js +0 -228
  120. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +0 -188
  121. package/dist/containers/Tenant/Diagnostics/TopShards/DateRange/DateRange.scss +0 -13
  122. package/dist/containers/Tenant/Diagnostics/TopShards/index.ts +0 -1
  123. package/dist/store/reducers/executeTopQueries.js +0 -66
  124. package/dist/types/api/consumers.ts +0 -3
@@ -1,43 +0,0 @@
1
- .nv-aside-header-logo {
2
- display: flex;
3
- flex-shrink: 0;
4
- align-items: center;
5
-
6
- height: 32px;
7
- margin: 12px 0;
8
-
9
- font-family: 'Rubik', sans-serif;
10
-
11
- &__logo-btn-place {
12
- display: flex;
13
- flex-shrink: 0;
14
- justify-content: center;
15
- align-items: center;
16
-
17
- width: var(--nv-aside-header-min-width);
18
- }
19
-
20
- &__logo {
21
- font-family: 'Rubik', sans-serif;
22
- font-size: 16px;
23
- line-height: 20px;
24
- vertical-align: middle;
25
- }
26
-
27
- &__logo-link {
28
- &,
29
- &:hover,
30
- &:active,
31
- &:visited,
32
- &:focus {
33
- text-decoration: none;
34
-
35
- color: inherit;
36
- outline: none;
37
- }
38
- }
39
-
40
- .yc-root &__btn-logo.button2_theme_flat.button2_hovered_yes::before {
41
- background-color: transparent;
42
- }
43
- }
@@ -1,82 +0,0 @@
1
- import React from 'react';
2
- import block from 'bem-cn-lite';
3
- import {Button, Icon} from '@gravity-ui/uikit';
4
-
5
- import './Logo.scss';
6
-
7
- const b = block('nv-aside-header-logo');
8
-
9
- export interface LogoProps {
10
- onLogoIconClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
11
- logoText: (() => React.ReactNode) | string;
12
- logoIcon: SVGIconData;
13
- logoIconClassName?: string;
14
- logoIconSize?: string | number;
15
- logoTextSize?: string | number;
16
- logoHref?: string;
17
- isCompact: boolean;
18
- logoWrapper?: (node: React.ReactNode, isCompact: boolean) => React.ReactNode;
19
- }
20
-
21
- export const Logo: React.FC<LogoProps> = ({
22
- onLogoIconClick,
23
- logoText,
24
- logoIcon,
25
- logoIconSize = 24,
26
- logoTextSize = 16,
27
- logoHref = '/',
28
- logoIconClassName,
29
- isCompact,
30
- logoWrapper,
31
- }) => {
32
- const hasClickHandler = typeof onLogoIconClick === 'function';
33
- const hasLogoWrapper = typeof logoWrapper === 'function';
34
-
35
- const linkProps = hasClickHandler
36
- ? {}
37
- : {
38
- target: '_self',
39
- href: logoHref,
40
- };
41
-
42
- const button = (
43
- <Button
44
- view="flat"
45
- size="l"
46
- className={b('btn-logo')}
47
- component={hasLogoWrapper ? 'span' : undefined}
48
- onClick={onLogoIconClick}
49
- {...linkProps}
50
- >
51
- <Icon data={logoIcon} size={logoIconSize} className={logoIconClassName} />
52
- </Button>
53
- );
54
-
55
- let logo: React.ReactNode;
56
-
57
- if (typeof logoText === 'function') {
58
- logo = logoText();
59
- } else {
60
- logo = (
61
- <div className={b('logo')} style={{fontSize: logoTextSize}}>
62
- {logoText}
63
- </div>
64
- );
65
- }
66
-
67
- return (
68
- <div className={b()}>
69
- <div className={b('logo-btn-place')}>
70
- {typeof logoWrapper === 'function' ? logoWrapper(button, isCompact) : button}
71
- </div>
72
- {!isCompact &&
73
- (typeof logoWrapper === 'function' ? (
74
- logoWrapper(logo, isCompact)
75
- ) : (
76
- <a {...linkProps} className={b('logo-link')} onClick={onLogoIconClick}>
77
- {logo}
78
- </a>
79
- ))}
80
- </div>
81
- );
82
- };
@@ -1,92 +0,0 @@
1
- ### Settings
2
-
3
- Компонент для отображения настроек сервиса. Поддерживает
4
-
5
- - одно-уровневую и двух-уровневую группировки настроек;
6
- - поиск по заголовкам настроек;
7
- - отображение состояния загрузки;
8
-
9
- ### PropTypes
10
-
11
- #### Settings
12
-
13
- | Property | Type | Required | Default | Description |
14
- | :------------- | :------- | :------: | :------ | :----------------------------------------------------------------------- |
15
- | loading | boolean | | | флаг неготовности настроек для отображения |
16
- | renderLoading | Function | | | Содержимое компонента на время загрузки |
17
- | renderNotFound | Function | | | Содержимое страницы при отсутствии найденных элементов |
18
- | initialPage | string | | | Активный раздел настроек по умолчанию в формате "/ид группы/ид страницы" |
19
- | onPageChange | Function | | | Обработчик события изменения активной страницы настроек |
20
-
21
- #### Settings.Group
22
-
23
- | Property | Type | Required | Default | Description |
24
- | :--------- | :----- | :------: | :------ | :--------------------------------------- |
25
- | id | string | | | Уникальный идентификатор группы настроек |
26
- | groupTitle | string | true | | заголовок группы страниц настроек |
27
-
28
- #### Settings.Page
29
-
30
- | Property | Type | Required | Default | Description |
31
- | :------- | :-------- | :------: | :------ | :--------------------------------------------------------- |
32
- | id | string | | | Уникальный идентификатор страницы настроек в рамках группы |
33
- | title | string | true | | заголовок страницы настроек |
34
- | icon | IconProps | true | | данные иконки, отображаемой в меню |
35
-
36
- #### Settings.Section
37
-
38
- | Property | Type | Required | Default | Description |
39
- | :-------- | :-------- | :------: | :------ | :------------------------------------- |
40
- | title | string | true | | заголовок раздела настроек на странице |
41
- | header | ReactNode | | | Шапка секции |
42
- | withBadge | boolean | | | Рисует бэйдж у секции и меню |
43
-
44
- #### Settings.Item
45
-
46
- | Property | Type | Required | Default | Description |
47
- | :------------------- | :-------------- | :------: | :------- | :------------------------------------------ |
48
- | title | string | true | | заголовок настройки |
49
- | renderTitleComponent | Function | | | Произвольное содержимое заголовка настройки |
50
- | align | 'top', 'center' | | 'center' | выравнивание заголовка и контрола |
51
-
52
- ### Использование
53
-
54
- Смотрите в storybook пример `src/strories/demo/SettingsDemo`.
55
-
56
- ### Описание
57
-
58
- Меню настроек может быть одно-уровневым:
59
-
60
- ```jsx
61
- <Settings>
62
- <Settings.Page title="Оформление">...</Settings.Page>
63
- <Settings.Page title="Коммуникации">...</Settings.Page>
64
- </Settings>
65
- ```
66
-
67
- или двух-уровневым:
68
-
69
- ```jsx
70
- <Settings>
71
- <Settings.Group groupTitle="Arcanum">
72
- <Settings.Page title="Оформление">...</Settings.Page>
73
- <Settings.Page title="Коммуникации">...</Settings.Page>
74
- </Settings.Group>
75
- <Settings.Group groupTitle="General">
76
- <Settings.Page title="Оформление">...</Settings.Page>
77
- <Settings.Page title="Коммуникации">...</Settings.Page>
78
- </Settings.Group>
79
- </Settings>
80
- ```
81
-
82
- Страницы настроек делятся на секции с наборами настроек:
83
-
84
- ```jsx
85
- <Settings.Page title="Features" icon={'...'}>
86
- <Settings.Section title="Common">
87
- <Settings.Item title="Default VCS">...</Settings.Item>
88
- <Settings.Item title="Search root">...</Settings.Item>
89
- </Settings.Section>
90
- <Settings.Section title="Beta functionality">...</Settings.Section>
91
- </Settings.Page>
92
- ```
@@ -1,128 +0,0 @@
1
- .nv-settings {
2
- display: grid;
3
- grid-template-columns: 216px 1fr;
4
-
5
- width: 834px;
6
- height: 100%;
7
-
8
- &_loading {
9
- grid-template-columns: auto;
10
- }
11
-
12
- &__loader {
13
- align-self: center;
14
- justify-self: center;
15
- }
16
-
17
- &__not-found {
18
- display: grid;
19
- align-items: center;
20
- justify-items: center;
21
-
22
- height: 100%;
23
- }
24
-
25
- &__menu {
26
- border-right: 1px solid var(--yc-color-line-generic);
27
- }
28
-
29
- &__heading {
30
- margin: 20px 20px 0;
31
-
32
- font-size: var(--yc-text-body-2-font-size);
33
- font-weight: 500;
34
- line-height: var(--yc-text-body-2-line-height);
35
- }
36
-
37
- &__search {
38
- margin: 12px 20px 16px;
39
- }
40
-
41
- &__page {
42
- overflow-y: auto;
43
-
44
- padding: 20px;
45
- }
46
-
47
- &__section {
48
- &-heading {
49
- margin: 0;
50
-
51
- font-size: var(--yc-text-body-2-font-size);
52
- font-weight: 500;
53
- line-height: var(--yc-text-body-2-line-height);
54
-
55
- &_badge {
56
- position: relative;
57
-
58
- display: inline-block;
59
-
60
- &::after {
61
- position: absolute;
62
- top: 1px;
63
- right: -8px;
64
-
65
- display: block;
66
-
67
- width: 6px;
68
- height: 6px;
69
-
70
- content: '';
71
-
72
- border-radius: 50%;
73
- background-color: var(--yc-color-text-danger);
74
- }
75
- }
76
- }
77
-
78
- &-item {
79
- margin-top: 24px;
80
- }
81
-
82
- & + & {
83
- margin-top: 32px;
84
- }
85
- }
86
-
87
- &__item {
88
- display: grid;
89
- grid-template-columns: 216px 1fr;
90
- justify-items: start;
91
-
92
- &_align_top {
93
- align-items: start;
94
- }
95
-
96
- &_align_center {
97
- align-items: center;
98
- }
99
- }
100
-
101
- &__item-heading {
102
- &_badge {
103
- position: relative;
104
-
105
- &::after {
106
- position: absolute;
107
- top: 1px;
108
- right: -10px;
109
-
110
- display: block;
111
-
112
- width: 4px;
113
- height: 4px;
114
-
115
- content: '';
116
-
117
- border-radius: 50%;
118
- background-color: var(--yc-color-text-danger);
119
- }
120
- }
121
- }
122
-
123
- &__found {
124
- font-weight: 500;
125
-
126
- background: var(--yc-color-base-selection);
127
- }
128
- }
@@ -1,270 +0,0 @@
1
- import React from 'react';
2
- import block from 'bem-cn-lite';
3
- import i18n from './i18n';
4
-
5
- import {IconProps, Loader} from '@gravity-ui/uikit';
6
- import {SettingsSearch} from './SettingsSearch/SettingsSearch';
7
- import {SettingsMenu, SettingsMenuItems, SettingsMenuInstance} from './SettingsMenu/SettingsMenu';
8
-
9
- import {getSettingsFromChildren} from './collect-settings';
10
- import {filterSettings} from './filter-settings';
11
- import {escapeStringForRegExp} from './helpers';
12
-
13
- import './Settings.scss';
14
-
15
- const b = block('nv-settings');
16
-
17
- interface SettingsProps {
18
- initialPage?: string;
19
- onPageChange?: (page: string | undefined) => void;
20
- children: React.ReactNode;
21
- renderNotFound?: () => React.ReactNode;
22
- renderLoading?: () => React.ReactNode;
23
- loading?: boolean;
24
- }
25
-
26
- interface SettingsGroupProps {
27
- id?: string;
28
- groupTitle: string;
29
- children: React.ReactNode;
30
- }
31
-
32
- interface SettingsPageProps {
33
- id?: string;
34
- title: string;
35
- icon: IconProps;
36
- children: React.ReactNode;
37
- }
38
-
39
- interface SettingsSectionProps {
40
- title: string;
41
- header?: React.ReactNode;
42
- children: React.ReactNode;
43
- withBadge?: boolean;
44
- }
45
-
46
- interface SettingsItemProps {
47
- title: string;
48
- renderTitleComponent?: (highlightedTitle: React.ReactNode | null) => React.ReactNode;
49
- align?: 'top' | 'center';
50
- children: React.ReactNode;
51
- withBadge?: boolean;
52
- }
53
-
54
- const ItemContext = React.createContext<React.ReactNode>(undefined);
55
-
56
- export function Settings({
57
- initialPage,
58
- onPageChange,
59
- children,
60
- renderNotFound,
61
- loading,
62
- renderLoading,
63
- }: SettingsProps) {
64
- const [search, setSearch] = React.useState('');
65
- const [selectedPage, setCurrentPage] = React.useState<string | undefined>(initialPage);
66
- const prevSelectedPageRef = React.useRef(initialPage);
67
- const searchInputRef = React.useRef<HTMLInputElement>(null);
68
- const menuRef = React.useRef<SettingsMenuInstance>(null);
69
-
70
- React.useEffect(() => {
71
- menuRef.current?.clearFocus();
72
- }, [search]);
73
-
74
- React.useEffect(() => {
75
- const handler = () => {
76
- menuRef.current?.clearFocus();
77
- };
78
- window.addEventListener('click', handler);
79
- return () => {
80
- window.removeEventListener('click', handler);
81
- };
82
- }, []);
83
-
84
- if (selectedPage !== prevSelectedPageRef.current) {
85
- onPageChange?.(selectedPage);
86
- prevSelectedPageRef.current = selectedPage;
87
- }
88
-
89
- if (loading) {
90
- return (
91
- <div className={b({loading: true})}>
92
- {typeof renderLoading === 'function' ? (
93
- renderLoading()
94
- ) : (
95
- <Loader className={b('loader')} size="m" />
96
- )}
97
- </div>
98
- );
99
- }
100
-
101
- const {menu, pages} = getSettingsFromChildren(children);
102
- filterSettings(pages, search, prepareTitle);
103
-
104
- const settingsMenu: SettingsMenuItems = [];
105
- for (const fistLevel of menu) {
106
- if ('groupTitle' in fistLevel) {
107
- settingsMenu.push({
108
- groupTitle: fistLevel.groupTitle,
109
- items: fistLevel.items.map((item) => ({
110
- id: item.pageId,
111
- title: item.title,
112
- icon: item.icon,
113
- disabled: pages[item.pageId].hide,
114
- withBadge: item.withBadge,
115
- })),
116
- });
117
- } else {
118
- settingsMenu.push({
119
- id: fistLevel.pageId,
120
- title: fistLevel.title,
121
- icon: fistLevel.icon,
122
- disabled: pages[fistLevel.pageId].hide,
123
- withBadge: fistLevel.withBadge,
124
- });
125
- }
126
- }
127
-
128
- let activePage = selectedPage;
129
- if (!activePage || pages[activePage]?.hide) {
130
- activePage = undefined;
131
- for (const firstLevel of settingsMenu) {
132
- if ('groupTitle' in firstLevel) {
133
- for (const item of firstLevel.items) {
134
- if (!item.disabled) {
135
- activePage = item.id;
136
- break;
137
- }
138
- }
139
- if (activePage) {
140
- break;
141
- }
142
- } else if (!firstLevel.disabled) {
143
- activePage = firstLevel.id;
144
- break;
145
- }
146
- }
147
- }
148
-
149
- if (activePage !== selectedPage) {
150
- setCurrentPage(activePage);
151
- }
152
-
153
- return (
154
- <div className={b()}>
155
- <div
156
- className={b('menu')}
157
- onClick={() => {
158
- if (searchInputRef.current) {
159
- searchInputRef.current.focus();
160
- }
161
- }}
162
- onKeyDown={(event) => {
163
- if (menuRef.current) {
164
- if (menuRef.current.handleKeyDown(event)) {
165
- event.preventDefault();
166
- }
167
- }
168
- }}
169
- >
170
- <h2 className={b('heading')}>{i18n('heading_settings')}</h2>
171
- <SettingsSearch
172
- inputRef={searchInputRef}
173
- className={b('search')}
174
- onChange={setSearch}
175
- />
176
- <SettingsMenu
177
- ref={menuRef}
178
- items={settingsMenu}
179
- onChange={setCurrentPage}
180
- activeItem={activePage}
181
- />
182
- </div>
183
- <div className={b('page')}>
184
- {activePage ? (
185
- pages[activePage].sections.map((section) => {
186
- if (section.hide) {
187
- return null;
188
- }
189
- return (
190
- <div key={section.title} className={b('section')}>
191
- <h3 className={b('section-heading', {badge: section.withBadge})}>
192
- {section.title}
193
- </h3>
194
- {section.header ? section.header : null}
195
- {section.items.map(({hide, title, children, titleComponent}) =>
196
- hide ? null : (
197
- <div key={title} className={b('section-item')}>
198
- <ItemContext.Provider value={titleComponent}>
199
- {children}
200
- </ItemContext.Provider>
201
- </div>
202
- ),
203
- )}
204
- </div>
205
- );
206
- })
207
- ) : typeof renderNotFound === 'function' ? (
208
- renderNotFound()
209
- ) : (
210
- <div className={b('not-found')}>{i18n('not-found')}</div>
211
- )}
212
- </div>
213
- </div>
214
- );
215
- }
216
-
217
- Settings.Group = function SettingsGroup({children}: SettingsGroupProps) {
218
- return <React.Fragment>{children}</React.Fragment>;
219
- };
220
-
221
- Settings.Page = function SettingsPage({children}: SettingsPageProps) {
222
- return <React.Fragment>{children}</React.Fragment>;
223
- };
224
-
225
- Settings.Section = function SettingsSection({children}: SettingsSectionProps) {
226
- return <React.Fragment>{children}</React.Fragment>;
227
- };
228
-
229
- Settings.Item = function SettingsItem({
230
- title,
231
- children,
232
- align = 'center',
233
- withBadge,
234
- }: SettingsItemProps) {
235
- const contextTitle = React.useContext(ItemContext);
236
- return (
237
- <div className={b('item', {align})}>
238
- <label className={b('item-heading', {badge: withBadge})}>{contextTitle ?? title}</label>
239
- <div>{children}</div>
240
- </div>
241
- );
242
- };
243
-
244
- function prepareTitle(string: string, search: string) {
245
- let temp = string.slice(0);
246
- const title: React.ReactNode[] = [];
247
- const parts = escapeStringForRegExp(search).split(' ').filter(Boolean);
248
- let key = 0;
249
- for (const part of parts) {
250
- const regex = new RegExp(part, 'ig');
251
- const match = regex.exec(temp);
252
- if (match) {
253
- const m = match[0];
254
- const i = match.index;
255
- if (i > 0) {
256
- title.push(temp.slice(0, i));
257
- }
258
- title.push(
259
- <strong key={key++} className={b('found')}>
260
- {m}
261
- </strong>,
262
- );
263
- temp = temp.slice(i + m.length);
264
- }
265
- }
266
- if (temp) {
267
- title.push(temp);
268
- }
269
- return title;
270
- }
@@ -1,78 +0,0 @@
1
- .nv-settings-menu {
2
- &__group {
3
- &-heading {
4
- display: inline-block;
5
-
6
- margin-bottom: 12px;
7
- padding: 0 20px;
8
-
9
- font-weight: 500;
10
- line-height: 18px;
11
- }
12
-
13
- & + & {
14
- margin-top: 24px;
15
- }
16
- }
17
-
18
- &__item {
19
- $item: &;
20
- display: flex;
21
- align-items: center;
22
-
23
- height: 40px;
24
- padding: 0 20px;
25
-
26
- &[class][class] {
27
- color: var(--yc-color-text-primary);
28
-
29
- &#{$item}_disabled {
30
- color: var(--yc-color-text-secondary);
31
-
32
- #{$item}-icon {
33
- color: var(--yc-color-base-misc-heavy);
34
- }
35
- }
36
- }
37
-
38
- &-icon {
39
- margin-right: 5px;
40
-
41
- color: var(--yc-color-text-misc);
42
- }
43
-
44
- &:hover,
45
- &_focused {
46
- background: var(--yc-color-base-simple-hover);
47
- }
48
-
49
- &_selected {
50
- background: var(--yc-color-base-selection);
51
- }
52
-
53
- &_selected:hover,
54
- &_selected#{$item}_focused {
55
- background: var(--yc-color-base-selection-hover);
56
- }
57
-
58
- &_badge {
59
- position: relative;
60
-
61
- &::after {
62
- position: absolute;
63
- top: calc(50% - 3px);
64
- right: 9px;
65
-
66
- display: block;
67
-
68
- width: 6px;
69
- height: 6px;
70
-
71
- content: '';
72
-
73
- border-radius: 50%;
74
- background-color: var(--yc-color-text-danger);
75
- }
76
- }
77
- }
78
- }