forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
UI: Regex validation on transform templates (hashicorp#11586)
* Add regex validator component with tests, add to form-field, use in transform template * Update tests with data-test selectors * Add changelog
- Loading branch information
Showing
8 changed files
with
205 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
```release-note:improvement | ||
ui: Add regex validation to Transform Template pattern input | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<div class="field"> | ||
<div class="regex-label-wrapper"> | ||
<div class="regex-label"> | ||
<label for="{{@attr.name}}" class="is-label"> | ||
{{@labelString}} | ||
{{#if @attr.options.helpText}} | ||
{{#info-tooltip}} | ||
<span data-test-help-text> | ||
{{@attr.options.helpText}} | ||
</span> | ||
{{/info-tooltip}} | ||
{{/if}} | ||
</label> | ||
{{#if @attr.options.subText}} | ||
<p class="sub-text">{{@attr.options.subText}} {{#if @attr.options.docLink}}<a href="{{@attr.options.docLink}}" target="_blank" rel="noopener noreferrer">See our documentation</a> for help.{{/if}}</p> | ||
{{/if}} | ||
</div> | ||
<div> | ||
<Toggle | ||
@name={{concat @attr.name "-validation-toggle"}} | ||
@status="success" | ||
@size="small" | ||
@checked={{this.showTestValue}} | ||
@onChange={{this.toggleTestValue}} | ||
> | ||
<span class="has-text-grey">Validation</span> | ||
</Toggle> | ||
</div> | ||
</div> | ||
<input | ||
id={{@attr.name}} | ||
data-test-input={{@attr.name}} | ||
autocomplete="off" | ||
spellcheck="false" | ||
{{on 'change' @onChange}} | ||
value={{@value}} | ||
class="input" | ||
/> | ||
</div> | ||
{{#if this.showTestValue}} | ||
<div data-test-regex-validator-test-string> | ||
<label for="{{@attr.name}}" class="is-label"> | ||
Test string | ||
</label> | ||
<input | ||
data-test-input={{concat @attr.name "-testval"}} | ||
id={{concat @attr.name "-testval"}} | ||
autocomplete="off" | ||
spellcheck="false" | ||
value={{this.testValue}} | ||
{{on 'change' this.updateTestValue}} | ||
class="input {{if this.regexError 'has-error'}}" /> | ||
|
||
{{#if (and this.testValue @value)}} | ||
<div data-test-regex-validation-message> | ||
{{#if this.regexError}} | ||
<AlertInline @type="danger" @message="Your regex doesn't match the subject string" /> | ||
{{else}} | ||
<div class="message-inline"> | ||
<Icon @glyph="check-circle-fill" class="has-text-success" aria-hidden="true" /> | ||
<p data-test-inline-success-message>Your regex matches the subject string</p> | ||
</div> | ||
{{/if}} | ||
</div> | ||
{{/if}} | ||
</div> | ||
{{/if}} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/** | ||
* @module RegexValidator | ||
* RegexValidator components are used to provide input forms for regex values, along with a toggle-able validation input which does not get saved to the model. | ||
* | ||
* @example | ||
* ```js | ||
* const attrExample = { | ||
* name: 'valName', | ||
* options: { | ||
* helpText: 'Shows in tooltip', | ||
* subText: 'Shows underneath label', | ||
* docLink: 'Adds docs link to subText if present', | ||
* defaultValue: 'hello', // Shows if no value on model | ||
* } | ||
* } | ||
* <RegexValidator @onChange={action 'myAction'} @attr={attrExample} @labelString="Label String" @value="initial value" /> | ||
* ``` | ||
* @param {func} onChange - the action that should trigger when the main input is changed. | ||
* @param {string} value - the value of the main input which will be updated in onChange | ||
* @param {string} labelString - Form label. Anticipated from form-field | ||
* @param {object} attr - attribute from model. Anticipated from form-field. Example of attribute shape above | ||
*/ | ||
|
||
import Component from '@glimmer/component'; | ||
import { tracked } from '@glimmer/tracking'; | ||
import { action } from '@ember/object'; | ||
|
||
export default class RegexValidator extends Component { | ||
@tracked testValue = ''; | ||
@tracked showTestValue = false; | ||
get regexError() { | ||
const testString = this.testValue; | ||
if (!testString || !this.args.value) return false; | ||
const regex = new RegExp(this.args.value, 'g'); | ||
const matchArray = testString.toString().match(regex); | ||
return testString !== matchArray?.join(''); | ||
} | ||
|
||
@action | ||
updateTestValue(evt) { | ||
this.testValue = evt.target.value; | ||
} | ||
|
||
@action | ||
toggleTestValue() { | ||
this.showTestValue = !this.showTestValue; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
.regex-label-wrapper { | ||
display: flex; | ||
align-items: flex-end; | ||
} | ||
.regex-label { | ||
flex: 1 0 auto; | ||
} | ||
.regex-toggle { | ||
flex: 0 1 auto; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import EmberObject from '@ember/object'; | ||
import sinon from 'sinon'; | ||
import { module, test } from 'qunit'; | ||
import { setupRenderingTest } from 'ember-qunit'; | ||
import { render, click, fillIn } from '@ember/test-helpers'; | ||
import { hbs } from 'ember-cli-htmlbars'; | ||
|
||
module('Integration | Component | regex-validator', function(hooks) { | ||
setupRenderingTest(hooks); | ||
|
||
test('it renders input and validation messages', async function(assert) { | ||
let attr = EmberObject.create({ | ||
name: 'example', | ||
}); | ||
let spy = sinon.spy(); | ||
this.set('onChange', spy); | ||
this.set('attr', attr); | ||
this.set('value', '(\\d{4})'); | ||
this.set('labelString', 'Regex Example'); | ||
|
||
await render( | ||
hbs`<RegexValidator | ||
@onChange={{onChange}} | ||
@attr={{attr}} | ||
@value={{value}} | ||
@labelString={{labelString}} | ||
/>` | ||
); | ||
assert.dom('.regex-label label').hasText('Regex Example', 'Label is correct'); | ||
assert.dom('[data-test-toggle-input="example-validation-toggle"]').exists('Validation toggle exists'); | ||
assert.dom('[data-test-regex-validator-test-string]').doesNotExist('Test string input does not show'); | ||
|
||
await click('[data-test-toggle-input="example-validation-toggle"]'); | ||
assert.dom('[data-test-regex-validator-test-string]').exists('Test string input shows after toggle'); | ||
assert | ||
.dom('[data-test-regex-validation-message]') | ||
.doesNotExist('Validation message does not show if test string is empty'); | ||
|
||
await fillIn('[data-test-input="example-testval"]', '123a'); | ||
assert.dom('[data-test-regex-validation-message]').exists('Validation message shows after input filled'); | ||
assert | ||
.dom('[data-test-inline-error-message]') | ||
.hasText("Your regex doesn't match the subject string", 'Shows error when regex does not match string'); | ||
|
||
await fillIn('[data-test-input="example-testval"]', '1234'); | ||
assert | ||
.dom('[data-test-inline-success-message]') | ||
.hasText('Your regex matches the subject string', 'Shows success when regex matches'); | ||
|
||
await fillIn('[data-test-input="example-testval"]', '12345'); | ||
assert | ||
.dom('[data-test-inline-error-message]') | ||
.hasText( | ||
"Your regex doesn't match the subject string", | ||
"Shows error if regex doesn't match complete string" | ||
); | ||
await fillIn('[data-test-input="example"]', '(\\d{5})'); | ||
assert.ok(spy.calledOnce, 'Calls the passed onChange function when main input is changed'); | ||
}); | ||
}); |