Skip to content

Commit

Permalink
Fix KeyValue connections form component (#2045)
Browse files Browse the repository at this point in the history
Co-authored-by: datalens-weblate-robot <robot-charts@yandex-team.com>
Co-authored-by: Darya Tikhonova <tihonova-d@yandex-team.ru>
Co-authored-by: Matthew Casserly <matveymc@yandex-team.ru>
  • Loading branch information
4 people authored Jan 24, 2025
1 parent 57b3d29 commit 2262be2
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 25 deletions.
3 changes: 3 additions & 0 deletions src/i18n-keysets/connections.form/en.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button_add": "Add",
"button_add-connection": "Create connection",
"button_already-saved": "Saved",
"button_attach-file": "Attach file",
Expand Down Expand Up @@ -83,6 +84,7 @@
"label_error-403-title": "You don't have access to this connection",
"label_error-404-title": "Connection not found",
"label_error-500-title": "Failed to load connection",
"label_error-duplicated-keys": "This key is already in use in another key-value pair",
"label_error-empty-field": "This is a required field",
"label_error-length-field": "Value has an incorrect number of characters",
"label_error-msg": "Failed to load list of connections",
Expand All @@ -108,6 +110,7 @@
"label_portal": "Portal",
"label_project-id": "Project ID",
"label_refresh-token-label": "Refresh token",
"label_secret-value": "Secret value",
"label_section-caption-counter-settings": "Tag settings",
"label_select-folder": "Select folder",
"label_service-acc-key-file": "Service account public key",
Expand Down
3 changes: 3 additions & 0 deletions src/i18n-keysets/connections.form/ru.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"button_add": "Добавить",
"button_add-connection": "Создать подключение",
"button_already-saved": "Сохранено",
"button_attach-file": "Прикрепить файл",
Expand Down Expand Up @@ -83,6 +84,7 @@
"label_error-403-title": "У вас нет доступа к подключению",
"label_error-404-title": "Подключение не найдено",
"label_error-500-title": "Не удалось загрузить подключение",
"label_error-duplicated-keys": "Ключ уже используется в другой паре «ключ — значение»",
"label_error-empty-field": "Поле обязательно для заполнения",
"label_error-length-field": "Значение имеет некорректное количество символов",
"label_error-msg": "Не удалось загрузить список подключений",
Expand All @@ -108,6 +110,7 @@
"label_portal": "Портал",
"label_project-id": "ID проекта",
"label_refresh-token-label": "Refresh-токен",
"label_secret-value": "Секретное значение",
"label_section-caption-counter-settings": "Настройки счетчика",
"label_select-folder": "Выберите каталог",
"label_service-acc-key-file": "Публичный ключ сервисного аккаунта",
Expand Down
2 changes: 1 addition & 1 deletion src/shared/schema/bi/types/forms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export type ValidatedItemAction = 'include' | 'skip';
export type ValidatedItem = {
name: string;
defaultAction: ValidatedItemAction;
type?: 'string' | 'boolean'; // default 'string'
type?: 'string' | 'boolean' | 'object'; // default 'string'
required?: boolean;
nullable?: boolean;
length?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@
row-gap: 10px;
width: 100%;

&__add-button-wrapper {
display: flex;
flex-direction: column;
row-gap: 2px;
}

&__add-button {
width: fit-content;
}

&__add-button-error-message {
color: var(--g-color-text-danger);
}

&__entry {
display: flex;
column-gap: 10px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import React from 'react';
import {Plus, Xmark} from '@gravity-ui/icons';
import {Button, Icon, PasswordInput, Select, TextInput} from '@gravity-ui/uikit';
import block from 'bem-cn-lite';
import {I18n} from 'i18n';
import type {KeyValueItem} from 'shared/schema/types';

import {i18n10647} from '../../../../constants';

import {useKeyValueProps, useKeyValueState} from './hooks';
import type {KeyValueEntry, KeyValueProps} from './types';

import './KeyValue.scss';

const b = block('conn-form-key-value');
const i18n = I18n.keyset('connections.form');
const ICON_SIZE = 18;

type KeyValueEntryViewProps = Omit<KeyValueItem, 'id' | 'name'> & {
Expand All @@ -27,7 +27,7 @@ const KeyValueEntryView = (props: KeyValueEntryViewProps) => {
let placeholder = valueInputProps?.placeholder;

if (entry.initial && secret && !placeholder) {
placeholder = i18n10647['label_secret-value'];
placeholder = i18n('label_secret-value');
}

if (entry.value === null) {
Expand All @@ -45,7 +45,7 @@ const KeyValueEntryView = (props: KeyValueEntryViewProps) => {
onUpdate(index, {key: value[0]});
}}
validationState={entry.error ? 'invalid' : undefined}
errorMessage={i18n10647['label_duplicated-keys']}
errorMessage={i18n('label_error-duplicated-keys')}
/>
{secret ? (
<PasswordInput
Expand Down Expand Up @@ -76,8 +76,8 @@ const KeyValueEntryView = (props: KeyValueEntryViewProps) => {
};

export const KeyValue = (props: KeyValueProps) => {
const {keys = [], keySelectProps, valueInputProps, secret} = props;
const {value, updateForm} = useKeyValueProps(props);
const {hasRequiredError, value, keys, keySelectProps, valueInputProps, secret, updateForm} =
useKeyValueProps(props);
const {keyValues, handleAddKeyValue, handleUpdateKeyValue, handleDeleteKeyValue} =
useKeyValueState({
value,
Expand All @@ -101,10 +101,21 @@ export const KeyValue = (props: KeyValueProps) => {
/>
);
})}
<Button className={b('add-button')} onClick={handleAddKeyValue}>
<Icon data={Plus} size={ICON_SIZE} />
{i18n10647['button_add']}
</Button>
<div className={b('add-button-wrapper')}>
<Button
className={b('add-button')}
onClick={handleAddKeyValue}
view={hasRequiredError ? 'outlined-danger' : 'normal'}
>
<Icon data={Plus} size={ICON_SIZE} />
{i18n('button_add')}
</Button>
{hasRequiredError && (
<span className={b('add-button-error-message')}>
{i18n('label_error-empty-field')}
</span>
)}
</div>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,25 @@ const getValidatedKeyValues = (keyValues: KeyValueEntry[]) => {
};

export function useKeyValueProps(props: KeyValueProps) {
const {name, inner, keys, keySelectProps, valueInputProps, secret} = props;
const {name, inner, keys = [], keySelectProps, valueInputProps, secret} = props;
const dispatch = useDispatch();
const form = useSelector(formSelector);
const innerForm = useSelector(innerFormSelector);
const validationErrors = useSelector(validationErrorsSelector);
const value = (inner ? innerForm[name] : form[name]) as KeyValueResult | undefined;
const error = getValidationError(name, validationErrors);
const hasRequiredError =
validationErrors.find((e) => e.name === props.name)?.type === ValidationErrorType.Required;

const updateForm = (nextKeyValues: KeyValueEntry[]) => {
const validatedNextKeyValues = getValidatedKeyValues(nextKeyValues);
const formUpdates: KeyValueResult = {
entries: keyValuesToEntries(validatedNextKeyValues),
};
const entries = keyValuesToEntries(validatedNextKeyValues);
const formUpdates: KeyValueResult | undefined =
Object.keys(entries).length === 0
? undefined
: {
entries: keyValuesToEntries(validatedNextKeyValues),
};

batch(() => {
if (inner) {
Expand All @@ -90,7 +96,7 @@ export function useKeyValueProps(props: KeyValueProps) {
});
};

return {value, keys, keySelectProps, valueInputProps, secret, updateForm};
return {hasRequiredError, value, keys, keySelectProps, valueInputProps, secret, updateForm};
}

export function useKeyValueState(props: {
Expand Down
7 changes: 0 additions & 7 deletions src/ui/units/connections/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,3 @@ export const ConverterErrorCode = {
TOO_MANY_COLUMNS: 'ERR.FILE.TOO_MANY_COLUMNS',
UNSUPPORTED_DOCUMENT: 'ERR.FILE.UNSUPPORTED_DOCUMENT',
};

// TODO: CHARTS-10647 i18n
export const i18n10647 = {
button_add: 'Add',
'label_duplicated-keys': 'Duplicated keys',
'label_secret-value': 'Secret value',
};
5 changes: 5 additions & 0 deletions src/ui/units/connections/store/utils/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type SchemaOptions = Record<
string,
| yup.StringSchema<string | null | undefined, Record<string, any>, string | null | undefined>
| yup.BooleanSchema<boolean | null | undefined, Record<string, any>, boolean | null | undefined>
| yup.ObjectSchema<Record<string, any>>
>;

type ValidationArgs = {
Expand Down Expand Up @@ -49,6 +50,10 @@ const createValidationSchema = (args: PartialBy<ValidationArgs, 'innerForm'>) =>
}
case 'string': {
acc[name] = yup.string();
break;
}
case 'object': {
acc[name] = yup.object();
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/ui/units/connections/utils/validation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {I18n} from 'i18n';

import {ValidationErrorType, i18n10647} from '../constants';
import {ValidationErrorType} from '../constants';
import type {ValidationError} from '../typings';

const i18n = I18n.keyset('connections.form');
Expand All @@ -18,7 +18,7 @@ export const getErrorMessage = (type?: ValidationErrorType) => {
return i18n('label_error-length-field');
}
case ValidationErrorType.DuplicatedKey: {
return i18n10647['label_duplicated-keys'];
return i18n('label_error-duplicated-keys');
}
default: {
return '';
Expand Down

0 comments on commit 2262be2

Please sign in to comment.