Skip to content

Commit 4c25054

Browse files
authored
feat(TopicData): add tab for topic data (#2145)
1 parent 12214a8 commit 4c25054

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1717
-159
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type {TextInputProps} from '@gravity-ui/uikit';
2+
import {TextInput} from '@gravity-ui/uikit';
3+
4+
import {useDebouncedValue} from '../../utils/hooks/useDebouncedValue';
5+
6+
interface DebouncedInputProps extends TextInputProps {
7+
debounce?: number;
8+
}
9+
10+
export const DebouncedInput = ({
11+
onUpdate,
12+
value = '',
13+
debounce = 200,
14+
...rest
15+
}: DebouncedInputProps) => {
16+
const [currentValue, handleUpdate] = useDebouncedValue<string>({value, onUpdate, debounce});
17+
18+
return <TextInput value={currentValue} onUpdate={handleUpdate} {...rest} />;
19+
};

src/components/EmptyState/EmptyState.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828

2929
margin: 0 auto;
3030
}
31+
&_position_left {
32+
margin: unset;
33+
}
3134
}
3235

3336
&__image {

src/components/MetricChart/getDefaultDataFormatter.ts

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {formatBytes} from '../../utils/bytesParsers';
22
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
33
import {roundToPrecision} from '../../utils/dataFormatters/dataFormatters';
44
import {formatToMs} from '../../utils/timeParsers';
5-
import {isNumeric} from '../../utils/utils';
5+
import {safeParseNumber} from '../../utils/utils';
66

77
import type {ChartDataType, ChartValue} from './types';
88

@@ -28,27 +28,18 @@ function formatChartValueToMs(value: ChartValue) {
2828
if (value === null) {
2929
return EMPTY_DATA_PLACEHOLDER;
3030
}
31-
return formatToMs(roundToPrecision(convertToNumber(value), 2));
31+
return formatToMs(roundToPrecision(safeParseNumber(value), 2));
3232
}
3333

3434
function formatChartValueToSize(value: ChartValue) {
3535
if (value === null) {
3636
return EMPTY_DATA_PLACEHOLDER;
3737
}
38-
return formatBytes({value: convertToNumber(value), precision: 3});
38+
return formatBytes({value: safeParseNumber(value), precision: 3});
3939
}
4040
function formatChartValueToPercent(value: ChartValue) {
4141
if (value === null) {
4242
return EMPTY_DATA_PLACEHOLDER;
4343
}
44-
return Math.round(convertToNumber(value) * 100) + '%';
45-
}
46-
47-
// Numeric values expected, not numeric value should be displayd as 0
48-
function convertToNumber(value: unknown): number {
49-
if (isNumeric(value)) {
50-
return Number(value);
51-
}
52-
53-
return 0;
44+
return Math.round(safeParseNumber(value) * 100) + '%';
5445
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.ydb-multiline-table-header {
2+
white-space: normal;
3+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import {cn} from '../../utils/cn';
2+
3+
import './MultilineTableHeader.scss';
4+
5+
const b = cn('ydb-multiline-table-header');
6+
7+
interface MultilineTableHeaderProps {
8+
title?: string;
9+
}
10+
11+
export function MultilineTableHeader({title}: MultilineTableHeaderProps) {
12+
if (!title) {
13+
return null;
14+
}
15+
return <div className={b()}>{title}</div>;
16+
}

src/components/PaginatedTable/PaginatedTable.scss

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,50 +79,69 @@
7979
display: flex;
8080
flex-direction: row;
8181
align-items: center;
82+
gap: var(--g-spacing-2);
8283

8384
width: 100%;
8485
max-width: 100%;
8586
padding: var(--paginated-table-cell-vertical-padding)
8687
var(--paginated-table-cell-horizontal-padding);
8788

89+
font-weight: bold;
90+
cursor: default;
8891
&_align {
8992
&_left {
9093
justify-content: left;
94+
95+
text-align: left;
9196
}
9297
&_center {
9398
justify-content: center;
99+
100+
text-align: center;
94101
}
95102
&_right {
96103
justify-content: right;
104+
105+
text-align: right;
106+
107+
#{$block}__head-cell-content-container {
108+
flex-direction: row-reverse;
109+
}
97110
}
98111
}
99112
}
100113

101-
&__head-cell {
102-
gap: 8px;
103-
104-
font-weight: bold;
105-
cursor: default;
106-
107-
&_sortable {
108-
cursor: pointer;
114+
&__head-cell_sortable {
115+
cursor: pointer;
109116

110-
&#{$block}__head-cell_align_right {
111-
flex-direction: row-reverse;
112-
}
117+
&#{$block}__head-cell_align_right {
118+
flex-direction: row-reverse;
113119
}
114120
}
115121

122+
&__head-cell-note {
123+
display: flex;
124+
}
125+
116126
// Separate head cell content class for correct text ellipsis overflow
117127
&__head-cell-content {
118128
overflow: hidden;
119129

120-
width: min-content;
121-
122130
white-space: nowrap;
123131
text-overflow: ellipsis;
124132
}
125133

134+
&__head-cell-content-container {
135+
display: inline-flex;
136+
overflow: hidden;
137+
gap: var(--g-spacing-1);
138+
139+
.g-help-mark__button {
140+
display: inline-flex;
141+
align-items: center;
142+
}
143+
}
144+
126145
&__row-cell {
127146
display: table-cell;
128147
overflow-x: hidden;

src/components/PaginatedTable/PaginatedTable.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export interface PaginatedTableProps<T, F> {
3838
renderErrorMessage?: RenderErrorMessage;
3939
containerClassName?: string;
4040
onDataFetched?: (data: PaginatedTableData<T>) => void;
41+
keepCache?: boolean;
4142
}
4243

4344
const DEFAULT_PAGINATION_LIMIT = 20;
@@ -46,7 +47,7 @@ export const PaginatedTable = <T, F>({
4647
limit: chunkSize = DEFAULT_PAGINATION_LIMIT,
4748
initialEntitiesCount,
4849
fetchData,
49-
filters,
50+
filters: rawFilters,
5051
tableName,
5152
columns,
5253
getRowClassName,
@@ -59,6 +60,7 @@ export const PaginatedTable = <T, F>({
5960
renderEmptyDataMessage,
6061
containerClassName,
6162
onDataFetched,
63+
keepCache = true,
6264
}: PaginatedTableProps<T, F>) => {
6365
const initialTotal = initialEntitiesCount || 0;
6466
const initialFound = initialEntitiesCount || 1;
@@ -78,6 +80,13 @@ export const PaginatedTable = <T, F>({
7880
chunkSize,
7981
});
8082

83+
// this prevent situation when filters are new, but active chunks is not yet recalculated (it will be done to the next rendrer, so we bring filters change on the next render too)
84+
const [filters, setFilters] = React.useState(rawFilters);
85+
86+
React.useEffect(() => {
87+
setFilters(rawFilters);
88+
}, [rawFilters]);
89+
8190
const lastChunkSize = React.useMemo(() => {
8291
// If foundEntities = 0, there will only first chunk
8392
// Display it with 1 row, to display empty data message
@@ -107,7 +116,7 @@ export const PaginatedTable = <T, F>({
107116
if (parentRef?.current) {
108117
parentRef.current.scrollTo(0, 0);
109118
}
110-
}, [filters, initialFound, initialTotal, parentRef]);
119+
}, [rawFilters, initialFound, initialTotal, parentRef]);
111120

112121
const renderChunks = () => {
113122
return activeChunks.map((isActive, index) => (
@@ -127,6 +136,7 @@ export const PaginatedTable = <T, F>({
127136
renderEmptyDataMessage={renderEmptyDataMessage}
128137
onDataFetched={handleDataFetched}
129138
isActive={isActive}
139+
keepCache={keepCache}
130140
/>
131141
));
132142
};

src/components/PaginatedTable/TableChunk.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ interface TableChunkProps<T, F> {
3737
renderErrorMessage?: RenderErrorMessage;
3838
renderEmptyDataMessage?: RenderEmptyDataMessage;
3939
onDataFetched: (data?: PaginatedTableData<T>) => void;
40+
41+
keepCache?: boolean;
4042
}
4143

4244
// Memoisation prevents chunks rerenders that could cause perfomance issues on big tables
@@ -55,6 +57,7 @@ export const TableChunk = typedMemo(function TableChunk<T, F>({
5557
renderEmptyDataMessage,
5658
onDataFetched,
5759
isActive,
60+
keepCache,
5861
}: TableChunkProps<T, F>) {
5962
const [isTimeoutActive, setIsTimeoutActive] = React.useState(true);
6063
const [autoRefreshInterval] = useAutoRefreshInterval();
@@ -74,6 +77,7 @@ export const TableChunk = typedMemo(function TableChunk<T, F>({
7477
tableDataApi.useFetchTableChunkQuery(queryParams, {
7578
skip: isTimeoutActive || !isActive,
7679
pollingInterval: autoRefreshInterval,
80+
refetchOnMountOrArgChange: !keepCache,
7781
});
7882

7983
const {currentData, error} = tableDataApi.endpoints.fetchTableChunk.useQueryState(queryParams);

src/components/PaginatedTable/TableHead.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import React from 'react';
22

3+
import type {HelpMarkProps} from '@gravity-ui/uikit';
4+
import {HelpMark} from '@gravity-ui/uikit';
5+
36
import {ResizeHandler} from './ResizeHandler';
47
import {
58
ASCENDING,
@@ -9,7 +12,14 @@ import {
912
DESCENDING,
1013
} from './constants';
1114
import {b} from './shared';
12-
import type {Column, HandleTableColumnsResize, OnSort, SortOrderType, SortParams} from './types';
15+
import type {
16+
AlignType,
17+
Column,
18+
HandleTableColumnsResize,
19+
OnSort,
20+
SortOrderType,
21+
SortParams,
22+
} from './types';
1323

1424
// Icon similar to original DataTable icons to keep the same tables across diferent pages and tabs
1525
const SortIcon = ({order}: {order?: SortOrderType}) => {
@@ -43,6 +53,12 @@ const ColumnSortIcon = ({sortOrder, sortable, defaultSortOrder}: ColumnSortIconP
4353
}
4454
};
4555

56+
const columnAlignToHelpMarkPlacement: Record<AlignType, Required<HelpMarkProps['placement']>> = {
57+
left: 'right',
58+
right: 'left',
59+
center: 'right',
60+
};
61+
4662
interface TableHeadCellProps<T> {
4763
column: Column<T>;
4864
resizeable?: boolean;
@@ -115,7 +131,17 @@ export const TableHeadCell = <T,>({
115131
}
116132
}}
117133
>
118-
<div className={b('head-cell-content')}>{content}</div>
134+
<div className={b('head-cell-content-container')}>
135+
<div className={b('head-cell-content')}>{content}</div>
136+
{column.note && (
137+
<HelpMark
138+
placement={columnAlignToHelpMarkPlacement[column.align]}
139+
className={b('head-cell-note')}
140+
>
141+
{column.note}
142+
</HelpMark>
143+
)}
144+
</div>
119145
<ColumnSortIcon
120146
sortOrder={sortOrder}
121147
sortable={column.sortable}

src/components/PaginatedTable/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type HandleTableColumnsResize = (columnId: string, width: number) => void
2525

2626
export interface Column<T> {
2727
name: string;
28+
note?: string;
2829
header?: React.ReactNode;
2930
className?: string;
3031
sortable?: boolean;

0 commit comments

Comments
 (0)