Skip to content

Commit 8047fe4

Browse files
feat(HotKeys): revive (#722)
1 parent e677f18 commit 8047fe4

File tree

10 files changed

+213
-216
lines changed

10 files changed

+213
-216
lines changed

src/containers/Tenant/Diagnostics/Diagnostics.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {StorageWrapper} from '../../Storage/StorageWrapper';
2525
import {Tablets} from '../../Tablets';
2626

2727
import Describe from './Describe/Describe';
28-
import HotKeys from './HotKeys/HotKeys';
28+
import {HotKeys} from './HotKeys/HotKeys';
2929
import Network from './Network/Network';
3030
import {Partitions} from './Partitions/Partitions';
3131
import {Consumers} from './Consumers';
@@ -145,7 +145,7 @@ function Diagnostics(props: DiagnosticsProps) {
145145
return <Describe tenant={tenantNameString} type={type} />;
146146
}
147147
case TENANT_DIAGNOSTICS_TABS_IDS.hotKeys: {
148-
return <HotKeys type={type} />;
148+
return <HotKeys path={currentSchemaPath} />;
149149
}
150150
case TENANT_DIAGNOSTICS_TABS_IDS.graph: {
151151
return <Heatmap path={currentSchemaPath} />;

src/containers/Tenant/Diagnostics/DiagnosticsPages.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export const DATABASE_PAGES = [
7777
];
7878

7979
export const TABLE_PAGES = [overview, topShards, nodes, graph, tablets, hotKeys, describe];
80+
export const COLUMN_TABLE_PAGES = [overview, topShards, nodes, graph, tablets, describe];
8081

8182
export const DIR_PAGES = [overview, topShards, nodes, describe];
8283

@@ -96,7 +97,7 @@ const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
9697
[EPathType.EPathTypeColumnStore]: DATABASE_PAGES,
9798

9899
[EPathType.EPathTypeTable]: TABLE_PAGES,
99-
[EPathType.EPathTypeColumnTable]: TABLE_PAGES,
100+
[EPathType.EPathTypeColumnTable]: COLUMN_TABLE_PAGES,
100101

101102
[EPathType.EPathTypeDir]: DIR_PAGES,
102103
[EPathType.EPathTypeTableIndex]: DIR_PAGES,

src/containers/Tenant/Diagnostics/HotKeys/HotKeys.js

Lines changed: 0 additions & 157 deletions
This file was deleted.

src/containers/Tenant/Diagnostics/HotKeys/HotKeys.scss

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
@import '../../../../styles/mixins.scss';
22

3-
.hot-keys {
4-
display: flex;
5-
overflow: auto;
6-
flex-grow: 1;
7-
flex-direction: column;
8-
align-items: flex-start;
9-
10-
max-height: 100%;
11-
12-
background-color: var(--g-color-base-background);
13-
3+
.ydb-hot-keys {
144
&__table-content {
155
overflow: auto;
166

@@ -19,28 +9,6 @@
199
@include freeze-nth-column(1);
2010
}
2111

22-
&__header {
23-
position: sticky;
24-
z-index: 2;
25-
top: 0px;
26-
left: 0;
27-
28-
width: 100%;
29-
padding: 10px 0;
30-
31-
background-color: var(--g-color-base-background);
32-
}
33-
&__loader {
34-
display: flex;
35-
justify-content: center;
36-
align-items: center;
37-
38-
width: 100%;
39-
height: 100%;
40-
}
41-
&__stub {
42-
margin: 10px;
43-
}
4412
&__primary-key-column {
4513
display: flex;
4614
gap: 5px;
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import {useEffect, useMemo, useRef} from 'react';
2+
import {useDispatch} from 'react-redux';
3+
import DataTable, {type Column} from '@gravity-ui/react-data-table';
4+
5+
import type {HotKey} from '../../../../types/api/hotkeys';
6+
import type {IResponseError} from '../../../../types/api/error';
7+
import {Icon} from '../../../../components/Icon';
8+
import {ResponseError} from '../../../../components/Errors/ResponseError';
9+
import {useTypedSelector} from '../../../../utils/hooks';
10+
import {cn} from '../../../../utils/cn';
11+
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
12+
import {
13+
setHotKeysData,
14+
setHotKeysDataWasNotLoaded,
15+
setHotKeysError,
16+
setHotKeysLoading,
17+
} from '../../../../store/reducers/hotKeys/hotKeys';
18+
19+
import './HotKeys.scss';
20+
import i18n from './i18n';
21+
22+
const b = cn('ydb-hot-keys');
23+
24+
const tableColumnsIds = {
25+
accessSample: 'accessSample',
26+
keyValues: 'keyValues',
27+
} as const;
28+
29+
const getHotKeysColumns = (keyColumnsIds: string[] = []): Column<HotKey>[] => {
30+
const keysColumns: Column<HotKey>[] = keyColumnsIds.map((col, index) => ({
31+
name: col,
32+
header: (
33+
<div className={b('primary-key-column')}>
34+
<Icon name="key" viewBox="0 0 12 7" width={12} height={7} />
35+
{col}
36+
</div>
37+
),
38+
render: ({row}) => row.keyValues[index],
39+
align: DataTable.RIGHT,
40+
sortable: false,
41+
}));
42+
43+
return [
44+
{
45+
name: tableColumnsIds.accessSample,
46+
header: 'Samples',
47+
render: ({row}) => row.accessSample,
48+
align: DataTable.RIGHT,
49+
sortable: false,
50+
},
51+
...keysColumns,
52+
];
53+
};
54+
55+
interface HotKeysProps {
56+
path: string;
57+
}
58+
59+
export function HotKeys({path}: HotKeysProps) {
60+
const dispatch = useDispatch();
61+
62+
const collectSamplesTimerRef = useRef<ReturnType<typeof setTimeout>>();
63+
64+
const {loading, wasLoaded, data, error} = useTypedSelector((state) => state.hotKeys);
65+
const {loading: schemaLoading, data: schemaData} = useTypedSelector((state) => state.schema);
66+
67+
const keyColumnsIds = schemaData[path]?.PathDescription?.Table?.KeyColumnNames;
68+
69+
const tableColumns = useMemo(() => {
70+
return getHotKeysColumns(keyColumnsIds);
71+
}, [keyColumnsIds]);
72+
73+
useEffect(() => {
74+
const fetchHotkeys = async (enableSampling: boolean) => {
75+
// Set hotkeys error, but not data, since data is set conditionally
76+
try {
77+
const response = await window.api.getHotKeys(path, enableSampling);
78+
return response;
79+
} catch (err) {
80+
dispatch(setHotKeysError(err as IResponseError));
81+
return undefined;
82+
}
83+
};
84+
85+
const fetchData = async () => {
86+
// If there is previous pending request for samples, cancel it
87+
if (collectSamplesTimerRef.current !== undefined) {
88+
window.clearInterval(collectSamplesTimerRef.current);
89+
}
90+
91+
dispatch(setHotKeysDataWasNotLoaded());
92+
dispatch(setHotKeysLoading());
93+
94+
// Send request that will trigger hot keys sampling (enable_sampling = true)
95+
const initialResponse = await fetchHotkeys(true);
96+
97+
// If there are hotkeys in the initial request (hotkeys was collected before)
98+
// we could just use colleted samples (collected hotkeys are stored only for 30 seconds)
99+
if (initialResponse && initialResponse.hotkeys) {
100+
dispatch(setHotKeysData(initialResponse));
101+
} else if (initialResponse) {
102+
// Else wait for 5 seconds, while hot keys are being collected
103+
// And request these samples (enable_sampling = false)
104+
const timer = setTimeout(async () => {
105+
const responseWithSamples = await fetchHotkeys(false);
106+
if (responseWithSamples) {
107+
dispatch(setHotKeysData(responseWithSamples));
108+
}
109+
}, 5000);
110+
collectSamplesTimerRef.current = timer;
111+
}
112+
};
113+
fetchData();
114+
}, [dispatch, path]);
115+
116+
// It takes a while to collect hot keys. Display explicit status message, while collecting
117+
if ((loading && !wasLoaded) || schemaLoading) {
118+
return <div>{i18n('hot-keys-collecting')}</div>;
119+
}
120+
121+
if (error) {
122+
return <ResponseError error={error} />;
123+
}
124+
125+
if (!data) {
126+
return <div>{i18n('no-data')}</div>;
127+
}
128+
129+
return (
130+
<div className={b('table-content')}>
131+
<DataTable
132+
columns={tableColumns}
133+
data={data}
134+
settings={DEFAULT_TABLE_SETTINGS}
135+
theme="yandex-cloud"
136+
initialSortOrder={{
137+
columnId: tableColumnsIds.accessSample,
138+
order: DataTable.DESCENDING,
139+
}}
140+
/>
141+
</div>
142+
);
143+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"hot-keys-collecting": "Please wait a little while we are collecting hot keys samples...",
3+
"no-data": "No information about hot keys"
4+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import {i18n, Lang} from '../../../../../utils/i18n';
2+
3+
import en from './en.json';
4+
5+
const COMPONENT = 'ydb-hot-keys';
6+
7+
i18n.registerKeyset(Lang.En, COMPONENT, en);
8+
9+
export default i18n.keyset(COMPONENT);

0 commit comments

Comments
 (0)