ydb-embedded-ui 4.8.1 → 4.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -2
  3. package/dist/components/Tablet/Tablet.tsx +2 -13
  4. package/dist/containers/Header/breadcrumbs.ts +22 -6
  5. package/dist/containers/Nodes/Nodes.tsx +1 -1
  6. package/dist/containers/Nodes/getNodesColumns.tsx +2 -2
  7. package/dist/containers/Storage/PDisk/PDisk.tsx +1 -1
  8. package/dist/containers/Storage/Storage.js +26 -48
  9. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +16 -19
  10. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +12 -10
  11. package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +27 -0
  12. package/dist/containers/Storage/StorageVisibleEntityFilter/StorageVisibleEntityFilter.tsx +31 -0
  13. package/dist/containers/Tablet/Tablet.tsx +2 -11
  14. package/dist/containers/TabletsFilters/TabletsFilters.js +8 -3
  15. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +17 -43
  16. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +20 -15
  17. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.tsx +74 -27
  18. package/dist/containers/Tenant/Query/i18n/en.json +1 -1
  19. package/dist/containers/Tenant/Query/i18n/ru.json +1 -1
  20. package/dist/containers/UserSettings/i18n/en.json +1 -1
  21. package/dist/containers/UserSettings/i18n/ru.json +1 -1
  22. package/dist/services/api.ts +6 -13
  23. package/dist/store/reducers/executeQuery.ts +2 -3
  24. package/dist/store/reducers/explainQuery.ts +2 -2
  25. package/dist/store/reducers/header/types.ts +0 -2
  26. package/dist/store/reducers/index.ts +2 -2
  27. package/dist/store/reducers/{nodes.ts → nodes/nodes.ts} +31 -30
  28. package/dist/{types/store/nodes.ts → store/reducers/nodes/types.ts} +24 -27
  29. package/dist/store/reducers/settings/settings.ts +10 -2
  30. package/dist/store/reducers/storage/constants.ts +10 -0
  31. package/dist/store/reducers/{storage.js → storage/storage.js} +19 -53
  32. package/dist/store/reducers/storage/types.ts +12 -0
  33. package/dist/types/store/query.ts +5 -6
  34. package/dist/utils/constants.ts +1 -0
  35. package/dist/utils/nodes.ts +2 -2
  36. package/dist/utils/query.ts +12 -0
  37. package/package.json +1 -1
  38. package/dist/containers/Tenant/Query/QueryEditorControls/OldQueryEditorControls.tsx +0 -90
  39. package/dist/containers/Tenant/Query/QueryEditorControls/shared.ts +0 -18
@@ -1,22 +1,23 @@
1
- import type {IResponseError} from '../api/error';
2
- import type {TEndpoint, TPoolStats} from '../api/nodes';
3
- import type {TTabletStateInfo as TComputeTabletStateInfo} from '../api/compute';
4
- import type {TTabletStateInfo as TFullTabletStateInfo} from '../api/tablet';
5
- import type {EFlag} from '../api/enums';
1
+ import type {IResponseError} from '../../../types/api/error';
2
+ import type {TEndpoint, TPoolStats} from '../../../types/api/nodes';
3
+ import type {TTabletStateInfo as TComputeTabletStateInfo} from '../../../types/api/compute';
4
+ import type {TTabletStateInfo as TFullTabletStateInfo} from '../../../types/api/tablet';
5
+ import type {EFlag} from '../../../types/api/enums';
6
+ import type {ApiRequestAction} from '../../utils';
7
+ import type {VisibleEntities} from '../storage/types';
6
8
 
7
- import {NodesUptimeFilterValues} from '../../utils/nodes';
9
+ import {NodesUptimeFilterValues} from '../../../utils/nodes';
8
10
  import {
9
11
  FETCH_NODES,
10
12
  resetNodesState,
11
13
  setDataWasNotLoaded,
12
14
  setNodesUptimeFilter,
13
15
  setSearchValue,
14
- } from '../../store/reducers/nodes';
15
- import {ApiRequestAction} from '../../store/utils';
16
+ } from './nodes';
16
17
 
