ydb-embedded-ui 3.3.3 → 3.3.4

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 (22) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +8 -0
  3. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -3
  4. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +7 -7
  5. package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.scss +8 -0
  6. package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.tsx +56 -0
  7. package/dist/containers/Tenant/Diagnostics/TopShards/Filters/index.ts +1 -0
  8. package/dist/containers/Tenant/Diagnostics/{OverloadedShards/OverloadedShards.scss → TopShards/TopShards.scss} +2 -10
  9. package/dist/containers/Tenant/Diagnostics/{OverloadedShards/OverloadedShards.tsx → TopShards/TopShards.tsx} +61 -31
  10. package/dist/containers/Tenant/Diagnostics/TopShards/i18n/en.json +6 -0
  11. package/dist/containers/Tenant/Diagnostics/{OverloadedShards → TopShards}/i18n/index.ts +1 -1
  12. package/dist/containers/Tenant/Diagnostics/TopShards/i18n/ru.json +6 -0
  13. package/dist/containers/Tenant/Diagnostics/TopShards/index.ts +1 -0
  14. package/dist/store/reducers/authentication.js +0 -15
  15. package/dist/store/reducers/shardsWorkload.ts +28 -2
  16. package/dist/store/state-url-mapping.js +3 -0
  17. package/dist/types/store/shardsWorkload.ts +6 -0
  18. package/dist/utils/typecheckers.ts +5 -0
  19. package/package.json +1 -1
  20. package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/en.json +0 -4
  21. package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/ru.json +0 -4
  22. package/dist/containers/Tenant/Diagnostics/OverloadedShards/index.ts +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.3.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.3...v3.3.4) (2023-02-16)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **OverloadedShards:** rename to top shards ([ffa4f27](https://github.com/ydb-platform/ydb-embedded-ui/commit/ffa4f27f2cf0a5e12b2800c81bf61b1d3c25912c))
9
+ * **StorageGroups:** display Erasure ([4a7ebc0](https://github.com/ydb-platform/ydb-embedded-ui/commit/4a7ebc08b87fe75af83df70a38ebd486d64d6d4e))
10
+ * **TopShards:** switch between history and immediate data ([eeb9bb0](https://github.com/ydb-platform/ydb-embedded-ui/commit/eeb9bb0911b9e889b633558c9d3c13f986f72bfe))
11
+
3
12
  ## [3.3.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.2...v3.3.3) (2023-02-08)
4
13
 
5
14
 
@@ -28,6 +28,7 @@ import './StorageGroups.scss';
28
28
  enum TableColumnsIds {
29
29
  PoolName = 'PoolName',
30
30
  Type = 'Type',
31
+ ErasureSpecies = 'ErasureSpecies',
31
32
  GroupID = 'GroupID',
32
33
  Used = 'Used',
33
34
  Limit = 'Limit',
@@ -53,6 +54,7 @@ interface StorageGroupsProps {
53
54
  const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
54
55
  PoolName: 'Pool Name',
55
56
  Type: 'Type',
57
+ ErasureSpecies: 'Erasure',
56
58
  GroupID: 'Group ID',
57
59
  Used: 'Used',
58
60
  Limit: 'Limit',
@@ -146,6 +148,12 @@ function StorageGroups({
146
148
  </>
147
149
  ),
148
150
  },
151
+ {
152
+ name: TableColumnsIds.ErasureSpecies,
153
+ header: tableColumnsNames[TableColumnsIds.ErasureSpecies],
154
+ render: ({row}) => (row.ErasureSpecies ? row.ErasureSpecies : '-'),
155
+ align: DataTable.LEFT,
156
+ },
149
157
  {
150
158
  name: TableColumnsIds.Missing,
151
159
  header: tableColumnsNames[TableColumnsIds.Missing],
@@ -12,7 +12,7 @@ import {Loader} from '../../../components/Loader';
12
12
  import {TopQueries} from './TopQueries';
13
13
  //@ts-ignore
14
14
  import DetailedOverview from './DetailedOverview/DetailedOverview';
15
- import {OverloadedShards} from './OverloadedShards';
15
+ import {TopShards} from './TopShards';
16
16
  //@ts-ignore
17
17
  import Storage from '../../Storage/Storage';
18
18
  //@ts-ignore
@@ -124,8 +124,8 @@ function Diagnostics(props: DiagnosticsProps) {
124
124
  />
125
125
  );
126
126
  }
127
- case GeneralPagesIds.overloadedShards: {
128
- return <OverloadedShards tenantPath={tenantNameString} type={type} />;
127
+ case GeneralPagesIds.topShards: {
128
+ return <TopShards tenantPath={tenantNameString} type={type} />;
129
129
  }
130
130
  case GeneralPagesIds.nodes: {
131
131
  return (
@@ -3,7 +3,7 @@ import {EPathType} from '../../../types/api/schema';
3
3
  export enum GeneralPagesIds {
4
4
  'overview' = 'Overview',
5
5
  'topQueries' = 'topQueries',
6
- 'overloadedShards' = 'overloadedShards',
6
+ 'topShards' = 'topShards',
7
7
  'nodes' = 'Nodes',
8
8
  'tablets' = 'Tablets',
9
9
  'storage' = 'Storage',
@@ -29,9 +29,9 @@ const topQueries = {
29
29
  title: 'Top queries',
30
30
  };
31
31
 
32
- const overloadedShards = {
33
- id: GeneralPagesIds.overloadedShards,
34
- title: 'Overloaded shards',
32
+ const topShards = {
33
+ id: GeneralPagesIds.topShards,
34
+ title: 'Top shards',
35
35
  };
36
36
 
37
37
  const nodes = {
@@ -75,7 +75,7 @@ const consumers = {
75
75
  export const DATABASE_PAGES = [
76
76
  overview,
77
77
  topQueries,
78
- overloadedShards,
78
+ topShards,
79
79
  nodes,
80
80
  tablets,
81
81
  storage,
@@ -83,9 +83,9 @@ export const DATABASE_PAGES = [
83
83
  describe,
84
84
  ];
85
85
 
86
- export const TABLE_PAGES = [overview, overloadedShards, graph, tablets, hotKeys, describe];
86
+ export const TABLE_PAGES = [overview, topShards, graph, tablets, hotKeys, describe];
87
87
 
88
- export const DIR_PAGES = [overview, overloadedShards, describe];
88
+ export const DIR_PAGES = [overview, topShards, describe];
89
89
 
90
90
  export const CDC_STREAM_PAGES = [overview, consumers, describe];
91
91
  export const TOPIC_PAGES = [overview, consumers, describe];
@@ -0,0 +1,8 @@
1
+ .top-shards {
2
+ &__filters {
3
+ display: flex;
4
+ flex-wrap: wrap;
5
+ align-items: baseline;
6
+ gap: 16px;
7
+ }
8
+ }
@@ -0,0 +1,56 @@
1
+ import {RadioButton} from '@gravity-ui/uikit';
2
+
3
+ import {DateRange, DateRangeValues} from '../../../../../components/DateRange';
4
+
5
+ import {
6
+ EShardsWorkloadMode,
7
+ IShardsWorkloadFilters,
8
+ } from '../../../../../types/store/shardsWorkload';
9
+
10
+ import {isEnumMember} from '../../../../../utils/typecheckers';
11
+
12
+ import i18n from '../i18n';
13
+ import {b} from '../TopShards';
14
+
15
+ import './Filters.scss';
16
+
17
+ interface FiltersProps {
18
+ value: IShardsWorkloadFilters;
19
+ onChange: (value: Partial<IShardsWorkloadFilters>) => void;
20
+ className?: string;
21
+ }
22
+
23
+ export const Filters = ({value, onChange, className}: FiltersProps) => {
24
+ const handleModeChange = (mode: string) => {
25
+ if (!isEnumMember(EShardsWorkloadMode, mode)) {
26
+ const values = Object.values(EShardsWorkloadMode).join(', ');
27
+ throw new Error(`Unexpected TopShards mode "${mode}". Should be one of: ${values}`);
28
+ }
29
+
30
+ onChange({mode});
31
+ };
32
+
33
+ const handleDateRangeChange = (dateRange: DateRangeValues) => {
34
+ onChange({
35
+ mode: EShardsWorkloadMode.History,
36
+ ...dateRange,
37
+ });
38
+ };
39
+
40
+ const from = value.mode === EShardsWorkloadMode.Immediate ? undefined : value.from;
41
+ const to = value.mode === EShardsWorkloadMode.Immediate ? undefined : value.to;
42
+
43
+ return (
44
+ <div className={b('filters', className)}>
45
+ <RadioButton value={value.mode} onUpdate={handleModeChange}>
46
+ <RadioButton.Option value={EShardsWorkloadMode.Immediate}>
47
+ {i18n('filters.mode.immediate')}
48
+ </RadioButton.Option>
49
+ <RadioButton.Option value={EShardsWorkloadMode.History}>
50
+ {i18n('filters.mode.history')}
51
+ </RadioButton.Option>
52
+ </RadioButton>
53
+ <DateRange from={from} to={to} onChange={handleDateRangeChange} />
54
+ </div>
55
+ );
56
+ };
@@ -0,0 +1 @@
1
+ export * from './Filters';
@@ -1,6 +1,7 @@
1
- .overloaded-shards {
1
+ .top-shards {
2
2
  display: flex;
3
3
  flex-direction: column;
4
+ gap: 10px;
4
5
 
5
6
  height: 100%;
6
7
 
@@ -11,15 +12,6 @@
11
12
  justify-content: center;
12
13
  }
13
14
 
14
- &__controls {
15
- display: flex;
16
- flex-wrap: wrap;
17
- align-items: baseline;
18
- gap: 16px;
19
-
20
- margin-bottom: 10px;
21
- }
22
-
23
15
  &__table {
24
16
  overflow: auto;
25
17
  flex-grow: 1;
@@ -5,7 +5,6 @@ import cn from 'bem-cn-lite';
5
5
  import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
6
6
  import {Loader} from '@gravity-ui/uikit';
7
7
 
8
- import {DateRange, DateRangeValues} from '../../../../components/DateRange';
9
8
  import {InternalLink} from '../../../../components/InternalLink';
10
9
 
11
10
  import HistoryContext from '../../../../contexts/HistoryContext';
@@ -18,7 +17,7 @@ import {
18
17
  setShardsQueryFilters,
19
18
  } from '../../../../store/reducers/shardsWorkload';
20
19
  import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
21
- import type {IShardsWorkloadFilters} from '../../../../types/store/shardsWorkload';
20
+ import {EShardsWorkloadMode, IShardsWorkloadFilters} from '../../../../types/store/shardsWorkload';
22
21
 
23
22
  import type {EPathType} from '../../../../types/api/schema';
24
23
 
@@ -31,10 +30,12 @@ import {getDefaultNodePath} from '../../../Node/NodePages';
31
30
 
32
31
  import {isColumnEntityType} from '../../utils/schema';
33
32
 
33
+ import {Filters} from './Filters';
34
+
34
35
  import i18n from './i18n';
35
- import './OverloadedShards.scss';
36
+ import './TopShards.scss';
36
37
 
37
- const b = cn('overloaded-shards');
38
+ export const b = cn('top-shards');
38
39
  const bLink = cn('yc-link');
39
40
 
40
41
  const TABLE_SETTINGS: Settings = {
@@ -83,12 +84,18 @@ function dataTableToStringSortOrder(value: SortOrder | SortOrder[] = []) {
83
84
  return sortOrders.map(({columnId}) => columnId).join(',');
84
85
  }
85
86
 
86
- interface OverloadedShardsProps {
87
+ function fillDateRangeFor(value: IShardsWorkloadFilters) {
88
+ value.to = Date.now();
89
+ value.from = value.to - HOUR_IN_SECONDS * 1000;
90
+ return value;
91
+ }
92
+
93
+ interface TopShardsProps {
87
94
  tenantPath: string;
88
95
  type?: EPathType;
89
96
  }
90
97
 
91
- export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
98
+ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
92
99
  const dispatch = useDispatch();
93
100
 
94
101
  const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
@@ -101,17 +108,20 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
101
108
  wasLoaded,
102
109
  } = useTypedSelector((state) => state.shardsWorkload);
103
110
 
104
- // default date range should be the last hour, but shouldn't propagate into URL until user interacts with the control
111
+ // default filters shouldn't propagate into URL until user interacts with the control
105
112
  // redux initial value can't be used, as it synchronizes with URL
106
113
  const [filters, setFilters] = useState<IShardsWorkloadFilters>(() => {
107
- if (!storeFilters?.from && !storeFilters?.to) {
108
- return {
109
- from: Date.now() - HOUR_IN_SECONDS * 1000,
110
- to: Date.now(),
111
- };
114
+ const defaultValue = {...storeFilters};
115
+
116
+ if (!defaultValue.mode) {
117
+ defaultValue.mode = EShardsWorkloadMode.Immediate;
118
+ }
119
+
120
+ if (!defaultValue.from && !defaultValue.to) {
121
+ fillDateRangeFor(defaultValue);
112
122
  }
113
123
 
114
- return storeFilters;
124
+ return defaultValue;
115
125
  });
116
126
 
117
127
  const [sortOrder, setSortOrder] = useState(tableColumnsNames.CPUCores);
@@ -144,18 +154,34 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
144
154
  const history = useContext(HistoryContext);
145
155
 
146
156
  const onSort = (newSortOrder?: SortOrder | SortOrder[]) => {
147
- // omit information about sort order to disable ASC order, only DESC makes sense for overloaded shards
157
+ // omit information about sort order to disable ASC order, only DESC makes sense for top shards
148
158
  // use a string (and not the DataTable default format) to prevent reference change,
149
159
  // which would cause an excess state change, to avoid repeating requests
150
160
  setSortOrder(dataTableToStringSortOrder(newSortOrder));
151
161
  };
152
162
 
153
- const handleDateRangeChange = (value: DateRangeValues) => {
163
+ const handleFiltersChange = (value: Partial<IShardsWorkloadFilters>) => {
164
+ const newStateValue = {...value};
165
+ const isDateRangePristine =
166
+ !storeFilters.from && !storeFilters.to && !value.from && !value.to;
167
+
168
+ if (isDateRangePristine) {
169
+ switch (value.mode) {
170
+ case EShardsWorkloadMode.Immediate:
171
+ newStateValue.from = newStateValue.to = undefined;
172
+ break;
173
+ case EShardsWorkloadMode.History:
174
+ // should default to the current datetime every time history mode activates
175
+ fillDateRangeFor(newStateValue);
176
+ break;
177
+ }
178
+ }
179
+
154
180
  dispatch(setShardsQueryFilters(value));
155
- setFilters(value);
181
+ setFilters((state) => ({...state, ...newStateValue}));
156
182
  };
157
183
 
158
- const tableColumns: Column<any>[] = useMemo(() => {
184
+ const tableColumns = useMemo(() => {
159
185
  const onSchemaClick = (schemaPath: string) => {
160
186
  return () => {
161
187
  dispatch(setCurrentSchemaPath(schemaPath));
@@ -164,7 +190,7 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
164
190
  };
165
191
  };
166
192
 
167
- return [
193
+ const columns: Column<any>[] = [
168
194
  {
169
195
  name: tableColumnsNames.Path,
170
196
  render: ({value: relativeNodePath}) => {
@@ -217,23 +243,29 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
217
243
  align: DataTable.RIGHT,
218
244
  sortable: false,
219
245
  },
220
- {
221
- name: tableColumnsNames.PeakTime,
222
- render: ({value}) => formatDateTime(new Date(value as string).valueOf()),
223
- sortable: false,
224
- },
225
246
  {
226
247
  name: tableColumnsNames.InFlightTxCount,
227
248
  render: ({value}) => formatNumber(value as number),
228
249
  align: DataTable.RIGHT,
229
250
  sortable: false,
230
251
  },
231
- {
252
+ ];
253
+
254
+ if (filters.mode === EShardsWorkloadMode.History) {
255
+ // after NodeId
256
+ columns.splice(5, 0, {
257
+ name: tableColumnsNames.PeakTime,
258
+ render: ({value}) => formatDateTime(new Date(value as string).valueOf()),
259
+ sortable: false,
260
+ });
261
+ columns.push({
232
262
  name: tableColumnsNames.IntervalEnd,
233
263
  render: ({value}) => formatDateTime(new Date(value as string).getTime()),
234
- }
235
- ];
236
- }, [dispatch, history, tenantPath]);
264
+ });
265
+ }
266
+
267
+ return columns;
268
+ }, [dispatch, filters.mode, history, tenantPath]);
237
269
 
238
270
  const renderLoader = () => {
239
271
  return (
@@ -272,10 +304,8 @@ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
272
304
 
273
305
  return (
274
306
  <div className={b()}>
275
- <div className={b('controls')}>
276
- {i18n('description')}
277
- <DateRange from={filters.from} to={filters.to} onChange={handleDateRangeChange} />
278
- </div>
307
+ <Filters value={filters} onChange={handleFiltersChange} />
308
+ {filters.mode === EShardsWorkloadMode.History && <div>{i18n('description')}</div>}
279
309
  {renderContent()}
280
310
  </div>
281
311
  );
@@ -0,0 +1,6 @@
1
+ {
2
+ "no-data": "No data",
3
+ "filters.mode.immediate": "Immediate",
4
+ "filters.mode.history": "Historical",
5
+ "description": "Historical data only tracks shards with CPU load over 70%"
6
+ }
@@ -3,7 +3,7 @@ import {i18n, Lang} from '../../../../../utils/i18n';
3
3
  import en from './en.json';
4
4
  import ru from './ru.json';
5
5
 
6
- const COMPONENT = 'ydb-diagnostics-overloaded-shards';
6
+ const COMPONENT = 'ydb-diagnostics-top-shards';
7
7
 
8
8
  i18n.registerKeyset(Lang.En, COMPONENT, en);
9
9
  i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
@@ -0,0 +1,6 @@
1
+ {
2
+ "no-data": "Нет данных",
3
+ "filters.mode.immediate": "Мгновенные",
4
+ "filters.mode.history": "Исторические",
5
+ "description": "Исторические данные хранятся только о шардах с загрузкой CPU выше 70%"
6
+ }
@@ -0,0 +1 @@
1
+ export * from './TopShards';
@@ -34,21 +34,6 @@ const authentication = function (state = initialState, action) {
34
34
  }
35
35
  };
36
36
 
37
- export const setIsNotAuthenticated = () => {
38
- return (dispatch) => {
39
- dispatch({
40
- type: SET_UNAUTHENTICATED.SUCCESS,
41
- });
42
- };
43
- };
44
- export const setIsAuthenticated = () => {
45
- return (dispatch) => {
46
- dispatch({
47
- type: SET_AUTHENTICATED.SUCCESS,
48
- });
49
- };
50
- };
51
-
52
37
  export const authenticate = (user, password) => {
53
38
  return createApiRequest({
54
39
  request: window.api.authenticate(user, password),
@@ -6,6 +6,7 @@ import type {
6
6
  IShardsWorkloadFilters,
7
7
  IShardsWorkloadState,
8
8
  } from '../../types/store/shardsWorkload';
9
+ import {EShardsWorkloadMode} from '../../types/store/shardsWorkload';
9
10
 
10
11
  import {parseQueryAPIExecuteResponse} from '../../utils/query';
11
12
 
@@ -51,7 +52,7 @@ function getFiltersConditions(filters?: IShardsWorkloadFilters) {
51
52
  return conditions.join(' AND ');
52
53
  }
53
54
 
54
- function createShardQuery(
55
+ function createShardQueryHistorical(
55
56
  path: string,
56
57
  filters?: IShardsWorkloadFilters,
57
58
  sortOrder?: SortOrder[],
@@ -85,6 +86,28 @@ ${orderBy}
85
86
  LIMIT 20`;
86
87
  }
87
88
 
89
+ function createShardQueryImmediate(path: string, sortOrder?: SortOrder[], tenantName?: string) {
90
+ const pathSelect = tenantName
91
+ ? `CAST(SUBSTRING(CAST(Path AS String), ${tenantName.length}) AS Utf8) AS Path`
92
+ : 'Path';
93
+
94
+ const orderBy = sortOrder ? `ORDER BY ${sortOrder.map(formatSortOrder).join(', ')}` : '';
95
+
96
+ return `SELECT
97
+ ${pathSelect},
98
+ TabletId,
99
+ CPUCores,
100
+ DataSize,
101
+ NodeId,
102
+ InFlightTxCount
103
+ FROM \`.sys/partition_stats\`
104
+ WHERE
105
+ Path='${path}'
106
+ OR Path LIKE '${path}/%'
107
+ ${orderBy}
108
+ LIMIT 20`;
109
+ }
110
+
88
111
  const queryAction = 'execute-scan';
89
112
 
90
113
  const shardsWorkload: Reducer<IShardsWorkloadState, IShardsWorkloadAction> = (
@@ -147,7 +170,10 @@ export const sendShardQuery = ({database, path = '', sortOrder, filters}: SendSh
147
170
  request: window.api.sendQuery(
148
171
  {
149
172
  schema: 'modern',
150
- query: createShardQuery(path, filters, sortOrder, database),
173
+ query:
174
+ filters?.mode === EShardsWorkloadMode.Immediate
175
+ ? createShardQueryImmediate(path, sortOrder, database)
176
+ : createShardQueryHistorical(path, filters, sortOrder, database),
151
177
  database,
152
178
  action: queryAction,
153
179
  },
@@ -48,6 +48,9 @@ const paramSetup = {
48
48
  generalTab: {
49
49
  stateKey: 'tenant.diagnosticsTab',
50
50
  },
51
+ shardsMode: {
52
+ stateKey: 'shardsWorkload.filters.mode',
53
+ },
51
54
  shardsDateFrom: {
52
55
  stateKey: 'shardsWorkload.filters.from',
53
56
  type: 'number',
@@ -3,11 +3,17 @@ import type {ApiRequestAction} from '../../store/utils';
3
3
  import type {IResponseError} from '../api/error';
4
4
  import type {IQueryResult} from './query';
5
5
 
6
+ export enum EShardsWorkloadMode {
7
+ Immediate = 'immediate',
8
+ History = 'history',
9
+ }
10
+
6
11
  export interface IShardsWorkloadFilters {
7
12
  /** ms from epoch */
8
13
  from?: number;
9
14
  /** ms from epoch */
10
15
  to?: number;
16
+ mode?: EShardsWorkloadMode;
11
17
  }
12
18
 
13
19
  export interface IShardsWorkloadState {
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Intended to typecheck enums, but also checks if the value is any of the arbitrary object values
3
+ */
4
+ export const isEnumMember = <T extends Object>(object: T, value: any): value is T[keyof T] =>
5
+ Object.values(object).includes(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "3.3.3",
3
+ "version": "3.3.4",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -1,4 +0,0 @@
1
- {
2
- "no-data": "No data",
3
- "description": "Shards with CPU load over 70% are listed"
4
- }
@@ -1,4 +0,0 @@
1
- {
2
- "no-data": "Нет данных",
3
- "description": "Отображаются шарды с загрузкой CPU выше 70%"
4
- }
@@ -1 +0,0 @@
1
- export * from './OverloadedShards';