Skip to content

Commit

Permalink
EPMRPP-78035 || Launch and Test item description validation update (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
tr1ble authored and Vadim73i committed Sep 12, 2022
1 parent de427d7 commit ca60a2b
Show file tree
Hide file tree
Showing 15 changed files with 223 additions and 33 deletions.
2 changes: 2 additions & 0 deletions app/localization/translated/be.json
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,8 @@
"DurationTooltip.message": "Працягласць - інтэрвал паміж пачаткам першага падзапуску і заканчэннем апошняга падзапуску. Але калі падзапускі ідуць у параллелі, час заканчэння - гэта час найдаўжэйшага падзапуску, у гэтым выпадку працягласць не будзе роўнай суме працягласцяў падзапускаў.",
"EditItemModal.attributesLabel": "Атрыбуты",
"EditItemModal.contentTitle": "Апісанне {type}а",
"EditItemModal.descriptionAdviceHint": "Вы выкарысталі {length} з 2048 сімвалаў",
"EditItemModal.descriptionHint": "Апісанне павінна мець памер ад '0' да '2048' сімвалаў",
"EditItemModal.descriptionPlaceholder": "Увядзіце апісанне {type}а",
"EditItemModal.detailsTabTitle": "Апісанне",
"EditItemModal.item": "элемент",
Expand Down
2 changes: 2 additions & 0 deletions app/localization/translated/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,8 @@
"DurationTooltip.message": "Длительность - это интервал между началом первого подпрогона и окончанием последнего подпрогона. Но если подпрогоны происходят параллельно, время окончания - это окончание наиболее длительного подпрогона, в этом случае длительность не будет равна сумме длительностей подпрогонов.",
"EditItemModal.attributesLabel": "Атрибуты",
"EditItemModal.contentTitle": "Детали {type}а",
"EditItemModal.descriptionAdviceHint": "Вы использовали {length} из 2048 символов",
"EditItemModal.descriptionHint": "Описание должно иметь размер от '0' до '2048' символов",
"EditItemModal.descriptionPlaceholder": "Введите описание {type}а",
"EditItemModal.detailsTabTitle": "Детали",
"EditItemModal.item": "элемент",
Expand Down
2 changes: 2 additions & 0 deletions app/localization/translated/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,8 @@
"DurationTooltip.message": "Тривалість - це інтервал між початком першої і закінченням останньої подпрогона подпрогона. Але якщо подпрогоны відбуваються паралельно, час закінчення - це закінчення найбільш тривалого подпрогона, час закінчення - це закінчення найбільш тривалого подпрогона",
"EditItemModal.attributesLabel": "Атрибути",
"EditItemModal.contentTitle": "Деталі {type}у",
"EditItemModal.descriptionAdviceHint": "Ви використали {length} із 2048 символів",
"EditItemModal.descriptionHint": "Опис повинен мати розмір від '0' до '2048' символів",
"EditItemModal.descriptionPlaceholder": "Внесіть опис {type}у",
"EditItemModal.detailsTabTitle": "Деталі",
"EditItemModal.item": "елемент",
Expand Down
5 changes: 5 additions & 0 deletions app/src/common/utils/validation/commonValidators.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,8 @@ export const createNumberOfLaunchesValidator = (message) =>
bindMessageToValidator(validate.widgetNumberOfLaunches, message);
export const createWidgetContentFieldsValidator = (message) =>
bindMessageToValidator(validate.isNotEmptyArray, message);

export const createDescriptionValidator = bindMessageToValidator(
validate.descriptionField,
'descriptionHint',
);
1 change: 1 addition & 0 deletions app/src/common/utils/validation/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const attributesArray = (value) =>
isEmpty(value) ||
!value.length ||
value.every((attribute) => attributeValue(attribute.value) && !attribute.edited);
export const descriptionField = maxLength(2048);

export const widgetNumberOfLaunches = composeValidators([isNotEmpty, range(1, 600)]);
export const cumulativeItemsValidation = composeValidators([isNotEmpty, range(1, 20000)]);
Expand Down
11 changes: 10 additions & 1 deletion app/src/components/fields/fieldErrorHint/fieldErrorHint.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ const messages = defineMessages({
id: 'MembersPageToolbar.membersSearchHint',
defaultMessage: 'Member name must not be empty',
},
descriptionHint: {
id: 'EditItemModal.descriptionHint',
defaultMessage: "Description should have size from '0' to '2048' symbols",
},
});

