@@ -29,9 +29,10 @@ const buttonGroupStyle = { width: '60px' }
2929 * Extract just the subset of fields to build the state variable.
3030 */
3131function extractStateFields ( props : Props ) : Substitution {
32- const { description, normalizeSpace, pattern, replacement } = props . substitution
32+ const { description, invalid , normalizeSpace, pattern, replacement } = props . substitution
3333 return {
3434 description : description || '' ,
35+ invalid,
3536 normalizeSpace,
3637 pattern,
3738 replacement
@@ -41,10 +42,17 @@ function extractStateFields (props: Props): Substitution {
4142/**
4243 * @returns true if the given substitution pattern is null or empty, false otherwise.
4344 */
44- export function isSubstitutionInvalid ( substitution : Substitution ) {
45+ export function isSubstitutionBlank ( substitution : Substitution ) {
4546 return ! substitution . pattern || substitution . pattern === ''
4647}
4748
49+ /**
50+ * @returns true if the given substitution is marked invalid by the backend, false otherwise.
51+ */
52+ export function isSubstitutionInvalid ( substitution : Substitution ) {
53+ return substitution . invalid
54+ }
55+
4856/**
4957 * Renders and lets user edit a substitution.
5058 */
@@ -137,18 +145,29 @@ export default class SubstitutionRow extends Component<Props, Substitution> {
137145 }
138146
139147 render ( ) {
140- const { activeEditingIndex } = this . props
141- const { description , normalizeSpace, pattern, replacement } = this . state
148+ const { activeEditingIndex, substitution : originalSubstitution } = this . props
149+ const { description , invalid , normalizeSpace, pattern, replacement } = this . state
142150 const regexTestLink = `https://regexr.com/?expression=${ encodeURIComponent ( pattern ) } &text=${ STRING_FOR_REGEXR_TEST } `
143151 const isEditing = this . _isEditing ( )
144152 const allowEdit = activeEditingIndex === - 1
145- const isEditingInvalid = isSubstitutionInvalid ( this . state )
153+ const isPatternBlank = isSubstitutionBlank ( this . state )
154+ const isPatternInvalid = invalid && pattern === originalSubstitution . pattern
155+ const isEditingInvalid = isPatternBlank || isPatternInvalid
156+ let validationMessage = null
157+ if ( isPatternBlank ) {
158+ validationMessage = 'The substitution search pattern cannot be empty'
159+ } else if ( isPatternInvalid ) {
160+ validationMessage = `The substitution search pattern '${ originalSubstitution . pattern } ' is invalid`
161+ }
146162
147163 // Construct CSS class for row
148164 const editingClassName = isEditing ? '' : 'inactive'
149165 const allowEditClassName = allowEdit ? 'allow-edit' : ''
150166 const rowClassName = `substitution-row ${ editingClassName } ${ allowEditClassName } `
151167
168+ // Override style for inputs with invalid search patterns.
169+ const patternStyleOverride = isPatternInvalid ? { borderColor : 'inherit' } : null
170+
152171 return (
153172 < tr className = { rowClassName } >
154173 < td >
@@ -163,10 +182,11 @@ export default class SubstitutionRow extends Component<Props, Substitution> {
163182 onKeyDown = { this . _onKeyDown }
164183 placeholder = 'Text (regex) to find'
165184 readOnly = { ! isEditing }
166- title = { isEditingInvalid ? 'Substitution search pattern cannot be empty' : null }
185+ style = { patternStyleOverride }
186+ title = { validationMessage }
167187 value = { pattern }
168188 />
169- < InputGroup . Addon >
189+ < InputGroup . Addon style = { patternStyleOverride } >
170190 < a
171191 href = { regexTestLink }
172192 target = '_blank'
@@ -217,9 +237,9 @@ export default class SubstitutionRow extends Component<Props, Substitution> {
217237 < ButtonGroup style = { buttonGroupStyle } >
218238 < Button
219239 bsSize = 'xsmall'
220- disabled = { isEditingInvalid }
240+ disabled = { isPatternInvalid }
221241 onClick = { this . _onClickSave }
222- title = { isEditingInvalid ? 'Unable to save, there are errors in this row.' : 'Save changes in this row' }
242+ title = { isPatternInvalid ? 'Unable to save, there are errors in this row.' : 'Save changes in this row' }
223243 >
224244 < Icon type = 'check' />
225245 </ Button >
0 commit comments