Skip to content

Commit

Permalink
feat(Storage,Nodes): request only needed fields
Browse files Browse the repository at this point in the history
  • Loading branch information
artemmufazalov committed Oct 18, 2024
1 parent a36d40c commit d017661
Show file tree
Hide file tree
Showing 32 changed files with 281 additions and 133 deletions.
19 changes: 11 additions & 8 deletions src/components/PaginatedTable/PaginatedTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ import {useScrollBasedChunks} from './useScrollBasedChunks';

import './PaginatedTable.scss';

export interface PaginatedTableProps<T, F> {
export interface PaginatedTableProps<EntityType, Filters, DataFieldType> {
limit: number;
initialEntitiesCount?: number;
fetchData: FetchData<T, F>;
filters?: F;
fetchData: FetchData<EntityType, Filters, DataFieldType>;
filters?: Filters;
dataFieldsRequired?: DataFieldType[];
tableName: string;
columns: Column<T>[];
getRowClassName?: GetRowClassName<T>;
columns: Column<EntityType>[];
getRowClassName?: GetRowClassName<EntityType>;
rowHeight?: number;
parentRef?: React.RefObject<HTMLElement>;
initialSortParams?: SortParams;
Expand All @@ -41,11 +42,12 @@ export interface PaginatedTableProps<T, F> {
containerClassName?: string;
}

export const PaginatedTable = <T, F>({
export const PaginatedTable = <EntityType, Filters, DataFieldType>({
limit,
initialEntitiesCount,
fetchData,
filters,
dataFieldsRequired,
tableName,
columns,
getRowClassName,
Expand All @@ -57,7 +59,7 @@ export const PaginatedTable = <T, F>({
renderErrorMessage,
renderEmptyDataMessage,
containerClassName,
}: PaginatedTableProps<T, F>) => {
}: PaginatedTableProps<EntityType, Filters, DataFieldType>) => {
const initialTotal = initialEntitiesCount || limit;
const initialFound = initialEntitiesCount || 0;

Expand Down Expand Up @@ -108,7 +110,7 @@ export const PaginatedTable = <T, F>({
const chunksCount = Math.ceil(totalLength / limit);

return getArray(chunksCount).map((value) => (
<TableChunk<T, F>
<TableChunk<EntityType, Filters, DataFieldType>
key={value}
id={value}
limit={limit}
Expand All @@ -117,6 +119,7 @@ export const PaginatedTable = <T, F>({
columns={columns}
fetchData={fetchData}
filters={filters}
dataFieldsRequired={dataFieldsRequired}
tableName={tableName}
sortParams={sortParams}
getRowClassName={getRowClassName}
Expand Down
13 changes: 8 additions & 5 deletions src/components/PaginatedTable/ResizeablePaginatedTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,25 @@ import {PaginatedTable} from './PaginatedTable';
import {b} from './shared';
import type {Column} from './types';

function updateColumnsWidth<T>(columns: Column<T>[], columnsWidthSetup: ColumnWidthByName) {
function updateColumnsWidth<EntityType>(
columns: Column<EntityType>[],
columnsWidthSetup: ColumnWidthByName,
) {
return columns.map((column) => {
return {...column, width: columnsWidthSetup[column.name] ?? column.width};
});
}

interface ResizeablePaginatedTableProps<T, F>
extends Omit<PaginatedTableProps<T, F>, 'onColumnsResize'> {
interface ResizeablePaginatedTableProps<EntityType, Filters, DataFieldType>
extends Omit<PaginatedTableProps<EntityType, Filters, DataFieldType>, 'onColumnsResize'> {
columnsWidthLSKey: string;
}

export function ResizeablePaginatedTable<T, F>({
export function ResizeablePaginatedTable<EntityType, Filters, DataFieldType>({
columnsWidthLSKey,
columns,
...props
}: ResizeablePaginatedTableProps<T, F>) {
}: ResizeablePaginatedTableProps<EntityType, Filters, DataFieldType>) {
const [tableColumnsWidth, setTableColumnsWidth] = useTableResize(columnsWidthLSKey);

const updatedColumns = updateColumnsWidth(columns, tableColumnsWidth);
Expand Down
21 changes: 12 additions & 9 deletions src/components/PaginatedTable/TableChunk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,26 @@ import type {Column, FetchData, GetRowClassName, SortParams} from './types';

const DEBOUNCE_TIMEOUT = 200;

interface TableChunkProps<T, F> {
interface TableChunkProps<EntityType, Filters, DataFieldType> {
id: number;
limit: number;
totalLength: number;
rowHeight: number;
columns: Column<T>[];
filters?: F;
columns: Column<EntityType>[];
filters?: Filters;
dataFieldsRequired?: DataFieldType[];
sortParams?: SortParams;
isActive: boolean;
tableName: string;

fetchData: FetchData<T, F>;
getRowClassName?: GetRowClassName<T>;
fetchData: FetchData<EntityType, Filters, DataFieldType>;
getRowClassName?: GetRowClassName<EntityType>;
renderErrorMessage?: (error: IResponseError) => React.ReactNode;
onDataFetched: (total: number, found: number) => void;
}

// Memoisation prevents chunks rerenders that could cause perfomance issues on big tables
export const TableChunk = <T, F>({
export const TableChunk = <EntityType, Filters, DataFieldType>({
id,
limit,
totalLength,
Expand All @@ -38,20 +39,22 @@ export const TableChunk = <T, F>({
fetchData,
tableName,
filters,
dataFieldsRequired,
sortParams,
getRowClassName,
renderErrorMessage,
onDataFetched,
isActive,
}: TableChunkProps<T, F>) => {
}: TableChunkProps<EntityType, Filters, DataFieldType>) => {
const [isTimeoutActive, setIsTimeoutActive] = React.useState(true);
const [autoRefreshInterval] = useAutoRefreshInterval();

const queryParams = {
offset: id * limit,
limit,
fetchData: fetchData as FetchData<T, unknown>,
fetchData: fetchData as FetchData<EntityType, unknown, unknown>,
filters,
dataFieldsRequired,
sortParams,
tableName,
};
Expand Down Expand Up @@ -123,7 +126,7 @@ export const TableChunk = <T, F>({
<TableRow
key={index}
index={index}
row={rowData as T}
row={rowData as EntityType}
columns={columns}
height={rowHeight}
getRowClassName={getRowClassName}
Expand Down
32 changes: 19 additions & 13 deletions src/components/PaginatedTable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import type {IResponseError} from '../../types/api/error';

import type {ASCENDING, CENTER, DESCENDING, LEFT, RIGHT} from './constants';

export interface Chunk<T> {
export interface Chunk<EntityType> {
active: boolean;
loading: boolean;
wasLoaded: boolean;
data?: T[];
data?: EntityType[];
error?: IResponseError;
}

Expand All @@ -23,36 +23,42 @@ export type OnSort = (params: SortParams) => void;

export type HandleTableColumnsResize = (columnId: string, width: number) => void;

export interface Column<T> {
export interface Column<EntityType> {
name: string;
header?: React.ReactNode;
className?: string;
sortable?: boolean;
resizeable?: boolean;
render: (props: {row: T; index: number}) => React.ReactNode;
render: (props: {row: EntityType; index: number}) => React.ReactNode;
width?: number;
resizeMaxWidth?: number;
resizeMinWidth?: number;
align: AlignType;
}

export interface PaginatedTableData<T> {
data: T[];
export interface PaginatedTableData<EntityType> {
data: EntityType[];
total: number;
found: number;
}

type FetchDataParams<F, E = {}> = {
type FetchDataParams<Filters, DataFieldType = undefined, AdditionalParams = {}> = {
limit: number;
offset: number;
filters?: F;
filters?: Filters;
dataFieldsRequired?: DataFieldType[];
sortParams?: SortParams;
signal?: AbortSignal;
} & E;
} & AdditionalParams;

export type FetchData<T, F = undefined, E = {}> = (
params: FetchDataParams<F, E>,
) => Promise<PaginatedTableData<T>>;
export type FetchData<
EntityType,
Filters = undefined,
DataFieldType = undefined,
AdditionalParams = {},
> = (
params: FetchDataParams<Filters, DataFieldType, AdditionalParams>,
) => Promise<PaginatedTableData<EntityType>>;

export type OnError = (error?: IResponseError) => void;

Expand All @@ -66,4 +72,4 @@ export type RenderControls = (params: ControlsParams) => React.ReactNode;
export type RenderEmptyDataMessage = () => React.ReactNode;
export type RenderErrorMessage = (error: IResponseError) => React.ReactNode;

export type GetRowClassName<T> = (row: T) => string | undefined;
export type GetRowClassName<EntityType> = (row: EntityType) => string | undefined;
3 changes: 2 additions & 1 deletion src/components/nodesColumns/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {valueIsDefined} from '../../utils';
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
import {formatStorageValuesToGb} from '../../utils/dataFormatters/dataFormatters';
import {getSpaceUsageSeverity} from '../../utils/storage';
import type {Column} from '../../utils/tableUtils/types';
import {CellWithPopover} from '../CellWithPopover/CellWithPopover';
import {NodeHostWrapper} from '../NodeHostWrapper/NodeHostWrapper';
import type {NodeHostData} from '../NodeHostWrapper/NodeHostWrapper';
Expand All @@ -16,7 +17,7 @@ import {TabletsStatistic} from '../TabletsStatistic';
import {UsageLabel} from '../UsageLabel/UsageLabel';

import {NODES_COLUMNS_IDS, NODES_COLUMNS_TITLES} from './constants';
import type {Column, GetNodesColumnsParams} from './types';
import type {GetNodesColumnsParams} from './types';

export function getNodeIdColumn<T extends {NodeId?: string | number}>(): Column<T> {
return {
Expand Down
27 changes: 27 additions & 0 deletions src/components/nodesColumns/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type {NodesRequiredField} from '../../types/api/nodes';
import type {ValueOf} from '../../types/common';

import i18n from './i18n';
Expand All @@ -21,6 +22,7 @@ export const NODES_COLUMNS_IDS = {
TotalSessions: 'TotalSessions',
Missing: 'Missing',
Tablets: 'Tablets',
PDisks: 'PDisks',
} as const;

export type NodesColumnId = ValueOf<typeof NODES_COLUMNS_IDS>;
Expand Down Expand Up @@ -76,4 +78,29 @@ export const NODES_COLUMNS_TITLES = {
get Tablets() {
return i18n('tablets');
},
get PDisks() {
return i18n('pdisks');
},
} as const satisfies Record<NodesColumnId, string>;

// Although columns ids mostly similar to backend fields, there might be some difference
// Also for some columns we may use more than one field
export const NODES_COLUMNS_TO_DATA_FIELDS: Record<NodesColumnId, NodesRequiredField[]> = {
NodeId: ['NodeId'],
Host: ['Host', 'Rack', 'Database', 'SystemState'],
NodeName: ['NodeName'],
DC: ['DC'],
Rack: ['Rack'],
Version: ['Version'],
Uptime: ['Uptime'],
Memory: ['Memory'],
CPU: ['CPU'],
LoadAverage: ['LoadAverage'],
Load: ['LoadAverage'],
DiskSpaceUsage: ['DiskSpaceUsage'],
SharedCacheUsage: ['SystemState'],
TotalSessions: ['SystemState'],
Missing: ['Missing'],
Tablets: ['Tablets', 'Database'],
PDisks: ['PDisks'],
};
3 changes: 2 additions & 1 deletion src/components/nodesColumns/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
"load": "Load",
"caches": "Caches",
"sessions": "Sessions",
"missing": "Missing"
"missing": "Missing",
"pdisks": "PDisks"
}
5 changes: 0 additions & 5 deletions src/components/nodesColumns/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import type {Column as DataTableColumn} from '@gravity-ui/react-data-table';

import type {GetNodeRefFunc} from '../../types/additionalProps';
import type {Column as PaginatedTableColumn} from '../PaginatedTable';

export type Column<T> = PaginatedTableColumn<T> & DataTableColumn<T>;

export interface GetNodesColumnsParams {
getNodeRef?: GetNodeRefFunc;
Expand Down
10 changes: 6 additions & 4 deletions src/containers/Nodes/PaginatedNodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ export const PaginatedNodes = ({path, database, parentRef, additionalNodesProps}
return {path, database, searchValue, problemFilter, uptimeFilter};
}, [path, database, searchValue, problemFilter, uptimeFilter]);

const {columnsToShow, columnsToSelect, setColumns} = useNodesSelectedColumns({
getNodeRef: additionalNodesProps?.getNodeRef,
database,
});
const {columnsToShow, columnsToSelect, setColumns, dataFieldsRequired} =
useNodesSelectedColumns({
getNodeRef: additionalNodesProps?.getNodeRef,
database,
});

const getRowClassName: GetRowClassName<NodesPreparedEntity> = (row) => {
return b('node', {unavailable: isUnavailableNode(row)});
Expand Down Expand Up @@ -144,6 +145,7 @@ export const PaginatedNodes = ({path, database, parentRef, additionalNodesProps}
renderEmptyDataMessage={renderEmptyDataMessage}
getRowClassName={getRowClassName}
filters={tableFilters}
dataFieldsRequired={dataFieldsRequired}
tableName="nodes"
/>
);
Expand Down
3 changes: 2 additions & 1 deletion src/containers/Nodes/columns/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import {
getUptimeColumn,
getVersionColumn,
} from '../../../components/nodesColumns/columns';
import type {Column, GetNodesColumnsParams} from '../../../components/nodesColumns/types';
import type {GetNodesColumnsParams} from '../../../components/nodesColumns/types';
import type {NodesPreparedEntity} from '../../../store/reducers/nodes/types';
import {isSortableNodesProperty} from '../../../utils/nodes';
import type {Column} from '../../../utils/tableUtils/types';

export function getNodesColumns(params: GetNodesColumnsParams): Column<NodesPreparedEntity>[] {
const columns = [
Expand Down
19 changes: 17 additions & 2 deletions src/containers/Nodes/columns/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from 'react';

import {NODES_COLUMNS_TITLES} from '../../../components/nodesColumns/constants';
import {
NODES_COLUMNS_TITLES,
NODES_COLUMNS_TO_DATA_FIELDS,
} from '../../../components/nodesColumns/constants';
import type {GetNodesColumnsParams} from '../../../components/nodesColumns/types';
import {useSelectedColumns} from '../../../utils/hooks/useSelectedColumns';
import {getRequiredDataFields} from '../../../utils/tableUtils/getRequiredDataFields';

import {getNodesColumns} from './columns';
import {
Expand All @@ -16,11 +20,22 @@ export function useNodesSelectedColumns(params: GetNodesColumnsParams) {
return getNodesColumns(params);
}, [params]);

return useSelectedColumns(
const {columnsToSelect, columnsToShow, setColumns} = useSelectedColumns(
columns,
NODES_TABLE_SELECTED_COLUMNS_LS_KEY,
NODES_COLUMNS_TITLES,
DEFAULT_NODES_COLUMNS,
REQUIRED_NODES_COLUMNS,
);

const dataFieldsRequired = React.useMemo(() => {
return getRequiredDataFields(columnsToShow, NODES_COLUMNS_TO_DATA_FIELDS);
}, [columnsToShow]);

return {
columnsToSelect,
columnsToShow,
setColumns,
dataFieldsRequired,
};
}
Loading

0 comments on commit d017661

Please sign in to comment.