17
18
  // Since nodes from different endpoints can have different types,
18
19
  // This type describes fields, that are expected by tables with nodes
19
- export interface INodesPreparedEntity {
20
+ export interface NodesPreparedEntity {
20
21
  NodeId: number;
21
22
  Host?: string;
22
23
  SystemState?: EFlag;
@@ -33,43 +34,39 @@ export interface INodesPreparedEntity {
33
34
  Endpoints?: TEndpoint[];
34
35
  }
35
36
 
36
- export interface INodesState {
37
+ export interface NodesState {
37
38
  loading: boolean;
38
39
  wasLoaded: boolean;
39
40
  nodesUptimeFilter: NodesUptimeFilterValues;
40
41
  searchValue: string;
41
- data?: INodesPreparedEntity[];
42
+ data?: NodesPreparedEntity[];
42
43
  totalNodes?: number;
43
44
  error?: IResponseError;
44
45
  }
45
46
 
46
- type INodesApiRequestNodeType = 'static' | 'dynamic' | 'any';
47
+ export type NodeType = 'static' | 'dynamic' | 'any';
47
48
 
48
- // Space - out of space nodes
49
- // Missing - nodes with missing disks
50
- type INodesApiRequestProblemType = 'missing' | 'space';
51
-
52
- export interface INodesApiRequestParams {
49
+ export interface NodesApiRequestParams {
53
50
  tenant?: string;
54
- type?: INodesApiRequestNodeType;
55
- filter?: INodesApiRequestProblemType;
51
+ type?: NodeType;
52
+ visibleEntities?: VisibleEntities;
56
53
  storage?: boolean;
57
54
  tablets?: boolean;
58
55
  }
59
56
 
60
- export interface INodesHandledResponse {
61
- Nodes?: INodesPreparedEntity[];
57
+ export interface NodesHandledResponse {
58
+ Nodes?: NodesPreparedEntity[];
62
59
  TotalNodes: number;
63
60
  }
64
61
 
65
- type INodesApiRequestAction = ApiRequestAction<
62
+ type NodesApiRequestAction = ApiRequestAction<
66
63
  typeof FETCH_NODES,
67
- INodesHandledResponse,
64
+ NodesHandledResponse,
68
65
  IResponseError
69
66
  >;
70
67
 
71
- export type INodesAction =
72
- | INodesApiRequestAction
68
+ export type NodesAction =
69
+ | NodesApiRequestAction
73
70
  | (
74
71
  | ReturnType<typeof setDataWasNotLoaded>
75
72
  | ReturnType<typeof setNodesUptimeFilter>
@@ -77,6 +74,6 @@ export type INodesAction =
77
74
  | ReturnType<typeof resetNodesState>
78
75
  );
79
76
 
80
- export interface INodesRootStateSlice {
81
- nodes: INodesState;
77
+ export interface NodesStateSlice {
78
+ nodes: NodesState;
82
79
  }
@@ -13,10 +13,11 @@ import {
13
13
  QUERY_INITIAL_MODE_KEY,
14
14
  ENABLE_ADDITIONAL_QUERY_MODES,
15
15
  CLUSTER_INFO_HIDDEN_KEY,
16
+ LAST_USED_QUERY_ACTION_KEY,
16
17
  } from '../../../utils/constants';
17
18
  import '../../../services/api';
18
19
  import {getValueFromLS, parseJson} from '../../../utils/utils';
19
- import {QueryModes} from '../../../types/store/query';
20
+ import {QUERY_ACTIONS, QUERY_MODES} from '../../../utils/query';
20
21
 
21
22
  import {TENANT_PAGES_IDS} from '../tenant/constants';
22
23
 
@@ -64,7 +65,14 @@ export const initialState = {
64
65
  TENANT_INITIAL_PAGE_KEY,
65
66
  TENANT_PAGES_IDS.query,
66
67
  ),
67
- [QUERY_INITIAL_MODE_KEY]: readSavedSettingsValue(QUERY_INITIAL_MODE_KEY, QueryModes.script),
68
+ [QUERY_INITIAL_MODE_KEY]: readSavedSettingsValue(
69
+ QUERY_INITIAL_MODE_KEY,
70
+ QUERY_MODES.script,
71
+ ),
72
+ [LAST_USED_QUERY_ACTION_KEY]: readSavedSettingsValue(
73
+ LAST_USED_QUERY_ACTION_KEY,
74
+ QUERY_ACTIONS.execute,
75
+ ),
68
76
  [ASIDE_HEADER_COMPACT_KEY]: readSavedSettingsValue(ASIDE_HEADER_COMPACT_KEY, 'true'),
69
77
  [PARTITIONS_HIDDEN_COLUMNS_KEY]: readSavedSettingsValue(PARTITIONS_HIDDEN_COLUMNS_KEY),
70
78
  [CLUSTER_INFO_HIDDEN_KEY]: readSavedSettingsValue(CLUSTER_INFO_HIDDEN_KEY, 'true'),
@@ -0,0 +1,10 @@
1
+ export const VISIBLE_ENTITIES = {
2
+ all: 'all',
3
+ missing: 'missing',
4
+ space: 'space',
5
+ } as const;
6
+
7
+ export const STORAGE_TYPES = {
8
+ groups: 'groups',
9
+ nodes: 'nodes',
10
+ } as const;
@@ -1,31 +1,16 @@
1
1
  import _ from 'lodash';
2
2
  import {createSelector} from 'reselect';
3
3
 
4
- import {calcUptime} from '../../utils';
5
- import {getUsage} from '../../utils/storage';
6
- import {NodesUptimeFilterValues} from '../../utils/nodes';
7
- import {getPDiskType} from '../../utils/pdisk';
8
- import '../../services/api';
9
-
10
- import {createRequestActionTypes, createApiRequest} from '../utils';
11
- import {filterNodesByUptime} from './nodes';
12
-
13
- export const VisibleEntities = {
14
- All: 'All',
15
- Missing: 'Missing',
16
- Space: 'Space',
17
- };
4
+ import {calcUptime} from '../../../utils';
5
+ import {getUsage} from '../../../utils/storage';
6
+ import {NodesUptimeFilterValues} from '../../../utils/nodes';
7
+ import {getPDiskType} from '../../../utils/pdisk';
8
+ import '../../../services/api';
18
9
 
19
- export const VisibleEntitiesTitles = {
20
- [VisibleEntities.All]: 'All',
21
- [VisibleEntities.Missing]: 'Degraded',
22
- [VisibleEntities.Space]: 'Out of Space',
23
- };
10
+ import {createRequestActionTypes, createApiRequest} from '../../utils';
11
+ import {filterNodesByUptime} from '../nodes/nodes';
24
12
 
25
- export const StorageTypes = {
26
- groups: 'Groups',
27
- nodes: 'Nodes',
28
- };
13
+ import {VISIBLE_ENTITIES, STORAGE_TYPES} from './constants';
29
14
 
30
15
  const FETCH_STORAGE = createRequestActionTypes('storage', 'FETCH_STORAGE');
31
16
  const SET_INITIAL = 'storage/SET_INITIAL';
@@ -41,9 +26,9 @@ const initialState = {
41
26
  wasLoaded: false,
42
27
  filter: '',
43
28
  usageFilter: [],
44
- visible: VisibleEntities.Missing,
29
+ visible: VISIBLE_ENTITIES.missing,
45
30
  nodesUptimeFilter: NodesUptimeFilterValues.All,
46
- type: StorageTypes.groups,
31
+ type: STORAGE_TYPES.groups,
47
32
  };
48
33
 
49
34
  const storage = (state = initialState, action) => {
@@ -134,16 +119,16 @@ export function setInitialState() {
134
119
  };
135
120
  }
136
121
 
137
- export function getStorageInfo({tenant, filter, nodeId, type}, {concurrentId}) {
138
- if (type === StorageTypes.nodes) {
122
+ export function getStorageInfo({tenant, visibleEntities, nodeId, type}, {concurrentId}) {
123
+ if (type === STORAGE_TYPES.nodes) {
139
124
  return createApiRequest({
140
- request: window.api.getNodes({tenant, filter, type: 'static'}, {concurrentId}),
125
+ request: window.api.getNodes({tenant, visibleEntities, type: 'static'}, {concurrentId}),
141
126
  actions: FETCH_STORAGE,
142
127
  });
143
128
  }
144
129
 
145
130
  return createApiRequest({
146
- request: window.api.getStorageInfo({tenant, filter, nodeId}, {concurrentId}),
131
+ request: window.api.getStorageInfo({tenant, visibleEntities, nodeId}, {concurrentId}),
147
132
  actions: FETCH_STORAGE,
148
133
  });
149
134
  }
@@ -343,26 +328,13 @@ export const getVDisksForPDisk = createSelector(
343
328
  export const getFlatListStorage = createSelector(
344
329
  [getStorageType, getFlatListStorageGroups, getFlatListStorageNodes],
345
330
  (storageType, groupsList, nodesList) => {
346
- if (storageType === StorageTypes.groups) {
331
+ if (storageType === STORAGE_TYPES.groups) {
347
332
  return groupsList;
348
333
  }
349
334
  return nodesList;
350
335
  },
351
336
  );
352
337
 
353
- export const getVisibleEntitiesList = createSelector(
354
- [getVisibleEntities, getFlatListStorage],
355
- (visibleGroups, storageList) => {
356
- if (visibleGroups === VisibleEntities.All) {
357
- return storageList;
358
- } else if (visibleGroups === VisibleEntities.Missing) {
359
- return _.filter(storageList, (g) => g.Missing > 0);
360
- } else {
361
- return _.filter(storageList, (g) => g.UsedSpaceFlag > 100);
362
- }
363
- },
364
- );
365
-
366
338
  const filterByText = (entities, type, text) => {
367
339
  const cleanedFilter = text.trim().toLowerCase();
368
340
 
@@ -371,7 +343,7 @@ const filterByText = (entities, type, text) => {
371
343
  }
372
344
 
373
345
  return entities.filter((entity) => {
374
- if (type === StorageTypes.groups) {
346
+ if (type === STORAGE_TYPES.groups) {
375
347
  return (
376
348
  entity.PoolName.toLowerCase().includes(cleanedFilter) ||
377
349
  entity.GroupID?.toString().includes(cleanedFilter)
@@ -397,19 +369,13 @@ const filterByUsage = (entities, usage) => {
397
369
  };
398
370
 
399
371
  export const getFilteredEntities = createSelector(
400
- [
401
- getStorageFilter,
402
- getUsageFilter,
403
- getStorageType,
404
- getNodesUptimeFilter,
405
- getVisibleEntitiesList,
406
- ],
372
+ [getStorageFilter, getUsageFilter, getStorageType, getNodesUptimeFilter, getFlatListStorage],
407
373
  (textFilter, usageFilter, type, nodesUptimeFilter, entities) => {
408
374
  let result = entities;
409
375
  result = filterByText(result, type, textFilter);
410
376
  result = filterByUsage(result, usageFilter);
411
377
 
412
- if (type === StorageTypes.nodes) {
378
+ if (type === STORAGE_TYPES.nodes) {
413
379
  result = filterNodesByUptime(result, nodesUptimeFilter);
414
380
  }
415
381
 
@@ -417,7 +383,7 @@ export const getFilteredEntities = createSelector(
417
383
  },
418
384
  );
419
385
 
420
- export const getUsageFilterOptions = createSelector(getVisibleEntitiesList, (entities) => {
386
+ export const getUsageFilterOptions = createSelector(getFlatListStorage, (entities) => {
421
387
  const items = {};
422
388
 
423
389
  entities.forEach((entity) => {
@@ -0,0 +1,12 @@
1
+ import type {ValueOf} from '../../../types/common';
2
+
3
+ import {STORAGE_TYPES, VISIBLE_ENTITIES} from './constants';
4
+
5
+ export type VisibleEntities = ValueOf<typeof VISIBLE_ENTITIES>;
6
+ export type StorageType = ValueOf<typeof STORAGE_TYPES>;
7
+
8
+ export interface StorageApiRequestParams {
9
+ tenant?: string;
10
+ nodeId?: string;
11
+ visibleEntities?: VisibleEntities;
12
+ }
@@ -1,3 +1,5 @@
1
+ import {QUERY_ACTIONS, QUERY_MODES} from '../../utils/query';
2
+
1
3
  import type {NetworkError} from '../api/error';
2
4
  import type {
3
5
  KeyValueRow,
@@ -7,6 +9,7 @@ import type {
7
9
  QueryPlan,
8
10
  TKqpStatsQuery,
9
11
  } from '../api/query';
12
+ import type {ValueOf} from '../common';
10
13
 
11
14
  export interface IQueryResult {
12
15
  result?: KeyValueRow[];
@@ -23,12 +26,8 @@ export interface QueryRequestParams {
23
26
 
24
27
  export type QueryError = NetworkError | ErrorResponse;
25
28
 
26
- export enum QueryModes {
27
- scan = 'scan',
28
- script = 'script',
29
- data = 'data',
30
- query = 'query',
31
- }
29
+ export type QueryAction = ValueOf<typeof QUERY_ACTIONS>;
30
+ export type QueryMode = ValueOf<typeof QUERY_MODES>;
32
31
 
33
32
  export interface SavedQuery {
34
33
  name: string;
@@ -105,6 +105,7 @@ export const DEFAULT_TABLE_SETTINGS = {
105
105
  } as const;
106
106
 
107
107
  export const QUERY_INITIAL_MODE_KEY = 'query_initial_mode';
108
+ export const LAST_USED_QUERY_ACTION_KEY = 'last_used_query_action';
108
109
 
109
110
  export const PARTITIONS_HIDDEN_COLUMNS_KEY = 'partitionsHiddenColumns';
110
111
 
@@ -1,6 +1,6 @@
1
1
  import type {TSystemStateInfo} from '../types/api/nodes';
2
2
  import type {TNodeInfo} from '../types/api/nodesList';
3
- import type {INodesPreparedEntity} from '../types/store/nodes';
3
+ import type {NodesPreparedEntity} from '../store/reducers/nodes/types';
4
4
  import type {NodesMap} from '../types/store/nodesList';
5
5
  import {EFlag} from '../types/api/enums';
6
6
 
@@ -14,7 +14,7 @@ export const NodesUptimeFilterTitles = {
14
14
  [NodesUptimeFilterValues.SmallUptime]: 'Uptime < 1h',
15
15
  };
16
16
 
17
- export const isUnavailableNode = (node: INodesPreparedEntity | TSystemStateInfo) =>
17
+ export const isUnavailableNode = (node: NodesPreparedEntity | TSystemStateInfo) =>
18
18
  !node.SystemState || node.SystemState === EFlag.Grey;
19
19
 
20
20
  export type NodeAddress = Pick<TSystemStateInfo, 'Host' | 'Endpoints'>;
@@ -9,6 +9,18 @@ import type {
9
9
  } from '../types/api/query';
10
10
  import type {IQueryResult} from '../types/store/query';
11
11
 
12
+ export const QUERY_ACTIONS = {
13
+ execute: 'execute',
14
+ explain: 'explain',
15
+ } as const;
16
+
17
+ export const QUERY_MODES = {
18
+ scan: 'scan',
19
+ script: 'script',
20
+ data: 'data',
21
+ query: 'query',
22
+ } as const;
23
+
12
24
  // eslint-disable-next-line complexity
13
25
  export const getColumnType = (type: string) => {
14
26
  switch (type.replace(/\?$/, '')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.8.1",
3
+ "version": "4.9.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -1,90 +0,0 @@
1
- import {Button, DropdownMenu} from '@gravity-ui/uikit';
2
- import {useMemo} from 'react';
3
-
4
- import {QueryModes} from '../../../../types/store/query';
5
- import {Icon} from '../../../../components/Icon';
6
-
7
- import SaveQuery from '../SaveQuery/SaveQuery';
8
-
9
- import {QueryEditorControlsProps, b} from './shared';
10
-
11
- import './QueryEditorControls.scss';
12
-
13
- type OldQueryModes = QueryModes.script | QueryModes.scan;
14
-
15
- export const QueryModeSelectorTitles = {
16
- [QueryModes.script]: 'Script',
17
- [QueryModes.scan]: 'Scan',
18
- } as const;
19
-
20
- export const OldQueryEditorControls = ({
21
- onRunButtonClick,
22
- runIsLoading,
23
- onExplainButtonClick,
24
- explainIsLoading,
25
- onSaveQueryClick,
26
- savedQueries,
27
- disabled,
28
- onUpdateQueryMode,
29
- queryMode,
30
- }: QueryEditorControlsProps) => {
31
- const runModeSelectorMenuItems = useMemo(() => {
32
- return Object.entries(QueryModeSelectorTitles).map(([mode, title]) => {
33
- return {
34
- text: `Run ${title}`,
35
- action: () => {
36
- onUpdateQueryMode(mode as OldQueryModes);
37
- },
38
- };
39
- });
40
- }, [onUpdateQueryMode]);
41
-
42
- return (
43
- <div className={b()}>
44
- <div className={b('left')}>
45
- <div className={b('run')}>
46
- <Button
47
- onClick={() => onRunButtonClick(queryMode)}
48
- view="action"
49
- pin="round-brick"
50
- disabled={disabled}
51
- loading={runIsLoading}
52
- >
53
- <Icon name="startPlay" viewBox="0 0 16 16" width={16} height={16} />
54
- {`Run ${QueryModeSelectorTitles[queryMode as OldQueryModes]}`}
55
- </Button>
56
- <DropdownMenu
57
- items={runModeSelectorMenuItems}
58
- popupProps={{className: b('select-query-action-popup')}}
59
- switcher={
60
- <Button
61
- view="action"
62
- pin="brick-round"
63
- disabled={disabled}
64
- loading={runIsLoading}
65
- className={b('select-query-action')}
66
- >
67
- <Icon name="chevron-down" width={16} height={16} />
68
- </Button>
69
- }
70
- />
71
- </div>
72
- <Button
73
- onClick={() => {
74
- // Without defined query mode it sends 'explain' action
75
- onExplainButtonClick();
76
- }}
77
- disabled={disabled}
78
- loading={explainIsLoading}
79
- >
80
- Explain
81
- </Button>
82
- </div>
83
- <SaveQuery
84
- savedQueries={savedQueries}
85
- onSaveQuery={onSaveQueryClick}
86
- saveButtonDisabled={disabled}
87
- />
88
- </div>
89
- );
90
- };
@@ -1,18 +0,0 @@
1
- import block from 'bem-cn-lite';
2
-
3
- import type {QueryModes} from '../../../../types/store/query';
4
-
5
- export const b = block('ydb-query-editor-controls');
6
-
7
- export interface QueryEditorControlsProps {
8
- onRunButtonClick: (mode?: QueryModes) => void;
9
- runIsLoading: boolean;
10
- onExplainButtonClick: (mode?: QueryModes) => void;
11
- explainIsLoading: boolean;
12
- onSaveQueryClick: (queryName: string) => void;
13
- savedQueries: unknown;
14
- disabled: boolean;
15
- onUpdateQueryMode: (mode: QueryModes) => void;
16
- queryMode: QueryModes;
17
- enableQueryModesForExplain: boolean;
18
- }