@@ -33,11 +33,18 @@ class AsyncView extends React.Component {
3333
3434 // XXX: cant call this getInitialState as React whines
3535 getDefaultState ( ) {
36- return {
37- data : null ,
36+ let endpoints = this . getEndpoints ( ) ;
37+ let state = {
38+ // has all data finished requesting?
3839 loading : true ,
39- error : false
40+ // is there an error loading ANY data?
41+ error : false ,
42+ errors : { }
4043 } ;
44+ endpoints . forEach ( ( [ stateKey , endpoint ] ) => {
45+ state [ stateKey ] = null ;
46+ } ) ;
47+ return state ;
4148 }
4249
4350 remountComponent ( ) {
@@ -46,41 +53,74 @@ class AsyncView extends React.Component {
4653
4754 // TODO(dcramer): we'd like to support multiple initial api requests
4855 fetchData ( ) {
49- let endpoint = this . getEndpoint ( ) ;
50- if ( ! endpoint ) {
56+ let endpoints = this . getEndpoints ( ) ;
57+ if ( ! endpoints . length ) {
5158 this . setState ( {
5259 loading : false ,
5360 error : false
5461 } ) ;
55- } else {
62+ return ;
63+ }
64+ // TODO(dcramer): this should cancel any existing API requests
65+ this . setState ( {
66+ loading : true ,
67+ error : false ,
68+ remainingRequests : endpoints . length
69+ } ) ;
70+ endpoints . forEach ( ( [ stateKey , endpoint , params ] ) => {
5671 this . api . request ( endpoint , {
5772 method : 'GET' ,
58- params : this . getEndpointParams ( ) ,
73+ params : params ,
5974 success : ( data , _ , jqXHR ) => {
60- this . setState ( {
61- loading : false ,
62- error : false ,
63- data : data
75+ this . setState ( prevState => {
76+ return {
77+ [ stateKey ] : data ,
78+ remainingRequests : prevState . remainingRequests - 1 ,
79+ loading : prevState . remainingRequests > 1
80+ } ;
6481 } ) ;
6582 } ,
6683 error : error => {
67- this . setState ( {
68- loading : false ,
69- error : error
84+ this . setState ( prevState => {
85+ return {
86+ [ stateKey ] : null ,
87+ errors : {
88+ ...prevState . errors ,
89+ [ stateKey ] : error
90+ } ,
91+ remainingRequests : prevState . remainingRequests - 1 ,
92+ loading : prevState . remainingRequests > 1 ,
93+ error : true
94+ } ;
7095 } ) ;
7196 }
7297 } ) ;
73- }
98+ } ) ;
7499 }
75100
101+ // DEPRECATED: use getEndpoints()
76102 getEndpointParams ( ) {
77103 return { } ;
78104 }
79105
106+ // DEPRECATED: use getEndpoints()
80107 getEndpoint ( ) {
81108 return null ;
82109 }
83110
111+ /**
112+ * Return a list of endpoint queries to make.
113+ *
114+ * return [
115+ * ['stateKeyName', '/endpoint/', {optional: 'query params'}]
116+ * ]
117+ */
118+ getEndpoints ( ) {
119+ let endpoint = this . getEndpoint ( ) ;
120+ if ( ! endpoint ) return [ ] ;
121+ return [ [ 'data' , endpoint , this . getEndpointParams ( ) ] ] ;
122+ }
123+
84124 getTitle ( ) {
85125 return 'Sentry' ;
86126 }
@@ -98,7 +138,9 @@ class AsyncView extends React.Component {
98138 < DocumentTitle title = { this . getTitle ( ) } >
99139 { this . state . loading
100140 ? this . renderLoading ( )
101- : this . state . error ? this . renderError ( this . state . error ) : this . renderBody ( ) }
141+ : this . state . error
142+ ? this . renderError ( new Error ( 'Unable to load all required endpoints' ) )
143+ : this . renderBody ( ) }
102144 </ DocumentTitle >
103145 ) ;
104146 }
0 commit comments