/
githubmirror
/
ydb-embedded-ui
Обзор
Документация
Войти
/
githubmirror
/
ydb-embedded-ui
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/containers/Tenant/Query/QuerySettingsDialog/QuerySettingsDialog.tsx
418 строк
18 KB
Konstantin Kozlov
feat: implement new Infra styles for yandex-team (#4197)
10 авг 2026, 10:44
Не верифицирован
10 авг 2026, 10:44
d2f3ac1
Код
Авторство
О чём код?
import React from 'react'; import {Button, Dialog, Flex, TextArea, TextInput, Tooltip} from '@gravity-ui/uikit'; import {zodResolver} from '@hookform/resolvers/zod'; import {Controller, useForm} from 'react-hook-form'; import type {z} from 'zod'; import { useSnapshotReadWriteAvailable, useTracingLevelOptionAvailable, } from '../../../../store/reducers/capabilities/hooks'; import { selectQueryAction, setQueryAction, } from '../../../../store/reducers/queryActions/queryActions'; import {SETTING_KEYS} from '../../../../store/reducers/settings/constants'; import type {QuerySettings} from '../../../../types/store/query'; import {cn} from '../../../../utils/cn'; import {BRAND_BUTTON_CLASS} from '../../../../utils/constants'; import { useQueryExecutionSettings, useQueryStreamingSetting, useResourcePools, useSetting, useTypedDispatch, useTypedSelector, } from '../../../../utils/hooks'; import type {ResourcePoolValue} from '../../../../utils/query'; import { RESOURCE_POOL_NO_OVERRIDE_VALUE, STATISTICS_MODES_WITH_SVG, TRANSACTION_MODES, isStreamingSupportedForMode, querySettingsValidationSchema, } from '../../../../utils/query'; import {useCurrentSchema} from '../../TenantContext'; import {QuerySettingsSelect} from './QuerySettingsSelect'; import {QuerySettingsTimeout} from './QuerySettingsTimeout'; import {QUERY_SETTINGS_FIELD_SETTINGS} from './constants'; import i18n from './i18n'; import './QuerySettingsDialog.scss'; const b = cn('ydb-query-settings-dialog'); export function QuerySettingsDialog() { const dispatch = useTypedDispatch(); const queryAction = useTypedSelector(selectQueryAction); const [querySettings, setQuerySettings] = useQueryExecutionSettings(); const onClose = React.useCallback(() => { dispatch(setQueryAction('idle')); }, [dispatch]); const onSubmit = React.useCallback( (data: QuerySettings) => { setQuerySettings(data); onClose(); }, [onClose, setQuerySettings], ); return ( <Dialog open={queryAction === 'settings'} size="s" onClose={onClose} className={b()} hasCloseButton={false} > <Dialog.Header caption={i18n('action.settings')} /> <QuerySettingsForm initialValues={querySettings} onSubmit={onSubmit} onClose={onClose} /> </Dialog> ); } interface QuerySettingsFormProps { initialValues: QuerySettings; onSubmit: (data: QuerySettings) => void; onClose: () => void; } type QuerySettingsFormInput = z.input<typeof querySettingsValidationSchema>; function QuerySettingsForm({initialValues, onSubmit, onClose}: QuerySettingsFormProps) { const { control, handleSubmit, setValue, watch, formState: {errors}, } = useForm<QuerySettingsFormInput, unknown, QuerySettings>({ defaultValues: initialValues, resolver: zodResolver(querySettingsValidationSchema), }); const [useShowPlanToSvg] = useSetting<boolean>(SETTING_KEYS.USE_SHOW_PLAN_SVG); const enableTracingLevel = useTracingLevelOptionAvailable(); const enableSnapshotReadWrite = useSnapshotReadWriteAvailable(); const [isQueryStreamingEnabled] = useQueryStreamingSetting(); const {database} = useCurrentSchema(); const {resourcePools, isLoading: isResourcePoolsLoading} = useResourcePools( database, initialValues.resourcePool, ); const resourcePoolOptions = React.useMemo( () => [ { value: RESOURCE_POOL_NO_OVERRIDE_VALUE, content: i18n('form.resource-pool.no-override'), }, ...resourcePools.map((name) => ({ value: name, content: name, })), ], [resourcePools], ); const timeout = watch('timeout'); const resourcePool = watch('resourcePool'); const queryMode = watch('queryMode'); const transactionMode = watch('transactionMode'); React.useEffect(() => { if (isResourcePoolsLoading) { return; } if (!resourcePool || resourcePool === RESOURCE_POOL_NO_OVERRIDE_VALUE) { return; } if (!resourcePools.length || !resourcePools.includes(resourcePool)) { setValue('resourcePool', RESOURCE_POOL_NO_OVERRIDE_VALUE); } }, [isResourcePoolsLoading, resourcePools, resourcePool, setValue]); React.useEffect(() => { if (!enableSnapshotReadWrite && transactionMode === TRANSACTION_MODES.snapshotrw) { setValue('transactionMode', TRANSACTION_MODES.implicit); } }, [enableSnapshotReadWrite, transactionMode, setValue]); const queryStatisticsOptions = React.useMemo(() => { return QUERY_SETTINGS_FIELD_SETTINGS.statisticsMode.options.map((option) => { if (!useShowPlanToSvg) { return option; } const isDisabled = !STATISTICS_MODES_WITH_SVG.includes(option.value); return {...option, disabled: isDisabled}; }); }, [useShowPlanToSvg]); const transactionModeOptions = React.useMemo(() => { return QUERY_SETTINGS_FIELD_SETTINGS.transactionMode.options.filter((option) => { if (option.value === TRANSACTION_MODES.snapshotrw) { return enableSnapshotReadWrite; } return true; }); }, [enableSnapshotReadWrite]); return ( <form onSubmit={handleSubmit(onSubmit)}> <Dialog.Body className={b('dialog-body')}> <Flex direction="row" alignItems="flex-start" className={b('dialog-row')}> <label htmlFor="queryMode" className={b('field-title')}> {QUERY_SETTINGS_FIELD_SETTINGS.queryMode.title} </label> <div className={b('control-wrapper', {queryMode: true})}> <Controller name="queryMode" control={control} render={({field}) => ( <QuerySettingsSelect id="queryMode" setting={field.value} onUpdateSetting={(mode) => { field.onChange(mode); if (mode !== 'query' && timeout === null) { setValue('timeout', ''); } else if (mode === 'query') { setValue('timeout', null); } }} settingOptions={QUERY_SETTINGS_FIELD_SETTINGS.queryMode.options} /> )} /> </div> </Flex> {enableTracingLevel && ( <Flex direction="row" alignItems="flex-start" className={b('dialog-row')}> <label htmlFor="tracingLevel" className={b('field-title')}> {QUERY_SETTINGS_FIELD_SETTINGS.tracingLevel.title} </label> <div className={b('control-wrapper')}> <Controller name="tracingLevel" control={control} render={({field}) => ( <QuerySettingsSelect id="tracingLevel" setting={field.value} onUpdateSetting={field.onChange} settingOptions={ QUERY_SETTINGS_FIELD_SETTINGS.tracingLevel.options } /> )} /> </div> </Flex> )} <Flex direction="row" alignItems="flex-start" className={b('dialog-row')}> <label htmlFor="transactionMode" className={b('field-title')}> {QUERY_SETTINGS_FIELD_SETTINGS.transactionMode.title} </label> <div className={b('control-wrapper', {transactionMode: true})}> <Controller name="transactionMode" control={control} render={({field}) => ( <QuerySettingsSelect id="transactionMode" setting={field.value} onUpdateSetting={field.onChange} settingOptions={transactionModeOptions} /> )} /> </div> </Flex> <Flex direction="row" alignItems="flex-start" className={b('dialog-row')}> <label htmlFor="statisticsMode" className={b('field-title')}> {QUERY_SETTINGS_FIELD_SETTINGS.statisticsMode.title} </label> <Tooltip className={b('statistics-mode-tooltip')} disabled={!useShowPlanToSvg} openDelay={0} content={i18n('tooltip_plan-to-svg-statistics')} > <div className={b('control-wrapper', {statisticsMode: true})}> <Controller name="statisticsMode" control={control} render={({field}) => ( <QuerySettingsSelect id="statisticsMode" setting={field.value} onUpdateSetting={field.onChange} settingOptions={queryStatisticsOptions} /> )} /> </div> </Tooltip> </Flex> <Flex direction="row" alignItems="flex-start" className={b('dialog-row')}> <label htmlFor="limitRows" className={b('field-title')}> {QUERY_SETTINGS_FIELD_SETTINGS.limitRows.title} </label> <div className={b('control-wrapper')}> <Controller name="limitRows" control={control} render={({field}) => ( <TextInput id="limitRows" type="number" {...field} value={field.value?.toString()} className={b('limit-rows')} placeholder="10000" validationState={errors.limitRows ? 'invalid' : undefined} errorMessage={errors.limitRows?.message} errorPlacement="inside" endContent={ <span className={b('postfix')}> {i18n('form.limit.rows')} </span> } /> )} /> </div> </Flex> {isQueryStreamingEnabled && ( <Flex direction="row" alignItems="flex-start" className={b('dialog-row')}> <label htmlFor="outputChunkMaxSize" className={b('field-title')}> {QUERY_SETTINGS_FIELD_SETTINGS.outputChunkMaxSize.title} </label> <div className={b('control-wrapper')}> <Controller name="outputChunkMaxSize" control={control} render={({field}) => ( <TextInput id="outputChunkMaxSize" type="number" {...field} value={field.value?.toString()} className={b('output-chunk-max-size')} placeholder="1000000" validationState={ errors.outputChunkMaxSize ? 'invalid' : undefined } errorMessage={errors.outputChunkMaxSize?.message} errorPlacement="inside" endContent={ <span className={b('postfix')}> {i18n('form.output.chunk.max.size.bytes')} </span> } /> )} /> </div> </Flex> )} <Flex direction="row" alignItems="flex-start" className={b('dialog-row')}> <label htmlFor="resourcePool" className={b('field-title')}> {QUERY_SETTINGS_FIELD_SETTINGS.resourcePool.title} </label> <div className={b('control-wrapper', {resourcePool: true})}> <Controller name="resourcePool" control={control} render={({field}) => ( <QuerySettingsSelect<ResourcePoolValue> id="resourcePool" setting={field.value ?? RESOURCE_POOL_NO_OVERRIDE_VALUE} disabled={isResourcePoolsLoading || !resourcePools.length} onUpdateSetting={(value) => field.onChange(value)} settingOptions={resourcePoolOptions} /> )} /> </div> </Flex> <Flex direction="row" alignItems="flex-start" className={b('dialog-row')}> <label htmlFor="pragmas" className={b('field-title')}> {QUERY_SETTINGS_FIELD_SETTINGS.pragmas.title} </label> <div className={b('control-wrapper')}> <Controller name="pragmas" control={control} render={({field}) => ( <TextArea id="pragmas" {...field} className={b('pragmas')} placeholder="PRAGMA OrderedColumns;" rows={3} validationState={errors.pragmas ? 'invalid' : undefined} errorMessage={errors.pragmas?.message} errorPlacement="inside" /> )} /> </div> </Flex> <Flex direction="row" alignItems="flex-start" className={b('dialog-row')}> <Controller name="timeout" control={control} render={({field}) => ( <QuerySettingsTimeout id="timeout" value={field.value as string | number | null | undefined} onChange={field.onChange} onToggle={(enabled) => field.onChange(enabled ? '' : null)} validationState={errors.timeout ? 'invalid' : undefined} errorMessage={errors.timeout?.message} isDisabled={!isStreamingSupportedForMode(queryMode)} /> )} /> </Flex> </Dialog.Body> <Dialog.Footer textButtonApply={i18n('button-done')} textButtonCancel={i18n('button-cancel')} onClickButtonCancel={onClose} propsButtonApply={{ type: 'submit', className: BRAND_BUTTON_CLASS, }} renderButtons={(buttonApply, buttonCancel) => ( <div className={b('buttons-container')}> <Button href="https://ydb.tech/docs" target="_blank" view="outlined" size="l" > {i18n('docs')} </Button> <div className={b('main-buttons')}> {buttonCancel} {buttonApply} </div> </div> )} /> </form> ); }