ydb-embedded-ui 4.7.0 → 4.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.8.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.8.0...v4.8.1) (2023-06-26)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **Tenants:** fix tenant link ([#439](https://github.com/ydb-platform/ydb-embedded-ui/issues/439)) ([432c621](https://github.com/ydb-platform/ydb-embedded-ui/commit/432c621eb2fb2ffd5a747299af930236d5cc06f7))
9
+
10
+ ## [4.8.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.7.0...v4.8.0) (2023-06-26)
11
+
12
+
13
+ ### Features
14
+
15
+ * **Tenant:** transform general tabs into left navigation items ([#431](https://github.com/ydb-platform/ydb-embedded-ui/issues/431)) ([7117b96](https://github.com/ydb-platform/ydb-embedded-ui/commit/7117b9622d5f6469dcc2bcc1c0d5cb71d4f94c0b))
16
+
3
17
  ## [4.7.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.6.0...v4.7.0) (2023-06-23)
4
18
 
5
19
 
@@ -7,6 +7,9 @@ import cn from 'bem-cn-lite';
7
7
  import {Icon, Button} from '@gravity-ui/uikit';
8
8
  import {AsideHeader, MenuItem as AsideHeaderMenuItem, FooterItem} from '@gravity-ui/navigation';
9
9
 
10
+ import squareChartBarIcon from '@gravity-ui/icons/svgs/square-chart-bar.svg';
11
+ import pulseIcon from '@gravity-ui/icons/svgs/pulse.svg';
12
+
10
13
  import signOutIcon from '../../assets/icons/signOut.svg';
11
14
  import signInIcon from '../../assets/icons/signIn.svg';
12
15
  import ydbLogoIcon from '../../assets/icons/ydb.svg';
@@ -15,18 +18,20 @@ import userChecked from '../../assets/icons/user-check.svg';
15
18
  import settingsIcon from '../../assets/icons/settings.svg';
16
19
  import supportIcon from '../../assets/icons/support.svg';
17
20
 
18
- import {UserSettings} from '../UserSettings/UserSettings';
19
-
20
- import routes, {createHref} from '../../routes';
21
-
22
21
  import {logout} from '../../store/reducers/authentication';
23
22
  import {getParsedSettingValue, setSettingValue} from '../../store/reducers/settings/settings';
23
+ import {TENANT_PAGE, TENANT_PAGES_IDS} from '../../store/reducers/tenant/constants';
24
+ import routes, {TENANT, createHref, parseQuery} from '../../routes';
25
+ import {useSetting, useTypedSelector} from '../../utils/hooks';
26
+ import {ASIDE_HEADER_COMPACT_KEY, TENANT_INITIAL_PAGE_KEY} from '../../utils/constants';
24
27
 
25
- import {ASIDE_HEADER_COMPACT_KEY} from '../../utils/constants';
28
+ import {getTenantPath} from '../Tenant/TenantPages';
29
+ import {UserSettings} from '../UserSettings/UserSettings';
26
30
 
27
31
  import './AsideNavigation.scss';
28
32
 
29
33
  const b = cn('kv-navigation');
34
+
30
35
  interface MenuItem {
31
36
  id: string;
32
37
  title: string;
@@ -111,32 +116,53 @@ interface AsideNavigationProps {
111
116
  setSettingValue: (name: string, value: string) => void;
112
117
  }
113
118
 
114
- // FIXME: add items or delete
115
- const items: MenuItem[] = [];
116
-
117
119
  enum Panel {
118
120
  UserSettings = 'UserSettings',
119
121
  }
120
122
 
121
- function AsideNavigation(props: AsideNavigationProps) {
123
+ export const useGetLeftNavigationItems = () => {
122
124
  const location = useLocation();
123
125
  const history = useHistory();
124
126
 
125
- const [visiblePanel, setVisiblePanel] = useState<Panel>();
127
+ const [initialTenantPage, setInitialTenantPage] = useSetting<string>(TENANT_INITIAL_PAGE_KEY);
128
+ const {tenantPage = initialTenantPage} = useTypedSelector((state) => state.tenant);
126
129
 
127
- const setIsCompact = (compact: boolean) => {
128
- props.setSettingValue(ASIDE_HEADER_COMPACT_KEY, JSON.stringify(compact));
129
- };
130
+ const {pathname} = location;
131
+ const queryParams = parseQuery(location);
132
+
133
+ const isTenantPage = pathname === `/${TENANT}`;
130
134
 
131
135
  const menuItems: AsideHeaderMenuItem[] = React.useMemo(() => {
132
- const {pathname} = location;
133
- const menuItems: AsideHeaderMenuItem[] = items.map((item) => {
134
- const locationKeysCoincidence = item.locationKeys?.filter((key) =>
135
- pathname.startsWith(key),
136
- );
137
- const current =
138
- (locationKeysCoincidence && locationKeysCoincidence.length > 0) ||
139
- item.location.startsWith(pathname);
136
+ if (!isTenantPage) {
137
+ return [];
138
+ }
139
+
140
+ const items: MenuItem[] = [
141
+ {
142
+ id: TENANT_PAGES_IDS.diagnostics,
143
+ title: 'Diagnostics',
144
+ icon: squareChartBarIcon,
145
+ iconSize: 20,
146
+ location: getTenantPath({
147
+ ...queryParams,
148
+ [TENANT_PAGE]: TENANT_PAGES_IDS.diagnostics,
149
+ }),
150
+ },
151
+ {
152
+ id: TENANT_PAGES_IDS.query,
153
+ title: 'Query',
154
+ icon: pulseIcon,
155
+ iconSize: 20,
156
+ location: getTenantPath({
157
+ ...queryParams,
158
+ [TENANT_PAGE]: TENANT_PAGES_IDS.query,
159
+ }),
160
+ },
161
+ ];
162
+
163
+ return items.map((item) => {
164
+ const current = item.id === tenantPage;
165
+
140
166
  return {
141
167
  id: item.id,
142
168
  title: item.title,
@@ -144,12 +170,26 @@ function AsideNavigation(props: AsideNavigationProps) {
144
170
  iconSize: item.iconSize,
145
171
  current,
146
172
  onItemClick: () => {
173
+ setInitialTenantPage(item.id);
147
174
  history.push(item.location);
148
175
  },
149
176
  };
150
177
  });
151
- return menuItems;
152
- }, [location, history]);
178
+ }, [tenantPage, isTenantPage, setInitialTenantPage, history, queryParams]);
179
+
180
+ return menuItems;
181
+ };
182
+
183
+ function AsideNavigation(props: AsideNavigationProps) {
184
+ const history = useHistory();
185
+
186
+ const [visiblePanel, setVisiblePanel] = useState<Panel>();
187
+
188
+ const setIsCompact = (compact: boolean) => {
189
+ props.setSettingValue(ASIDE_HEADER_COMPACT_KEY, JSON.stringify(compact));
190
+ };
191
+
192
+ const menuItems = useGetLeftNavigationItems();
153
193
 
154
194
  return (
155
195
  <React.Fragment>
@@ -11,9 +11,9 @@ import type {EPathType} from '../../../types/api/schema';
11
11
 
12
12
  import {useTypedSelector} from '../../../utils/hooks';
13
13
  import routes, {createHref} from '../../../routes';
14
- import type {TenantDiagnosticsTab, TenantGeneralTab} from '../../../store/reducers/tenant/types';
14
+ import type {TenantDiagnosticsTab} from '../../../store/reducers/tenant/types';
15
15
  import {enableAutorefresh, disableAutorefresh} from '../../../store/reducers/schema/schema';
16
- import {setTopLevelTab, setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
16
+ import { setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
17
17
  import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
18
18
 
19
19
  import {Loader} from '../../../components/Loader';
@@ -96,10 +96,6 @@ function Diagnostics(props: DiagnosticsProps) {
96
96
  }
97
97
  };
98
98
 
99
- const forwardToGeneralTab = (tab: TenantGeneralTab) => {
100
- dispatch(setTopLevelTab(tab));
101
- };
102
-
103
99
  const renderTabContent = () => {
104
100
  const {type} = props;
105
101
 
@@ -116,13 +112,7 @@ function Diagnostics(props: DiagnosticsProps) {
116
112
  );
117
113
  }
118
114
  case TENANT_DIAGNOSTICS_TABS_IDS.topQueries: {
119
- return (
120
- <TopQueries
121
- path={tenantNameString}
122
- changeSchemaTab={forwardToGeneralTab}
123
- type={type}
124
- />
125
- );
115
+ return <TopQueries path={tenantNameString} type={type} />;
126
116
  }
127
117
  case TENANT_DIAGNOSTICS_TABS_IDS.topShards: {
128
118
  return <TopShards tenantPath={tenantNameString} type={type} />;
@@ -22,12 +22,8 @@ import type {KeyValueRow} from '../../../../types/api/query';
22
22
  import type {EPathType} from '../../../../types/api/schema';
23
23
  import type {ITopQueriesFilters} from '../../../../types/store/executeTopQueries';
24
24
  import type {IQueryResult} from '../../../../types/store/query';
25
- import type {TenantGeneralTab} from '../../../../store/reducers/tenant/types';
26
25
 
27
- import {
28
- TENANT_GENERAL_TABS_IDS,
29
- TENANT_QUERY_TABS_ID,
30
- } from '../../../../store/reducers/tenant/constants';
26
+ import {TENANT_PAGE, TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
31
27
  import {formatDateTime, formatNumber} from '../../../../utils';
32
28
  import {HOUR_IN_SECONDS} from '../../../../utils/constants';
33
29
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
@@ -85,7 +81,6 @@ const COLUMNS: Column<KeyValueRow>[] = [
85
81
 
86
82
  interface TopQueriesProps {
87
83
  path: string;
88
- changeSchemaTab: (tab: TenantGeneralTab) => void;
89
84
  type?: EPathType;
90
85
  }
91
86
 
@@ -177,7 +172,7 @@ export const TopQueries = ({path, type}: TopQueriesProps) => {
177
172
 
178
173
  const queryPath = getTenantPath({
179
174
  ...queryParams,
180
- [TenantTabsGroups.general]: TENANT_GENERAL_TABS_IDS.query,
175
+ [TENANT_PAGE]: TENANT_PAGES_IDS.query,
181
176
  [TenantTabsGroups.queryTab]: TENANT_QUERY_TABS_ID.newQuery,
182
177
  });
183
178
 
@@ -1,11 +1,13 @@
1
- import qs from 'qs';
2
1
  import {useLocation} from 'react-router';
3
2
  import cn from 'bem-cn-lite';
4
3
 
5
4
  import {useThemeValue} from '@gravity-ui/uikit';
6
5
 
7
6
  import type {EPathType} from '../../../types/api/schema';
8
- import {TENANT_GENERAL_TABS_IDS} from '../../../store/reducers/tenant/constants';
7
+ import {TENANT_PAGES_IDS} from '../../../store/reducers/tenant/constants';
8
+ import {useSetting} from '../../../utils/hooks';
9
+ import {TENANT_INITIAL_PAGE_KEY} from '../../../utils/constants';
10
+ import {parseQuery} from '../../../routes';
9
11
 
10
12
  import {Query} from '../Query/Query';
11
13
  import Diagnostics from '../Diagnostics/Diagnostics';
@@ -22,19 +24,17 @@ interface ObjectGeneralProps {
22
24
 
23
25
  function ObjectGeneral(props: ObjectGeneralProps) {
24
26
  const location = useLocation();
25
-
26
27
  const theme = useThemeValue();
27
28
 
28
- const queryParams = qs.parse(location.search, {
29
- ignoreQueryPrefix: true,
30
- });
29
+ const [initialPage] = useSetting<string>(TENANT_INITIAL_PAGE_KEY);
31
30
 
32
- const {name: tenantName, general: generalTab} = queryParams;
31
+ const queryParams = parseQuery(location);
32
+ const {name: tenantName, tenantPage = initialPage} = queryParams;
33
33
 
34
34
  const renderTabContent = () => {
35
35
  const {type, additionalTenantInfo, additionalNodesInfo} = props;
36
- switch (generalTab) {
37
- case TENANT_GENERAL_TABS_IDS.query: {
36
+ switch (tenantPage) {
37
+ case TENANT_PAGES_IDS.query: {
38
38
  return <Query path={tenantName as string} theme={theme} type={type} />;
39
39
  }
40
40
  default: {
@@ -47,9 +47,9 @@ import {
47
47
  PaneVisibilityToggleButtons,
48
48
  } from '../utils/paneVisibilityToggleHelpers';
49
49
  import {setShowPreview} from '../../../store/reducers/schema/schema';
50
- import {setQueryTab, setTopLevelTab} from '../../../store/reducers/tenant/tenant';
50
+ import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
51
51
  import {
52
- TENANT_GENERAL_TABS_IDS,
52
+ TENANT_PAGES_IDS,
53
53
  TENANT_QUERY_TABS_ID,
54
54
  } from '../../../store/reducers/tenant/constants';
55
55
 
@@ -278,7 +278,7 @@ function ObjectSummary(props: ObjectSummaryProps) {
278
278
 
279
279
  const onOpenPreview = () => {
280
280
  dispatch(setShowPreview(true));
281
- dispatch(setTopLevelTab(TENANT_GENERAL_TABS_IDS.query));
281
+ dispatch(setTenantPage(TENANT_PAGES_IDS.query));
282
282
  dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
283
283
  };
284
284
 
@@ -15,6 +15,7 @@ import {
15
15
  goToNextQuery,
16
16
  MONACO_HOT_KEY_ACTIONS,
17
17
  setMonacoHotKey,
18
+ setTenantPath,
18
19
  } from '../../../../store/reducers/executeQuery';
19
20
  import {getExplainQuery, getExplainQueryAst} from '../../../../store/reducers/explainQuery';
20
21
  import {getParsedSettingValue, setSettingValue} from '../../../../store/reducers/settings/settings';
@@ -75,6 +76,7 @@ const propTypes = {
75
76
  theme: PropTypes.string,
76
77
  type: PropTypes.string,
77
78
  initialQueryMode: PropTypes.string,
79
+ setTenantPath: PropTypes.func,
78
80
  };
79
81
 
80
82
  const initialTenantCommonInfoState = {
@@ -83,6 +85,9 @@ const initialTenantCommonInfoState = {
83
85
  collapsed: true,
84
86
  };
85
87
  function QueryEditor(props) {
88
+ const {path, executeQuery, theme, setTenantPath, changeUserInput} = props;
89
+ const {tenantPath: savedPath} = executeQuery;
90
+
86
91
  const [resultType, setResultType] = useState(RESULT_TYPES.EXECUTE);
87
92
 
88
93
  const [isResultLoaded, setIsResultLoaded] = useState(false);
@@ -96,6 +101,13 @@ function QueryEditor(props) {
96
101
  }
97
102
  }, [enableAdditionalQueryModes, queryMode, setQueryMode]);
98
103
 
104
+ useEffect(() => {
105
+ if (savedPath !== path) {
106
+ setTenantPath(path);
107
+ changeUserInput({input: ''});
108
+ }
109
+ }, [changeUserInput, setTenantPath, path, savedPath]);
110
+
99
111
  const [resultVisibilityState, dispatchResultVisibilityState] = useReducer(
100
112
  paneVisibilityToggleReducerCreator(DEFAULT_IS_QUERY_RESULT_COLLAPSED),
101
113
  initialTenantCommonInfoState,
@@ -507,7 +519,6 @@ function QueryEditor(props) {
507
519
  );
508
520
  };
509
521
 
510
- const {executeQuery, theme} = props;
511
522
  const result = renderResult();
512
523
 
513
524
  return (
@@ -569,6 +580,7 @@ const mapDispatchToProps = {
569
580
  setSettingValue,
570
581
  setShowPreview,
571
582
  setMonacoHotKey,
583
+ setTenantPath,
572
584
  };
573
585
 
574
586
  QueryEditor.propTypes = propTypes;
@@ -6,12 +6,4 @@
6
6
  font-size: var(--yc-text-body-2-font-size);
7
7
  line-height: var(--yc-text-body-2-line-height);
8
8
  @include flex-container();
9
-
10
- .yc-tabs {
11
- overflow: initial;
12
- }
13
-
14
- &__tab-content {
15
- height: calc(100% - 56px); // general tabs height
16
- }
17
9
  }
@@ -15,7 +15,6 @@ import {getSchemaAcl} from '../../store/reducers/schemaAcl/schemaAcl';
15
15
  import SplitPane from '../../components/SplitPane';
16
16
  import {AccessDenied} from '../../components/Errors/403';
17
17
 
18
- import ObjectGeneralTabs from './ObjectGeneralTabs/ObjectGeneralTabs';
19
18
  import ObjectSummary from './ObjectSummary/ObjectSummary';
20
19
  import ObjectGeneral from './ObjectGeneral/ObjectGeneral';
21
20
 
@@ -111,33 +110,28 @@ function Tenant(props: TenantProps) {
111
110
  {showBlockingError ? (
112
111
  <AccessDenied />
113
112
  ) : (
114
- <>
115
- <ObjectGeneralTabs />
116
- <div className={b('tab-content')}>
117
- <SplitPane
118
- defaultSizePaneKey={DEFAULT_SIZE_TENANT_KEY}
119
- defaultSizes={[25, 75]}
120
- triggerCollapse={summaryVisibilityState.triggerCollapse}
121
- triggerExpand={summaryVisibilityState.triggerExpand}
122
- minSize={[36, 200]}
123
- onSplitStartDragAdditional={onSplitStartDragAdditional}
124
- >
125
- <ObjectSummary
126
- type={preloadedPathType || currentPathType}
127
- subType={preloadedPathSubType || currentPathSubType}
128
- onCollapseSummary={onCollapseSummaryHandler}
129
- onExpandSummary={onExpandSummaryHandler}
130
- isCollapsed={summaryVisibilityState.collapsed}
131
- additionalTenantInfo={props.additionalTenantInfo}
132
- />
133
- <ObjectGeneral
134
- type={preloadedPathType || currentPathType}
135
- additionalTenantInfo={props.additionalTenantInfo}
136
- additionalNodesInfo={props.additionalNodesInfo}
137
- />
138
- </SplitPane>
139
- </div>
140
- </>
113
+ <SplitPane
114
+ defaultSizePaneKey={DEFAULT_SIZE_TENANT_KEY}
115
+ defaultSizes={[25, 75]}
116
+ triggerCollapse={summaryVisibilityState.triggerCollapse}
117
+ triggerExpand={summaryVisibilityState.triggerExpand}
118
+ minSize={[36, 200]}
119
+ onSplitStartDragAdditional={onSplitStartDragAdditional}
120
+ >
121
+ <ObjectSummary
122
+ type={preloadedPathType || currentPathType}
123
+ subType={preloadedPathSubType || currentPathSubType}
124
+ onCollapseSummary={onCollapseSummaryHandler}
125
+ onExpandSummary={onExpandSummaryHandler}
126
+ isCollapsed={summaryVisibilityState.collapsed}
127
+ additionalTenantInfo={props.additionalTenantInfo}
128
+ />
129
+ <ObjectGeneral
130
+ type={preloadedPathType || currentPathType}
131
+ additionalTenantInfo={props.additionalTenantInfo}
132
+ additionalNodesInfo={props.additionalNodesInfo}
133
+ />
134
+ </SplitPane>
141
135
  )}
142
136
  </div>
143
137
  );
@@ -1,6 +1,4 @@
1
- import {TENANT_GENERAL_TABS_IDS} from '../../store/reducers/tenant/constants';
2
1
  import routes, {createHref} from '../../routes';
3
- import {Icon} from '../../components/Icon';
4
2
 
5
3
  export enum TenantInfoTabsIds {
6
4
  overview = 'overview',
@@ -10,23 +8,10 @@ export enum TenantInfoTabsIds {
10
8
 
11
9
  export enum TenantTabsGroups {
12
10
  info = 'info',
13
- general = 'general',
14
11
  queryTab = 'queryTab',
15
12
  diagnosticsTab = 'diagnosticsTab',
16
13
  }
17
14
 
18
- export const TENANT_GENERAL_TABS = [
19
- {
20
- id: TENANT_GENERAL_TABS_IDS.query,
21
- title: 'Query',
22
- icon: <Icon name="query" viewBox="0 0 16 16" />,
23
- },
24
- {
25
- id: TENANT_GENERAL_TABS_IDS.diagnostics,
26
- title: 'Diagnostics',
27
- icon: <Icon name="diagnostics" viewBox="0 0 17 16" />,
28
- },
29
- ];
30
15
  export const TENANT_INFO_TABS = [
31
16
  {
32
17
  id: TenantInfoTabsIds.overview,
@@ -3,10 +3,10 @@ import type {NavigationTreeNodeType, NavigationTreeProps} from 'ydb-ui-component
3
3
 
4
4
  import {changeUserInput} from '../../../store/reducers/executeQuery';
5
5
  import {setShowPreview} from '../../../store/reducers/schema/schema';
6
- import {setQueryTab, setTopLevelTab} from '../../../store/reducers/tenant/tenant';
6
+ import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
7
7
  import {
8
8
  TENANT_QUERY_TABS_ID,
9
- TENANT_GENERAL_TABS_IDS,
9
+ TENANT_PAGES_IDS,
10
10
  } from '../../../store/reducers/tenant/constants';
11
11
  import createToast from '../../../utils/createToast';
12
12
 
@@ -40,7 +40,7 @@ const bindActions = (
40
40
  ) => {
41
41
  const inputQuery = (tmpl: (path: string) => string) => () => {
42
42
  dispatch(changeUserInput({input: tmpl(path)}));
43
- dispatch(setTopLevelTab(TENANT_GENERAL_TABS_IDS.query));
43
+ dispatch(setTenantPage(TENANT_PAGES_IDS.query));
44
44
  dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
45
45
  setActivePath(path);
46
46
  };
@@ -70,7 +70,7 @@ const bindActions = (
70
70
  },
71
71
  openPreview: () => {
72
72
  dispatch(setShowPreview(true));
73
- dispatch(setTopLevelTab(TENANT_GENERAL_TABS_IDS.query));
73
+ dispatch(setTenantPage(TENANT_PAGES_IDS.query));
74
74
  dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
75
75
  setActivePath(path);
76
76
  },
@@ -18,16 +18,12 @@ import {AutoFetcher} from '../../utils/autofetcher';
18
18
  import routes, {createHref} from '../../routes';
19
19
  import {formatCPU, formatBytesToGigabyte, formatNumber} from '../../utils';
20
20
  import {withSearch} from '../../HOCS';
21
- import {DEFAULT_TABLE_SETTINGS, TENANT_INITIAL_TAB_KEY} from '../../utils/constants';
21
+ import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
22
22
  import {getTenantsInfo} from '../../store/reducers/tenants/tenants';
23
- import {
24
- changeFilter,
25
- getSettingValue,
26
- ProblemFilterValues,
27
- } from '../../store/reducers/settings/settings';
23
+ import {changeFilter, ProblemFilterValues} from '../../store/reducers/settings/settings';
28
24
 
29
25
  import {clusterName} from '../../store';
30
- import {TenantTabsGroups, TENANT_GENERAL_TABS, TENANT_INFO_TABS} from '../Tenant/TenantPages';
26
+ import {TenantTabsGroups, TENANT_INFO_TABS} from '../Tenant/TenantPages';
31
27
 
32
28
  import './Tenants.scss';
33
29
 
@@ -114,7 +110,6 @@ class Tenants extends React.Component {
114
110
  filter,
115
111
  handleSearchQuery,
116
112
  additionalTenantsInfo = {},
117
- savedTenantInitialTab,
118
113
  } = this.props;
119
114
 
120
115
  const filteredTenantsBySearch = tenants.filter((item) => {
@@ -123,7 +118,6 @@ class Tenants extends React.Component {
123
118
  });
124
119
  const filteredTenants = Tenants.filterTenants(filteredTenantsBySearch, filter);
125
120
 
126
- const initialTenantGeneralTab = savedTenantInitialTab || TENANT_GENERAL_TABS[0].id;
127
121
  const initialTenantInfoTab = TENANT_INFO_TABS[0].id;
128
122
 
129
123
  const getTenantBackend = (tenant) => {
@@ -153,7 +147,6 @@ class Tenants extends React.Component {
153
147
  name: value,
154
148
  backend,
155
149
  [TenantTabsGroups.info]: initialTenantInfoTab,
156
- [TenantTabsGroups.general]: initialTenantGeneralTab,
157
150
  })}
158
151
  />
159
152
  {additionalTenantsInfo.name && additionalTenantsInfo.name(value, row)}
@@ -359,7 +352,6 @@ const mapStateToProps = (state) => {
359
352
  loading,
360
353
  error,
361
354
  filter: state.settings.problemFilter,
362
- savedTenantInitialTab: getSettingValue(state, TENANT_INITIAL_TAB_KEY),
363
355
  };
364
356
  };
365
357
 
package/dist/routes.ts CHANGED
@@ -5,13 +5,18 @@ import isEmpty from 'lodash/isEmpty';
5
5
 
6
6
  import {backend, clusterName, webVersion} from './store';
7
7
 
8
+ export const CLUSTER = 'cluster';
9
+ export const TENANT = 'tenant';
10
+ export const NODE = 'node';
11
+ export const TABLET = 'tablet';
12
+
8
13
  const routes = {
9
- cluster: '/cluster/:activeTab?',
10
- tenant: '/tenant',
11
- node: '/node/:id/:activeTab?',
12
- tablet: '/tablet/:id',
13
- tabletsFilters: '/tabletsFilters',
14
- auth: '/auth',
14
+ cluster: `/${CLUSTER}/:activeTab?`,
15
+ tenant: `/${TENANT}`,
16
+ node: `/${NODE}/:id/:activeTab?`,
17
+ tablet: `/${TABLET}/:id`,
18
+ tabletsFilters: `/tabletsFilters`,
19
+ auth: `/auth`,
15
20
  };
16
21
 
17
22
  export const parseQuery = (location: Location) => {
@@ -23,7 +23,8 @@ const CHANGE_USER_INPUT = 'query/CHANGE_USER_INPUT';
23
23
  const SAVE_QUERY_TO_HISTORY = 'query/SAVE_QUERY_TO_HISTORY';
24
24
  const GO_TO_PREVIOUS_QUERY = 'query/GO_TO_PREVIOUS_QUERY';
25
25
  const GO_TO_NEXT_QUERY = 'query/GO_TO_NEXT_QUERY';
26
- const MONACO_HOT_KEY = 'query/MONACO_HOT_KEY';
26
+ const SET_MONACO_HOT_KEY = 'query/SET_MONACO_HOT_KEY';
27
+ const SET_TENANT_PATH = 'query/SET_TENANT_PATH';
27
28
 
28
29
  const queriesHistoryInitial: string[] = parseJson(getValueFromLS(QUERIES_HISTORY_KEY, '[]'));
29
30
 
@@ -128,12 +129,18 @@ const executeQuery: Reducer<ExecuteQueryState, ExecuteQueryAction> = (
128
129
  };
129
130
  }
130
131
 
131
- case MONACO_HOT_KEY: {
132
+ case SET_MONACO_HOT_KEY: {
132
133
  return {
133
134
  ...state,
134
135
  monacoHotKey: action.data,
135
136
  };
136
137
  }
138
+ case SET_TENANT_PATH: {
139
+ return {
140
+ ...state,
141
+ tenantPath: action.data,
142
+ };
143
+ }
137
144
 
138
145
  default:
139
146
  return state;
@@ -188,7 +195,14 @@ export const changeUserInput = ({input}: {input: string}) => {
188
195
 
189
196
  export const setMonacoHotKey = (value: MonacoHotKeyAction | null) => {
190
197
  return {
191
- type: MONACO_HOT_KEY,
198
+ type: SET_MONACO_HOT_KEY,
199
+ data: value,
200
+ } as const;
201
+ };
202
+
203
+ export const setTenantPath = (value: string) => {
204
+ return {
205
+ type: SET_TENANT_PATH,
192
206
  data: value,
193
207
  } as const;
194
208
  };
@@ -5,7 +5,7 @@ import type {ValueOf} from '../../../types/common';
5
5
  import {
6
6
  SAVED_QUERIES_KEY,
7
7
  THEME_KEY,
8
- TENANT_INITIAL_TAB_KEY,
8
+ TENANT_INITIAL_PAGE_KEY,
9
9
  INVERTED_DISKS_KEY,
10
10
  ASIDE_HEADER_COMPACT_KEY,
11
11
  USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
@@ -18,6 +18,8 @@ import '../../../services/api';
18
18
  import {getValueFromLS, parseJson} from '../../../utils/utils';
19
19
  import {QueryModes} from '../../../types/store/query';
20
20
 
21
+ import {TENANT_PAGES_IDS} from '../tenant/constants';
22
+
21
23
  import type {RootState} from '..';
22
24
  import type {
23
25
  SetSettingValueAction,
@@ -58,7 +60,10 @@ export const initialState = {
58
60
  'false',
59
61
  ),
60
62
  [SAVED_QUERIES_KEY]: readSavedSettingsValue(SAVED_QUERIES_KEY, '[]'),
61
- [TENANT_INITIAL_TAB_KEY]: readSavedSettingsValue(TENANT_INITIAL_TAB_KEY),
63
+ [TENANT_INITIAL_PAGE_KEY]: readSavedSettingsValue(
64
+ TENANT_INITIAL_PAGE_KEY,
65
+ TENANT_PAGES_IDS.query,
66
+ ),
62
67
  [QUERY_INITIAL_MODE_KEY]: readSavedSettingsValue(QUERY_INITIAL_MODE_KEY, QueryModes.script),
63
68
  [ASIDE_HEADER_COMPACT_KEY]: readSavedSettingsValue(ASIDE_HEADER_COMPACT_KEY, 'true'),
64
69
  [PARTITIONS_HIDDEN_COLUMNS_KEY]: readSavedSettingsValue(PARTITIONS_HIDDEN_COLUMNS_KEY),
@@ -1,4 +1,6 @@
1
- export const TENANT_GENERAL_TABS_IDS = {
1
+ export const TENANT_PAGE = 'tenantPage';
2
+
3
+ export const TENANT_PAGES_IDS = {
2
4
  query: 'query',
3
5
  diagnostics: 'diagnostics',
4
6
  } as const;
@@ -4,7 +4,7 @@ import type {TTenant} from '../../../types/api/tenant';
4
4
  import type {
5
5
  TenantAction,
6
6
  TenantDiagnosticsTab,
7
- TenantGeneralTab,
7
+ TenantPage,
8
8
  TenantQueryTab,
9
9
  TenantState,
10
10
  } from './types';
@@ -60,7 +60,7 @@ const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState,
60
60
  case SET_TOP_LEVEL_TAB: {
61
61
  return {
62
62
  ...state,
63
- topLevelTab: action.data,
63
+ tenantPage: action.data,
64
64
  };
65
65
  }
66
66
  case SET_QUERY_TAB: {
@@ -95,10 +95,10 @@ export const clearTenant = () => {
95
95
  return {type: CLEAR_TENANT} as const;
96
96
  };
97
97
 
98
- export function setTopLevelTab(tab: TenantGeneralTab) {
98
+ export function setTenantPage(page: TenantPage) {
99
99
  return {
100
100
  type: SET_TOP_LEVEL_TAB,
101
- data: tab,
101
+ data: page,
102
102
  } as const;
103
103
  }
104
104
 
@@ -3,21 +3,18 @@ import type {TTenant} from '../../../types/api/tenant';
3
3
  import type {ValueOf} from '../../../types/common';
4
4
  import type {ApiRequestAction} from '../../utils';
5
5
 
6
- import {
7
- TENANT_QUERY_TABS_ID,
8
- TENANT_DIAGNOSTICS_TABS_IDS,
9
- TENANT_GENERAL_TABS_IDS,
10
- } from './constants';
11
- import {FETCH_TENANT, clearTenant, setDiagnosticsTab, setQueryTab, setTopLevelTab} from './tenant';
6
+ import {TENANT_QUERY_TABS_ID, TENANT_DIAGNOSTICS_TABS_IDS, TENANT_PAGES_IDS} from './constants';
7
+ import {FETCH_TENANT, clearTenant, setDiagnosticsTab, setQueryTab, setTenantPage} from './tenant';
8
+
9
+ export type TenantPage = ValueOf<typeof TENANT_PAGES_IDS>;
12
10
 
13
- export type TenantGeneralTab = ValueOf<typeof TENANT_GENERAL_TABS_IDS>;
14
11
  export type TenantQueryTab = ValueOf<typeof TENANT_QUERY_TABS_ID>;
15
12
  export type TenantDiagnosticsTab = ValueOf<typeof TENANT_DIAGNOSTICS_TABS_IDS>;
16
13
 
17
14
  export interface TenantState {
18
15
  loading: boolean;
19
16
  wasLoaded: boolean;
20
- topLevelTab?: TenantGeneralTab;
17
+ tenantPage?: TenantPage;
21
18
  queryTab?: TenantQueryTab;
22
19
  diagnosticsTab?: TenantDiagnosticsTab;
23
20
  tenant?: TTenant;
@@ -27,6 +24,6 @@ export interface TenantState {
27
24
  export type TenantAction =
28
25
  | ApiRequestAction<typeof FETCH_TENANT, TTenant | undefined, IResponseError>
29
26
  | ReturnType<typeof clearTenant>
30
- | ReturnType<typeof setTopLevelTab>
27
+ | ReturnType<typeof setTenantPage>
31
28
  | ReturnType<typeof setQueryTab>
32
29
  | ReturnType<typeof setDiagnosticsTab>;
@@ -42,8 +42,8 @@ const paramSetup = {
42
42
  stateKey: 'tablets.typeFilter',
43
43
  type: 'array',
44
44
  },
45
- general: {
46
- stateKey: 'tenant.topLevelTab',
45
+ tenantPage: {
46
+ stateKey: 'tenant.tenantPage',
47
47
  },
48
48
  queryTab: {
49
49
  stateKey: 'tenant.queryTab',
@@ -5,6 +5,7 @@ import {
5
5
  goToPreviousQuery,
6
6
  setMonacoHotKey,
7
7
  goToNextQuery,
8
+ setTenantPath,
8
9
  MONACO_HOT_KEY_ACTIONS,
9
10
  } from '../../store/reducers/executeQuery';
10
11
  import type {ApiRequestAction} from '../../store/utils';
@@ -22,6 +23,7 @@ export interface ExecuteQueryState {
22
23
  currentIndex: number;
23
24
  };
24
25
  monacoHotKey: null | MonacoHotKeyAction;
26
+ tenantPath?: string;
25
27
  data?: IQueryResult;
26
28
  stats?: IQueryResult['stats'];
27
29
  error?: string | ErrorResponse;
@@ -35,4 +37,5 @@ export type ExecuteQueryAction =
35
37
  | ReturnType<typeof goToPreviousQuery>
36
38
  | ReturnType<typeof changeUserInput>
37
39
  | ReturnType<typeof saveQueryToHistory>
38
- | ReturnType<typeof setMonacoHotKey>;
40
+ | ReturnType<typeof setMonacoHotKey>
41
+ | ReturnType<typeof setTenantPath>;
@@ -104,9 +104,11 @@ export const DEFAULT_TABLE_SETTINGS = {
104
104
  highlightRows: true,
105
105
  } as const;
106
106
 
107
- export const TENANT_INITIAL_TAB_KEY = 'saved_tenant_initial_tab';
108
107
  export const QUERY_INITIAL_MODE_KEY = 'query_initial_mode';
109
108
 
110
109
  export const PARTITIONS_HIDDEN_COLUMNS_KEY = 'partitionsHiddenColumns';
111
110
 
112
111
  export const CLUSTER_INFO_HIDDEN_KEY = 'clusterInfoHidden';
112
+
113
+ // Remain "tab" in key name for backward compatibility
114
+ export const TENANT_INITIAL_PAGE_KEY = 'saved_tenant_initial_tab';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.7.0",
3
+ "version": "4.8.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -1,9 +0,0 @@
1
- @import '../../../styles/mixins.scss';
2
-
3
- .object-general-tabs {
4
- padding: 12px 20px 0 12px;
5
-
6
- &__tab {
7
- text-decoration: none;
8
- }
9
- }
@@ -1,68 +0,0 @@
1
- import qs from 'qs';
2
- import {connect} from 'react-redux';
3
- import {useLocation} from 'react-router';
4
- import {Link} from 'react-router-dom';
5
- import cn from 'bem-cn-lite';
6
-
7
- import {Tabs} from '@gravity-ui/uikit';
8
-
9
- import routes, {createHref} from '../../../routes';
10
- import {TENANT_INITIAL_TAB_KEY} from '../../../utils/constants';
11
- import {setSettingValue} from '../../../store/reducers/settings/settings';
12
-
13
- import {TenantTabsGroups, TENANT_GENERAL_TABS} from '../TenantPages';
14
-
15
- import './ObjectGeneralTabs.scss';
16
-
17
- const b = cn('object-general-tabs');
18
-
19
- interface ObjectGeneralTabsProps {
20
- setSettingValue: (name: string, value: string) => void;
21
- }
22
-
23
- function ObjectGeneralTabs(props: ObjectGeneralTabsProps) {
24
- const location = useLocation();
25
-
26
- const queryParams = qs.parse(location.search, {
27
- ignoreQueryPrefix: true,
28
- });
29
-
30
- const {name: tenantName, general: generalTab} = queryParams;
31
-
32
- const renderContent = () => {
33
- if (!tenantName) {
34
- return null;
35
- }
36
- return (
37
- <div className={b()}>
38
- <Tabs
39
- size="xl"
40
- items={TENANT_GENERAL_TABS}
41
- activeTab={generalTab as string}
42
- wrapTo={({id}, node) => {
43
- const path = createHref(routes.tenant, undefined, {
44
- ...queryParams,
45
- name: tenantName as string,
46
- [TenantTabsGroups.general]: id,
47
- });
48
- return (
49
- <Link to={path} key={id} className={b('tab')}>
50
- {node}
51
- </Link>
52
- );
53
- }}
54
- allowNotSelected
55
- onSelectTab={(id) => props.setSettingValue(TENANT_INITIAL_TAB_KEY, id)}
56
- />
57
- </div>
58
- );
59
- };
60
-
61
- return renderContent();
62
- }
63
-
64
- const mapDispatchToProps = {
65
- setSettingValue,
66
- };
67
-
68
- export default connect(null, mapDispatchToProps)(ObjectGeneralTabs);