1
1
import React from "react" ;
2
2
import { useParams } from "react-router-dom" ;
3
- import {
4
- Spin ,
5
- Typography ,
6
- Card ,
7
- Row ,
8
- Col ,
9
- Tag ,
10
- Tabs ,
11
- Alert ,
12
- Descriptions ,
3
+ import {
4
+ Spin ,
5
+ Typography ,
6
+ Card ,
7
+ Row ,
8
+ Col ,
9
+ Tag ,
10
+ Tabs ,
11
+ Alert ,
12
+ Descriptions ,
13
13
Button ,
14
- Statistic
14
+ Statistic ,
15
+ Divider ,
15
16
} from "antd" ;
16
- import {
17
- ReloadOutlined ,
18
- LinkOutlined ,
19
- ClusterOutlined ,
20
- TeamOutlined ,
21
- UserOutlined
17
+ import {
18
+ ReloadOutlined ,
19
+ LinkOutlined ,
20
+ ClusterOutlined ,
21
+ TeamOutlined ,
22
+ UserOutlined ,
23
+ SyncOutlined ,
22
24
} from "@ant-design/icons" ;
23
- import { useEnvironmentDetail } from './hooks/useEnvironmentDetail' ;
25
+ import { useEnvironmentDetail } from "./hooks/useEnvironmentDetail" ;
26
+ import WorkspacesList from "./components/WorkspacesList" ;
24
27
25
28
const { Title, Text } = Typography ;
26
29
const { TabPane } = Tabs ;
@@ -32,19 +35,37 @@ const { TabPane } = Tabs;
32
35
const EnvironmentDetail : React . FC = ( ) => {
33
36
// Get environment ID from URL params
34
37
const { environmentId : id } = useParams < { environmentId : string } > ( ) ;
35
-
38
+
39
+ // Use the custom hook to handle data fetching and state management
36
40
// Use the custom hook to handle data fetching and state management
37
- const { environment, loading, error, refresh } = useEnvironmentDetail ( id ) ;
38
-
41
+ const {
42
+ environment,
43
+ loading,
44
+ error,
45
+ refresh,
46
+ workspaces,
47
+ workspacesLoading,
48
+ workspacesError,
49
+ refreshWorkspaces,
50
+ workspaceStats,
51
+ } = useEnvironmentDetail ( id ) ;
39
52
// If loading, show spinner
40
53
if ( loading ) {
41
54
return (
42
- < div style = { { display : 'flex' , justifyContent : 'center' , alignItems : 'center' , height : '100%' , padding : '50px' } } >
55
+ < div
56
+ style = { {
57
+ display : "flex" ,
58
+ justifyContent : "center" ,
59
+ alignItems : "center" ,
60
+ height : "100%" ,
61
+ padding : "50px" ,
62
+ } }
63
+ >
43
64
< Spin size = "large" tip = "Loading environment details..." />
44
65
</ div >
45
66
) ;
46
67
}
47
-
68
+
48
69
// If error, show error message
49
70
if ( error ) {
50
71
return (
@@ -53,7 +74,7 @@ const EnvironmentDetail: React.FC = () => {
53
74
description = { error }
54
75
type = "error"
55
76
showIcon
56
- style = { { margin : ' 24px' } }
77
+ style = { { margin : " 24px" } }
57
78
action = {
58
79
< Button type = "primary" icon = { < ReloadOutlined /> } onClick = { refresh } >
59
80
Try Again
@@ -62,7 +83,7 @@ const EnvironmentDetail: React.FC = () => {
62
83
/>
63
84
) ;
64
85
}
65
-
86
+
66
87
// If no environment data, show message
67
88
if ( ! environment ) {
68
89
return (
@@ -71,122 +92,219 @@ const EnvironmentDetail: React.FC = () => {
71
92
description = "The requested environment could not be found"
72
93
type = "warning"
73
94
showIcon
74
- style = { { margin : ' 24px' } }
95
+ style = { { margin : " 24px" } }
75
96
/>
76
97
) ;
77
98
}
78
-
99
+
79
100
return (
80
- < div className = "environment-detail-container" style = { { padding : ' 24px' } } >
101
+ < div className = "environment-detail-container" style = { { padding : " 24px" } } >
81
102
{ /* Header with environment name and controls */ }
82
- < div className = "environment-header" style = { { marginBottom : '24px' , display : 'flex' , justifyContent : 'space-between' , alignItems : 'center' } } >
103
+ < div
104
+ className = "environment-header"
105
+ style = { {
106
+ marginBottom : "24px" ,
107
+ display : "flex" ,
108
+ justifyContent : "space-between" ,
109
+ alignItems : "center" ,
110
+ } }
111
+ >
83
112
< div >
84
- < Title level = { 3 } > { environment . environmentName || 'Unnamed Environment' } </ Title >
113
+ < Title level = { 3 } >
114
+ { environment . environmentName || "Unnamed Environment" }
115
+ </ Title >
85
116
< Text type = "secondary" > ID: { environment . environmentId } </ Text >
86
117
</ div >
87
- < Button
88
- icon = { < ReloadOutlined /> }
89
- onClick = { refresh }
90
- >
118
+ < Button icon = { < ReloadOutlined /> } onClick = { refresh } >
91
119
Refresh
92
120
</ Button >
93
121
</ div >
94
-
122
+
95
123
{ /* Basic Environment Information Card */ }
96
- < Card
97
- title = "Environment Overview"
98
- style = { { marginBottom : ' 24px' } }
124
+ < Card
125
+ title = "Environment Overview"
126
+ style = { { marginBottom : " 24px" } }
99
127
extra = { environment . isMaster && < Tag color = "green" > Master</ Tag > }
100
128
>
101
- < Descriptions bordered column = { { xxl : 4 , xl : 3 , lg : 3 , md : 2 , sm : 1 , xs : 1 } } >
129
+ < Descriptions
130
+ bordered
131
+ column = { { xxl : 4 , xl : 3 , lg : 3 , md : 2 , sm : 1 , xs : 1 } }
132
+ >
102
133
< Descriptions . Item label = "Domain" >
103
134
{ environment . environmentFrontendUrl ? (
104
- < a href = { environment . environmentFrontendUrl } target = "_blank" rel = "noopener noreferrer" >
135
+ < a
136
+ href = { environment . environmentFrontendUrl }
137
+ target = "_blank"
138
+ rel = "noopener noreferrer"
139
+ >
105
140
{ environment . environmentFrontendUrl } < LinkOutlined />
106
141
</ a >
107
142
) : (
108
- ' No domain set'
143
+ " No domain set"
109
144
) }
110
145
</ Descriptions . Item >
111
146
< Descriptions . Item label = "Environment Type" >
112
- < Tag color = { environment . environmentType === 'production' ? 'red' : environment . environmentType === 'testing' ? 'orange' : 'blue' } >
147
+ < Tag
148
+ color = {
149
+ environment . environmentType === "production"
150
+ ? "red"
151
+ : environment . environmentType === "testing"
152
+ ? "orange"
153
+ : "blue"
154
+ }
155
+ >
113
156
{ environment . environmentType }
114
157
</ Tag >
115
158
</ Descriptions . Item >
116
159
< Descriptions . Item label = "API Key Status" >
117
- { environment . environmentApikey ? < Tag color = "green" > Configured</ Tag > : < Tag color = "red" > Not Configured</ Tag > }
160
+ { environment . environmentApikey ? (
161
+ < Tag color = "green" > Configured</ Tag >
162
+ ) : (
163
+ < Tag color = "red" > Not Configured</ Tag >
164
+ ) }
118
165
</ Descriptions . Item >
119
166
< Descriptions . Item label = "Master Environment" >
120
- { environment . isMaster ? ' Yes' : 'No' }
167
+ { environment . isMaster ? " Yes" : "No" }
121
168
</ Descriptions . Item >
122
169
</ Descriptions >
123
170
</ Card >
124
-
171
+
125
172
{ /* Tabs for Workspaces and User Groups */ }
126
173
< Tabs defaultActiveKey = "workspaces" >
127
- < TabPane
128
- tab = { < span > < ClusterOutlined /> Workspaces</ span > }
174
+ < TabPane
175
+ tab = {
176
+ < span >
177
+ < ClusterOutlined /> Workspaces
178
+ </ span >
179
+ }
129
180
key = "workspaces"
130
181
>
131
182
< Card >
132
- { /* Placeholder for workspace statistics */ }
133
- < Row gutter = { 16 } style = { { marginBottom : '24px' } } >
183
+ { /* Header with refresh button */ }
184
+ < div
185
+ style = { {
186
+ display : "flex" ,
187
+ justifyContent : "space-between" ,
188
+ alignItems : "center" ,
189
+ marginBottom : "16px" ,
190
+ } }
191
+ >
192
+ < Title level = { 5 } > Workspaces in this Environment</ Title >
193
+ < Button
194
+ icon = { < SyncOutlined /> }
195
+ onClick = { refreshWorkspaces }
196
+ size = "small"
197
+ loading = { workspacesLoading }
198
+ >
199
+ Refresh Workspaces
200
+ </ Button >
201
+ </ div >
202
+
203
+ { /* Workspace Statistics */ }
204
+ < Row gutter = { 16 } style = { { marginBottom : "24px" } } >
134
205
< Col span = { 8 } >
135
- < Statistic
136
- title = "Total Workspaces"
137
- value = { 0 }
138
- prefix = { < ClusterOutlined /> }
206
+ < Statistic
207
+ title = "Total Workspaces"
208
+ value = { workspaceStats . total }
209
+ prefix = { < ClusterOutlined /> }
139
210
/>
140
211
</ Col >
141
212
< Col span = { 8 } >
142
- < Statistic
143
- title = "Managed Workspaces"
144
- value = { 0 }
145
- prefix = { < ClusterOutlined /> }
213
+ < Statistic
214
+ title = "Managed Workspaces"
215
+ value = { workspaceStats . managed }
216
+ prefix = { < ClusterOutlined /> }
146
217
/>
147
218
</ Col >
148
219
< Col span = { 8 } >
149
- < Statistic
150
- title = "Unmanaged Workspaces"
151
- value = { 0 }
152
- prefix = { < ClusterOutlined /> }
220
+ < Statistic
221
+ title = "Unmanaged Workspaces"
222
+ value = { workspaceStats . unmanaged }
223
+ prefix = { < ClusterOutlined /> }
153
224
/>
154
225
</ Col >
155
226
</ Row >
156
-
157
- { /* Placeholder for workspace list */ }
158
- < Alert
159
- message = "Workspace Information"
160
- description = "Workspace data will be implemented in the next phase. This section will display workspace details and management options."
161
- type = "info"
162
- showIcon
227
+
228
+ < Divider style = { { margin : "16px 0" } } />
229
+
230
+ { /* Show error if workspace loading failed */ }
231
+ { workspacesError && (
232
+ < Alert
233
+ message = "Error loading workspaces"
234
+ description = { workspacesError }
235
+ type = "error"
236
+ showIcon
237
+ style = { { marginBottom : "16px" } }
238
+ action = {
239
+ workspacesError . includes ( "No API key configured" ) ? (
240
+ < Button size = "small" type = "primary" disabled >
241
+ API Key Required
242
+ </ Button >
243
+ ) : (
244
+ < Button
245
+ size = "small"
246
+ type = "primary"
247
+ onClick = { refreshWorkspaces }
248
+ >
249
+ Try Again
250
+ </ Button >
251
+ )
252
+ }
253
+ />
254
+ ) }
255
+
256
+ { ( ! environment . environmentApikey ||
257
+ ! environment . environmentApiServiceUrl ) &&
258
+ ! workspacesError && (
259
+ < Alert
260
+ message = "Configuration Issue"
261
+ description = {
262
+ ! environment . environmentApikey
263
+ ? "An API key is required to fetch workspaces for this environment."
264
+ : "An API service URL is required to fetch workspaces for this environment."
265
+ }
266
+ type = "warning"
267
+ showIcon
268
+ style = { { marginBottom : "16px" } }
269
+ />
270
+ ) }
271
+
272
+ { /* Workspaces List */ }
273
+ < WorkspacesList
274
+ workspaces = { workspaces }
275
+ loading = { workspacesLoading && ! workspacesError }
276
+ error = { workspacesError }
163
277
/>
164
278
</ Card >
165
279
</ TabPane >
166
-
167
- < TabPane
168
- tab = { < span > < TeamOutlined /> User Groups</ span > }
280
+
281
+ < TabPane
282
+ tab = {
283
+ < span >
284
+ < TeamOutlined /> User Groups
285
+ </ span >
286
+ }
169
287
key = "userGroups"
170
288
>
171
289
< Card >
172
290
{ /* Placeholder for user group statistics */ }
173
- < Row gutter = { 16 } style = { { marginBottom : ' 24px' } } >
291
+ < Row gutter = { 16 } style = { { marginBottom : " 24px" } } >
174
292
< Col span = { 8 } >
175
- < Statistic
176
- title = "Total User Groups"
177
- value = { 0 }
178
- prefix = { < TeamOutlined /> }
293
+ < Statistic
294
+ title = "Total User Groups"
295
+ value = { 0 }
296
+ prefix = { < TeamOutlined /> }
179
297
/>
180
298
</ Col >
181
299
< Col span = { 8 } >
182
- < Statistic
183
- title = "Total Users"
184
- value = { 0 }
185
- prefix = { < UserOutlined /> }
300
+ < Statistic
301
+ title = "Total Users"
302
+ value = { 0 }
303
+ prefix = { < UserOutlined /> }
186
304
/>
187
305
</ Col >
188
306
</ Row >
189
-
307
+
190
308
{ /* Placeholder for user group list */ }
191
309
< Alert
192
310
message = "User Group Information"
0 commit comments