mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-11 16:31:57 +00:00
* fix: #19621 Introduce "clear sample" in entity config to have an explicit `null` * added playwright test * added clear button * fixed playwright failure * addressing review comment
This commit is contained in:
parent
1a18c7d7f8
commit
a5eb90f797
@ -505,8 +505,10 @@ test(
|
|||||||
await page.reload();
|
await page.reload();
|
||||||
await page.waitForLoadState('networkidle');
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
await test.step('Update profiler setting', async () => {
|
||||||
await page.click('[data-testid="profiler-setting-btn"]');
|
await page.click('[data-testid="profiler-setting-btn"]');
|
||||||
await page.waitForSelector('.ant-modal-body');
|
await page.waitForSelector('.ant-modal-body');
|
||||||
|
|
||||||
await page.locator('[data-testid="slider-input"]').clear();
|
await page.locator('[data-testid="slider-input"]').clear();
|
||||||
await page
|
await page
|
||||||
.locator('[data-testid="slider-input"]')
|
.locator('[data-testid="slider-input"]')
|
||||||
@ -577,6 +579,63 @@ test(
|
|||||||
sampleDataCount: 100,
|
sampleDataCount: 100,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Reset profile sample type', async () => {
|
||||||
|
await page.click('[data-testid="profiler-setting-btn"]');
|
||||||
|
await page.waitForSelector('.ant-modal-body');
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
page.locator('[data-testid="profile-sample"]')
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await page.getByTestId('clear-slider-input').click();
|
||||||
|
|
||||||
|
await expect(page.locator('[data-testid="slider-input"]')).toBeEmpty();
|
||||||
|
|
||||||
|
const updateTableProfilerConfigResponse = page.waitForResponse(
|
||||||
|
(response) =>
|
||||||
|
response.url().includes('/api/v1/tables/') &&
|
||||||
|
response.url().includes('/tableProfilerConfig') &&
|
||||||
|
response.request().method() === 'PUT'
|
||||||
|
);
|
||||||
|
await page.getByRole('button', { name: 'Save' }).click();
|
||||||
|
const updateResponse = await updateTableProfilerConfigResponse;
|
||||||
|
const requestBody = await updateResponse.request().postData();
|
||||||
|
|
||||||
|
expect(requestBody).toEqual(
|
||||||
|
JSON.stringify({
|
||||||
|
excludeColumns: [table1.entity?.columns[0].name],
|
||||||
|
profileQuery: 'select * from table',
|
||||||
|
profileSample: null,
|
||||||
|
profileSampleType: 'PERCENTAGE',
|
||||||
|
includeColumns: [{ columnName: table1.entity?.columns[1].name }],
|
||||||
|
partitioning: {
|
||||||
|
partitionColumnName: table1.entity?.columns[2].name,
|
||||||
|
partitionIntervalType: 'COLUMN-VALUE',
|
||||||
|
partitionValues: ['test'],
|
||||||
|
enablePartitioning: true,
|
||||||
|
},
|
||||||
|
sampleDataCount: 100,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.waitForSelector('.ant-modal-body', {
|
||||||
|
state: 'detached',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Validate the profiler setting is updated
|
||||||
|
await page.click('[data-testid="profiler-setting-btn"]');
|
||||||
|
await page.waitForSelector('.ant-modal-body');
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
page.locator('[data-testid="profile-sample"]')
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(page.locator('[data-testid="slider-input"]')).toBeEmpty();
|
||||||
|
await expect(
|
||||||
|
page.getByTestId('profile-sample').locator('div')
|
||||||
|
).toBeVisible();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -175,23 +175,22 @@ const ProfilerSettingsModal: React.FC<ProfilerSettingsModalProps> = ({
|
|||||||
sqlQuery: profileQuery ?? '',
|
sqlQuery: profileQuery ?? '',
|
||||||
profileSample: profileSample,
|
profileSample: profileSample,
|
||||||
excludeCol: excludeColumns ?? [],
|
excludeCol: excludeColumns ?? [],
|
||||||
selectedProfileSampleType:
|
selectedProfileSampleType: profileSampleType,
|
||||||
profileSampleType ?? ProfileSampleType.Percentage,
|
|
||||||
sampleDataCount,
|
sampleDataCount,
|
||||||
});
|
});
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
sampleDataCount: sampleDataCount ?? initialState.sampleDataCount,
|
sampleDataCount: sampleDataCount ?? initialState.sampleDataCount,
|
||||||
});
|
});
|
||||||
|
|
||||||
const profileSampleTypeCheck =
|
|
||||||
profileSampleType === ProfileSampleType.Percentage;
|
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
profileSampleType,
|
profileSampleType,
|
||||||
profileSamplePercentage: profileSampleTypeCheck
|
profileSamplePercentage:
|
||||||
? profileSample ?? 100
|
profileSample && profileSampleType === ProfileSampleType.Percentage
|
||||||
: 100,
|
? profileSample
|
||||||
profileSampleRows: !profileSampleTypeCheck
|
: undefined,
|
||||||
? profileSample ?? 100
|
profileSampleRows:
|
||||||
|
profileSample && profileSampleType === ProfileSampleType.Rows
|
||||||
|
? profileSample
|
||||||
: undefined,
|
: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -287,11 +286,14 @@ const ProfilerSettingsModal: React.FC<ProfilerSettingsModalProps> = ({
|
|||||||
const profileConfig: TableProfilerConfig = {
|
const profileConfig: TableProfilerConfig = {
|
||||||
excludeColumns: excludeCol.length > 0 ? excludeCol : undefined,
|
excludeColumns: excludeCol.length > 0 ? excludeCol : undefined,
|
||||||
profileQuery: !isEmpty(sqlQuery) ? sqlQuery : undefined,
|
profileQuery: !isEmpty(sqlQuery) ? sqlQuery : undefined,
|
||||||
profileSample:
|
profileSample: profileSampleType
|
||||||
profileSampleType === ProfileSampleType.Percentage
|
? profileSampleType === ProfileSampleType.Percentage
|
||||||
? profileSamplePercentage
|
? profileSamplePercentage
|
||||||
: profileSampleRows,
|
: profileSampleRows
|
||||||
profileSampleType: profileSampleType,
|
: undefined,
|
||||||
|
profileSampleType: isUndefined(profileSampleType)
|
||||||
|
? null
|
||||||
|
: profileSampleType,
|
||||||
includeColumns: !isEqual(includeCol, DEFAULT_INCLUDE_PROFILE)
|
includeColumns: !isEqual(includeCol, DEFAULT_INCLUDE_PROFILE)
|
||||||
? getIncludesColumns()
|
? getIncludesColumns()
|
||||||
: undefined,
|
: undefined,
|
||||||
@ -461,31 +463,37 @@ const ProfilerSettingsModal: React.FC<ProfilerSettingsModalProps> = ({
|
|||||||
})}
|
})}
|
||||||
name="profileSampleType">
|
name="profileSampleType">
|
||||||
<Select
|
<Select
|
||||||
|
allowClear
|
||||||
autoFocus
|
autoFocus
|
||||||
className="w-full"
|
className="w-full"
|
||||||
data-testid="profile-sample"
|
data-testid="profile-sample"
|
||||||
options={PROFILE_SAMPLE_OPTIONS}
|
options={PROFILE_SAMPLE_OPTIONS}
|
||||||
|
placeholder={t('label.please-select-entity', {
|
||||||
|
entity: t('label.profile-sample-type', {
|
||||||
|
type: '',
|
||||||
|
}),
|
||||||
|
})}
|
||||||
onChange={handleProfileSampleType}
|
onChange={handleProfileSampleType}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{state?.selectedProfileSampleType ===
|
{state?.selectedProfileSampleType ===
|
||||||
ProfileSampleType.Percentage ? (
|
ProfileSampleType.Percentage && (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
className="m-b-0"
|
|
||||||
label={t('label.profile-sample-type', {
|
label={t('label.profile-sample-type', {
|
||||||
type: t('label.value'),
|
type: t('label.value'),
|
||||||
})}
|
})}
|
||||||
name="profileSamplePercentage">
|
name="profileSamplePercentage">
|
||||||
<SliderWithInput
|
<SliderWithInput
|
||||||
className="p-x-xs"
|
className="p-x-xs"
|
||||||
value={state?.profileSample || 0}
|
value={state?.profileSample}
|
||||||
onChange={handleProfileSample}
|
onChange={handleProfileSample}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
) : (
|
)}
|
||||||
|
|
||||||
|
{state?.selectedProfileSampleType === ProfileSampleType.Rows && (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
className="m-b-0"
|
|
||||||
label={t('label.profile-sample-type', {
|
label={t('label.profile-sample-type', {
|
||||||
type: t('label.value'),
|
type: t('label.value'),
|
||||||
})}
|
})}
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export interface SliderWithInputProps {
|
export interface SliderWithInputProps {
|
||||||
value: number;
|
value?: number;
|
||||||
onChange: (value: number | null) => void;
|
onChange: (value: number | null) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,20 +11,22 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Col, InputNumber, Row, Slider } from 'antd';
|
import { CloseOutlined } from '@ant-design/icons';
|
||||||
import React, { useCallback } from 'react';
|
import { Button, Col, InputNumber, Row, Slider, Tooltip } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { percentageFormatter } from '../../../utils/ChartUtils';
|
||||||
import { SliderWithInputProps } from './SliderWithInput.interface';
|
import { SliderWithInputProps } from './SliderWithInput.interface';
|
||||||
|
|
||||||
const SliderWithInput = ({
|
const SliderWithInput = ({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
className,
|
className,
|
||||||
}: SliderWithInputProps) => {
|
}: SliderWithInputProps) => {
|
||||||
const formatter = useCallback((value) => `${value}%`, [value]);
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row className={className} data-testid="percentage-input" gutter={20}>
|
<Row className={className} data-testid="percentage-input" gutter={20}>
|
||||||
<Col span={20}>
|
<Col flex="auto">
|
||||||
<Slider
|
<Slider
|
||||||
marks={{
|
marks={{
|
||||||
0: '0%',
|
0: '0%',
|
||||||
@ -37,16 +39,27 @@ const SliderWithInput = ({
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
<Col className="w-32">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
<InputNumber
|
<InputNumber
|
||||||
data-testid="slider-input"
|
data-testid="slider-input"
|
||||||
formatter={formatter}
|
formatter={percentageFormatter}
|
||||||
max={100}
|
max={100}
|
||||||
min={0}
|
min={0}
|
||||||
step={1}
|
step={1}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
|
<Tooltip title={t('label.clear')}>
|
||||||
|
<Button
|
||||||
|
className="p-0"
|
||||||
|
data-testid="clear-slider-input"
|
||||||
|
type="text"
|
||||||
|
onClick={() => onChange(null)}>
|
||||||
|
<CloseOutlined />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { percentageFormatter } from './ChartUtils';
|
||||||
|
|
||||||
|
describe('ChartUtils', () => {
|
||||||
|
describe('percentageFormatter', () => {
|
||||||
|
it('should format number with percentage symbol', () => {
|
||||||
|
expect(percentageFormatter(50)).toBe('50%');
|
||||||
|
expect(percentageFormatter(100)).toBe('100%');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle decimal numbers', () => {
|
||||||
|
expect(percentageFormatter(50.5)).toBe('50.5%');
|
||||||
|
expect(percentageFormatter(33.33)).toBe('33.33%');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return empty string for undefined value', () => {
|
||||||
|
expect(percentageFormatter(undefined)).toBe('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -42,3 +42,7 @@ export const updateActiveChartFilter = (
|
|||||||
|
|
||||||
return updatedData;
|
return updatedData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const percentageFormatter = (value?: number) => {
|
||||||
|
return value ? `${value}%` : '';
|
||||||
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user