1
+ import { propertyIsDefined } from '@sourcegraph/codeintellify/lib/helpers'
1
2
import * as React from 'react'
2
- import { of , Subject , Subscription } from 'rxjs'
3
- import { catchError , map , switchMap , tap } from 'rxjs/operators'
3
+ import { Observable , of , Subject , Subscription } from 'rxjs'
4
+ import { catchError , filter , map , switchMap } from 'rxjs/operators'
4
5
import { getExtensionVersionSync } from '../../browser/runtime'
5
- import { ERAUTHREQUIRED , isErrorLike } from '../../shared/backend/errors '
6
- import { fetchSite } from '../../shared/backend/server '
7
- import { sourcegraphUrl } from '../../shared/util/context '
6
+ import { AccessToken , FeatureFlags } from '../../browser/types '
7
+ import { ERAUTHREQUIRED , ErrorLike , isErrorLike } from '../../shared/backend/errors '
8
+ import { GQL } from '../../types/gqlschema '
8
9
import { OptionsMenu , OptionsMenuProps } from './Menu'
9
10
import { ConnectionErrors } from './ServerURLForm'
10
- import { getConfigurableSettings , setConfigurabelSettings , setSourcegraphURL } from './settings'
11
+
12
+ export interface OptionsContainerProps {
13
+ sourcegraphURL : string
14
+
15
+ fetchSite : ( url : string ) => Observable < void >
16
+ fetchCurrentUser : ( useToken : boolean ) => Observable < GQL . IUser | undefined >
17
+
18
+ setSourcegraphURL : ( url : string ) => void
19
+ getConfigurableSettings : ( ) => Observable < Partial < FeatureFlags > >
20
+ setConfigurableSettings : ( settings : Observable < Partial < FeatureFlags > > ) => Observable < Partial < FeatureFlags > >
21
+
22
+ createAccessToken : ( url : string ) => Observable < AccessToken >
23
+ getAccessToken : ( url : string ) => Observable < AccessToken | undefined >
24
+ setAccessToken : ( url : string ) => ( tokens : Observable < AccessToken > ) => Observable < AccessToken >
25
+ fetchAccessTokenIDs : ( url : string ) => Observable < Pick < AccessToken , 'id' > [ ] >
26
+ }
11
27
12
28
interface OptionsContainerState
13
29
extends Pick <
14
30
OptionsMenuProps ,
15
31
'isSettingsOpen' | 'status' | 'sourcegraphURL' | 'settings' | 'settingsHaveChanged' | 'connectionError'
16
32
> { }
17
33
18
- export class OptionsContainer extends React . Component < { } , OptionsContainerState > {
19
- public state : OptionsContainerState = {
20
- status : 'connecting' ,
21
- sourcegraphURL : sourcegraphUrl ,
22
- isSettingsOpen : false ,
23
- settingsHaveChanged : false ,
24
- settings : { } ,
25
- }
26
-
34
+ export class OptionsContainer extends React . Component < OptionsContainerProps , OptionsContainerState > {
27
35
private version = getExtensionVersionSync ( )
28
36
29
37
private urlUpdates = new Subject < string > ( )
30
38
private settingsSaves = new Subject < any > ( )
31
39
32
40
private subscriptions = new Subscription ( )
33
41
34
- constructor ( props : { } ) {
42
+ constructor ( props : OptionsContainerProps ) {
35
43
super ( props )
36
44
45
+ this . state = {
46
+ status : 'connecting' ,
47
+ sourcegraphURL : props . sourcegraphURL ,
48
+ isSettingsOpen : false ,
49
+ settingsHaveChanged : false ,
50
+ settings : { } ,
51
+ connectionError : undefined ,
52
+ }
53
+
54
+ const fetchingSite : Observable < string | ErrorLike > = this . urlUpdates . pipe (
55
+ switchMap ( url => this . props . fetchSite ( url ) . pipe ( map ( ( ) => url ) ) ) ,
56
+ catchError ( err => of ( err ) )
57
+ )
58
+
37
59
this . subscriptions . add (
38
- this . urlUpdates
60
+ fetchingSite . subscribe ( res => {
61
+ let url = ''
62
+
63
+ if ( isErrorLike ( res ) ) {
64
+ this . setState ( {
65
+ status : 'error' ,
66
+ connectionError :
67
+ res . code === ERAUTHREQUIRED ? ConnectionErrors . AuthError : ConnectionErrors . UnableToConnect ,
68
+ } )
69
+ url = this . state . sourcegraphURL
70
+ } else {
71
+ this . setState ( { status : 'connected' } )
72
+ url = res
73
+ }
74
+
75
+ props . setSourcegraphURL ( url )
76
+ } )
77
+ )
78
+
79
+ this . subscriptions . add (
80
+ // Ensure the site is valid.
81
+ fetchingSite
39
82
. pipe (
40
- tap ( a => {
41
- console . log ( 'a' , a )
42
- } ) ,
43
- switchMap ( url => fetchSite ( url ) . pipe ( map ( ( ) => url ) ) ) ,
44
- catchError ( err => of ( err ) )
83
+ filter ( urlOrError => ! isErrorLike ( urlOrError ) ) ,
84
+ map ( urlOrError => urlOrError as string ) ,
85
+ // Get the access token for this server if we have it.
86
+ switchMap ( url => this . props . getAccessToken ( url ) . pipe ( map ( token => ( { token, url } ) ) ) ) ,
87
+ switchMap ( ( { url, token } ) =>
88
+ this . props . fetchCurrentUser ( false ) . pipe ( map ( user => ( { user, token, url } ) ) )
89
+ ) ,
90
+ filter ( propertyIsDefined ( 'user' ) ) ,
91
+ // Get the IDs for all access tokens for the user.
92
+ switchMap ( ( { token, user, url } ) =>
93
+ this . props
94
+ . fetchAccessTokenIDs ( user . id )
95
+ . pipe ( map ( usersTokenIDs => ( { usersTokenIDs, user, token, url } ) ) )
96
+ ) ,
97
+ // Make sure the token still exists on the server. If it
98
+ // does exits, use it, otherwise create a new one.
99
+ switchMap ( ( { user, token, usersTokenIDs, url } ) => {
100
+ const tokenExists = token && usersTokenIDs . map ( ( { id } ) => id ) . includes ( token . id )
101
+
102
+ return token && tokenExists
103
+ ? of ( token )
104
+ : this . props . createAccessToken ( user . id ) . pipe ( this . props . setAccessToken ( url ) )
105
+ } )
45
106
)
46
- . subscribe ( res => {
47
- let url = ''
48
-
49
- if ( isErrorLike ( res ) ) {
50
- this . setState ( {
51
- status : 'error' ,
52
- connectionError :
53
- res . code === ERAUTHREQUIRED
54
- ? ConnectionErrors . AuthError
55
- : ConnectionErrors . UnableToConnect ,
56
- } )
57
- url = this . state . sourcegraphURL
58
- } else {
59
- this . setState ( { status : 'connected' } )
60
- url = res
61
- }
62
-
63
- console . log ( res , url )
64
-
65
- setSourcegraphURL ( url )
107
+ . subscribe ( ( ) => {
108
+ // We don't need to do anything with the token now. We just
109
+ // needed to ensure we had one saved.
66
110
} )
67
111
)
68
112
69
113
this . subscriptions . add (
70
- this . settingsSaves . pipe ( switchMap ( settings => setConfigurabelSettings ( settings ) ) ) . subscribe ( settings => {
71
- this . setState ( {
72
- settings,
73
- settingsHaveChanged : false ,
114
+ this . settingsSaves
115
+ . pipe ( switchMap ( settings => props . setConfigurableSettings ( settings ) ) )
116
+ . subscribe ( settings => {
117
+ this . setState ( {
118
+ settings,
119
+ settingsHaveChanged : false ,
120
+ } )
74
121
} )
75
- } )
76
122
)
77
123
}
78
124
79
125
public componentDidMount ( ) : void {
80
- getConfigurableSettings ( ) . subscribe ( settings => {
126
+ this . props . getConfigurableSettings ( ) . subscribe ( settings => {
81
127
this . setState ( { settings } )
82
128
} )
83
129
84
- console . log ( 'next url' )
85
130
this . urlUpdates . next ( this . state . sourcegraphURL )
86
131
}
87
132
@@ -108,7 +153,6 @@ export class OptionsContainer extends React.Component<{}, OptionsContainerState>
108
153
}
109
154
110
155
private handleURLSubmit = ( ) => {
111
- console . log ( 'submitted' , this . state . sourcegraphURL )
112
156
this . urlUpdates . next ( this . state . sourcegraphURL )
113
157
}
114
158
0 commit comments