Skip to content

Commit

Permalink
feat: add top nodes by memory table
Browse files Browse the repository at this point in the history
  • Loading branch information
krosy1337 committed Oct 19, 2023
1 parent 3048f84 commit 523c92f
Show file tree
Hide file tree
Showing 12 changed files with 258 additions and 16 deletions.
43 changes: 42 additions & 1 deletion src/containers/Nodes/getNodesColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import {PoolsGraph} from '../../components/PoolsGraph/PoolsGraph';
import {ProgressViewer} from '../../components/ProgressViewer/ProgressViewer';
import {TabletsStatistic} from '../../components/TabletsStatistic';
import {NodeHostWrapper} from '../../components/NodeHostWrapper/NodeHostWrapper';
import {formatBytesToGigabyte} from '../../utils/dataFormatters/dataFormatters';
import {
formatBytesToGigabyte,
formatStorageValuesToGb,
} from '../../utils/dataFormatters/dataFormatters';
import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
import type {GetNodeRefFunc} from '../../types/additionalProps';
import {getLoadSeverityForNode} from '../../store/reducers/tenantOverview/topNodesByLoad/utils';
Expand All @@ -23,6 +26,7 @@ const NODES_COLUMNS_IDS = {
LoadAverage: 'LoadAverage',
Tablets: 'Tablets',
TopNodesLoadAverage: 'TopNodesLoadAverage',
TopNodesMemory: 'TopNodesMemory',
};

interface GetNodesColumnsProps {
Expand Down Expand Up @@ -83,6 +87,7 @@ const uptimeColumn: Column<NodesPreparedEntity> = {
sortAccessor: ({StartTime}) => StartTime && -StartTime,
align: DataTable.RIGHT,
width: '110px',
sortable: false,
};

const memoryColumn: Column<NodesPreparedEntity> = {
Expand Down Expand Up @@ -149,6 +154,7 @@ const getTabletsColumn = (tabletsPath?: string): Column<NodesPreparedEntity> =>
);
},
align: DataTable.LEFT,
sortable: false,
});