@injectIntl
Expand Down Expand Up @@ -273,7 +277,12 @@ export class FieldErrorHint extends Component {

return (
<div className={classes}>
{children && cloneElement(children, { error, active, ...rest })}
{children &&
cloneElement(children, {
error: error && messages[error] ? intl.formatMessage(messages[error]) : error,
active,
...rest,
})}
<div
className={cx('hint', `type-${hintType}`, {
'static-hint': staticHint,
Expand Down
66 changes: 51 additions & 15 deletions app/src/components/main/markdown/markdownEditor/markdownEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ export class MarkdownEditor extends React.Component {
getTrackingData: PropTypes.func,
}).isRequired,
manipulateEditorOutside: PropTypes.func,
active: PropTypes.bool,
touched: PropTypes.bool,
error: PropTypes.string,
hint: PropTypes.shape({
hintText: PropTypes.func,
hintCondition: PropTypes.func,
}),
provideErrorHint: PropTypes.bool,
};
static defaultProps = {
value: '',
Expand All @@ -109,6 +117,11 @@ export class MarkdownEditor extends React.Component {
eventsInfo: {},
mode: MODE_DEFAULT,
manipulateEditorOutside: () => {},
active: false,
touched: false,
error: '',
hint: { hintText: () => '', hintCondition: () => true },
provideErrorHint: false,
};

state = {
Expand Down Expand Up @@ -262,23 +275,46 @@ export class MarkdownEditor extends React.Component {
};

render() {
const { value, onChange, mode } = this.props;
const {
value,
onChange,
mode,
active,
error,
touched,
provideErrorHint,
hint: { hintText, hintCondition },
} = this.props;

return (
<div
className={cx(
'markdown-editor',
{ [`mode-${mode}`]: mode },
{ preview: this.state.isPreview },
<>
<div
className={cx(
'markdown-editor',
{ [`mode-${mode}`]: mode },
{ preview: this.state.isPreview },
{ invalid: error && (touched || active) },
)}
>
<textarea
ref={(holder) => {
this.holder = holder;
}}
value={value}
onChange={onChange}
/>
</div>
{provideErrorHint && error && (touched || active) ? (
<div className={cx('error')}>{error}</div>
) : (
hintText &&
hintCondition(this.simpleMDE ? this.simpleMDE.value() : value) && (
<div className={cx('hint')}>
{hintText(this.simpleMDE ? this.simpleMDE.value() : value)}
</div>
)
)}
>
<textarea
ref={(holder) => {
this.holder = holder;
}}
value={value}
onChange={onChange}
/>
</div>
</>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
&.focused {
border-color: $COLOR--topaz;
}
&.invalid {
border-color: $COLOR--failed;
}
:global {
.editor-toolbar {
opacity: 1;
Expand Down Expand Up @@ -269,3 +272,21 @@
}
}
}

@mixin additional-text($color) {
margin-top: 4px;
width: 100%;
height: 100%;
font-size: 10px;
box-sizing: border-box;
text-align: left;
color: $color;
}

.error {
@include additional-text($COLOR--failed);
}

.hint {
@include additional-text($COLOR--gray-47);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const cx = classNames.bind(styles);
export class ModalFooter extends Component {
static propTypes = {
warningMessage: PropTypes.string,
warningType: PropTypes.string,
okButton: PropTypes.shape({
text: PropTypes.string.isRequired,
disabled: PropTypes.bool,
Expand Down Expand Up @@ -73,6 +74,7 @@ export class ModalFooter extends Component {
};
static defaultProps = {
warningMessage: '',
warningType: 'error',
okButton: null,
cancelButton: null,
customButton: null,
Expand All @@ -98,6 +100,7 @@ export class ModalFooter extends Component {
render() {
const {
warningMessage,
warningType,
okButton,
cancelButton,
customButton,
Expand Down Expand Up @@ -135,8 +138,12 @@ export class ModalFooter extends Component {
)}
{warningMessage && (
<div className={cx('warning-block')}>
<i className={cx('warning-icon')}>{Parser(WarningIcon)}</i>
<span className={cx('warning-message')}>{warningMessage}</span>
<i className={cx('warning-icon', { [`type-${warningType}`]: warningType })}>
{Parser(WarningIcon)}
</i>
<span className={cx('warning-message', { [`type-${warningType}`]: warningType })}>
{warningMessage}
</span>
</div>
)}
<div className={cx('buttons-block')}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@
svg {
fill: $COLOR--failed;
}

&.type-error {
svg {
fill: $COLOR--failed;
}
}

&.type-info {
svg {
fill: $COLOR--warning;
}
}
}
.warning-message {
display: inline-block;
Expand All @@ -55,6 +67,13 @@
font-size: 10px;
line-height: 1.4;
color: $COLOR--failed;

&.type-error {
color: $COLOR--failed;
}
&.type-info {
color: $COLOR--black-1;
}
}
}
.buttons-block {
Expand Down
4 changes: 4 additions & 0 deletions app/src/components/main/modal/modalLayout/modalLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export class ModalLayout extends Component {
title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), // header props
children: PropTypes.node, // content props
warningMessage: PropTypes.string, // footer props
warningType: PropTypes.string,
okButton: PropTypes.shape({
text: PropTypes.string.isRequired,
disabled: PropTypes.bool,
Expand Down Expand Up @@ -84,6 +85,7 @@ export class ModalLayout extends Component {
title: '',
children: null,
warningMessage: '',
warningType: '',
okButton: null,
cancelButton: null,
customButton: null,
Expand Down Expand Up @@ -182,6 +184,7 @@ export class ModalLayout extends Component {
const {
title,
warningMessage,
warningType,
okButton,
cancelButton,
customButton,
Expand All @@ -191,6 +194,7 @@ export class ModalLayout extends Component {
} = this.props;
const footerProps = {
warningMessage,
warningType,
okButton,
cancelButton,
customButton,
Expand Down
38 changes: 31 additions & 7 deletions app/src/pages/inside/common/modals/editItemModal/editItemModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { CopyToClipboard } from 'react-copy-to-clipboard';
import Parser from 'html-react-parser';
import IconDuplicate from 'common/img/duplicate-inline.svg';
import { fetch } from 'common/utils/fetch';
import { validate } from 'common/utils/validation';
import { commonValidators, validate } from 'common/utils/validation';
import { URLS } from 'common/urls';
import { COMMON_LOCALE_KEYS } from 'common/constants/localization';
import { LAUNCH_ITEM_TYPES } from 'common/constants/launchItemTypes';
Expand All @@ -46,6 +46,7 @@ import { AccordionContainer } from 'components/main/accordionContainer';
import { canEditLaunch } from 'common/utils/permissions';
import { ScrollWrapper } from 'components/main/scrollWrapper';
import { TestParameters } from 'pages/inside/common/testParameters';
import { FieldErrorHint } from 'components/fields/fieldErrorHint';
import styles from './editItemModal.scss';

const cx = classNames.bind(styles);
Expand Down Expand Up @@ -104,15 +105,20 @@ const messages = defineMessages({
id: 'TestItemDetailsModal.parametersLabel',
defaultMessage: 'Parameters:',
},
descriptionHint: {
id: 'EditItemModal.descriptionAdviceHint',
defaultMessage: 'You used {length} of 2048 symbols',
},
});

@withModal('editItemModal')
@injectIntl
@track()
@reduxForm({
form: 'editItemForm',
validate: ({ attributes }) => ({
validate: ({ attributes, description }) => ({
attributes: !validate.attributesArray(attributes),
description: commonValidators.createDescriptionValidator(description),
}),
})
@connect(
Expand Down Expand Up @@ -148,6 +154,7 @@ export class EditItemModal extends Component {
trackEvent: PropTypes.func,
getTrackingData: PropTypes.func,
}).isRequired,
invalid: PropTypes.bool.isRequired,
};

static defaultProps = {
Expand Down Expand Up @@ -243,6 +250,15 @@ export class EditItemModal extends Component {
eventsInfo.CLICK_COPY_ICON_UUID && tracking.trackEvent(eventsInfo.CLICK_COPY_ICON_UUID);
};

checkDescriptionLengthForHint = (description) => description.length > 1948;

getDescriptionText = (description) => {
const {
intl: { formatMessage },
} = this.props;
return formatMessage(messages.descriptionHint, { length: description.length });
};

render() {
const {
intl: { formatMessage },
Expand Down Expand Up @@ -281,6 +297,7 @@ export class EditItemModal extends Component {
warningMessage={
type === LAUNCH_ITEM_TYPES.launch && editable && formatMessage(messages.launchWarning)
}
warningType={!this.props.invalid && 'info'}
>
<form>
<ModalField>
Expand Down Expand Up @@ -342,11 +359,18 @@ export class EditItemModal extends Component {
{editable ? (
<ModalField>
<FieldProvider name="description">
<MarkdownEditor
placeholder={formatMessage(messages.descriptionPlaceholder, {
type: formatMessage(messages[type]),
})}
/>
<FieldErrorHint provideHint={false}>
<MarkdownEditor
placeholder={formatMessage(messages.descriptionPlaceholder, {
type: formatMessage(messages[type]),
})}
provideErrorHint
hint={{
hintText: this.getDescriptionText,
hintCondition: this.checkDescriptionLengthForHint,
}}
/>
</FieldErrorHint>
</FieldProvider>
</ModalField>
) : (
Expand Down
Loading

0 comments on commit ca60a2b

Please sign in to comment.