77 body {
88 background-color : # 1a202c ;
99 color : # e2e8f0 ;
10- font-family : Arial , sans-serif;
10+ font-family : 'Segoe UI' , Tahoma , Geneva , Verdana , sans-serif;
1111 }
1212 .container {
1313 max-width : 800px ;
2020 padding : 20px ;
2121 border-radius : 8px ;
2222 margin-bottom : 20px ;
23+ box-shadow : 0 4px 6px rgba (0 , 0 , 0 , 0.1 );
24+ transition : transform 0.3s ease, box-shadow 0.3s ease;
25+ }
26+ .network-card : hover {
27+ transform : translateY (-5px );
28+ box-shadow : 0 6px 10px rgba (0 , 0 , 0 , 0.15 );
2329 }
2430 .network-title {
2531 font-size : 24px ;
2632 font-weight : bold;
2733 margin-bottom : 10px ;
34+ color : # 63b3ed ;
35+ }
36+ .network-token {
37+ font-size : 14px ;
38+ font-style : italic;
39+ color : # cbd5e0 ;
40+ margin-bottom : 10px ;
41+ word-break : break-word; /* Breaks words to prevent overflow */
42+ overflow-wrap : break-word; /* Ensures long strings break */
43+ white-space : pre-wrap; /* Preserves whitespace for breaking */
2844 }
2945 .cluster {
3046 margin-top : 10px ;
3147 background-color : # 4a5568 ;
3248 padding : 10px ;
3349 border-radius : 6px ;
50+ transition : background-color 0.3s ease;
51+ }
52+ .cluster : hover {
53+ background-color : # 5a6b78 ;
3454 }
3555 .cluster-title {
3656 font-size : 18px ;
3757 font-weight : bold;
58+ color : # e2e8f0 ;
3859 }
3960 .form-container {
4061 background-color : # 2d3748 ;
4162 padding : 20px ;
4263 border-radius : 8px ;
4364 margin-bottom : 20px ;
65+ box-shadow : 0 4px 6px rgba (0 , 0 , 0 , 0.1 );
4466 }
4567 .form-control {
46- margin-bottom : 10 px ;
68+ margin-bottom : 15 px ;
4769 }
4870 label {
4971 display : block;
5072 margin-bottom : 5px ;
5173 font-weight : bold;
5274 }
53- input [type = "text" ], textarea {
75+ input [type = "text" ],
76+ textarea {
5477 width : 100% ;
55- padding : 8 px ;
78+ padding : 10 px ;
5679 border-radius : 4px ;
57- border : none ;
58- background-color : # 4a5568 ;
80+ border : 1 px solid # 4a5568 ;
81+ background-color : # 3a4250 ;
5982 color : # e2e8f0 ;
83+ transition : border-color 0.3s ease, background-color 0.3s ease;
84+ }
85+ input [type = "text" ]: focus ,
86+ textarea : focus {
87+ border-color : # 63b3ed ;
88+ background-color : # 4a5568 ;
6089 }
6190 button {
6291 background-color : # 3182ce ;
6392 color : # e2e8f0 ;
64- padding : 10px 15 px ;
93+ padding : 10px 20 px ;
6594 border : none;
6695 border-radius : 4px ;
6796 cursor : pointer;
6897 transition : background-color 0.3s ease;
6998 }
70- button : hover {
71- background-color : # 63b3ed ;
72- }
73- .toggle-button {
74- position : absolute;
75- top : 20px ;
76- right : 20px ;
77- background-color : # e53e3e ;
78- }
7999 .error {
80100 color : # e53e3e ;
81101 margin-top : 5px ;
84104 color : # 38a169 ;
85105 margin-top : 5px ;
86106 }
107+ /* Spinner Styles */
108+ .spinner {
109+ display : inline-block;
110+ width : 50px ;
111+ height : 50px ;
112+ border : 5px solid rgba (255 , 255 , 255 , 0.2 );
113+ border-radius : 50% ;
114+ border-top-color : # 3182ce ;
115+ animation : spin 1s linear infinite;
116+ margin : 0 auto;
117+ }
118+
119+ @keyframes spin {
120+ to { transform : rotate (360deg ); }
121+ }
122+
123+ /* Center the loading text and spinner */
124+ .loading-container {
125+ text-align : center;
126+ padding : 50px ;
127+ }
128+ .warning-box {
129+ border-radius : 5px ;
130+ }
131+ .warning-box i {
132+ margin-right : 10px ;
133+ }
87134</ style >
135+
88136< body class ="bg-gray-900 text-gray-200 ">
89137 < div class ="flex flex-col min-h-screen " x-data ="networkClusters() " x-init ="init() ">
90138 {{template "views/partials/navbar_explorer" .}}
91139
92140 < header class ="text-center py-12 ">
93- < h1 class ="text-5xl font-bold text-gray-100 "> Network Clusters</ h1 >
141+ < h1 class ="text-5xl font-bold text-gray-100 "> Network Clusters Explorer </ h1 >
94142 < p class ="mt-4 text-lg "> View the clusters and workers available in each network.</ p >
95143 </ header >
96144
97145 < div class ="container mx-auto px-4 flex-grow ">
146+ <!-- Warning Box -->
147+ < div class ="warning-box bg-yellow-500 mb-20 pt-5 pb-5 pr-5 pl-5 text-lg ">
148+ < i class ="fa-solid fa-triangle-exclamation "> </ i >
149+ This application is provided without any warranty. Use it at your own risk. We are not responsible for any potential harm or misuse. Be aware that malicious actors might attempt to compromise your systems. Although the community will address bugs, this is experimental software and may be insecure to deploy on your hardware unless you take all necessary precautions.
150+ </ div >
151+ < div class ="flow-root ">
152+ <!-- Toggle button for showing/hiding the form -->
153+ < button class ="bg-red-600 hover:bg-blue-600 float-right mb-2 flex items-center px-4 py-2 rounded " @click ="toggleForm() ">
154+ <!-- Conditional icon display -->
155+ < i :class ="showForm ? 'fa-solid fa-times' : 'fa-solid fa-plus' " class ="mr-2 "> </ i >
156+ < span x-text ="showForm ? 'Close' : 'Add New Network' "> </ span >
157+ </ button >
158+ </ div >
159+ <!-- Form for adding a new network -->
160+ < div class ="form-container " x-show ="showForm " @click.outside ="showForm = false ">
161+ < h2 class ="text-3xl font-bold mb-4 "> < i class ="fa-solid fa-plus "> </ i > Add New Network</ h2 >
162+ < div class ="form-control ">
163+ < label for ="name "> Network Name</ label >
164+ < input type ="text " id ="name " x-model ="newNetwork.name " placeholder ="Enter network name " />
165+ </ div >
166+ < div class ="form-control ">
167+ < label for ="description "> Description</ label >
168+ < textarea id ="description " x-model ="newNetwork.description " placeholder ="Enter description "> </ textarea >
169+ </ div >
170+ < div class ="form-control ">
171+ < label for ="token "> Token</ label >
172+ < textarea id ="token " x-model ="newNetwork.token " placeholder ="Enter token "> </ textarea >
173+ </ div >
174+ < button @click ="addNetwork "> < i class ="fa-solid fa-plus "> </ i > Add Network</ button >
175+ < template x-if ="errorMessage ">
176+ < p class ="error " x-text ="errorMessage "> </ p >
177+ </ template >
178+ < template x-if ="successMessage ">
179+ < p class ="success " x-text ="successMessage "> </ p >
180+ </ template >
181+ </ div >
182+
183+ <!-- Loading Spinner -->
184+ < template x-if ="networks.length === 0 && !loadingComplete ">
185+ < div class ="loading-container ">
186+ < div class ="spinner "> </ div >
187+ < p class ="text-center mt-4 "> Loading networks...</ p >
188+ </ div >
189+ </ template >
98190
99- <!-- Toggle button for showing/hiding the form -->
100- < button class ="toggle-button " @click ="toggleForm() " x-text ="showForm ? 'Close' : 'Add New Network' "> </ button >
101-
102- <!-- Form for adding a new network -->
103- < div class ="form-container " x-show ="showForm " @click.outside ="showForm = false ">
104- < h2 class ="text-3xl font-bold mb-4 "> Add New Network</ h2 >
105- < div class ="form-control ">
106- < label for ="name "> Network Name</ label >
107- < input type ="text " id ="name " x-model ="newNetwork.name " placeholder ="Enter network name " />
108- </ div >
109- < div class ="form-control ">
110- < label for ="description "> Description</ label >
111- < textarea id ="description " x-model ="newNetwork.description " placeholder ="Enter description "> </ textarea >
112- </ div >
113- < div class ="form-control ">
114- < label for ="token "> Token</ label >
115- < textarea id ="token " x-model ="newNetwork.token " placeholder ="Enter token "> </ textarea >
116- </ div >
117- < button @click ="addNetwork "> Add Network</ button >
118- < template x-if ="errorMessage ">
119- < p class ="error " x-text ="errorMessage "> </ p >
120- </ template >
121- < template x-if ="successMessage ">
122- < p class ="success " x-text ="successMessage "> </ p >
123- </ template >
124- </ div >
125-
126- < template x-if ="networks.length === 0 ">
127- < p class ="text-center "> Loading networks...</ p >
191+ < template x-if ="networks.length === 0 && loadingComplete ">
192+ < div class ="loading-container ">
193+ < p class ="text-center mt-4 "> No networks available with online workers</ p >
194+ </ div >
128195 </ template >
129-
196+
197+ <!-- Display Networks -->
130198 < template x-for ="network in networks " :key ="network.name ">
131199 < div class ="network-card ">
132200 < div class ="network-title " x-text ="network.name "> </ div >
133- < div class ="network-token " x-text ="network.token "> </ div >
201+ < div class ="network-token " x-text ="'Token: ' + network.token "> </ div >
134202 < p x-text ="network.description "> </ p >
135-
203+
136204 < template x-for ="cluster in network.Clusters " :key ="cluster.NetworkID + cluster.Type ">
137205 < div class ="cluster ">
138206 < div class ="cluster-title " x-text ="'Cluster Type: ' + cluster.Type "> </ div >
@@ -155,6 +223,7 @@ <h2 class="text-3xl font-bold mb-4">Add New Network</h2>
155223 errorMessage : '' ,
156224 successMessage : '' ,
157225 showForm : false , // Form visibility state
226+ loadingComplete : false , // To track if loading is complete
158227 toggleForm ( ) {
159228 this . showForm = ! this . showForm ;
160229 console . log ( 'Toggling form:' , this . showForm ) ;
@@ -166,51 +235,53 @@ <h2 class="text-3xl font-bold mb-4">Add New Network</h2>
166235 . then ( data => {
167236 console . log ( 'Data fetched successfully:' , data ) ;
168237 this . networks = data ;
238+ this . loadingComplete = true ; // Set loading complete
169239 } )
170240 . catch ( error => {
171241 console . error ( 'Error fetching networks:' , error ) ;
242+ this . loadingComplete = true ; // Ensure spinner is hidden if error occurs
172243 } ) ;
173244 } ,
174-
245+
175246 addNetwork ( ) {
176247 this . errorMessage = '' ;
177248 this . successMessage = '' ;
178249 console . log ( 'Adding new network:' , this . newNetwork ) ;
179-
250+
180251 // Validate input
181252 if ( ! this . newNetwork . name || ! this . newNetwork . description || ! this . newNetwork . token ) {
182253 this . errorMessage = 'All fields are required.' ;
183254 return ;
184255 }
185-
256+
186257 fetch ( '/network/add' , {
187258 method : 'POST' ,
188259 headers : {
189260 'Content-Type' : 'application/json'
190261 } ,
191262 body : JSON . stringify ( this . newNetwork )
192263 } )
193- . then ( response => {
194- if ( ! response . ok ) {
195- return response . json ( ) . then ( err => { throw err ; } ) ;
196- }
197- return response . json ( ) ;
198- } )
199- . then ( data => {
200- console . log ( 'Network added successfully:' , data ) ;
201- this . successMessage = 'Network added successfully!' ;
202- this . fetchNetworks ( ) ; // Refresh the networks list
203- this . newNetwork = { name : '' , description : '' , token : '' } ; // Clear form
204- } )
205- . catch ( error => {
206- console . error ( 'Error adding network:' , error ) ;
207- this . errorMessage = 'Failed to add network. Please try again.'
208- if ( error . error ) {
209- this . errorMessage += " Error : " + error . error ;
210- }
211- } ) ;
264+ . then ( response => {
265+ if ( ! response . ok ) {
266+ return response . json ( ) . then ( err => { throw err ; } ) ;
267+ }
268+ return response . json ( ) ;
269+ } )
270+ . then ( data => {
271+ console . log ( 'Network added successfully:' , data ) ;
272+ this . successMessage = 'Network added successfully!' ;
273+ this . fetchNetworks ( ) ; // Refresh the networks list
274+ this . newNetwork = { name : '' , description : '' , token : '' } ; // Clear form
275+ } )
276+ . catch ( error => {
277+ console . error ( 'Error adding network:' , error ) ;
278+ this . errorMessage = 'Failed to add network. Please try again.'
279+ if ( error . error ) {
280+ this . errorMessage += " Error : " + error . error ;
281+ }
282+ } ) ;
212283 } ,
213-
284+
214285 init ( ) {
215286 console . log ( 'Initializing Alpine component...' ) ;
216287 this . fetchNetworks ( ) ;
@@ -222,8 +293,9 @@ <h2 class="text-3xl font-bold mb-4">Add New Network</h2>
222293 }
223294 </ script >
224295
225- {{template "views/partials/footer" .}}
226- </ div >
296+ {{template "views/partials/footer" .}}
297+ </ div >
227298
228299</ body >
300+
229301</ html >
0 commit comments