ydb-embedded-ui 4.5.0 → 4.5.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.
Files changed (26) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/components/CriticalActionDialog/CriticalActionDialog.tsx +3 -0
  3. package/dist/containers/Tablet/Tablet.scss +4 -0
  4. package/dist/containers/Tablet/Tablet.tsx +2 -1
  5. package/dist/containers/Tablet/TabletControls/TabletControls.tsx +19 -27
  6. package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +2 -2
  7. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +37 -38
  8. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -28
  9. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +2 -2
  10. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +5 -3
  11. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +2 -3
  12. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +3 -3
  13. package/dist/containers/Tenant/Tenant.tsx +14 -15
  14. package/dist/containers/Tenant/TenantPages.tsx +3 -6
  15. package/dist/containers/Tenant/utils/schemaActions.ts +4 -4
  16. package/dist/routes.ts +1 -1
  17. package/dist/store/reducers/index.ts +1 -1
  18. package/dist/store/reducers/tenant/constants.ts +19 -0
  19. package/dist/store/reducers/{tenant.js → tenant/tenant.ts} +27 -36
  20. package/dist/store/reducers/tenant/types.ts +25 -0
  21. package/dist/utils/index.js +2 -1
  22. package/package.json +2 -1
  23. package/dist/components/Breadcrumbs/Breadcrumbs.js +0 -25
  24. package/dist/components/Breadcrumbs/Breadcrumbs.scss +0 -5
  25. package/dist/components/Collapse/Collapse.js +0 -84
  26. package/dist/components/Collapse/Collapse.scss +0 -70
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.5.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.5.0...v4.5.1) (2023-06-02)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **Tablet:** fetch data on action finish ([#405](https://github.com/ydb-platform/ydb-embedded-ui/issues/405)) ([f1d71c5](https://github.com/ydb-platform/ydb-embedded-ui/commit/f1d71c5af330a0a13246f8d87433e6bba1d3509a))
9
+
3
10
  ## [4.5.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.4.2...v4.5.0) (2023-06-01)
4
11
 
5
12
 
@@ -13,6 +13,7 @@ interface CriticalActionDialogProps {
13
13
  text: string;
14
14
  onClose: VoidFunction;
15
15
  onConfirm: () => Promise<unknown>;
16
+ onConfirmActionFinish: VoidFunction;
16
17
  }
17
18
 
18
19
  export const CriticalActionDialog = ({
@@ -20,6 +21,7 @@ export const CriticalActionDialog = ({
20
21
  text,
21
22
  onClose,
22
23
  onConfirm,
24
+ onConfirmActionFinish,
23
25
  }: CriticalActionDialogProps) => {
24
26
  const [isLoading, setIsLoading] = useState(false);
25
27
 
@@ -28,6 +30,7 @@ export const CriticalActionDialog = ({
28
30
  setIsLoading(true);
29
31
 
30
32
  return onConfirm().then(() => {
33
+ onConfirmActionFinish();
31
34
  setIsLoading(false);
32
35
  onClose();
33
36
  });
@@ -52,6 +52,10 @@
52
52
  text-transform: uppercase;
53
53
  }
54
54
 
55
+ &__loader {
56
+ width: 25px;
57
+ }
58
+
55
59
  .info-viewer__items {
56
60
  grid-template-columns: auto;
57
61
  }
@@ -108,9 +108,10 @@ export const Tablet = () => {
108
108
  <Icon name="external" />
109
109
  </a>
110
110
  {Leader && <Tag text="Leader" type="blue" />}
111
+ <span className={b('loader')}>{loading && <Loader size="s" />}</span>
111
112
  </div>
112
113
  <TabletInfo tablet={tablet} tenantPath={tenantPath} />
113
- <TabletControls tablet={tablet} />
114
+ <TabletControls tablet={tablet} fetchData={fetchData} />
114
115
  </div>
115
116
  <div className={b('rigth-pane')}>
116
117
  <TabletTable history={history} />
@@ -17,18 +17,19 @@ type VisibleDialogType = EVisibleDialogType | null;
17
17
 
18
18
  interface TabletControlsProps {
19
19
  tablet: TTabletStateInfo;
20
+ fetchData: VoidFunction;
20
21
  }
21
22
 
22
- export const TabletControls = ({tablet}: TabletControlsProps) => {
23
+ export const TabletControls = ({tablet, fetchData}: TabletControlsProps) => {
23
24
  const {TabletId, HiveId} = tablet;
24
25
 
25
26
  const [isDialogVisible, setIsDialogVisible] = useState(false);
26
27
  const [visibleDialogType, setVisibleDialogType] = useState<VisibleDialogType>(null);
27
- const [isTabletActionsDisabled, setIsTabletActionsDisabled] = useState(false);
28
+ const [isTabletActionLoading, setIsTabletActionLoading] = useState(false);
28
29
 
29
30
  // Enable controls after data update
30
31
  useEffect(() => {
31
- setIsTabletActionsDisabled(false);
32
+ setIsTabletActionLoading(false);
32
33
  }, [tablet]);
33
34
 
34
35
  const makeShowDialog = (type: VisibleDialogType) => () => {
@@ -46,15 +47,15 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
46
47
  };
47
48
 
48
49
  const _onKillClick = () => {
49
- setIsTabletActionsDisabled(true);
50
+ setIsTabletActionLoading(true);
50
51
  return window.api.killTablet(TabletId);
51
52
  };
52
53
  const _onStopClick = () => {
53
- setIsTabletActionsDisabled(true);
54
+ setIsTabletActionLoading(true);
54
55
  return window.api.stopTablet(TabletId, HiveId);
55
56
  };
56
57
  const _onResumeClick = () => {
57
- setIsTabletActionsDisabled(true);
58
+ setIsTabletActionLoading(true);
58
59
  return window.api.resumeTablet(TabletId, HiveId);
59
60
  };
60
61
 
@@ -62,25 +63,11 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
62
63
  return HiveId && HiveId !== '0';
63
64
  };
64
65
 
65
- const isDisabledResume = () => {
66
- if (isTabletActionsDisabled) {
67
- return true;
68
- }
69
-
70
- return tablet.State !== ETabletState.Stopped && tablet.State !== ETabletState.Dead;
71
- };
72
-
73
- const isDisabledKill = () => {
74
- return isTabletActionsDisabled;
75
- };
76
-
77
- const isDisabledStop = () => {
78
- if (isTabletActionsDisabled) {
79
- return true;
80
- }
66
+ const isDisabledResume =
67
+ tablet.State !== ETabletState.Stopped && tablet.State !== ETabletState.Dead;
81
68
 
82
- return tablet.State === ETabletState.Stopped || tablet.State === ETabletState.Deleted;
83
- };
69
+ const isDisabledStop =
70
+ tablet.State === ETabletState.Stopped || tablet.State === ETabletState.Deleted;
84
71
 
85
72
  const renderDialog = () => {
86
73
  if (!isDialogVisible) {
@@ -95,6 +82,7 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
95
82
  text={i18n('dialog.kill')}
96
83
  onClose={hideDialog}
97
84
  onConfirm={_onKillClick}
85
+ onConfirmActionFinish={fetchData}
98
86
  />
99
87
  );
100
88
  }
@@ -105,6 +93,7 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
105
93
  text={i18n('dialog.stop')}
106
94
  onClose={hideDialog}
107
95
  onConfirm={_onStopClick}
96
+ onConfirmActionFinish={fetchData}
108
97
  />
109
98
  );
110
99
  }
@@ -115,6 +104,7 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
115
104
  text={i18n('dialog.resume')}
116
105
  onClose={hideDialog}
117
106
  onConfirm={_onResumeClick}
107
+ onConfirmActionFinish={fetchData}
118
108
  />
119
109
  );
120
110
  }
@@ -128,7 +118,7 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
128
118
  <Button
129
119
  onClick={showKillDialog}
130
120
  view="action"
131
- disabled={isDisabledKill()}
121
+ loading={isTabletActionLoading}
132
122
  className={b('control')}
133
123
  >
134
124
  {i18n('controls.kill')}
@@ -138,7 +128,8 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
138
128
  <Button
139
129
  onClick={showStopDialog}
140
130
  view="action"
141
- disabled={isDisabledStop()}
131
+ disabled={isDisabledStop}
132
+ loading={!isDisabledStop && isTabletActionLoading}
142
133
  className={b('control')}
143
134
  >
144
135
  {i18n('controls.stop')}
@@ -146,7 +137,8 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
146
137
  <Button
147
138
  onClick={showResumeDialog}
148
139
  view="action"
149
- disabled={isDisabledResume()}
140
+ disabled={isDisabledResume}
141
+ loading={!isDisabledResume && isTabletActionLoading}
150
142
  className={b('control')}
151
143
  >
152
144
  {i18n('controls.resume')}
@@ -3,13 +3,13 @@ import block from 'bem-cn-lite';
3
3
  import qs from 'qs';
4
4
 
5
5
  import type {IPreparedConsumerData} from '../../../../../types/store/topic';
6
+ import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants';
6
7
  import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
7
8
  import {InternalLink} from '../../../../../components/InternalLink';
8
9
  import {formatMsToUptime} from '../../../../../utils';
9
10
  import routes, {createHref} from '../../../../../routes';
10
11
 
11
12
  import {TenantTabsGroups} from '../../../TenantPages';
12
- import {GeneralPagesIds} from '../../DiagnosticsPages';
13
13
 
14
14
  import {
15
15
  CONSUMERS_COLUMNS_IDS,
@@ -42,7 +42,7 @@ export const columns: Column<IPreparedConsumerData>[] = [
42
42
  <InternalLink
43
43
  to={createHref(routes.tenant, undefined, {
44
44
  ...queryParams,
45
- [TenantTabsGroups.generalTab]: GeneralPagesIds.partitions,
45
+ [TenantTabsGroups.generalTab]: TENANT_DIAGNOSTICS_TABS_IDS.partitions,
46
46
  selectedConsumer: row.name,
47
47
  })}
48
48
  >
@@ -7,37 +7,36 @@ import {useLocation} from 'react-router';
7
7
 
8
8
  import {Switch, Tabs} from '@gravity-ui/uikit';
9
9
 
10
+ import type {EPathType} from '../../../types/api/schema';
11
+
12
+ import {useTypedSelector} from '../../../utils/hooks';
13
+ import routes, {createHref} from '../../../routes';
14
+ import type {TenantDiagnosticsTab, TenantGeneralTab} from '../../../store/reducers/tenant/types';
15
+ import {enableAutorefresh, disableAutorefresh} from '../../../store/reducers/schema';
16
+ import {setTopLevelTab, setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
17
+ import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
18
+
10
19
  import {Loader} from '../../../components/Loader';
11
20
 
12
- import {TopQueries} from './TopQueries';
13
- //@ts-ignore
14
- import DetailedOverview from './DetailedOverview/DetailedOverview';
15
- import {TopShards} from './TopShards';
16
- //@ts-ignore
17
- import Storage from '../../Storage/Storage';
18
- //@ts-ignore
19
- import Network from './Network/Network';
20
- //@ts-ignore
21
- import Describe from './Describe/Describe';
22
- //@ts-ignore
23
- import HotKeys from './HotKeys/HotKeys';
24
- //@ts-ignore
25
21
  import {Heatmap} from '../../Heatmap';
26
22
  import {Nodes} from '../../Nodes';
27
- //@ts-ignore
23
+ import Storage from '../../Storage/Storage';
28
24
  import {Tablets} from '../../Tablets';
29
- import {Consumers} from './Consumers';
25
+
26
+ import Describe from './Describe/Describe';
27
+ import HotKeys from './HotKeys/HotKeys';
28
+ import Network from './Network/Network';
30
29
  import {Partitions} from './Partitions/Partitions';
30
+ import {Consumers} from './Consumers';
31
+ import {TopQueries} from './TopQueries';
32
+ import {TopShards} from './TopShards';
33
+ import DetailedOverview from './DetailedOverview/DetailedOverview';
31
34
 
32
- import routes, {createHref} from '../../../routes';
33
- import type {EPathType} from '../../../types/api/schema';
34
- import {TenantGeneralTabsIds, TenantTabsGroups} from '../TenantPages';
35
- import {GeneralPagesIds, DATABASE_PAGES, getPagesByType} from './DiagnosticsPages';
36
- //@ts-ignore
37
- import {enableAutorefresh, disableAutorefresh} from '../../../store/reducers/schema';
38
- import {setTopLevelTab, setDiagnosticsTab} from '../../../store/reducers/tenant';
39
35
  import {isDatabaseEntityType} from '../utils/schema';
40
36
 
37
+ import {TenantTabsGroups} from '../TenantPages';
38
+ import {DATABASE_PAGES, getPagesByType} from './DiagnosticsPages';
39
+
41
40
  import './Diagnostics.scss';
42
41
 
43
42
  interface DiagnosticsProps {
@@ -51,8 +50,8 @@ const b = cn('kv-tenant-diagnostics');
51
50
  function Diagnostics(props: DiagnosticsProps) {
52
51
  const dispatch = useDispatch();
53
52
  const {currentSchemaPath, autorefresh} = useSelector((state: any) => state.schema);
54
- const {diagnosticsTab = GeneralPagesIds.overview, wasLoaded} = useSelector(
55
- (state: any) => state.tenant,
53
+ const {diagnosticsTab = TENANT_DIAGNOSTICS_TABS_IDS.overview, wasLoaded} = useTypedSelector(
54
+ (state) => state.tenant,
56
55
  );
57
56
 
58
57
  const location = useLocation();
@@ -73,7 +72,7 @@ function Diagnostics(props: DiagnosticsProps) {
73
72
  return getPagesByType(props.type);
74
73
  }, [props.type, isDatabase]);
75
74
 
76
- const forwardToDiagnosticTab = (tab: GeneralPagesIds) => {
75
+ const forwardToDiagnosticTab = (tab: TenantDiagnosticsTab) => {
77
76
  dispatch(setDiagnosticsTab(tab));
78
77
  };
79
78
  const activeTab = useMemo(() => {
@@ -97,7 +96,7 @@ function Diagnostics(props: DiagnosticsProps) {
97
96
  }
98
97
  };
99
98
 
100
- const forwardToGeneralTab = (tab: TenantGeneralTabsIds) => {
99
+ const forwardToGeneralTab = (tab: TenantGeneralTab) => {
101
100
  dispatch(setTopLevelTab(tab));
102
101
  };
103
102
 
@@ -107,7 +106,7 @@ function Diagnostics(props: DiagnosticsProps) {
107
106
  const tenantNameString = tenantName as string;
108
107
 
109
108
  switch (diagnosticsTab) {
110
- case GeneralPagesIds.overview: {
109
+ case TENANT_DIAGNOSTICS_TABS_IDS.overview: {
111
110
  return (
112
111
  <DetailedOverview
113
112
  type={type}
@@ -116,7 +115,7 @@ function Diagnostics(props: DiagnosticsProps) {
116
115
  />
117
116
  );
118
117
  }
119
- case GeneralPagesIds.topQueries: {
118
+ case TENANT_DIAGNOSTICS_TABS_IDS.topQueries: {
120
119
  return (
121
120
  <TopQueries
122
121
  path={tenantNameString}
@@ -125,10 +124,10 @@ function Diagnostics(props: DiagnosticsProps) {
125
124
  />
126
125
  );
127
126
  }
128
- case GeneralPagesIds.topShards: {
127
+ case TENANT_DIAGNOSTICS_TABS_IDS.topShards: {
129
128
  return <TopShards tenantPath={tenantNameString} type={type} />;
130
129
  }
131
- case GeneralPagesIds.nodes: {
130
+ case TENANT_DIAGNOSTICS_TABS_IDS.nodes: {
132
131
  return (
133
132
  <Nodes
134
133
  path={currentSchemaPath}
@@ -137,28 +136,28 @@ function Diagnostics(props: DiagnosticsProps) {
137
136
  />
138
137
  );
139
138
  }
140
- case GeneralPagesIds.tablets: {
139
+ case TENANT_DIAGNOSTICS_TABS_IDS.tablets: {
141
140
  return <Tablets path={currentSchemaPath} />;
142
141
  }
143
- case GeneralPagesIds.storage: {
142
+ case TENANT_DIAGNOSTICS_TABS_IDS.storage: {
144
143
  return <Storage tenant={tenantNameString} database={true} />;
145
144
  }
146
- case GeneralPagesIds.network: {
145
+ case TENANT_DIAGNOSTICS_TABS_IDS.network: {
147
146
  return <Network path={tenantNameString} />;
148
147
  }
149
- case GeneralPagesIds.describe: {
148
+ case TENANT_DIAGNOSTICS_TABS_IDS.describe: {
150
149
  return <Describe tenant={tenantNameString} type={type} />;
151
150
  }
152
- case GeneralPagesIds.hotKeys: {
151
+ case TENANT_DIAGNOSTICS_TABS_IDS.hotKeys: {
153
152
  return <HotKeys type={type} />;
154
153
  }
155
- case GeneralPagesIds.graph: {
154
+ case TENANT_DIAGNOSTICS_TABS_IDS.graph: {
156
155
  return <Heatmap path={currentSchemaPath} />;
157
156
  }
158
- case GeneralPagesIds.consumers: {
157
+ case TENANT_DIAGNOSTICS_TABS_IDS.consumers: {
159
158
  return <Consumers path={currentSchemaPath} type={type} />;
160
159
  }
161
- case GeneralPagesIds.partitions: {
160
+ case TENANT_DIAGNOSTICS_TABS_IDS.partitions: {
162
161
  return <Partitions path={currentSchemaPath} />;
163
162
  }
164
163
  default: {
@@ -1,80 +1,67 @@
1
+ import type {TenantDiagnosticsTab} from '../../../store/reducers/tenant/types';
2
+ import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
1
3
  import {EPathType} from '../../../types/api/schema';
2
4
 
3
- export enum GeneralPagesIds {
4
- 'overview' = 'Overview',
5
- 'topQueries' = 'topQueries',
6
- 'topShards' = 'topShards',
7
- 'nodes' = 'Nodes',
8
- 'tablets' = 'Tablets',
9
- 'storage' = 'Storage',
10
- 'network' = 'Network',
11
- 'describe' = 'Describe',
12
- 'hotKeys' = 'hotKeys',
13
- 'graph' = 'graph',
14
- 'consumers' = 'consumers',
15
- 'partitions' = 'partitions',
16
- }
17
-
18
5
  type Page = {
19
- id: GeneralPagesIds;
6
+ id: TenantDiagnosticsTab;
20
7
  title: string;
21
8
  };
22
9
 
23
10
  const overview = {
24
- id: GeneralPagesIds.overview,
11
+ id: TENANT_DIAGNOSTICS_TABS_IDS.overview,
25
12
  title: 'Info',
26
13
  };
27
14
 
28
15
  const topQueries = {
29
- id: GeneralPagesIds.topQueries,
16
+ id: TENANT_DIAGNOSTICS_TABS_IDS.topQueries,
30
17
  title: 'Top queries',
31
18
  };
32
19
 
33
20
  const topShards = {
34
- id: GeneralPagesIds.topShards,
21
+ id: TENANT_DIAGNOSTICS_TABS_IDS.topShards,
35
22
  title: 'Top shards',
36
23
  };
37
24
 
38
25
  const nodes = {
39
- id: GeneralPagesIds.nodes,
26
+ id: TENANT_DIAGNOSTICS_TABS_IDS.nodes,
40
27
  title: 'Nodes',
41
28
  };
42
29
 
43
30
  const tablets = {
44
- id: GeneralPagesIds.tablets,
31
+ id: TENANT_DIAGNOSTICS_TABS_IDS.tablets,
45
32
  title: 'Tablets',
46
33
  };
47
34
  const storage = {
48
- id: GeneralPagesIds.storage,
35
+ id: TENANT_DIAGNOSTICS_TABS_IDS.storage,
49
36
  title: 'Storage',
50
37
  };
51
38
  const network = {
52
- id: GeneralPagesIds.network,
39
+ id: TENANT_DIAGNOSTICS_TABS_IDS.network,
53
40
  title: 'Network',
54
41
  };
55
42
 
56
43
  const describe = {
57
- id: GeneralPagesIds.describe,
44
+ id: TENANT_DIAGNOSTICS_TABS_IDS.describe,
58
45
  title: 'Describe',
59
46
  };
60
47
 
61
48
  const hotKeys = {
62
- id: GeneralPagesIds.hotKeys,
49
+ id: TENANT_DIAGNOSTICS_TABS_IDS.hotKeys,
63
50
  title: 'Hot keys',
64
51
  };
65
52
 
66
53
  const graph = {
67
- id: GeneralPagesIds.graph,
54
+ id: TENANT_DIAGNOSTICS_TABS_IDS.graph,
68
55
  title: 'Graph',
69
56
  };
70
57
 
71
58
  const consumers = {
72
- id: GeneralPagesIds.consumers,
59
+ id: TENANT_DIAGNOSTICS_TABS_IDS.consumers,
73
60
  title: 'Consumers',
74
61
  };
75
62
 
76
63
  const partitions = {
77
- id: GeneralPagesIds.partitions,
64
+ id: TENANT_DIAGNOSTICS_TABS_IDS.partitions,
78
65
  title: 'Partitions',
79
66
  };
80
67
 
@@ -9,7 +9,7 @@ import InfoViewer from '../../../../components/InfoViewer/InfoViewer';
9
9
  import PoolUsage from '../../../../components/PoolUsage/PoolUsage';
10
10
  import {Tablet} from '../../../../components/Tablet';
11
11
 
12
- import {getTenantInfo} from '../../../../store/reducers/tenant';
12
+ import {getTenantInfo} from '../../../../store/reducers/tenant/tenant';
13
13
 
14
14
  import {formatCPU} from '../../../../utils';
15
15
  import {bytesToGB} from '../../../../utils/utils';
@@ -191,7 +191,7 @@ class TenantOverview extends React.Component {
191
191
  }
192
192
 
193
193
  function mapStateToProps(state) {
194
- const {tenant = {}, loading, data: {status} = {}} = state.tenant;
194
+ const {tenant = {}, loading, error: {status} = {}} = state.tenant;
195
195
  const {autorefresh} = state.schema;
196
196
 
197
197
  return {
@@ -22,7 +22,9 @@ 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';
25
26
 
27
+ import {TENANT_GENERAL_TABS_IDS} from '../../../../store/reducers/tenant/constants';
26
28
  import {formatDateTime, formatNumber} from '../../../../utils';
27
29
  import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
28
30
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
@@ -30,7 +32,7 @@ import {prepareQueryError} from '../../../../utils/query';
30
32
  import routes, {createHref} from '../../../../routes';
31
33
 
32
34
  import {isColumnEntityType} from '../../utils/schema';
33
- import {TenantGeneralTabsIds, TenantTabsGroups} from '../../TenantPages';
35
+ import {TenantTabsGroups} from '../../TenantPages';
34
36
 
35
37
  import i18n from './i18n';
36
38
  import './TopQueries.scss';
@@ -86,7 +88,7 @@ const COLUMNS: Column<KeyValueRow>[] = [
86
88
 
87
89
  interface TopQueriesProps {
88
90
  path: string;
89
- changeSchemaTab: (tab: TenantGeneralTabsIds) => void;
91
+ changeSchemaTab: (tab: TenantGeneralTab) => void;
90
92
  type?: EPathType;
91
93
  }
92
94
 
@@ -178,7 +180,7 @@ export const TopQueries = ({path, type}: TopQueriesProps) => {
178
180
 
179
181
  const queryPath = createHref(routes.tenant, undefined, {
180
182
  ...queryParams,
181
- [TenantTabsGroups.general]: TenantGeneralTabsIds.query,
183
+ [TenantTabsGroups.general]: TENANT_GENERAL_TABS_IDS.query,
182
184
  });
183
185
 
184
186
  history.push(queryPath);
@@ -5,12 +5,11 @@ import cn from 'bem-cn-lite';
5
5
  import {useThemeValue} from '@gravity-ui/uikit';
6
6
 
7
7
  import type {EPathType} from '../../../types/api/schema';
8
+ import {TENANT_GENERAL_TABS_IDS} from '../../../store/reducers/tenant/constants';
8
9
 
9
10
  import QueryEditor from '../QueryEditor/QueryEditor';
10
11
  import Diagnostics from '../Diagnostics/Diagnostics';
11
12
 
12
- import {TenantGeneralTabsIds} from '../TenantPages';
13
-
14
13
  import './ObjectGeneral.scss';
15
14
 
16
15
  const b = cn('object-general');
@@ -35,7 +34,7 @@ function ObjectGeneral(props: ObjectGeneralProps) {
35
34
  const renderTabContent = () => {
36
35
  const {type, additionalTenantInfo, additionalNodesInfo} = props;
37
36
  switch (generalTab) {
38
- case TenantGeneralTabsIds.query: {
37
+ case TENANT_GENERAL_TABS_IDS.query: {
39
38
  return <QueryEditor path={tenantName as string} theme={theme} type={type} />;
40
39
  }
41
40
  default: {
@@ -35,7 +35,6 @@ import {
35
35
  DEFAULT_SIZE_TENANT_SUMMARY_KEY,
36
36
  } from '../../../utils/constants';
37
37
  import {
38
- TenantGeneralTabsIds,
39
38
  TenantInfoTabsIds,
40
39
  TenantTabsGroups,
41
40
  TENANT_INFO_TABS,
@@ -48,7 +47,8 @@ import {
48
47
  PaneVisibilityToggleButtons,
49
48
  } from '../utils/paneVisibilityToggleHelpers';
50
49
  import {setShowPreview} from '../../../store/reducers/schema';
51
- import {setTopLevelTab} from '../../../store/reducers/tenant';
50
+ import {setTopLevelTab} from '../../../store/reducers/tenant/tenant';
51
+ import {TENANT_GENERAL_TABS_IDS} from '../../../store/reducers/tenant/constants';
52
52
 
53
53
  import './ObjectSummary.scss';
54
54
 
@@ -275,7 +275,7 @@ function ObjectSummary(props: ObjectSummaryProps) {
275
275
 
276
276
  const onOpenPreview = () => {
277
277
  dispatch(setShowPreview(true));
278
- dispatch(setTopLevelTab(TenantGeneralTabsIds.query));
278
+ dispatch(setTopLevelTab(TENANT_GENERAL_TABS_IDS.query));
279
279
  };
280
280
 
281
281
  const renderCommonInfoControls = () => {
@@ -4,28 +4,27 @@ import cn from 'bem-cn-lite';
4
4
  import {useLocation} from 'react-router';
5
5
  import qs from 'qs';
6
6
 
7
- import {AccessDenied} from '../../components/Errors/403';
7
+ import type {TEvDescribeSchemeResult} from '../../types/api/schema';
8
8
 
9
+ import {DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY} from '../../utils/constants';
10
+ import {useTypedSelector} from '../../utils/hooks';
11
+ import routes, {CLUSTER_PAGES, createHref} from '../../routes';
9
12
  import {setHeader} from '../../store/reducers/header';
13
+ import {disableAutorefresh, getSchema, resetLoadingState} from '../../store/reducers/schema';
14
+ import {getSchemaAcl} from '../../store/reducers/schemaAcl';
15
+ import {getTenantInfo, clearTenant} from '../../store/reducers/tenant/tenant';
16
+
17
+ import SplitPane from '../../components/SplitPane';
18
+ import {AccessDenied} from '../../components/Errors/403';
19
+
10
20
  import ObjectGeneralTabs from './ObjectGeneralTabs/ObjectGeneralTabs';
11
21
  import ObjectSummary from './ObjectSummary/ObjectSummary';
12
22
  import ObjectGeneral from './ObjectGeneral/ObjectGeneral';
13
- //@ts-ignore
14
- import SplitPane from '../../components/SplitPane';
15
- //@ts-ignore
16
- import {DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY} from '../../utils/constants';
17
- //@ts-ignore
18
- import {disableAutorefresh, getSchema, resetLoadingState} from '../../store/reducers/schema';
19
- //@ts-ignore
20
- import {getSchemaAcl} from '../../store/reducers/schemaAcl';
23
+
21
24
  import {
22
25
  PaneVisibilityActionTypes,
23
26
  paneVisibilityToggleReducerCreator,
24
27
  } from './utils/paneVisibilityToggleHelpers';
25
- //@ts-ignore
26
- import {getTenantInfo, clearTenant} from '../../store/reducers/tenant';
27
- import routes, {CLUSTER_PAGES, createHref} from '../../routes';
28
- import type {TEvDescribeSchemeResult} from '../../types/api/schema';
29
28
 
30
29
  import './Tenant.scss';
31
30
 
@@ -63,8 +62,8 @@ function Tenant(props: TenantProps) {
63
62
  const {PathType: currentPathType, PathSubType: currentPathSubType} =
64
63
  (currentItem as TEvDescribeSchemeResult).PathDescription?.Self || {};
65
64
 
66
- const {data: {status: tenantStatus = 200} = {}} = useSelector((state: any) => state.tenant);
67
- const {error: {status: schemaStatus = 200} = {}} = useSelector((state: any) => state.schema);
65
+ const {error: {status: tenantStatus = 200} = {}} = useTypedSelector((state) => state.tenant);
66
+ const {error: {status: schemaStatus = 200} = {}} = useTypedSelector((state) => state.schema);
68
67
 
69
68
  const dispatch = useDispatch();
70
69
 
@@ -1,9 +1,6 @@
1
1
  import {Icon} from '../../components/Icon';
2
+ import {TENANT_GENERAL_TABS_IDS} from '../../store/reducers/tenant/constants';
2
3
 
3
- export enum TenantGeneralTabsIds {
4
- query = 'query',
5
- diagnostics = 'diagnostics',
6
- }
7
4
  export enum TenantInfoTabsIds {
8
5
  overview = 'overview',
9
6
  acl = 'acl',
@@ -18,12 +15,12 @@ export enum TenantTabsGroups {
18
15
 
19
16
  export const TENANT_GENERAL_TABS = [
20
17
  {
21
- id: TenantGeneralTabsIds.query,
18
+ id: TENANT_GENERAL_TABS_IDS.query,
22
19
  title: 'Query',
23
20
  icon: <Icon name="query" viewBox="0 0 16 16" />,
24
21
  },
25
22
  {
26
- id: TenantGeneralTabsIds.diagnostics,
23
+ id: TENANT_GENERAL_TABS_IDS.diagnostics,
27
24
  title: 'Diagnostics',
28
25
  icon: <Icon name="diagnostics" viewBox="0 0 17 16" />,
29
26
  },
@@ -3,9 +3,9 @@ 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';
6
- import {setTopLevelTab} from '../../../store/reducers/tenant';
6
+ import {setTopLevelTab} from '../../../store/reducers/tenant/tenant';
7
+ import {TENANT_GENERAL_TABS_IDS} from '../../../store/reducers/tenant/constants';
7
8
  import createToast from '../../../utils/createToast';
8
- import {TenantGeneralTabsIds} from '../TenantPages';
9
9
 
10
10
  const createTableTemplate = (path: string) => {
11
11
  return `CREATE TABLE \`${path}/my_table\`
@@ -37,7 +37,7 @@ const bindActions = (
37
37
  ) => {
38
38
  const inputQuery = (tmpl: (path: string) => string) => () => {
39
39
  dispatch(changeUserInput({input: tmpl(path)}));
40
- dispatch(setTopLevelTab(TenantGeneralTabsIds.query));
40
+ dispatch(setTopLevelTab(TENANT_GENERAL_TABS_IDS.query));
41
41
  setActivePath(path);
42
42
  };
43
43
 
@@ -66,7 +66,7 @@ const bindActions = (
66
66
  },
67
67
  openPreview: () => {
68
68
  dispatch(setShowPreview(true));
69
- dispatch(setTopLevelTab(TenantGeneralTabsIds.query));
69
+ dispatch(setTopLevelTab(TENANT_GENERAL_TABS_IDS.query));
70
70
  setActivePath(path);
71
71
  },
72
72
  };
package/dist/routes.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import qs from 'qs';
2
2
  import {compile} from 'path-to-regexp';
3
3
  import isEmpty from 'lodash/isEmpty';
4
- //@ts-ignore
4
+
5
5
  import {backend, clusterName, webVersion} from './store';
6
6
 
7
7
  const routes = {
@@ -3,7 +3,7 @@ import {combineReducers} from 'redux';
3
3
  import nodes from './nodes';
4
4
  import cluster from './cluster/cluster';
5
5
  import clusterNodes from './clusterNodes/clusterNodes';
6
- import tenant from './tenant';
6
+ import tenant from './tenant/tenant';
7
7
  import storage from './storage';
8
8
  import node from './node';
9
9
  import tooltip from './tooltip';
@@ -0,0 +1,19 @@
1
+ export const TENANT_GENERAL_TABS_IDS = {
2
+ query: 'query',
3
+ diagnostics: 'diagnostics',
4
+ } as const;
5
+
6
+ export const TENANT_DIAGNOSTICS_TABS_IDS = {
7
+ overview: 'overview',
8
+ topQueries: 'topQueries',
9
+ topShards: 'topShards',
10
+ nodes: 'nodes',
11
+ tablets: 'tablets',
12
+ storage: 'storage',
13
+ network: 'network',
14
+ describe: 'describe',
15
+ hotKeys: 'hotKeys',
16
+ graph: 'graph',
17
+ consumers: 'consumers',
18
+ partitions: 'partitions',
19
+ } as const;
@@ -1,13 +1,20 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
2
- import '../../services/api';
3
- import _ from 'lodash';
1
+ import type {Reducer} from 'redux';
2
+
3
+ import type {TTenant} from '../../../types/api/tenant';
4
+ import type {TenantAction, TenantDiagnosticsTab, TenantGeneralTab, TenantState} from './types';
5
+
6
+ import '../../../services/api';
7
+ import {createRequestActionTypes, createApiRequest} from '../../utils';
8
+
9
+ export const FETCH_TENANT = createRequestActionTypes('tenant', 'FETCH_TENANT');
4
10
 
5
- const FETCH_TENANT = createRequestActionTypes('tenant', 'FETCH_TENANT');
6
11
  const SET_TOP_LEVEL_TAB = 'tenant/SET_TOP_LEVEL_TAB';
7
12
  const SET_DIAGNOSTICS_TAB = 'tenant/SET_DIAGNOSTICS_TAB';
8
13
  const CLEAR_TENANT = 'tenant/CLEAR_TENANT';
9
14
 
10
- const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, action) => {
15
+ const initialState = {loading: false, wasLoaded: false};
16
+
17
+ const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState, action) => {
11
18
  switch (action.type) {
12
19
  case FETCH_TENANT.REQUEST: {
13
20
  return {
@@ -17,12 +24,9 @@ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, a
17
24
  }
18
25
 
19
26
  case FETCH_TENANT.SUCCESS: {
20
- const {tenant, tenantNodes} = action.data;
21
-
22
27
  return {
23
28
  ...state,
24
- tenant,
25
- tenantNodes,
29
+ tenant: action.data,
26
30
  loading: false,
27
31
  wasLoaded: true,
28
32
  error: undefined,
@@ -32,7 +36,7 @@ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, a
32
36
  case FETCH_TENANT.FAILURE: {
33
37
  return {
34
38
  ...state,
35
- data: action.error,
39
+ error: action.error,
36
40
  loading: false,
37
41
  wasLoaded: true,
38
42
  };
@@ -41,7 +45,7 @@ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, a
41
45
  case CLEAR_TENANT: {
42
46
  return {
43
47
  ...state,
44
- tenant: {},
48
+ tenant: undefined,
45
49
  loading: true,
46
50
  };
47
51
  }
@@ -65,45 +69,32 @@ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, a
65
69
  }
66
70
  };
67
71
 
68
- export const clearTenant = () => {
69
- return {type: CLEAR_TENANT};
70
- };
71
-
72
- export const getTenantInfo = ({path}) => {
72
+ export const getTenantInfo = ({path}: {path: string}) => {
73
73
  return createApiRequest({
74
- request: Promise.all([window.api.getTenantInfo({path}), window.api.getCompute(path)]),
74
+ request: window.api.getTenantInfo({path}),
75
75
  actions: FETCH_TENANT,
76
- dataHandler: ([tenantData, nodesData]) => {
77
- const tenant = tenantData.TenantInfo[0];
78
- const tenantNodes = _.map(nodesData?.Tenants[0]?.Nodes, (item) => {
79
- if (item.Host && item.Endpoints) {
80
- const address = _.find(item.Endpoints, {Name: 'http-mon'})?.Address;
81
- return {
82
- id: item.NodeId,
83
- backend: `${item.Host}${address ? address : ''}`,
84
- };
85
- }
86
-
87
- return undefined;
88
- }).filter(Boolean);
89
-
90
- return {tenant, tenantNodes};
76
+ dataHandler: (tenantData): TTenant | undefined => {
77
+ return tenantData.TenantInfo?.[0];
91
78
  },
92
79
  });
93
80
  };
94
81
 
95
- export function setTopLevelTab(tab) {
82
+ export const clearTenant = () => {
83
+ return {type: CLEAR_TENANT} as const;
84
+ };
85
+
86
+ export function setTopLevelTab(tab: TenantGeneralTab) {
96
87
  return {
97
88
  type: SET_TOP_LEVEL_TAB,
98
89
  data: tab,
99
- };
90
+ } as const;
100
91
  }
101
92
 
102
- export function setDiagnosticsTab(tab) {
93
+ export function setDiagnosticsTab(tab: TenantDiagnosticsTab) {
103
94
  return {
104
95
  type: SET_DIAGNOSTICS_TAB,
105
96
  data: tab,
106
- };
97
+ } as const;
107
98
  }
108
99
 
109
100
  export default tenantReducer;
@@ -0,0 +1,25 @@
1
+ import type {IResponseError} from '../../../types/api/error';
2
+ import type {TTenant} from '../../../types/api/tenant';
3
+ import type {ValueOf} from '../../../types/common';
4
+ import type {ApiRequestAction} from '../../utils';
5
+
6
+ import {TENANT_DIAGNOSTICS_TABS_IDS, TENANT_GENERAL_TABS_IDS} from './constants';
7
+ import {FETCH_TENANT, clearTenant, setDiagnosticsTab, setTopLevelTab} from './tenant';
8
+
9
+ export type TenantGeneralTab = ValueOf<typeof TENANT_GENERAL_TABS_IDS>;
10
+ export type TenantDiagnosticsTab = ValueOf<typeof TENANT_DIAGNOSTICS_TABS_IDS>;
11
+
12
+ export interface TenantState {
13
+ loading: boolean;
14
+ wasLoaded: boolean;
15
+ topLevelTab?: TenantGeneralTab;
16
+ diagnosticsTab?: TenantDiagnosticsTab;
17
+ tenant?: TTenant;
18
+ error?: IResponseError;
19
+ }
20
+
21
+ export type TenantAction =
22
+ | ApiRequestAction<typeof FETCH_TENANT, TTenant | undefined, IResponseError>
23
+ | ReturnType<typeof clearTenant>
24
+ | ReturnType<typeof setTopLevelTab>
25
+ | ReturnType<typeof setDiagnosticsTab>;
@@ -97,7 +97,8 @@ export const formatDateTime = (value) => {
97
97
 
98
98
  export const calcUptimeInSeconds = (milliseconds) => {
99
99
  const currentDate = new Date();
100
- return (currentDate - Number(milliseconds)) / 1000;
100
+ const diff = currentDate - Number(milliseconds);
101
+ return diff <= 0 ? 0 : diff / 1000;
101
102
  };
102
103
 
103
104
  export const calcUptime = (milliseconds) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.5.0",
3
+ "version": "4.5.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -48,6 +48,7 @@
48
48
  "//build:embedded": "echo 'PUBLIC_URL is a setting for create-react-app. Embedded version is built and hosted as is on ydb servers, with no way of knowing the final URL pattern. PUBLIC_URL=. keeps paths to all static relative, allowing servers to handle them as needed'",
49
49
  "build:embedded": "rm -rf build && PUBLIC_URL=. REACT_APP_BACKEND=http://localhost:8765 npm run build",
50
50
  "lint:styles": "stylelint 'src/**/*.scss'",
51
+ "unimported": "npx unimported --no-cache",
51
52
  "package": "rm -rf dist && copyfiles -u 1 'src/**/*' dist",
52
53
  "test": "react-app-rewired test",
53
54
  "eject": "react-scripts eject",
@@ -1,25 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import cn from 'bem-cn-lite';
4
- import {Breadcrumbs as BreadcrumbsUiKit} from '@gravity-ui/uikit';
5
-
6
- import './Breadcrumbs.scss';
7
-
8
- const b = cn('kv-breadcrumbs');
9
-
10
- class Breadcrumbs extends React.Component {
11
- static propTypes = {
12
- items: PropTypes.array,
13
- };
14
-
15
- static defaultProps = {
16
- items: [],
17
- };
18
-
19
- render() {
20
- const {items} = this.props;
21
- return <BreadcrumbsUiKit items={items} firstDisplayedItemsCount={1} className={b()} />;
22
- }
23
- }
24
-
25
- export default Breadcrumbs;
@@ -1,5 +0,0 @@
1
- .kv-breadcrumbs {
2
- padding: 20px 0;
3
-
4
- font-size: var(--yc-text-body-2-font-size);
5
- }
@@ -1,84 +0,0 @@
1
- import {useState, useEffect, useRef} from 'react';
2
- import block from 'bem-cn-lite';
3
- import {ArrowToggle, Button} from '@gravity-ui/uikit';
4
-
5
- import './Collapse.scss';
6
-
7
- const b = block('yc-collapse');
8
-
9
- function useEffectSkipFirst(fn, arr) {
10
- const isFirst = useRef(true);
11
-
12
- useEffect(() => {
13
- if (isFirst.current) {
14
- isFirst.current = false;
15
- return;
16
- }
17
-
18
- return fn();
19
- }, arr);
20
- }
21
-
22
- export const Collapse = ({
23
- title,
24
- children,
25
- arrowView = 'icon',
26
- emptyState = 'No data',
27
- titleSize = 'l',
28
- contentMarginTop = 12,
29
- defaultIsExpand,
30
- onChange,
31
- }) => {
32
- const [isExpand, setIsExpand] = useState(defaultIsExpand);
33
-
34
- const arrowDirection = isExpand ? 'top' : 'bottom';
35
-
36
- const arrowComponent =
37
- arrowView === 'button' ? (
38
- <Button view="flat" className={b('arrow-button')}>
39
- <ArrowToggle className={b('arrow')} direction={arrowDirection} size={20} />
40
- </Button>
41
- ) : (
42
- <ArrowToggle className={b('arrow')} direction={arrowDirection} size={20} />
43
- );
44
-
45
- useEffectSkipFirst(onChange, [isExpand]);
46
-
47
- return (
48
- <div className={b()}>
49
- <div
50
- className={b('panel', {
51
- 'no-data': !children,
52
- })}
53
- onClick={() => {
54
- setIsExpand(!isExpand);
55
- }}
56
- >
57
- {typeof title === 'string' ? (
58
- <h2
59
- className={b('title', {
60
- size: titleSize,
61
- })}
62
- >
63
- {title}
64
- </h2>
65
- ) : (
66
- title
67
- )}
68
-
69
- {children && <div className={b('arrow-wrapper')}>{arrowComponent}</div>}
70
- </div>
71
-
72
- {!children && <h4 className={b('empty-state-title')}>{emptyState}</h4>}
73
-
74
- {children && (
75
- <div
76
- className={b('content', {visible: isExpand})}
77
- style={{marginTop: contentMarginTop}}
78
- >
79
- {children}
80
- </div>
81
- )}
82
- </div>
83
- );
84
- };
@@ -1,70 +0,0 @@
1
- .yc-collapse {
2
- &__panel {
3
- display: inline-flex;
4
- align-items: center;
5
-
6
- cursor: pointer;
7
-
8
- &_no-data {
9
- cursor: default;
10
- }
11
- }
12
-
13
- &__title {
14
- margin: 0;
15
- }
16
-
17
- &__title_secondary {
18
- color: var(--yc-color-text-secondary);
19
- }
20
-
21
- &__title_size {
22
- &_s {
23
- font-size: var(--yc-text-body-1-font-size);
24
- line-height: var(--yc-text-body-1-line-height);
25
- }
26
-
27
- &_m {
28
- font-size: var(--yc-text-body-2-font-size);
29
- line-height: var(--yc-text-body-2-line-height);
30
- }
31
-
32
- &_l {
33
- font-size: var(--yc-text-body-3-font-size);
34
- line-height: var(--yc-text-body-3-line-height);
35
- }
36
- }
37
-
38
- &__arrow-wrapper {
39
- margin-left: 8px;
40
- }
41
-
42
- &__arrow-wrapper_secondary {
43
- color: var(--yc-color-text-secondary);
44
- .button2__text {
45
- color: var(--yc-color-text-secondary);
46
- }
47
- }
48
-
49
- &__content {
50
- display: none;
51
-
52
- &_visible {
53
- display: block;
54
- }
55
- }
56
-
57
- &__empty-state-title {
58
- font-size: var(--yc-text-body-1-font-size);
59
- font-weight: normal;
60
- line-height: var(--yc-text-body-1-line-height);
61
-
62
- opacity: 0.5;
63
- }
64
-
65
- &__arrow-button {
66
- .button2__text {
67
- margin: 0 4px;
68
- }
69
- }
70
- }