feat(Tracer Bullet)
This commit is contained in:
@@ -1,36 +1,173 @@
|
||||
package at.mocode.client.web
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import at.mocode.client.common.BaseApp
|
||||
import androidx.compose.runtime.*
|
||||
import org.jetbrains.compose.web.dom.*
|
||||
import org.jetbrains.compose.web.css.*
|
||||
import kotlinx.coroutines.launch
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
@Serializable
|
||||
data class PingResponse(val status: String)
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun App() {
|
||||
BaseApp {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text("Meldestelle - Reitersport Management") }
|
||||
)
|
||||
var responseStatus by remember { mutableStateOf<String?>(null) }
|
||||
var isLoading by remember { mutableStateOf(false) }
|
||||
var errorMessage by remember { mutableStateOf<String?>(null) }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val httpClient = remember {
|
||||
HttpClient {
|
||||
install(ContentNegotiation) {
|
||||
json(Json { ignoreUnknownKeys = true })
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier.padding(paddingValues).fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
// Placeholder content
|
||||
Text("Welcome to Meldestelle - Reitersport Management")
|
||||
Text("This is a desktop application for managing equestrian events")
|
||||
}
|
||||
}
|
||||
|
||||
Div({
|
||||
style {
|
||||
fontFamily("Arial, sans-serif")
|
||||
padding(20.px)
|
||||
maxWidth(800.px)
|
||||
margin("0 auto")
|
||||
}
|
||||
}) {
|
||||
H1({
|
||||
style {
|
||||
color(Color.darkblue)
|
||||
textAlign("center")
|
||||
marginBottom(30.px)
|
||||
}
|
||||
}) {
|
||||
Text("Meldestelle - Reitersport Management")
|
||||
}
|
||||
|
||||
Div({
|
||||
style {
|
||||
textAlign("center")
|
||||
marginBottom(20.px)
|
||||
}
|
||||
}) {
|
||||
P { Text("Welcome to the Meldestelle Web Application") }
|
||||
P { Text("Click the button below to test the backend connection") }
|
||||
}
|
||||
|
||||
Div({
|
||||
style {
|
||||
textAlign("center")
|
||||
marginBottom(20.px)
|
||||
}
|
||||
}) {
|
||||
Button({
|
||||
style {
|
||||
backgroundColor(Color.lightblue)
|
||||
color(Color.white)
|
||||
border(0.px)
|
||||
padding(10.px, 20.px)
|
||||
fontSize(16.px)
|
||||
cursor("pointer")
|
||||
borderRadius(5.px)
|
||||
}
|
||||
onClick {
|
||||
scope.launch {
|
||||
try {
|
||||
isLoading = true
|
||||
errorMessage = null
|
||||
responseStatus = null
|
||||
|
||||
// Try different potential gateway URLs with correct routing
|
||||
val gatewayUrls = listOf(
|
||||
"http://localhost:8080/api/ping/ping", // Correct gateway path
|
||||
"http://localhost:8080/ping", // Direct service call (fallback)
|
||||
"http://localhost:8081/api/ping/ping" // Alternative gateway port
|
||||
)
|
||||
|
||||
var success = false
|
||||
for (url in gatewayUrls) {
|
||||
try {
|
||||
val response: HttpResponse = httpClient.get(url)
|
||||
val responseText = response.bodyAsText()
|
||||
|
||||
// Try to parse as JSON first
|
||||
try {
|
||||
val pingResponse = Json.decodeFromString<PingResponse>(responseText)
|
||||
responseStatus = pingResponse.status
|
||||
success = true
|
||||
break
|
||||
} catch (e: Exception) {
|
||||
// If JSON parsing fails, use the raw response
|
||||
responseStatus = responseText
|
||||
success = true
|
||||
break
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// Continue to next URL
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
errorMessage = "Could not reach any backend service. Please ensure the backend is running."
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
errorMessage = "Error: ${e.message}"
|
||||
} finally {
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
disabled(isLoading)
|
||||
}) {
|
||||
Text(if (isLoading) "Loading..." else "Ping Backend")
|
||||
}
|
||||
}
|
||||
|
||||
// Response display area
|
||||
Div({
|
||||
style {
|
||||
textAlign("center")
|
||||
marginTop(20.px)
|
||||
minHeight(100.px)
|
||||
border(1.px, LineStyle.Solid, Color.lightgray)
|
||||
borderRadius(5.px)
|
||||
padding(20.px)
|
||||
backgroundColor(Color.lightyellow)
|
||||
}
|
||||
}) {
|
||||
when {
|
||||
isLoading -> {
|
||||
P { Text("Sending request to backend...") }
|
||||
}
|
||||
errorMessage != null -> {
|
||||
P({
|
||||
style {
|
||||
color(Color.red)
|
||||
fontWeight("bold")
|
||||
}
|
||||
}) {
|
||||
Text(errorMessage!!)
|
||||
}
|
||||
}
|
||||
responseStatus != null -> {
|
||||
P({
|
||||
style {
|
||||
color(Color.green)
|
||||
fontWeight("bold")
|
||||
fontSize(18.px)
|
||||
}
|
||||
}) {
|
||||
Text("Backend Response: $responseStatus")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
P { Text("Click the button above to test backend connection") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
package at.mocode.client.web
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.application
|
||||
import org.jetbrains.compose.web.renderComposable
|
||||
|
||||
fun main() = application {
|
||||
Window(
|
||||
title = "Meldestelle - Reitersport Management",
|
||||
onCloseRequest = ::exitApplication
|
||||
) {
|
||||
fun main() {
|
||||
renderComposable(rootElementId = "root") {
|
||||
App()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Meldestelle - Reitersport Management</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="MeldestelleWebApp.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user