Skip to content

Commit 40546bc

Browse files
author
ci bot
committed
Merge branch 'password-fields' into 'enterprise'
fix: display a show/hide icon for password fields See merge request dkinternal/testgen/dataops-testgen!290
2 parents 6ee7e37 + 3620af0 commit 40546bc

4 files changed

Lines changed: 82 additions & 35 deletions

File tree

testgen/ui/assets/style.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,11 @@ div[data-testid="stPopoverBody"] [data-testid="stVerticalBlock"]:has(i.tg--expor
478478
}
479479
/* */
480480

481+
input::-ms-reveal,
482+
input::-ms-clear {
483+
display: none;
484+
}
485+
481486
/* Dark mode */
482487
@media (prefers-color-scheme: dark) {
483488
body {

testgen/ui/components/frontend/css/shared.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,3 +631,8 @@ code > .tg-icon:hover {
631631
.border-radius-1 {
632632
border-radius: 4px;
633633
}
634+
635+
input::-ms-reveal,
636+
input::-ms-clear {
637+
display: none;
638+
}

testgen/ui/components/frontend/js/components/connection_form.js

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,8 @@ const SnowflakeForm = (
879879
}),
880880
() => {
881881
if (connectByKey.val) {
882+
const hasPrivateKeyPhrase = originalConnection?.private_key_passphrase || connectionPrivateKeyPassphrase.val;
883+
882884
return div(
883885
{ class: 'flex-column fx-gap-3' },
884886
div(
@@ -899,24 +901,13 @@ const SnowflakeForm = (
899901
validityPerField['private_key_passphrase'] = state.valid;
900902
isValid.val = Object.values(validityPerField).every(v => v);
901903
},
904+
clearable: hasPrivateKeyPhrase,
905+
clearableCondition: 'always',
906+
onClear: () => {
907+
clearPrivateKeyPhrase.val = true;
908+
connectionPrivateKeyPassphrase.val = '';
909+
},
902910
}),
903-
() => {
904-
const hasPrivateKeyPhrase = originalConnection?.private_key_passphrase || connectionPrivateKeyPassphrase.val;
905-
if (!hasPrivateKeyPhrase) {
906-
return '';
907-
}
908-
909-
return i(
910-
{
911-
class: 'material-symbols-rounded clickable text-secondary',
912-
onclick: () => {
913-
clearPrivateKeyPhrase.val = true;
914-
connectionPrivateKeyPassphrase.val = '';
915-
},
916-
},
917-
'clear',
918-
);
919-
},
920911
),
921912
FileInput({
922913
name: 'private_key',

testgen/ui/components/frontend/js/components/input.js

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
* @property {string[]?} autocompleteOptions
2020
* @property {string?} icon
2121
* @property {boolean?} clearable
22-
* @property {boolean?} disabled
22+
* @property {('value' | 'always')?} clearableCondition
2323
* @property {function(string, InputState)?} onChange
24+
* @property {boolean?} disabled
25+
* @property {function(string, InputState)?} onClear
2426
* @property {number?} width
2527
* @property {number?} height
2628
* @property {string?} style
@@ -39,7 +41,11 @@ import { Portal } from './portal.js';
3941
const { div,input, label, i, small } = van.tags;
4042
const defaultHeight = 32;
4143
const iconSize = 22;
42-
const clearIconSize = 20;
44+
const addonIconSize = 20;
45+
const passwordFieldTypeSwitch = {
46+
password: 'text',
47+
text: 'password',
48+
};
4349

4450
const Input = (/** @type Properties */ props) => {
4551
loadStylesheet('input', stylesheet);
@@ -54,6 +60,9 @@ const Input = (/** @type Properties */ props) => {
5460
return errors.val[0] ?? '';
5561
});
5662

63+
const originalInputType = van.derive(() => getValue(props.type) ?? 'text');
64+
const inputType = van.state(originalInputType.rawVal);
65+
5766
const onChange = props.onChange?.val ?? props.onChange;
5867
if (onChange) {
5968
onChange(value.val, { errors: errors.val, valid: errors.val.length <= 0 });
@@ -65,6 +74,8 @@ const Input = (/** @type Properties */ props) => {
6574
}
6675
});
6776

77+
const onClear = props.onClear?.val ?? props.onClear ?? (() => value.val = '');
78+
6879
const autocompleteOpened = van.state(false);
6980
const autocompleteOptions = van.derive(() => {
7081
const filtered = getValue(props.autocompleteOptions)?.filter(option => option.toLowerCase().includes(value.val.toLowerCase()));
@@ -97,23 +108,49 @@ const Input = (/** @type Properties */ props) => {
97108
),
98109
() => getValue(props.icon) ? i(
99110
{
100-
class: 'material-symbols-rounded tg-input--icon',
111+
class: 'material-symbols-rounded tg-input--icon text-secondary',
101112
style: `bottom: ${((getValue(props.height) || defaultHeight) - iconSize) / 2}px`,
102113
},
103114
props.icon,
104115
) : '',
105-
() => getValue(props.clearable) ? i(
106-
{
107-
class: () => `material-symbols-rounded tg-input--clear clickable ${value.val ? '' : 'hidden'}`,
108-
style: `bottom: ${((getValue(props.height) || defaultHeight) - clearIconSize) / 2}px`,
109-
onclick: () => value.val = '',
110-
},
111-
'clear',
112-
) : '',
116+
() => {
117+
const clearableCondition = getValue(props.clearableCondition) ?? 'value';
118+
const showClearable = getValue(props.clearable) && (
119+
clearableCondition === 'always'
120+
|| (clearableCondition === 'value' && value.val)
121+
);
122+
123+
return div(
124+
{ class: 'flex-row' },
125+
originalInputType.val === 'password' && value.val
126+
? i(
127+
{
128+
class: 'material-symbols-rounded tg-input--visibility clickable text-secondary',
129+
style: `bottom: ${((getValue(props.height) || defaultHeight) - addonIconSize) / 2}px`,
130+
onclick: () => inputType.val = passwordFieldTypeSwitch[inputType.val],
131+
},
132+
inputType.val === 'password' ? 'visibility' : 'visibility_off',
133+
)
134+
: '',
135+
showClearable
136+
? i(
137+
{
138+
class: () => `material-symbols-rounded tg-input--clear text-secondary clickable`,
139+
style: `bottom: ${((getValue(props.height) || defaultHeight) - addonIconSize) / 2}px`,
140+
onclick: onClear,
141+
},
142+
'clear',
143+
)
144+
: '',
145+
);
146+
},
113147

114148
div(
115149
{
116-
class: () => `flex-row tg-input--field ${getValue(props.disabled) ? 'tg-input--disabled' : ''}`,
150+
class: () => {
151+
const sufixIconCount = Number(value.val && originalInputType.val === 'password') + Number(value.val && getValue(props.clearable));
152+
return `flex-row tg-input--field ${getValue(props.disabled) ? 'tg-input--disabled' : ''} sufix-padding-${sufixIconCount}`;
153+
},
117154
style: () => `height: ${getValue(props.height) || defaultHeight}px;`,
118155
},
119156
props.prefix
@@ -125,7 +162,7 @@ const Input = (/** @type Properties */ props) => {
125162
input({
126163
value,
127164
name: props.name ?? '',
128-
type: props.type ?? 'text',
165+
type: inputType,
129166
disabled: props.disabled,
130167
placeholder: () => getValue(props.placeholder) ?? '',
131168
oninput: debounce((/** @type Event */ event) => value.val = event.target.value, 300),
@@ -178,14 +215,23 @@ stylesheet.replace(`
178215
padding-left: 28px;
179216
}
180217
181-
.tg-input--clear {
218+
.tg-input--clear,
219+
.tg-input--visibility {
182220
position: absolute;
183-
right: 4px;
184-
font-size: ${clearIconSize}px;
221+
font-size: ${addonIconSize}px;
222+
right: 8px;
223+
}
224+
225+
.tg-input--visibility + .tg-input--clear {
226+
right: ${addonIconSize + 16}px;
227+
}
228+
229+
.tg-input--field.sufix-padding-1 {
230+
padding-right: ${addonIconSize + 8}px;
185231
}
186232
187-
.tg-input--clear ~ .tg-input--field {
188-
padding-right: 24px;
233+
.tg-input--field.sufix-padding-2 {
234+
padding-right: ${addonIconSize * 2 + 8 * 2}px;;
189235
}
190236
191237
.tg-input--field {

0 commit comments

Comments
 (0)