ydb-embedded-ui 2.2.1 → 2.4.0

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 (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;