@@ -4,6 +4,9 @@ import { HttpError } from "../../common/http"
4
4
import { getSession , killSession } from "../api"
5
5
import { RequestError } from "../components/error"
6
6
7
+ /**
8
+ * An application's details (name and icon).
9
+ */
7
10
export const AppDetails : React . FunctionComponent < Application > = ( props ) => {
8
11
return (
9
12
< >
@@ -23,6 +26,9 @@ export interface AppRowProps {
23
26
open ( app : Application ) : void
24
27
}
25
28
29
+ /**
30
+ * A single application row. Can be killed if it's a running application.
31
+ */
26
32
export const AppRow : React . FunctionComponent < AppRowProps > = ( props ) => {
27
33
const [ killing , setKilling ] = React . useState < boolean > ( false )
28
34
const [ error , setError ] = React . useState < HttpError > ( )
@@ -65,6 +71,11 @@ export interface AppListProps {
65
71
onKilled ( app : Application ) : void
66
72
}
67
73
74
+ /**
75
+ * A list of applications. If undefined, show loading text. If empty, show a
76
+ * message saying no items are found. Applications can be clicked and killed
77
+ * (when applicable).
78
+ */
68
79
export const AppList : React . FunctionComponent < AppListProps > = ( props ) => {
69
80
return (
70
81
< div className = "app-list" >
@@ -92,11 +103,12 @@ export interface AppLoaderProps {
92
103
}
93
104
94
105
/**
95
- * Display provided applications or sessions and allow opening them.
106
+ * Application sections/groups. Handles loading of the application
107
+ * sections, errors, opening applications, and killing applications.
96
108
*/
97
109
export const AppLoader : React . FunctionComponent < AppLoaderProps > = ( props ) => {
98
110
const [ apps , setApps ] = React . useState < ReadonlyArray < ApplicationSection > > ( )
99
- const [ error , setError ] = React . useState < HttpError > ( )
111
+ const [ error , setError ] = React . useState < HttpError | Error > ( )
100
112
101
113
const refresh = ( ) : void => {
102
114
props
@@ -105,33 +117,51 @@ export const AppLoader: React.FunctionComponent<AppLoaderProps> = (props) => {
105
117
. catch ( ( e ) => setError ( e . message ) )
106
118
}
107
119
120
+ // Every time the component loads go ahead and refresh the list.
108
121
React . useEffect ( ( ) => {
109
122
refresh ( )
110
123
} , [ props ] )
111
124
125
+ /**
126
+ * Open an application if not already open. For executable applications create
127
+ * a session first.
128
+ */
112
129
function open ( app : Application ) : void {
130
+ if ( props . app && props . app . name === app . name ) {
131
+ return setError ( new Error ( `${ app . name } is already open` ) )
132
+ }
113
133
props . setApp ( app )
114
134
if ( ! isRunningApplication ( app ) && isExecutableApplication ( app ) ) {
115
135
getSession ( app )
116
136
. then ( ( session ) => {
117
137
props . setApp ( { ...app , ...session } )
118
138
} )
119
- . catch ( setError )
139
+ . catch ( ( error ) => {
140
+ props . setApp ( undefined )
141
+ setError ( error )
142
+ } )
120
143
}
121
144
}
122
145
146
+ // In the case of an error fetching the apps, have the ability to try again.
147
+ // In the case of failing to load an app, have the ability to go back to the
148
+ // list (where the user can try again if they wish).
123
149
if ( error ) {
124
- props . setApp ( undefined )
125
150
return (
126
151
< RequestError
127
152
error = { error }
153
+ onCloseText = { props . app ? "Go Back" : "Try Again" }
128
154
onClose = { ( ) : void => {
129
155
setError ( undefined )
156
+ if ( ! props . app ) {
157
+ refresh ( )
158
+ }
130
159
} }
131
160
/>
132
161
)
133
162
}
134
163
164
+ // If an app is currently loading, provide the option to cancel.
135
165
if ( props . app && ! props . app . loaded ) {
136
166
return (
137
167
< div className = "app-loader" >
@@ -151,14 +181,16 @@ export const AppLoader: React.FunctionComponent<AppLoaderProps> = (props) => {
151
181
)
152
182
}
153
183
184
+ // Apps are currently loading.
154
185
if ( ! apps ) {
155
186
return (
156
187
< div className = "app-loader" >
157
- < div className = "loader" > loading</ div >
188
+ < div className = "loader" > loading... </ div >
158
189
</ div >
159
190
)
160
191
}
161
192
193
+ // Apps have loaded.
162
194
return (
163
195
< >
164
196
{ apps . map ( ( section , i ) => (
0 commit comments