1- import { Card , Classes , Elevation , NonIdealState , Spinner , SpinnerSize } from '@blueprintjs/core' ;
1+ import {
2+ Button ,
3+ ButtonGroup ,
4+ Card ,
5+ Classes ,
6+ Elevation ,
7+ H4 ,
8+ Icon ,
9+ NonIdealState ,
10+ Spinner ,
11+ SpinnerSize
12+ } from '@blueprintjs/core' ;
13+ import { IconNames } from '@blueprintjs/icons' ;
214import classNames from 'classnames' ;
315import React , { useEffect } from 'react' ;
416import { useTranslation } from 'react-i18next' ;
517import { useDispatch } from 'react-redux' ;
618import { useLocation , useNavigate } from 'react-router' ;
719import SessionActions from 'src/commons/application/actions/SessionActions' ;
20+ import { Links } from 'src/commons/utils/Constants' ;
21+ import { useSession } from 'src/commons/utils/Hooks' ;
22+ import { useTypedSelector } from 'src/commons/utils/Hooks' ;
823import { parseQuery } from 'src/commons/utils/QueryHelper' ;
924import classes from 'src/styles/Login.module.scss' ;
1025
@@ -13,10 +28,32 @@ const LoginVscodeCallback: React.FC = () => {
1328 const dispatch = useDispatch ( ) ;
1429 const location = useLocation ( ) ;
1530 const { t } = useTranslation ( 'login' ) ;
16-
31+ const { isLoggedIn } = useSession ( ) ;
32+ const {
33+ code,
34+ provider : providerId ,
35+ 'client-request-id' : clientRequestId
36+ } = parseQuery ( location . search ) ;
37+ const isVscode = useTypedSelector ( state => state . vscode . isVscode ) ;
1738 const { access_token : accessToken , refresh_token : refreshToken } = parseQuery ( location . search ) ;
1839
40+ const launchVscode = ( ) => {
41+ window . location . href = `${ Links . vscode } /sso?code=${ code } &client-request-id=${ clientRequestId } ` ;
42+ } ;
43+
1944 useEffect ( ( ) => {
45+ if ( code ) {
46+ if ( ! isVscode ) {
47+ launchVscode ( ) ;
48+ } else {
49+ if ( isLoggedIn ) {
50+ return ;
51+ }
52+ // Fetch JWT tokens and user info from backend when auth provider code is present
53+ dispatch ( SessionActions . fetchAuth ( code , providerId ) ) ;
54+ }
55+ }
56+
2057 if ( accessToken && refreshToken ) {
2158 dispatch (
2259 SessionActions . setTokens ( {
@@ -27,10 +64,11 @@ const LoginVscodeCallback: React.FC = () => {
2764 dispatch ( SessionActions . fetchUserAndCourse ( ) ) ;
2865 navigate ( '/welcome' ) ;
2966 }
67+ // Only isVscode is expected to change in the lifecycle
3068 // eslint-disable-next-line react-hooks/exhaustive-deps
31- } , [ ] ) ;
69+ } , [ isVscode ] ) ;
3270
33- return (
71+ return isVscode ? (
3472 < div className = { classNames ( classes [ 'Login' ] , Classes . DARK ) } >
3573 < Card elevation = { Elevation . FOUR } >
3674 < div >
@@ -41,6 +79,30 @@ const LoginVscodeCallback: React.FC = () => {
4179 </ div >
4280 </ Card >
4381 </ div >
82+ ) : (
83+ < div className = { classNames ( classes [ 'Login' ] , Classes . DARK ) } >
84+ < Card elevation = { Elevation . FOUR } >
85+ < div >
86+ < div className = { classes [ 'login-header' ] } >
87+ < H4 >
88+ < Icon className = { classes [ 'login-icon' ] } icon = { IconNames . LOG_IN } />
89+ Sign in with SSO
90+ </ H4 >
91+ </ div >
92+ < p >
93+ Click < b > Open link</ b > on the dialog shown by your browser.
94+ </ p >
95+ < p > If you don't see a dialog, click the button below.</ p >
96+ < div >
97+ < ButtonGroup fill = { true } >
98+ < Button onClick = { launchVscode } className = { Classes . LARGE } >
99+ Launch VS Code extension
100+ </ Button >
101+ </ ButtonGroup >
102+ </ div >
103+ </ div >
104+ </ Card >
105+ </ div >
44106 ) ;
45107} ;
46108
0 commit comments