Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Navigation/Table): add remount option [YTFRONT-3593] #984

Merged
merged 1 commit into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions packages/ui/src/shared/yt-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@ export type PipelineParams = {
pipeline_path: string;
};

export type TableParams = {
path: string;
};

export type ExpectedVersion = {
expected_version?: string | number;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.remount-alert {
&__button {
width: fit-content;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, {useState} from 'react';
import b from 'bem-cn-lite';
import {useDispatch, useSelector} from 'react-redux';
import {Alert, Button} from '@gravity-ui/uikit';
import ypath from '../../../../../common/thor/ypath';

import {remountTable} from '../../../../../store/actions/navigation/content/table/remount-table';
import {getAttributesWithTypes} from '../../../../../store/selectors/navigation';

import './RemountAlert.scss';

const block = b('remount-alert');

export function RemountAlert() {
const dispatch = useDispatch();
const attributesWithTypes = useSelector(getAttributesWithTypes);
const [pending, setPending] = useState(false);

const handleOnRemount = async () => {
setPending(true);
await dispatch(remountTable());
setPending(false);
};

const [remountNeededTabletCount, tabletCount] = ypath.getValues(attributesWithTypes, [
'/remount_needed_tablet_count',
'/tablet_count',
]);

const showDiffInfo = remountNeededTabletCount !== tabletCount;
const diffInfo = ` (${remountNeededTabletCount} of ${tabletCount} tablets pending)`;

const message = `Table should be remounted to apply new settings${showDiffInfo ? diffInfo : ''}.
This action will not cause any downtime. See Mount config tab for details.`;

return (
<Alert
theme="warning"
layout="horizontal"
title="Some table settings are not applied to tablets"
message={message}
className={block()}
actions={
<Button
onClick={handleOnRemount}
disabled={pending}
className={block('button')}
view="normal-contrast"
size="s"
>
Remount
</Button>
}
></Alert>
);
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
import React, {useMemo} from 'react';
import cn from 'bem-cn-lite';
import {connect, useSelector} from 'react-redux';
import ypath from '../../../../../common/thor/ypath';

import {makeMetaItems} from '../../../../../components/MetaTable/presets/presets';
import CollapsibleSection from '../../../../../components/CollapsibleSection/CollapsibleSection';
import MetaTable from '../../../../../components/MetaTable/MetaTable';
import {RemountAlert} from '../RemountAlert/RemountAlert';

import {getTableType} from '../../../../../store/selectors/navigation/content/table';
import {getIsDynamic} from '../../../../../store/selectors/navigation/content/table-ts';
import {getAttributes} from '../../../../../store/selectors/navigation';
import {getAttributes, getAttributesWithTypes} from '../../../../../store/selectors/navigation';
import {getTabletErrorsBackgroundCount} from '../../../../../store/selectors/navigation/tabs/tablet-errors-background';
import {Props as AutomaticModeSwitchProps} from './AutomaticModeSwitch';

import {RootState} from '../../../../../store/reducers';
import {getCluster} from '../../../../../store/selectors/global';

import './TableMeta.scss';
import {RootState} from '../../../../../store/reducers';
import {UI_COLLAPSIBLE_SIZE} from '../../../../../constants/global';

import './TableMeta.scss';

const block = cn('navigation-meta-table');

interface Props {
attributes: any;
mediumList: string[];
isDynamic: boolean;
tableType: string;
remountNeeded: boolean;
onEditEnableReplicatedTableTracker: AutomaticModeSwitchProps['onEdit'];
}

Expand All @@ -33,6 +37,7 @@ function TableMeta({
tableType,
mediumList,
isDynamic,
remountNeeded,
onEditEnableReplicatedTableTracker,
}: Props) {
const tabletErrorCount = useSelector(getTabletErrorsBackgroundCount);
Expand Down Expand Up @@ -61,6 +66,7 @@ function TableMeta({
return (
<CollapsibleSection name="Metadata" size={UI_COLLAPSIBLE_SIZE}>
<MetaTable className={block()} items={items} />
{remountNeeded && <RemountAlert />}
</CollapsibleSection>
);
}
Expand All @@ -71,12 +77,18 @@ const mapStateToProps = (state: RootState) => {
const isDynamic = getIsDynamic(state);
const tableType = getTableType(state);
const attributes = getAttributes(state);
const attributesWithTypes = getAttributesWithTypes(state);

const remountNeeded =
Boolean(Number(ypath.getValue(attributesWithTypes, '/remount_needed_tablet_count'))) &&
isDynamic;

return {
attributes,
mediumList,
isDynamic,
tableType,
remountNeeded,
};
};

Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/ui/rum/rum-wrap-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
OutputFormat,
PathParams,
PipelineParams,
TableParams,
} from '../../shared/yt-types';
import {YTApiId} from '../../shared/constants/yt-api-id';

Expand Down Expand Up @@ -106,6 +107,8 @@ type YTApiV4 = {
getFlowView(...args: ApiMethodParameters<PipelineParams>): Promise<GetFlowViewData>;
listJobs(...args: ApiMethodParameters<ListJobsParameters>): Promise<ListJobsResponse>;

remountTable(...args: ApiMethodParameters<TableParams>): Promise<void>;

[method: string]: (...args: ApiMethodParameters<any>) => Promise<any>;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {ThunkAction} from 'redux-thunk';
import {UnknownAction} from '@reduxjs/toolkit';

import {RootState} from '../../../../reducers';
import {updateView} from '../..';

import {wrapApiPromiseByToaster} from '../../../../../utils/utils';
import {ytApiV4} from '../../../../../rum/rum-wrap-api';

type AsyncAction<R = void> = ThunkAction<R, RootState, unknown, UnknownAction>;

export function remountTable(): AsyncAction<Promise<void>> {
return async (dispatch, getState) => {
const state = getState();
const path = state.navigation.navigation.path;

return wrapApiPromiseByToaster(ytApiV4.remountTable({path}), {
toasterName: 'remount_tabe',
errorTitle: 'Failed to remount table',
skipSuccessToast: true,
}).finally(() => {
dispatch(updateView());
});
};
}
2 changes: 2 additions & 0 deletions packages/ui/src/ui/store/actions/navigation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ const attributesToLoad = [
'effective_expiration',
'replicated_table_options',
'replica_path',
'remount_needed_tablet_count',
'erasure_codec',
'id',
'in_memory_mode',
Expand Down Expand Up @@ -335,6 +336,7 @@ const attributesToLoad = [
'start_time',
'state',
'tablet_cell_bundle',
'tablet_count',
'tablet_error_count',
'tablet_state',
'target_path',
Expand Down
1 change: 1 addition & 0 deletions packages/ui/tests/init-cluster-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function createAndMountDynamicTable {
schema=$2
yt create -i --attributes "{dynamic=%true;schema=$schema}" table $path
yt mount-table $path
yt set $path/@mount_config/temp 1
}

# userColumnPresets
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/tests/screenshots/pages/navigation/TablePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import {replaceInnerHtml} from '../../../utils/dom';
import type {Locator} from '@playwright/test';

export class TablePage extends NavigationPage {
async waitForTablContent(selector: string, rowCount: number) {
async waitForTableContent(selector: string, rowCount: number) {
await this.waitForTable(selector, rowCount);
await this.page.waitForSelector(':text("Data weight")');
await this.waitForTableSyncedWidth(selector);
}

async replaceStaticTableMeta() {
async replaceTableMeta() {
await this.replaceBreadcrumbsTestDir();
await replaceInnerHtml(this.page, {
'[data-qa="expiration_timeout_path"]': 'e2e.1970-01-01.00:00:00.xxxxxxxxxxx',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ function tablePage(page: Page) {
test('Navigation: table - Content', async ({page}) => {
await page.goto(makeClusterUrl(`navigation?path=${E2E_DIR}/static-table`));

await tablePage(page).waitForTablContent('.navigation-table', 10);
await tablePage(page).replaceStaticTableMeta();
await tablePage(page).waitForTableContent('.navigation-table', 10);
await tablePage(page).replaceTableMeta();

await expect(page).toHaveScreenshot();

Expand Down Expand Up @@ -63,6 +63,29 @@ test('Navigation: table - Schema', async ({page}) => {
await expect(page).toHaveScreenshot();
});

test('Navigation: table - Remount needed', async ({page}) => {
await page.goto(makeClusterUrl(`navigation?path=${E2E_DIR}/dynamic-table`));

page.locator('.data-table_theme_yt-internal').waitFor();

await tablePage(page).replaceBreadcrumbsTestDir();
await tablePage(page).replaceTableMeta();

await test.step('Remount alert visible', async () => {
await expect(page).toHaveScreenshot();
});
await test.step('Page after remount', async () => {
await page.locator('.remount-alert__button').click();

await expect(page.locator('.remount-alert')).toBeHidden();

await tablePage(page).replaceBreadcrumbsTestDir();
await tablePage(page).replaceTableMeta();

await expect(page).toHaveScreenshot();
});
});

test('Navigation: table - Tablets', async ({page}) => {
await page.goto(makeClusterUrl(`navigation?path=${E2E_DIR}/dynamic-table&navmode=tablets`));

Expand All @@ -81,8 +104,8 @@ test('Navigation: table - Tablets', async ({page}) => {
test('Navigation: static-table - rowselector', async ({page}) => {
await page.goto(makeClusterUrl(`navigation?path=${E2E_DIR}/static-table`));

await tablePage(page).replaceStaticTableMeta();
await tablePage(page).waitForTablContent('.navigation-table', 10);
await tablePage(page).replaceTableMeta();
await tablePage(page).waitForTableContent('.navigation-table', 10);

await page.click('.navigation-table-overview__input', {force: true});
const slider = await page.waitForSelector('.rc-slider-handle');
Expand All @@ -108,8 +131,8 @@ test('Navigation: table - userColumnPresets', async ({page, context}) => {

await page.goto(makeClusterUrl(`navigation?path=${E2E_DIR}/static-table`));

await tablePage(page).waitForTablContent('.navigation-table', 10);
await tablePage(page).replaceStaticTableMeta();
await tablePage(page).waitForTableContent('.navigation-table', 10);
await tablePage(page).replaceTableMeta();

await test.step('select only the "key" column', async () => {
await page.getByTestId('table-columns-button').click();
Expand Down Expand Up @@ -138,8 +161,8 @@ test('Navigation: table - userColumnPresets', async ({page, context}) => {

await context.waitForEvent('page', {
predicate: async (page) => {
await tablePage(page).waitForTablContent('.navigation-table', 10);
await tablePage(page).replaceStaticTableMeta();
await tablePage(page).waitForTableContent('.navigation-table', 10);
await tablePage(page).replaceTableMeta();

await page.getByText('key0').waitFor();

Expand All @@ -154,8 +177,8 @@ test('Navigation: table - userColumnPresets', async ({page, context}) => {
test('Navigation: yql-v3-types', async ({page}) => {
await page.goto(makeClusterUrl(`navigation?path=${E2E_DIR}/tmp/yql-v3-types-table`));

await tablePage(page).replaceStaticTableMeta();
await tablePage(page).waitForTablContent('.navigation-table', 5);
await tablePage(page).replaceTableMeta();
await tablePage(page).waitForTableContent('.navigation-table', 5);

await test.step('yql-v3-types enabled', async () => {
await expect(page).toHaveScreenshot();
Expand All @@ -170,7 +193,7 @@ test('Navigation: yql-v3-types', async ({page}) => {

await test.step('yql-v3-types disabled', async () => {
await tablePage(page).waitForHidden('.data-table__row .yql_datetime64');
await tablePage(page).waitForTablContent('.navigation-table', 5);
await tablePage(page).waitForTableContent('.navigation-table', 5);
await expect(page).toHaveScreenshot();
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ test('Navigation: truncated table - Content', async ({page}) => {
waitUntil: 'networkidle',
});

await tablePage.waitForTablContent('.navigation-table', 1);
await tablePage.replaceStaticTableMeta();
await tablePage.waitForTableContent('.navigation-table', 1);
await tablePage.replaceTableMeta();

await tablePage.resizePageForScreenshot();

Expand Down
Loading