Skip to content

Commit e913502

Browse files
committed
replace "real time" username lookup with two phase - validation and then a button to check for availability [PTV-1884]
1 parent 481d596 commit e913502

3 files changed

Lines changed: 189 additions & 28 deletions

File tree

src/plugin/iframe_root/modules/reactComponents/SignInContinueView.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ define([
55
'./CollapsiblePanel',
66
'./TextSpan',
77
'./ContinueHeader',
8+
'./Alert',
89
'../lib/provider',
910

1011
'bootstrap',
@@ -16,6 +17,7 @@ define([
1617
CollapsiblePanel,
1718
TextSpan,
1819
ContinueHeader,
20+
Alert,
1921
provider
2022
) => {
2123
const {h, Component, Fragment} = preact;
@@ -147,11 +149,13 @@ define([
147149
<p>There is no KBase account associated with it.</p>
148150
<p>
149151
If you wish to create a new KBase account, you may
150-
<${TextSpan}>
151-
<a href="/#signup">
152-
<${TextSpan}><span className="fa fa-user-plus" /></>
153-
Sign Up now using this <${TextSpan} bold=${true}>${this.props.choice.provider}</> account
154-
</a>.
152+
<${Alert} variant="info" type="inline" style=${{marginLeft: '0.5rem'}}>
153+
<${TextSpan}>
154+
<a href="/#signup">
155+
<${TextSpan}><span className="fa fa-user-plus" /></>
156+
Sign Up now using this <${TextSpan} bold=${true}>${this.props.choice.provider}</> account
157+
</a>.
158+
</>
155159
</>
156160
</p>
157161

src/plugin/iframe_root/modules/reactComponents/SignUpForm.js

Lines changed: 169 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,16 @@ define([
174174
requiredIcon(fieldName) {
175175
const fieldState = this.state.form.fields[fieldName];
176176
const classes = (() => {
177-
if (fieldState.status !== 'VALID') {
177+
switch (fieldState.status) {
178+
case 'VALID':
179+
return 'glyphicon-ok text-success';
180+
case 'LOCAL_VALID':
181+
return 'glyphicon-asterisk text-danger';
182+
case 'REMOTE_VALIDATING':
183+
return 'glyphicon-asterisk text-danger';
184+
case 'INVALID':
178185
return 'glyphicon-asterisk text-danger';
179186
}
180-
return 'glyphicon-ok text-success';
181187
})();
182188

183189
return html`
@@ -189,26 +195,17 @@ define([
189195

190196
getFieldBorderClass(fieldName) {
191197
const fieldState = this.state.form.fields[fieldName];
192-
if (fieldState.status !== 'VALID') {
198+
switch (fieldState.status) {
199+
case 'VALID':
200+
return '';
201+
case 'LOCAL_VALID':
202+
return 'has-error';
203+
case 'REMOTE_VALIDATING':
204+
return 'has-error';
205+
case 'INVALID':
193206
return 'has-error';
194207
}
195208
return '';
196-
197-
// if (fieldState.isValidating) {
198-
// // return '1px solid yellow';
199-
// return 'bs-border-warning';
200-
// }
201-
// if (fieldState.isModified) {
202-
// if (fieldState.status === 'VALID') {
203-
// // return '1px solid transparent';
204-
// return 'bs-border-invisible';
205-
// }
206-
// // return '1px solid red';
207-
// return 'bs-border-danger';
208-
209-
// }
210-
// // return '1px solid transparent';
211-
// return 'bs-border-invisible';
212209
}
213210

214211
renderFormRow(field, info) {
@@ -348,6 +345,9 @@ define([
348345
};
349346
}
350347
},
348+
],
349+
remoteRuleMessage: 'Username is valid, check if available with KBase',
350+
remoteRules: [
351351
{
352352
validate: async (value) => {
353353
const auth2Client = new auth2.Auth2({
@@ -474,6 +474,42 @@ define([
474474
}
475475
}
476476

477+
if ('remoteRules' in fieldDefinition) {
478+
return {
479+
value,
480+
isModified: true,
481+
status: 'LOCAL_VALID',
482+
validationMessage: fieldDefinition.remoteRuleMessage
483+
};
484+
}
485+
return {
486+
value,
487+
isModified: true,
488+
status: 'VALID'
489+
};
490+
}
491+
492+
async evaluateRemoteRules(fieldName) {
493+
if (!('remoteRules' in fieldDefinition)) {
494+
return;
495+
}
496+
// Apply remote rules.
497+
const fieldState = this.getFieldState(fieldName);
498+
const fieldDefinition = this.getFieldDefinition(fieldName);
499+
500+
const value = fieldState.value;
501+
502+
for (const rule of fieldDefinition.remoteRules) {
503+
const {isValid, message} = await rule.validate(value);
504+
if (!isValid) {
505+
return {
506+
value,
507+
isModified: true,
508+
status: 'INVALID',
509+
validationMessage: message
510+
};
511+
}
512+
}
477513
return {
478514
value,
479515
isModified: true,
@@ -511,6 +547,17 @@ define([
511547

512548
renderRealnameField() {
513549
const fieldState = this.state.form.fields.realname;
550+
const messageClass = (() => {
551+
switch (fieldState.status) {
552+
case 'VALID':
553+
return 'success';
554+
case 'LOCAL_VALID':
555+
return 'success';
556+
case 'INVALID':
557+
return 'danger';
558+
}
559+
560+
})();
514561
const field = html`
515562
<div className=${`form-group ${this.getFieldBorderClass('realname')}`} style=${{padding: '2px'}}>
516563
<label for="signup_realname">
@@ -524,7 +571,7 @@ define([
524571
value=${fieldState.value}
525572
onInput=${(e) => {return this.updateField('realname', e.target.value);}}
526573
/>
527-
<div className="text-danger"
574+
<div className="text-${messageClass}"
528575
style=${{padding: '4px'}}>
529576
${fieldState.validationMessage}
530577
</div>
@@ -604,7 +651,7 @@ define([
604651
}
605652

606653
renderUsernameField() {
607-
const field = this.renderInputField('username');
654+
const field = this.renderLookupInputField('username');
608655
const info = html`
609656
<div>
610657
<div>
@@ -646,13 +693,25 @@ define([
646693
renderField(fieldName, control) {
647694
const fieldDefinition = this.getFieldDefinition(fieldName);
648695
const fieldState = this.state.form.fields[fieldName];
696+
const messageClassName = (() => {
697+
switch (fieldState.status) {
698+
case 'VALID':
699+
return 'text-success';
700+
case 'LOCAL_VALID':
701+
return 'text-warning';
702+
case 'REMOTE_VALIDATING':
703+
return 'text-warning';
704+
case 'INVALID':
705+
return 'text-danger';
706+
}
707+
})();
649708
return html`
650709
<div className=${`form-group ${this.getFieldBorderClass(fieldName)}`} style=${{padding: '2px'}}>
651710
<label for=${`signup_${fieldName}`}>
652711
${fieldDefinition.label} ${this.requiredIcon(fieldName)}
653712
</label>
654713
${control}
655-
<div className="text-danger"
714+
<div className=${messageClassName}
656715
style=${{padding: '4px'}}>
657716
${fieldState.validationMessage}
658717
</div>
@@ -675,6 +734,94 @@ define([
675734
return this.renderField(fieldName, control);
676735
}
677736

737+
renderLookupInputField(fieldName) {
738+
const fieldState = this.state.form.fields[fieldName];
739+
const onLookup = async () => {
740+
const validate = async (value) => {
741+
const auth2Client = new auth2.Auth2({
742+
baseUrl: this.props.runtime.config('services.auth.url')
743+
});
744+
try {
745+
const {availablename} = await auth2Client.loginUsernameSuggest(value);
746+
if (availablename === value) {
747+
return {
748+
isValid: true
749+
};
750+
}
751+
return {
752+
isValid: false,
753+
message: `This username is not available: a suggested available username is ${availablename}`
754+
};
755+
} catch (ex) {
756+
console.error('error looking up username in auth', ex);
757+
}
758+
};
759+
760+
const value = this.state.form.fields[fieldName].value;
761+
this.setFieldState(fieldName, {
762+
value, isModified: true, status: 'REMOTE_VALIDATING',
763+
validationMessage: html`Checking if username is available at KBase... <span className="fa fa-spinner fa-pulse " /> `
764+
});
765+
const {isValid, message} = await validate(value);
766+
const fieldState = (() => {
767+
if (isValid) {
768+
return {
769+
value,
770+
isModified: true,
771+
status: 'VALID',
772+
validationMessage: 'This username is available'
773+
};
774+
}
775+
return {
776+
value,
777+
isModified: true,
778+
status: 'INVALID',
779+
validationMessage: message
780+
};
781+
})();
782+
this.setFieldState(fieldName, fieldState);
783+
};
784+
// const buttonMessage = (() => {
785+
// switch (fieldState.status) {
786+
// case 'REQUIRED_MISSING':
787+
// return 'Check Username with KBase';
788+
// case 'VALID':
789+
// return 'Username available';
790+
// case 'LOCAL_VALID':
791+
// return 'Check Username with KBase';
792+
// case 'REMOTE_VALIDATING':
793+
// return 'Checking for availability...';
794+
// case 'INVALID':
795+
// return 'Check Username with KBase';
796+
// }
797+
// return fieldState.status;
798+
// })();
799+
800+
801+
const control = html`
802+
<div style=${{display: 'flex', flexDirection: 'row'}}>
803+
<input type="text"
804+
style=${{flex: '1 1 0'}}
805+
className="form-control"
806+
id=${`signup_${fieldName}`}
807+
name=${fieldName}
808+
autocomplete="off"
809+
value=${fieldState.value}
810+
onInput=${(e) => {this.updateField(fieldName, e.target.value);}}
811+
/>
812+
<button type="button"
813+
style=${{flex: '0 0 auto'}}
814+
className="btn btn-primary"
815+
disabled=${fieldState.status !== 'LOCAL_VALID'}
816+
onClick=${onLookup}
817+
>
818+
Check for Availability
819+
</button>
820+
</div>
821+
`;
822+
return this.renderField(fieldName, control);
823+
}
824+
678825
renderDescriptionField() {
679826
const field = this.renderInputField('department');
680827
const info = '';

src/plugin/iframe_root/modules/reactComponents/SignUpView.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ define([
1111
'./SignUpForm',
1212
'./SignInOops',
1313
'./ContinueHeader',
14+
'./Alert',
1415
'kb_service/client/userProfile',
1516

1617
// For effect
@@ -29,6 +30,7 @@ define([
2930
SignUpForm,
3031
SignInOops,
3132
ContinueHeader,
33+
Alert,
3234
UserProfileService
3335
) => {
3436
const {Component} = preact;
@@ -439,7 +441,15 @@ define([
439441
</p>
440442
441443
<p style=${{maxWidth: '60em'}}>
442-
You may continue to <a href="/#auth2/login/continue?override-source=signin" target="_parent"><span className="fa fa-sign-in" /> Sign In</a> or <a href="#" onClick=${this.onCancelSignUp.bind(this)}><span className="fa fa-ban" /> cancel and try again</a>.
444+
You may continue to
445+
<${Alert} variant="info" type="inline" style=${{margin: '0 0.5rem'}}>
446+
<a href="/#auth2/login/continue?override-source=signin" target="_parent"><span className="fa fa-sign-in" /> Sign In</a>
447+
</>
448+
or
449+
<${Alert} variant="info" type="inline" style=${{marginLeft: '0.5rem'}}>
450+
<a href="#" onClick=${this.onCancelSignUp.bind(this)}><span className="fa fa-ban" /> cancel and try again</a>
451+
</>
452+
.
443453
</p>
444454
</div>
445455
`;

0 commit comments

Comments
 (0)