Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions src/containers/Cluster/Cluster.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,6 @@
top: 40px;
}

&__tablets {
.data-table__sticky_moving {
// Place table head right after controls
top: 40px !important;
}
}

.ydb-table-with-controls-layout {
--data-table-sticky-top-offset: 102px;
}
Expand Down
8 changes: 1 addition & 7 deletions src/containers/Cluster/Cluster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,7 @@ export function Cluster({
getLocationObjectFromHref(getClusterPath(clusterTabsIds.tablets)).pathname
}
>
<div className={b('tablets')}>
<TabletsTable
loading={infoLoading}
tablets={clusterTablets}
className={b('tablets-table')}
/>
</div>
<TabletsTable loading={infoLoading} tablets={clusterTablets} />
</Route>
<Route
path={
Expand Down
2 changes: 1 addition & 1 deletion src/containers/Node/Node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import type {PreparedNode} from '../../store/reducers/node/types';
import {cn} from '../../utils/cn';
import {useAutoRefreshInterval, useTypedDispatch} from '../../utils/hooks';
import {PaginatedStorage} from '../Storage/PaginatedStorage';
import {Tablets} from '../Tablets';
import {Tablets} from '../Tablets/Tablets';

import type {NodeTab} from './NodePages';
import {NODE_TABS, getDefaultNodePath, nodePageQueryParams, nodePageTabSchema} from './NodePages';
Expand Down
25 changes: 6 additions & 19 deletions src/containers/Tablets/Tablets.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,35 @@
import {skipToken} from '@reduxjs/toolkit/query';

import {ResponseError} from '../../components/Errors/ResponseError';
import {selectTabletsWithFqdn, tabletsApi} from '../../store/reducers/tablets';
import type {TabletsApiRequestParams} from '../../types/store/tablets';
import {cn} from '../../utils/cn';
import {valueIsDefined} from '../../utils';
import {useAutoRefreshInterval, useTypedSelector} from '../../utils/hooks';

import {TabletsTable} from './TabletsTable';

const b = cn('tablets');

interface TabletsProps {
path?: string;
database?: string;
nodeId?: string | number;
className?: string;
}

export function Tablets({nodeId, path, database, className}: TabletsProps) {
export function Tablets({nodeId, path, database}: TabletsProps) {
const [autoRefreshInterval] = useAutoRefreshInterval();

let params: TabletsApiRequestParams = {};
const node = nodeId === undefined ? undefined : String(nodeId);
if (node !== undefined) {
params = {nodeId: node, database};
if (valueIsDefined(nodeId)) {
params = {nodeId, database};
} else if (path) {
params = {path, database};
}
const {currentData, isFetching, error} = tabletsApi.useGetTabletsInfoQuery(
const {isLoading, error} = tabletsApi.useGetTabletsInfoQuery(
Object.keys(params).length === 0 ? skipToken : params,
{
pollingInterval: autoRefreshInterval,
},
);

const loading = isFetching && currentData === undefined;
const tablets = useTypedSelector((state) => selectTabletsWithFqdn(state, params));

return (
<div className={b(null, className)}>
{error ? <ResponseError error={error} /> : null}
{currentData || loading ? (
<TabletsTable tablets={tablets} database={database} loading={loading} />
) : null}
</div>
);
return <TabletsTable tablets={tablets} database={database} loading={isLoading} error={error} />;
}
55 changes: 43 additions & 12 deletions src/containers/Tablets/TabletsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import React from 'react';

import {ArrowRotateLeft} from '@gravity-ui/icons';
import type {Column as DataTableColumn} from '@gravity-ui/react-data-table';
import {Icon, Text} from '@gravity-ui/uikit';
import {StringParam, useQueryParams} from 'use-query-params';

import {ButtonWithConfirmDialog} from '../../components/ButtonWithConfirmDialog/ButtonWithConfirmDialog';
import {EntityStatus} from '../../components/EntityStatus/EntityStatus';
import {ResponseError} from '../../components/Errors/ResponseError';
import {InternalLink} from '../../components/InternalLink';
import {ResizeableDataTable} from '../../components/ResizeableDataTable/ResizeableDataTable';
import {TableSkeleton} from '../../components/TableSkeleton/TableSkeleton';
import {Search} from '../../components/Search/Search';
import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout';
import {TabletNameWrapper} from '../../components/TabletNameWrapper/TabletNameWrapper';
import {TabletState} from '../../components/TabletState/TabletState';
import {TabletUptime} from '../../components/UptimeViewer/UptimeViewer';
Expand Down Expand Up @@ -156,19 +161,45 @@ interface TabletsTableProps {
})[];
className?: string;
loading?: boolean;
error?: unknown;
}

export function TabletsTable({database, tablets, className, loading}: TabletsTableProps) {
if (loading) {
return <TableSkeleton />;
}
export function TabletsTable({database, tablets, loading, error}: TabletsTableProps) {
const [{tabletsSearch}, setQueryParams] = useQueryParams({
tabletsSearch: StringParam,
});

const columns = React.useMemo(() => getColumns({database}), [database]);

const data = React.useMemo(() => {
return tablets.filter((tablet) => {
return String(tablet.TabletId).includes(tabletsSearch ?? '');
});
}, [tablets, tabletsSearch]);

const handleSearchQueryChange = (value: string) => {
setQueryParams({tabletsSearch: value || undefined}, 'replaceIn');
};

return (
<ResizeableDataTable
wrapperClassName={className}
columns={getColumns({database})}
data={tablets}
settings={DEFAULT_TABLE_SETTINGS}
emptyDataMessage={i18n('noTabletsData')}
/>
<TableWithControlsLayout>
<TableWithControlsLayout.Controls>
<Search
placeholder={i18n('controls.search-placeholder')}
onChange={handleSearchQueryChange}
value={tabletsSearch ?? ''}
width={190}
/>
</TableWithControlsLayout.Controls>
{error ? <ResponseError error={error} /> : null}
<TableWithControlsLayout.Table loading={loading}>
<ResizeableDataTable
columns={columns}
data={data}
settings={DEFAULT_TABLE_SETTINGS}
emptyDataMessage={i18n('noTabletsData')}
/>
</TableWithControlsLayout.Table>
</TableWithControlsLayout>
);
}
3 changes: 2 additions & 1 deletion src/containers/Tablets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"Uptime": "Uptime",
"dialog.kill-header": "Restart tablet",
"dialog.kill-text": "The tablet will be restarted. Do you want to proceed?",
"controls.kill-not-allowed": "You don't have enough rights to restart tablet"
"controls.kill-not-allowed": "You don't have enough rights to restart tablet",
"controls.search-placeholder": "Tablet ID"
}
1 change: 0 additions & 1 deletion src/containers/Tablets/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/containers/Tenant/Diagnostics/Diagnostics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {Heatmap} from '../../Heatmap';
import {Nodes} from '../../Nodes/Nodes';
import {Operations} from '../../Operations';
import {PaginatedStorage} from '../../Storage/PaginatedStorage';
import {Tablets} from '../../Tablets';
import {Tablets} from '../../Tablets/Tablets';
import {SchemaViewer} from '../Schema/SchemaViewer/SchemaViewer';
import {TenantTabsGroups, getTenantPath} from '../TenantPages';
import {isDatabaseEntityType} from '../utils/schema';
Expand Down
Loading