ydb-embedded-ui 2.2.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/assets/icons/shield.svg +3 -0
  3. package/dist/components/Errors/403/AccessDenied.tsx +19 -0
  4. package/dist/components/Errors/403/index.ts +1 -0
  5. package/dist/components/Errors/i18n/en.json +4 -0
  6. package/dist/components/Errors/i18n/index.ts +11 -0
  7. package/dist/components/Errors/i18n/ru.json +4 -0
  8. package/dist/components/NodesViewer/NodesViewer.js +1 -1
  9. package/dist/components/QueryResultTable/QueryResultTable.tsx +16 -21
  10. package/dist/{containers/Storage/StorageFilter/StorageFilter.tsx → components/Search/Search.tsx} +22 -22
  11. package/dist/components/Search/index.ts +1 -0
  12. package/dist/containers/App/App.scss +5 -1
  13. package/dist/containers/Nodes/Nodes.js +6 -1
  14. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +7 -5
  15. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -11
  16. package/dist/containers/Storage/Pdisk/Pdisk.scss +15 -8
  17. package/dist/containers/Storage/Pdisk/Pdisk.tsx +22 -14
  18. package/dist/containers/Storage/Storage.js +39 -50
  19. package/dist/containers/Storage/StorageGroups/StorageGroups.scss +1 -4
  20. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +27 -2
  21. package/dist/containers/Storage/StorageGroups/i18n/en.json +2 -1
  22. package/dist/containers/Storage/StorageGroups/i18n/ru.json +2 -1
  23. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +14 -12
  24. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -5
  25. package/dist/containers/Storage/Vdisk/Vdisk.js +36 -23
  26. package/dist/containers/Storage/Vdisk/Vdisk.scss +6 -0
  27. package/dist/containers/TabletsFilters/TabletsFilters.js +5 -0
  28. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.scss +6 -0
  29. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +82 -0
  30. package/dist/containers/Tenant/Diagnostics/Consumers/i18n/en.json +6 -0
  31. package/dist/containers/Tenant/Diagnostics/Consumers/i18n/index.ts +11 -0
  32. package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +6 -0
  33. package/dist/containers/Tenant/Diagnostics/Consumers/index.ts +1 -0
  34. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +7 -0
  35. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +29 -11
  36. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -8
  37. package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/Details.tsx +55 -0
  38. package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/index.ts +1 -0
  39. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +5 -5
  40. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +16 -6
  41. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/{IssueViewer.scss → IssueTree.scss} +3 -54
  42. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTree.tsx +87 -0
  43. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +50 -0
  44. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +25 -0
  45. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/index.ts +1 -0
  46. package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/Preview.tsx +13 -16
  47. package/dist/containers/Tenant/Diagnostics/Healthcheck/{IssuePreview/IssuePreview.tsx → Preview/PreviewItem/PreviewItem.tsx} +6 -8
  48. package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/PreviewItem/index.ts +1 -0
  49. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +34 -19
  50. package/dist/containers/Tenant/Preview/Preview.scss +6 -0
  51. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +1 -9
  52. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
  53. package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +1 -1
  54. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +27 -20
  55. package/dist/containers/Tenant/Tenant.tsx +14 -16
  56. package/dist/containers/Tenants/Tenants.js +1 -1
  57. package/dist/store/reducers/describe.ts +71 -0
  58. package/dist/store/reducers/healthcheckInfo.ts +123 -0
  59. package/dist/store/reducers/olapStats.js +13 -0
  60. package/dist/store/reducers/schema.js +43 -1
  61. package/dist/store/reducers/storage.js +27 -17
  62. package/dist/store/reducers/tenant.js +3 -1
  63. package/dist/store/utils.ts +21 -13
  64. package/dist/styles/mixins.scss +1 -1
  65. package/dist/types/api/consumers.ts +3 -0
  66. package/dist/types/api/healthcheck.ts +1 -1
  67. package/dist/types/api/storage.ts +35 -10
  68. package/dist/types/store/healthcheck.ts +5 -1
  69. package/dist/types/store/storage.ts +1 -0
  70. package/dist/utils/hooks/useAutofetcher.ts +9 -3
  71. package/package.json +1 -1
  72. package/dist/containers/Storage/StorageFilter/index.ts +0 -1
  73. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuePreview/index.ts +0 -1
  74. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/IssuesList.tsx +0 -62
  75. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/index.ts +0 -1
  76. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssuesViewer.js +0 -151
  77. package/dist/store/reducers/describe.js +0 -45
  78. package/dist/store/reducers/healthcheckInfo.js +0 -45