const topNodesLoadAverageColumn: Column<NodesPreparedEntity> = {
Expand All @@ -168,6 +174,27 @@ const topNodesLoadAverageColumn: Column<NodesPreparedEntity> = {
sortable: false,
};

const topNodesMemoryColumn: Column<NodesPreparedEntity> = {
name: NODES_COLUMNS_IDS.TopNodesMemory,
header: 'Memory',
render: ({row}) =>
row.MemoryUsed ? (
<>
<ProgressViewer
value={row.MemoryUsed}
capacity={row.MemoryLimit}
formatValues={formatStorageValuesToGb}
colorizeProgress={true}
/>
</>
) : (
'—'
),
align: DataTable.LEFT,
width: 140,
sortable: false,
};

export function getNodesColumns({
tabletsPath,
getNodeRef,
Expand Down Expand Up @@ -197,3 +224,17 @@ export function getTopNodesByCpuColumns(
): Column<NodesPreparedEntity>[] {
return [cpuColumn, nodeIdColumn, getHostColumn(getNodeRef)];
}

export function getTopNodesByMemoryColumns({
tabletsPath,
getNodeRef,
}: GetNodesColumnsProps): Column<NodesPreparedEntity>[] {
return [
nodeIdColumn,
getHostColumn(getNodeRef, true),
uptimeColumn,
topNodesMemoryColumn,
topNodesLoadAverageColumn,
getTabletsColumn(tabletsPath),
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
flex-direction: column;

min-width: 300px;
height: max-content;
}

&__modal {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {TopNodesByMemory} from './TopNodesByMemory';

interface TenantMemoryProps {
path: string;
}

export function TenantMemory({path}: TenantMemoryProps) {
return <TopNodesByMemory path={path} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {useDispatch} from 'react-redux';
import {useCallback} from 'react';

import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
import {
getTopNodesByMemory,
selectTopNodesByMemory,
setDataWasNotLoaded,
} from '../../../../../store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory';
import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
import {getTopNodesByMemoryColumns} from '../../../../Nodes/getNodesColumns';
import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';

import i18n from '../i18n';

interface TopNodesByMemoryProps {
path: string;
additionalNodesProps?: AdditionalNodesProps;
}

export function TopNodesByMemory({path, additionalNodesProps}: TopNodesByMemoryProps) {
const dispatch = useDispatch();

const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByMemory);
const {autorefresh} = useTypedSelector((state) => state.schema);
const topNodes = useTypedSelector(selectTopNodesByMemory);
const columns = getTopNodesByMemoryColumns({
getNodeRef: additionalNodesProps?.getNodeRef,
});

const fetchNodes = useCallback(
(isBackground) => {
if (!isBackground) {
dispatch(setDataWasNotLoaded());
}

dispatch(getTopNodesByMemory({tenant: path}));
},
[dispatch, path],
);

useAutofetcher(fetchNodes, [fetchNodes], autorefresh);

return (
<TenantOverviewTableLayout
data={topNodes || []}
columns={columns}
title="Top nodes by memory"
loading={loading}
wasLoaded={wasLoaded}
error={error}
emptyDataMessage={i18n('top-nodes.empty-data')}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
@import '../../../../styles/mixins.scss';

.tenant-overview {
overflow: auto;

height: 100%;
padding-bottom: 20px;

&__loader {
Expand Down Expand Up @@ -81,6 +84,13 @@
line-height: var(--yc-text-body-2-line-height);
}

&__info {
position: sticky;
left: 0;

width: max-content;
}

&__title {
margin-bottom: 10px;

Expand Down
30 changes: 16 additions & 14 deletions src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import {TenantCpu} from './TenantCpu/TenantCpu';
import {HealthcheckDetails} from './Healthcheck/HealthcheckDetails';
import {MetricsCards, type TenantMetrics} from './MetricsCards/MetricsCards';
import {TenantStorage} from './TenantStorage/TenantStorage';
import {TenantMemory} from './TenantMemory/TenantMemory';
import {useHealthcheck} from './useHealthcheck';

import i18n from './i18n';
import './TenantOverview.scss';

const b = cn('tenant-overview');
Expand Down Expand Up @@ -127,7 +127,7 @@ export function TenantOverview({
return <TenantStorage tenantName={tenantName} metrics={storageMetrics} />;
}
case TENANT_METRICS_TABS_IDS.memory: {
return i18n('label.under-development');
return <TenantMemory path={tenantName} />;
}
case TENANT_METRICS_TABS_IDS.healthcheck: {
return <HealthcheckDetails issueTrees={issueTrees} error={healthcheckError} />;
Expand All @@ -148,19 +148,21 @@ export function TenantOverview({

return (
<div className={b()}>
<div className={b('top-label')}>{tenantType}</div>
<div className={b('top')}>
{renderName()}
{additionalTenantProps?.getMonitoringLink?.(Name, Type)}
<div className={b('info')}>
<div className={b('top-label')}>{tenantType}</div>
<div className={b('top')}>
{renderName()}
{additionalTenantProps?.getMonitoringLink?.(Name, Type)}
</div>
<MetricsCards
metrics={calculatedMetrics}
issuesStatistics={issuesStatistics}
selfCheckResult={selfCheckResult}
fetchHealthcheck={fetchHealthcheck}
healthcheckLoading={healthcheckLoading}
healthcheckError={healthcheckError}
/>
</div>
<MetricsCards
metrics={calculatedMetrics}
issuesStatistics={issuesStatistics}
selfCheckResult={selfCheckResult}
fetchHealthcheck={fetchHealthcheck}
healthcheckLoading={healthcheckLoading}
healthcheckError={healthcheckError}
/>
{renderTabContent()}
</div>
);
Expand Down
2 changes: 2 additions & 0 deletions src/store/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {combineReducers} from 'redux';
import nodes from './nodes/nodes';
import {topNodesByLoad} from './tenantOverview/topNodesByLoad/topNodesByLoad';
import {topNodesByCpu} from './tenantOverview/topNodesByCpu/topNodesByCpu';
import {topNodesByMemory} from './tenantOverview/topNodesByMemory/topNodesByMemory';
import cluster from './cluster/cluster';
import clusterNodes from './clusterNodes/clusterNodes';
import tenant from './tenant/tenant';
Expand Down Expand Up @@ -47,6 +48,7 @@ export const rootReducer = {
nodes,
topNodesByLoad,
topNodesByCpu,
topNodesByMemory,
cluster,
clusterNodes,
tenant,
Expand Down
1 change: 1 addition & 0 deletions src/store/reducers/nodes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface NodesPreparedEntity {
StartTime?: string;
Uptime: string;
MemoryUsed?: string;
MemoryLimit?: string;
PoolStats?: TPoolStats[];
LoadAverage?: number[];
Tablets?: TFullTabletStateInfo[] | TComputeTabletStateInfo[];
Expand Down
3 changes: 3 additions & 0 deletions src/store/reducers/nodes/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {TComputeInfo, TComputeNodeInfo, TComputeTenantInfo} from '../../../types/api/compute';
import type {TNodesInfo} from '../../../types/api/nodes';
import {calcUptime} from '../../../utils/dataFormatters/dataFormatters';
import {generateEvaluator} from '../../../utils/generateEvaluator';

import type {NodesHandledResponse, NodesPreparedEntity} from './types';

Expand Down Expand Up @@ -64,3 +65,5 @@ export const prepareNodesData = (data: TNodesInfo): NodesHandledResponse => {
FoundNodes: Number(data.FoundNodes),
};
};

export const getLoadSeverityForNode = generateEvaluator(60, 80, ['success', 'warning', 'danger']);
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import type {Reducer} from 'redux';

import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants';
import {createApiRequest, createRequestActionTypes} from '../../../utils';
import {prepareNodesData} from '../../nodes/utils';
import type {NodesApiRequestParams} from '../../nodes/types';
import type {TopNodesByMemoryAction, TopNodesByMemoryState, TopNodesByMemorySlice} from './types';

export const FETCH_TOP_NODES_BY_MEMORY = createRequestActionTypes(
'topNodesByMemory',
'FETCH_TOP_NODES_BY_MEMORY',
);
const SET_DATA_WAS_NOT_LOADED = 'topNodesByMemory/SET_DATA_WAS_NOT_LOADED';

const initialState = {
loading: false,
wasLoaded: false,
};

export const topNodesByMemory: Reducer<TopNodesByMemoryState, TopNodesByMemoryAction> = (
state = initialState,
action,
) => {
switch (action.type) {
case FETCH_TOP_NODES_BY_MEMORY.REQUEST: {
return {
...state,
loading: true,
};
}
case FETCH_TOP_NODES_BY_MEMORY.SUCCESS: {
return {
...state,
data: action.data?.Nodes,
loading: false,
wasLoaded: true,
error: undefined,
};
}
case FETCH_TOP_NODES_BY_MEMORY.FAILURE: {
if (action.error?.isCancelled) {
return state;
}

return {
...state,
error: action.error,
loading: false,
};
}
case SET_DATA_WAS_NOT_LOADED: {
return {
...state,
wasLoaded: false,
};
}
default:
return state;
}
};

const concurrentId = 'getTopNodeByMemory';

export function getTopNodesByMemory({
type = 'any',
sortOrder = -1,
sortValue = 'Memory',
limit = TENANT_OVERVIEW_TABLES_LIMIT,
...params
}: NodesApiRequestParams) {
return createApiRequest({
request: window.api.getNodes(
{type, sortOrder, sortValue, limit, ...params},
{concurrentId},
),
actions: FETCH_TOP_NODES_BY_MEMORY,
dataHandler: prepareNodesData,
});
}

export const selectTopNodesByMemory = (state: TopNodesByMemorySlice) => state.topNodesByMemory.data;

export const setDataWasNotLoaded = () => {
return {
type: SET_DATA_WAS_NOT_LOADED,
} as const;
};
29 changes: 29 additions & 0 deletions src/store/reducers/tenantOverview/topNodesByMemory/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type {IResponseError} from '../../../../types/api/error';
import type {ApiRequestAction} from '../../../utils';
import type {NodesPreparedEntity} from '../../nodes/types';
import {FETCH_TOP_NODES_BY_MEMORY, setDataWasNotLoaded} from './topNodesByMemory';

export interface TopNodesByMemoryState {
loading: boolean;
wasLoaded: boolean;
data?: NodesPreparedEntity[];
error?: IResponseError;
}

export interface TopNodesByMemoryHandledResponse {
Nodes?: NodesPreparedEntity[];
}

type TopNodesByMemoryApiRequestAction = ApiRequestAction<
typeof FETCH_TOP_NODES_BY_MEMORY,
TopNodesByMemoryHandledResponse,
IResponseError
>;

export type TopNodesByMemoryAction =
| TopNodesByMemoryApiRequestAction
| ReturnType<typeof setDataWasNotLoaded>;

export interface TopNodesByMemorySlice {
topNodesByMemory: TopNodesByMemoryState;
}
Loading

0 comments on commit 523c92f

Please sign in to comment.