Skip to content

Commit

Permalink
feat(Navigation/Table): add remount option [YTFRONT-3593]
Browse files Browse the repository at this point in the history
  • Loading branch information
KostyaAvtushko committed Feb 26, 2025
1 parent 1a94c7f commit 68b1964
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 18 deletions.
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 @@ -313,6 +313,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,27 +1,31 @@
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;
attributesWithTypes: any;
mediumList: string[];
isDynamic: boolean;
tableType: string;
Expand All @@ -30,6 +34,7 @@ interface Props {

function TableMeta({
attributes,
attributesWithTypes,
tableType,
mediumList,
isDynamic,
Expand Down Expand Up @@ -58,9 +63,14 @@ function TableMeta({
onEditEnableReplicatedTableTracker,
]);

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

return (
<CollapsibleSection name="Metadata" size={UI_COLLAPSIBLE_SIZE}>
<MetaTable className={block()} items={items} />
{remountNeeded && <RemountAlert />}
</CollapsibleSection>
);
}
Expand All @@ -71,9 +81,11 @@ const mapStateToProps = (state: RootState) => {
const isDynamic = getIsDynamic(state);
const tableType = getTableType(state);
const attributes = getAttributes(state);
const attributesWithTypes = getAttributesWithTypes(state);

return {
attributes,
attributesWithTypes,
mediumList,
isDynamic,
tableType,
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 @@ -15,6 +15,7 @@ import {
OutputFormat,
PathParams,
PipelineParams,
TableParams,
} from '../../shared/yt-types';
import {YTApiId} from '../../shared/constants/yt-api-id';

Expand Down Expand Up @@ -102,6 +103,8 @@ type YTApiV4 = {
getPipelineState(...args: ApiMethodParameters<PipelineParams>): Promise<GetPipelineStateData>;
getFlowView(...args: ApiMethodParameters<PipelineParams>): Promise<GetFlowViewData>;

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,23 @@
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',
}).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

0 comments on commit 68b1964

Please sign in to comment.