@@ -4,8 +4,7 @@ import cn from 'bem-cn-lite';
4
4
  import {useLocation} from 'react-router';
5
5
  import qs from 'qs';
6
6
 
7
- import EmptyState from '../../components/EmptyState/EmptyState';
8
- import {Illustration} from '../../components/Illustration';
7
+ import {AccessDenied} from '../../components/Errors/403';
9
8
 
10
9
  import {setHeader} from '../../store/reducers/header';
11
10
  import ObjectGeneralTabs from './ObjectGeneralTabs/ObjectGeneralTabs';
@@ -16,7 +15,7 @@ import SplitPane from '../../components/SplitPane';
16
15
  //@ts-ignore
17
16
  import {DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY} from '../../utils/constants';
18
17
  //@ts-ignore
19
- import {disableAutorefresh, getSchema} from '../../store/reducers/schema';
18
+ import {disableAutorefresh, getSchema, resetLoadingState} from '../../store/reducers/schema';
20
19
  //@ts-ignore
21
20
  import {getSchemaAcl} from '../../store/reducers/schemaAcl';
22
21
  import {
@@ -57,6 +56,13 @@ function Tenant(props: TenantProps) {
57
56
  (state: any) => state.schema,
58
57
  );
59
58
 
59
+ const {PathType: preloadedPathType, PathSubType: preloadedPathSubType} = useSelector(
60
+ (state: any) => state.schema.data[currentSchemaPath]?.PathDescription?.Self || {},
61
+ );
62
+
63
+ const {PathType: currentPathType, PathSubType: currentPathSubType} =
64
+ (currentItem as TEvDescribeSchemeResult).PathDescription?.Self || {};
65
+
60
66
  const {data: {status: tenantStatus = 200} = {}} = useSelector((state: any) => state.tenant);
61
67
  const {error: {status: schemaStatus = 200} = {}} = useSelector((state: any) => state.schema);
62
68
 
@@ -73,6 +79,7 @@ function Tenant(props: TenantProps) {
73
79
 
74
80
  useEffect(() => {
75
81
  const schemaPath = currentSchemaPath || tenantName;
82
+ dispatch(resetLoadingState());
76
83
  dispatch(getSchema({path: tenantName}));
77
84
  dispatch(getSchema({path: schemaPath}));
78
85
  dispatch(getSchemaAcl({path: schemaPath}));
@@ -105,11 +112,6 @@ function Tenant(props: TenantProps) {
105
112
  };
106
113
  }, [tenantName, dispatch]);
107
114
 
108
- const {
109
- PathType: currentPathType,
110
- PathSubType: currentPathSubType,
111
- } = (currentItem as TEvDescribeSchemeResult).PathDescription?.Self || {};
112
-
113
115
  const onCollapseSummaryHandler = () => {
114
116
  dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.triggerCollapse);
115
117
  };
@@ -126,11 +128,7 @@ function Tenant(props: TenantProps) {
126
128
  return (
127
129
  <div className={b()}>
128
130
  {showBlockingError ? (
129
- <EmptyState
130
- image={<Illustration name="403" />}
131
- title="Access denied"
132
- description="You don’t have the necessary roles to view this page."
133
- />
131
+ <AccessDenied />
134
132
  ) : (
135
133
  <>
136
134
  <ObjectGeneralTabs />
@@ -144,15 +142,15 @@ function Tenant(props: TenantProps) {
144
142
  onSplitStartDragAdditional={onSplitStartDragAdditional}
145
143
  >
146
144
  <ObjectSummary
147
- type={currentPathType}
148
- subType={currentPathSubType}
145
+ type={preloadedPathType || currentPathType}
146
+ subType={preloadedPathSubType || currentPathSubType}
149
147
  onCollapseSummary={onCollapseSummaryHandler}
150
148
  onExpandSummary={onExpandSummaryHandler}
151
149
  isCollapsed={summaryVisibilityState.collapsed}
152
150
  additionalTenantInfo={props.additionalTenantInfo}
153
151
  />
154
152
  <ObjectGeneral
155
- type={currentPathType}
153
+ type={preloadedPathType || currentPathType}
156
154
  additionalTenantInfo={props.additionalTenantInfo}
157
155
  additionalNodesInfo={props.additionalNodesInfo}
158
156
  />
@@ -95,7 +95,7 @@ class Tenants extends React.Component {
95
95
  <TextInput
96
96
  className={b('search')}
97
97
  placeholder="Database name"
98
- text={searchQuery}
98
+ value={searchQuery}
99
99
  onUpdate={handleSearchQuery}
100
100
  hasClear
101
101
  autoFocus
@@ -0,0 +1,71 @@
1
+ import {createSelector} from 'reselect';
2
+
3
+ import '../../services/api';
4
+ import {TEvDescribeSchemeResult} from '../../types/api/schema';
5
+ import {IConsumer} from '../../types/api/consumers';
6
+ import {createRequestActionTypes, createApiRequest, ApiRequestAction} from '../utils';
7
+
8
+ const FETCH_DESCRIBE = createRequestActionTypes('describe', 'FETCH_DESCRIBE');
9
+
10
+ const describe = (
11
+ state = {loading: false, wasLoaded: false, data: {}},
12
+ action: ApiRequestAction<typeof FETCH_DESCRIBE, TEvDescribeSchemeResult, unknown>,
13
+ ) => {
14
+ switch (action.type) {
15
+ case FETCH_DESCRIBE.REQUEST: {
16
+ return {
17
+ ...state,
18
+ loading: true,
19
+ };
20
+ }
21
+ case FETCH_DESCRIBE.SUCCESS: {
22
+ let newData;
23
+
24
+ if (action.data.Path) {
25
+ newData = JSON.parse(JSON.stringify(state.data));
26
+ newData[action.data.Path] = action.data;
27
+ } else {
28
+ newData = state.data;
29
+ }
30
+
31
+ return {
32
+ ...state,
33
+ data: newData,
34
+ currentDescribe: action.data,
35
+ loading: false,
36
+ wasLoaded: true,
37
+ error: undefined,
38
+ };
39
+ }
40
+ case FETCH_DESCRIBE.FAILURE: {
41
+ return {
42
+ ...state,
43
+ error: action.error,
44
+ loading: false,
45
+ };
46
+ }
47
+ default:
48
+ return state;
49
+ }
50
+ };
51
+
52
+ // Consumers selectors
53
+ const selectConsumersNames = (state: any, path: string): string[] | undefined =>
54
+ state.describe.data[path]?.PathDescription?.PersQueueGroup?.PQTabletConfig?.ReadRules;
55
+
56
+ export const selectConsumers = createSelector(selectConsumersNames, (names = []): IConsumer[] => {
57
+ const consumers = names.map((name) => {
58
+ return {name};
59
+ });
60
+
61
+ return consumers;
62
+ });
63
+
64
+ export function getDescribe({path}: {path: string}) {
65
+ return createApiRequest({
66
+ request: window.api.getDescribe({path}),
67
+ actions: FETCH_DESCRIBE,
68
+ });
69
+ }
70
+
71
+ export default describe;
@@ -0,0 +1,123 @@
1
+ import _flow from 'lodash/fp/flow';
2
+ import _sortBy from 'lodash/fp/sortBy';
3
+ import _uniqBy from 'lodash/fp/uniqBy';
4
+ import _omit from 'lodash/omit';
5
+ import {createSelector} from 'reselect';
6
+
7
+ import {IIssuesTree} from '../../types/store/healthcheck';
8
+ import {HealthCheckAPIResponse, IssueLog, StatusFlag} from '../../types/api/healthcheck';
9
+
10
+ import '../../services/api';
11
+ import {createRequestActionTypes, createApiRequest, ApiRequestAction} from '../utils';
12
+
13
+ const FETCH_HEALTHCHECK = createRequestActionTypes('cluster', 'FETCH_HEALTHCHECK');
14
+
15
+ const initialState = {loading: false, wasLoaded: false};
16
+
17
+ const healthcheckInfo = function (
18
+ state = initialState,
19
+ action: ApiRequestAction<typeof FETCH_HEALTHCHECK, HealthCheckAPIResponse, unknown>,
20
+ ) {
21
+ switch (action.type) {
22
+ case FETCH_HEALTHCHECK.REQUEST: {
23
+ return {
24
+ ...state,
25
+ loading: true,
26
+ };
27
+ }
28
+ case FETCH_HEALTHCHECK.SUCCESS: {
29
+ const {data} = action;
30
+
31
+ return {
32
+ ...state,
33
+ data,
34
+ wasLoaded: true,
35
+ loading: false,
36
+ error: undefined,
37
+ };
38
+ }
39
+ case FETCH_HEALTHCHECK.FAILURE: {
40
+ return {
41
+ ...state,
42
+ error: action.error,
43
+ loading: false,
44
+ };
45
+ }
46
+ default:
47
+ return state;
48
+ }
49
+ };
50
+
51
+ const mapStatusToPriority: Partial<Record<StatusFlag, number>> = {
52
+ RED: 0,
53
+ ORANGE: 1,
54
+ YELLOW: 2,
55
+ BLUE: 3,
56
+ GREEN: 4,
57
+ };
58
+
59
+ const getReasonsForIssue = ({issue, data}: {issue: IssueLog; data: IssueLog[]}) => {
60
+ return data.filter((item) => issue.reason && issue.reason.indexOf(item.id) !== -1);
61
+ };
62
+
63
+ const getRoots = (data: IssueLog[]) => {
64
+ let roots = data.filter((item) => {
65
+ return !data.find((issue) => issue.reason && issue.reason.indexOf(item.id) !== -1);
66
+ });
67
+
68
+ roots = _flow([
69
+ _uniqBy((item: IssueLog) => item.id),
70
+ _sortBy(({status}: {status: StatusFlag}) => mapStatusToPriority[status]),
71
+ ])(roots);
72
+
73
+ return roots;
74
+ };
75
+
76
+ const getInvertedConsequencesTree = ({
77
+ data,
78
+ roots,
79
+ }: {
80
+ data: IssueLog[];
81
+ roots?: IssueLog[];
82
+ }): IIssuesTree[] => {
83
+ return roots
84
+ ? roots.map((issue) => {
85
+ const reasonsItems = getInvertedConsequencesTree({
86
+ roots: getReasonsForIssue({issue, data}),
87
+ data,
88
+ });
89
+
90
+ return {
91
+ ...issue,
92
+ reasonsItems,
93
+ };
94
+ })
95
+ : [];
96
+ };
97
+
98
+ const getIssuesLog = (state: any): IssueLog[] | undefined => state.healthcheckInfo.data?.issue_log;
99
+
100
+ export const selectIssuesTreesRoots = createSelector(getIssuesLog, (issues = []) =>
101
+ getRoots(issues),
102
+ );
103
+
104
+ export const selectIssuesTrees = createSelector(
105
+ [getIssuesLog, selectIssuesTreesRoots],
106
+ (data = [], roots = []) => {
107
+ return getInvertedConsequencesTree({data, roots});
108
+ },
109
+ );
110
+
111
+ export const selectIssuesTreeById = createSelector(
112
+ [selectIssuesTrees, (_: any, id: string | undefined) => id],
113
+ (issuesTrees = [], id) => issuesTrees.find((issuesTree: IIssuesTree) => issuesTree.id === id),
114
+ );
115
+
116
+ export function getHealthcheckInfo(database: string) {
117
+ return createApiRequest({
118
+ request: window.api.getHealthcheckInfo(database),
119
+ actions: FETCH_HEALTHCHECK,
120
+ });
121
+ }
122
+
123
+ export default healthcheckInfo;
@@ -6,6 +6,7 @@ import {createRequestActionTypes, createApiRequest} from '../utils';
6
6
 
7
7
  const FETCH_OLAP_STATS = createRequestActionTypes('query', 'SEND_OLAP_STATS_QUERY');
8
8
  const SET_OLAP_STATS_OPTIONS = createRequestActionTypes('query', 'SET_OLAP_STATS_OPTIONS');
9
+ const RESET_LOADING_STATE = 'olapStats/RESET_LOADING_STATE';
9
10
 
10
11
  const initialState = {
11
12
  loading: false,
@@ -48,6 +49,12 @@ const olapStats = (state = initialState, action) => {
48
49
  ...state,
49
50
  ...action.data,
50
51
  };
52
+ case RESET_LOADING_STATE: {
53
+ return {
54
+ ...state,
55
+ wasLoaded: initialState.wasLoaded,
56
+ };
57
+ }
51
58
  default:
52
59
  return state;
53
60
  }
@@ -73,4 +80,10 @@ export function setOlapStatsOptions(options) {
73
80
  };
74
81
  }
75
82
 
83
+ export function resetLoadingState() {
84
+ return {
85
+ type: RESET_LOADING_STATE,
86
+ };
87
+ }
88
+
76
89
  export default olapStats;
@@ -2,10 +2,12 @@ import {createRequestActionTypes, createApiRequest} from '../utils';
2
2
  import '../../services/api';
3
3
 
4
4
  const FETCH_SCHEMA = createRequestActionTypes('schema', 'FETCH_SCHEMA');
5
+ const PRELOAD_SCHEMA = 'schema/PRELOAD_SCHEMA';
5
6
  const SET_SCHEMA = 'schema/SET_SCHEMA';
6
7
  const SET_SHOW_PREVIEW = 'schema/SET_SHOW_PREVIEW';
7
8
  const ENABLE_AUTOREFRESH = 'schema/ENABLE_AUTOREFRESH';
8
9
  const DISABLE_AUTOREFRESH = 'schema/DISABLE_AUTOREFRESH';
10
+ const RESET_LOADING_STATE = 'schema/RESET_LOADING_STATE';
9
11
 
10
12
  export const initialState = {
11
13
  loading: true,
@@ -16,7 +18,7 @@ export const initialState = {
16
18
  showPreview: false,
17
19
  };
18
20
 
19
- const schema = function z(state = initialState, action) {
21
+ const schema = (state = initialState, action) => {
20
22
  switch (action.type) {
21
23
  case FETCH_SCHEMA.REQUEST: {
22
24
  return {
@@ -42,16 +44,34 @@ const schema = function z(state = initialState, action) {
42
44
  };
43
45
  }
44
46
  case FETCH_SCHEMA.FAILURE: {
47
+ if (action.error?.isCancelled) {
48
+ return state;
49
+ }
50
+
45
51
  return {
46
52
  ...state,
47
53
  error: action.error,
48
54
  loading: false,
49
55
  };
50
56
  }
57
+ case PRELOAD_SCHEMA: {
58
+ if (state.data[action.path]) {
59
+ return state;
60
+ }
61
+
62
+ return {
63
+ ...state,
64
+ data: {
65
+ ...state.data,
66
+ [action.path]: action.data,
67
+ },
68
+ };
69
+ }
51
70
  case SET_SCHEMA: {
52
71
  return {
53
72
  ...state,
54
73
  currentSchemaPath: action.data,
74
+ wasLoaded: false,
55
75
  };
56
76
  }
57
77
  case ENABLE_AUTOREFRESH: {
@@ -72,6 +92,12 @@ const schema = function z(state = initialState, action) {
72
92
  showPreview: action.data,
73
93
  };
74
94
  }
95
+ case RESET_LOADING_STATE: {
96
+ return {
97
+ ...state,
98
+ wasLoaded: initialState.wasLoaded,
99
+ };
100
+ }
75
101
  default:
76
102
  return state;
77
103
  }
@@ -106,4 +132,20 @@ export function setShowPreview(value) {
106
132
  data: value,
107
133
  };
108
134
  }
135
+
136
+ // only stores the passed data if the path doesn't exist yet
137
+ export function preloadSchema(path, data) {
138
+ return {
139
+ type: PRELOAD_SCHEMA,
140
+ path,
141
+ data,
142
+ };
143
+ }
144
+
145
+ export function resetLoadingState() {
146
+ return {
147
+ type: RESET_LOADING_STATE,
148
+ };
149
+ }
150
+
109
151
  export default schema;
@@ -4,6 +4,7 @@ import _ from 'lodash';
4
4
  import {createSelector} from 'reselect';
5
5
  import {calcUptime} from '../../utils';
6
6
  import {getUsage} from '../../utils/storage';
7
+ import {getPDiskType} from '../../utils/pdisk';
7
8
 
8
9
  export const VisibleEntities = {
9
10
  All: 'All',
@@ -38,7 +39,7 @@ const initialState = {
38
39
  type: StorageTypes.groups,
39
40
  };
40
41
 
41
- const storage = function z(state = initialState, action) {
42
+ const storage = (state = initialState, action) => {
42
43
  switch (action.type) {
43
44
  case FETCH_STORAGE.REQUEST: {
44
45
  return {
@@ -56,10 +57,15 @@ const storage = function z(state = initialState, action) {
56
57
  };
57
58
  }
58
59
  case FETCH_STORAGE.FAILURE: {
60
+ if (action.error?.isCancelled) {
61
+ return state;
62
+ }
63
+
59
64
  return {
60
65
  ...state,
61
66
  error: action.error,
62
67
  loading: false,
68
+ wasLoaded: true,
63
69
  };
64
70
  }
65
71
  case SET_INITIAL: {
@@ -229,6 +235,12 @@ export const getFlatListStorageGroups = createSelector([getStoragePools], (stora
229
235
  },
230
236
  0,
231
237
  );
238
+ const mediaType = group.VDisks?.reduce((type, vdisk) => {
239
+ const currentType = getPDiskType(vdisk.PDisk || {});
240
+ return currentType && (currentType === type || type === '')
241
+ ? currentType
242
+ : 'Mixed';
243
+ }, '');
232
244
  return [
233
245
  ...acc,
234
246
  {
@@ -240,6 +252,7 @@ export const getFlatListStorageGroups = createSelector([getStoragePools], (stora
240
252
  Limit: limitSizeBytes,
241
253
  Missing: missing,
242
254
  UsedSpaceFlag,
255
+ Type: mediaType || null,
243
256
  },
244
257
  ];
245
258
  },
@@ -334,25 +347,22 @@ export const getFilteredEntities = createSelector(
334
347
  },
335
348
  );
336
349
 
337
- export const getUsageFilterOptions = createSelector(
338
- getVisibleEntitiesList,
339
- (entities) => {
340
- const items = {};
350
+ export const getUsageFilterOptions = createSelector(getVisibleEntitiesList, (entities) => {
351
+ const items = {};
341
352
 
342
- entities.forEach((entity) => {
343
- const usage = getUsage(entity, 5);
353
+ entities.forEach((entity) => {
354
+ const usage = getUsage(entity, 5);
344
355
 
345
- if (!Object.hasOwn(items, usage)) {
346
- items[usage] = 0;
347
- }
356
+ if (!Object.hasOwn(items, usage)) {
357
+ items[usage] = 0;
358
+ }
348
359
 
349
- items[usage] += 1;
350
- });
360
+ items[usage] += 1;
361
+ });
351
362
 
352
- return Object.entries(items)
353
- .map(([threshold, count]) => ({threshold, count}))
354
- .sort((a, b) => b.threshold - a.threshold);
355
- },
356
- );
363
+ return Object.entries(items)
364
+ .map(([threshold, count]) => ({threshold, count}))
365
+ .sort((a, b) => b.threshold - a.threshold);
366
+ });
357
367
 
358
368
  export default storage;
@@ -6,7 +6,7 @@ const FETCH_TENANT = createRequestActionTypes('tenant', 'FETCH_TENANT');
6
6
  const SET_TOP_LEVEL_TAB = 'tenant/SET_TOP_LEVEL_TAB';
7
7
  const SET_DIAGNOSTICS_TAB = 'tenant/SET_DIAGNOSTICS_TAB';
8
8
 
9
- const tenantReducer = (state = {loading: false, tenant: {}}, action) => {
9
+ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, action) => {
10
10
  switch (action.type) {
11
11
  case FETCH_TENANT.REQUEST: {
12
12
  return {
@@ -23,6 +23,7 @@ const tenantReducer = (state = {loading: false, tenant: {}}, action) => {
23
23
  tenant,
24
24
  tenantNodes,
25
25
  loading: false,
26
+ wasLoaded: true,
26
27
  error: undefined,
27
28
  };
28
29
  }
@@ -32,6 +33,7 @@ const tenantReducer = (state = {loading: false, tenant: {}}, action) => {
32
33
  ...state,
33
34
  data: action.error,
34
35
  loading: false,
36
+ wasLoaded: true,
35
37
  };
36
38
  }
37
39
 
@@ -7,7 +7,10 @@ import {SET_UNAUTHENTICATED} from './reducers/authentication';
7
7
 
8
8
  export const nop = (result: any) => result;
9
9
 
10
- export function createRequestActionTypes<Prefix extends string, Type extends string>(prefix: Prefix, type: Type) {
10
+ export function createRequestActionTypes<Prefix extends string, Type extends string>(
11
+ prefix: Prefix,
12
+ type: Type,
13
+ ) {
11
14
  return {
12
15
  REQUEST: `${prefix}/${type}_REQUEST`,
13
16
  SUCCESS: `${prefix}/${type}_SUCCESS`,
@@ -15,19 +18,24 @@ export function createRequestActionTypes<Prefix extends string, Type extends str
15
18
  } as const;
16
19
  }
17
20
 
18
- const isAxiosResponse = (response: any): response is AxiosResponse => response && 'status' in response;
21
+ const isAxiosResponse = (response: any): response is AxiosResponse =>
22
+ response && 'status' in response;
19
23
 
20
24
  type CreateApiRequestParams<Actions, Response, HandledResponse> = {
21
25
  actions: Actions;
22
26
  request: Promise<Response>;
23
- dataHandler: (data: Response, getState?: () => any) => HandledResponse;
27
+ dataHandler?: (data: Response, getState?: () => any) => HandledResponse;
24
28
  };
25
29
 
26
30
  export function createApiRequest<
27
31
  Actions extends ReturnType<typeof createRequestActionTypes>,
28
32
  Response,
29
33
  HandledResponse,
30
- >({actions, request, dataHandler = nop}: CreateApiRequestParams<Actions, Response, HandledResponse>) {
34
+ >({
35
+ actions,
36
+ request,
37
+ dataHandler = nop,
38
+ }: CreateApiRequestParams<Actions, Response, HandledResponse>) {
31
39
  const doRequest = async function (dispatch: Dispatch, getState: () => any) {
32
40
  dispatch({
33
41
  type: actions.REQUEST,
@@ -73,16 +81,16 @@ export function createApiRequest<
73
81
  export type ApiRequestAction<
74
82
  Actions extends ReturnType<typeof createRequestActionTypes>,
75
83
  SuccessResponse = unknown,
76
- ErrorResponse = unknown
84
+ ErrorResponse = unknown,
77
85
  > =
78
86
  | {
79
- type: Actions['REQUEST'],
80
- }
87
+ type: Actions['REQUEST'];
88
+ }
81
89
  | {
82
- type: Actions['SUCCESS'],
83
- data: SuccessResponse,
84
- }
90
+ type: Actions['SUCCESS'];
91
+ data: SuccessResponse;
92
+ }
85
93
  | {
86
- type: Actions['FAILURE'],
87
- error: ErrorResponse,
88
- };
94
+ type: Actions['FAILURE'];
95
+ error: ErrorResponse;
96
+ };
@@ -150,7 +150,7 @@
150
150
  background-color: var(--yc-color-base-background);
151
151
  }
152
152
  .data-table__row:hover .data-table__td:nth-child(#{$nth}) {
153
- background-color: var(--yc-color-base-float-hover) !important;
153
+ background-color: var(--ydb-data-table-color-hover) !important;
154
154
  }
155
155
  }
156
156
 
@@ -0,0 +1,3 @@
1
+ export interface IConsumer {
2
+ name: string;
3
+ }
@@ -6,7 +6,7 @@ export enum SelfCheckResult {
6
6
  EMERGENCY = 'EMERGENCY',
7
7
  }
8
8
 
9
- enum StatusFlag {
9
+ export enum StatusFlag {
10
10
  UNSPECIFIED = 'UNSPECIFIED',
11
11
  GREY = 'GREY',
12
12
  GREEN = 'GREEN',
@@ -172,28 +172,53 @@ export interface TVDiskStateInfo {
172
172
  }
173
173
 
174
174
  export interface TBSGroupStateInfo {
175
- /** uint32 */
176
- GroupID?: string;
175
+ GroupID?: number;
177
176
  ErasureSpecies?: string;
178
177
  VDisks?: TVDiskStateInfo[];
179
178
  /** uint64 */
180
179
  ChangeTime?: string;
181
- /** uint32 */
182
- NodeId?: string; // filled during merge
183
- /** uint32 */
184
- GroupGeneration?: string;
180
+ NodeId?: number;
181
+ GroupGeneration?: number;
185
182
  Overall?: EFlag;
186
183
  Latency?: EFlag;
187
- /** uint32 */
188
- Count?: string; // filled during group count
189
- StoragePoolName?: string; // from BS_CONTROLLER
184
+ Count?: number;
185
+ StoragePoolName?: string;
186
+ /** uint64 */
187
+ AllocatedSize?: string;
188
+ /** uint64 */
189
+ AvailableSize?: string;
190
+ /** uint64 */
191
+ ReadThroughput?: string;
192
+ /** uint64 */
193
+ WriteThroughput?: string;
194
+ Encryption?: boolean;
195
+ }
196
+
197
+ interface THiveStorageGroupStats {
198
+ GroupID?: number;
199
+ /** uint64 */
200
+ AcquiredUnits?: string;
201
+ AcquiredIOPS?: number;
202
+ /** uint64 */
203
+ AcquiredThroughput?: string;
204
+ /** uint64 */
205
+ AcquiredSize?: string;
206
+ MaximumIOPS?: number;
207
+ /** uint64 */
208
+ MaximumThroughput?: string;
209
+ /** uint64 */
210
+ MaximumSize?: string;
211
+ /** uint64 */
212
+ AllocatedSize?: string;
213
+ /** uint64 */
214
+ AvailableSize?: string;
190
215
  }
191
216
 
192
217
  export interface TStoragePoolInfo {
193
218
  Overall?: EFlag;
194
219
  Name?: string;
195
220
  Kind?: string;
196
- Groups?: TBSGroupStateInfo[];
221
+ Groups?: (TBSGroupStateInfo & THiveStorageGroupStats)[];
197
222
  /** uint64 */
198
223
  AcquiredUnits?: string;
199
224
  AcquiredIOPS?: number;