chore(frontend): remove custom Webpack sqlite-wasm integration plugins and cleanup config

- Deleted `dummy.js` and its usage for sqlite-wasm integration as custom Webpack adjustments are no longer necessary.
- Removed outdated Webpack configuration files: `ignore-sqlite-wasm.js`, `ignore-sqlite-wasm-critical-dependency.js`, and `sqljs-fix.js`.
- Introduced `sqlite-config.js` for simplified and streamlined sqlite-wasm and Skiko Webpack configuration.
- Minor code formatting adjustments across frontend modules for improved consistency.
This commit is contained in:
2026-01-26 20:37:23 +01:00
parent 29ad73b508
commit 3e587381ed
30 changed files with 1535 additions and 941 deletions
@@ -23,274 +23,274 @@ import at.mocode.frontend.core.designsystem.theme.Dimens
@Composable
fun PingScreen(
viewModel: PingViewModel,
onBack: () -> Unit = {}
viewModel: PingViewModel,
onBack: () -> Unit = {}
) {
val uiState = viewModel.uiState
val uiState = viewModel.uiState
// Wir nutzen jetzt das globale Theme (Hintergrund kommt vom Theme)
Column(
// Wir nutzen jetzt das globale Theme (Hintergrund kommt vom Theme)
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.padding(Dimens.SpacingS) // Globales Spacing
) {
// 1. Header
PingHeader(
onBack = onBack,
isSyncing = uiState.isSyncing,
isLoading = uiState.isLoading
)
Spacer(Modifier.height(Dimens.SpacingS))
// 2. Main Dashboard Area (Split View)
Row(modifier = Modifier.weight(1f)) {
// Left Panel: Controls & Status Grid (60%)
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.padding(Dimens.SpacingS) // Globales Spacing
) {
// 1. Header
PingHeader(
onBack = onBack,
isSyncing = uiState.isSyncing,
isLoading = uiState.isLoading
)
.weight(0.6f)
.fillMaxHeight()
.padding(end = Dimens.SpacingS)
) {
ActionToolbar(viewModel)
Spacer(Modifier.height(Dimens.SpacingS))
StatusGrid(uiState)
}
// 2. Main Dashboard Area (Split View)
Row(modifier = Modifier.weight(1f)) {
// Left Panel: Controls & Status Grid (60%)
Column(
modifier = Modifier
.weight(0.6f)
.fillMaxHeight()
.padding(end = Dimens.SpacingS)
) {
ActionToolbar(viewModel)
Spacer(Modifier.height(Dimens.SpacingS))
StatusGrid(uiState)
}
// Right Panel: Terminal Log (40%)
// Hier nutzen wir bewusst einen dunklen "Terminal"-Look, unabhängig vom Theme
DashboardCard(
modifier = Modifier
.weight(0.4f)
.fillMaxHeight()
) {
LogHeader(onClear = { viewModel.clearLogs() })
LogConsole(uiState.logs)
}
}
Spacer(Modifier.height(Dimens.SpacingXS))
// 3. Footer
PingStatusBar(uiState.lastSyncResult)
// Right Panel: Terminal Log (40%)
// Hier nutzen wir bewusst einen dunklen "Terminal"-Look, unabhängig vom Theme
DashboardCard(
modifier = Modifier
.weight(0.4f)
.fillMaxHeight()
) {
LogHeader(onClear = { viewModel.clearLogs() })
LogConsole(uiState.logs)
}
}
Spacer(Modifier.height(Dimens.SpacingXS))
// 3. Footer
PingStatusBar(uiState.lastSyncResult)
}
}
@Composable
private fun PingHeader(
onBack: () -> Unit,
isSyncing: Boolean,
isLoading: Boolean
onBack: () -> Unit,
isSyncing: Boolean,
isLoading: Boolean
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().height(40.dp)
) {
IconButton(onClick = onBack) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back", tint = MaterialTheme.colorScheme.onBackground)
}
Text(
"PING SERVICE // DASHBOARD",
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.weight(1f).padding(start = Dimens.SpacingS)
)
if (isLoading) {
StatusBadge("BUSY", Color(0xFFFFA000)) // Amber
Spacer(Modifier.width(Dimens.SpacingS))
}
if (isSyncing) {
StatusBadge("SYNCING", MaterialTheme.colorScheme.primary)
Spacer(Modifier.width(Dimens.SpacingS))
CircularProgressIndicator(
modifier = Modifier.size(16.dp),
strokeWidth = 2.dp,
color = MaterialTheme.colorScheme.primary
)
} else {
StatusBadge("IDLE", Color(0xFF388E3C)) // Green
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().height(40.dp)
) {
IconButton(onClick = onBack) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back", tint = MaterialTheme.colorScheme.onBackground)
}
Text(
"PING SERVICE // DASHBOARD",
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.weight(1f).padding(start = Dimens.SpacingS)
)
if (isLoading) {
StatusBadge("BUSY", Color(0xFFFFA000)) // Amber
Spacer(Modifier.width(Dimens.SpacingS))
}
if (isSyncing) {
StatusBadge("SYNCING", MaterialTheme.colorScheme.primary)
Spacer(Modifier.width(Dimens.SpacingS))
CircularProgressIndicator(
modifier = Modifier.size(16.dp),
strokeWidth = 2.dp,
color = MaterialTheme.colorScheme.primary
)
} else {
StatusBadge("IDLE", Color(0xFF388E3C)) // Green
}
}
}
@Composable
private fun StatusBadge(text: String, color: Color) {
Surface(
color = color.copy(alpha = 0.1f),
contentColor = color,
shape = MaterialTheme.shapes.small,
border = androidx.compose.foundation.BorderStroke(1.dp, color)
) {
Text(
text = text,
style = MaterialTheme.typography.labelSmall,
modifier = Modifier.padding(horizontal = 8.dp, vertical = 2.dp)
)
}
Surface(
color = color.copy(alpha = 0.1f),
contentColor = color,
shape = MaterialTheme.shapes.small,
border = androidx.compose.foundation.BorderStroke(1.dp, color)
) {
Text(
text = text,
style = MaterialTheme.typography.labelSmall,
modifier = Modifier.padding(horizontal = 8.dp, vertical = 2.dp)
)
}
}
@Composable
private fun ActionToolbar(viewModel: PingViewModel) {
// Wrap buttons to avoid overflow on small screens
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(Dimens.SpacingXS)
) {
DenseButton(text = "Simple", onClick = { viewModel.performSimplePing() })
DenseButton(text = "Enhanced", onClick = { viewModel.performEnhancedPing() })
DenseButton(text = "Secure", onClick = { viewModel.performSecurePing() })
DenseButton(text = "Health", onClick = { viewModel.performHealthCheck() })
DenseButton(
text = "Sync",
onClick = { viewModel.triggerSync() },
containerColor = MaterialTheme.colorScheme.secondary
)
}
// Wrap buttons to avoid overflow on small screens
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(Dimens.SpacingXS)
) {
DenseButton(text = "Simple", onClick = { viewModel.performSimplePing() })
DenseButton(text = "Enhanced", onClick = { viewModel.performEnhancedPing() })
DenseButton(text = "Secure", onClick = { viewModel.performSecurePing() })
DenseButton(text = "Health", onClick = { viewModel.performHealthCheck() })
DenseButton(
text = "Sync",
onClick = { viewModel.triggerSync() },
containerColor = MaterialTheme.colorScheme.secondary
)
}
}
@Composable
private fun StatusGrid(uiState: PingUiState) {
Column(verticalArrangement = Arrangement.spacedBy(Dimens.SpacingS)) {
// Row 1
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(Dimens.SpacingS)) {
DashboardCard(modifier = Modifier.weight(1f)) {
StatusHeader("SIMPLE / SECURE PING")
if (uiState.simplePingResponse != null) {
KeyValueRow("Status", uiState.simplePingResponse.status)
KeyValueRow("Service", uiState.simplePingResponse.service)
KeyValueRow("Time", uiState.simplePingResponse.timestamp)
} else {
EmptyStateText()
}
}
DashboardCard(modifier = Modifier.weight(1f)) {
StatusHeader("HEALTH CHECK")
if (uiState.healthResponse != null) {
KeyValueRow("Status", uiState.healthResponse.status)
KeyValueRow("Healthy", uiState.healthResponse.healthy.toString())
KeyValueRow("Service", uiState.healthResponse.service)
} else {
EmptyStateText()
}
}
Column(verticalArrangement = Arrangement.spacedBy(Dimens.SpacingS)) {
// Row 1
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(Dimens.SpacingS)) {
DashboardCard(modifier = Modifier.weight(1f)) {
StatusHeader("SIMPLE / SECURE PING")
if (uiState.simplePingResponse != null) {
KeyValueRow("Status", uiState.simplePingResponse.status)
KeyValueRow("Service", uiState.simplePingResponse.service)
KeyValueRow("Time", uiState.simplePingResponse.timestamp)
} else {
EmptyStateText()
}
}
// Row 2
DashboardCard(modifier = Modifier.fillMaxWidth()) {
StatusHeader("ENHANCED PING (RESILIENCE)")
if (uiState.enhancedPingResponse != null) {
Row(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.weight(1f)) {
KeyValueRow("Status", uiState.enhancedPingResponse.status)
KeyValueRow("Timestamp", uiState.enhancedPingResponse.timestamp)
}
Column(modifier = Modifier.weight(1f)) {
KeyValueRow("Circuit Breaker", uiState.enhancedPingResponse.circuitBreakerState)
KeyValueRow("Latency", "${uiState.enhancedPingResponse.responseTime}ms")
}
}
} else {
EmptyStateText()
}
DashboardCard(modifier = Modifier.weight(1f)) {
StatusHeader("HEALTH CHECK")
if (uiState.healthResponse != null) {
KeyValueRow("Status", uiState.healthResponse.status)
KeyValueRow("Healthy", uiState.healthResponse.healthy.toString())
KeyValueRow("Service", uiState.healthResponse.service)
} else {
EmptyStateText()
}
}
}
// Row 2
DashboardCard(modifier = Modifier.fillMaxWidth()) {
StatusHeader("ENHANCED PING (RESILIENCE)")
if (uiState.enhancedPingResponse != null) {
Row(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.weight(1f)) {
KeyValueRow("Status", uiState.enhancedPingResponse.status)
KeyValueRow("Timestamp", uiState.enhancedPingResponse.timestamp)
}
Column(modifier = Modifier.weight(1f)) {
KeyValueRow("Circuit Breaker", uiState.enhancedPingResponse.circuitBreakerState)
KeyValueRow("Latency", "${uiState.enhancedPingResponse.responseTime}ms")
}
}
} else {
EmptyStateText()
}
}
}
}
@Composable
private fun StatusHeader(title: String) {
Text(
text = title,
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(bottom = Dimens.SpacingXS)
)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
Spacer(Modifier.height(Dimens.SpacingXS))
Text(
text = title,
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(bottom = Dimens.SpacingXS)
)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp)
Spacer(Modifier.height(Dimens.SpacingXS))
}
@Composable
private fun EmptyStateText() {
Text("No Data", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
Text("No Data", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
@Composable
private fun KeyValueRow(key: String, value: String) {
Row(modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp)) {
Text(
text = "$key:",
modifier = Modifier.width(100.dp),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = value,
style = MaterialTheme.typography.bodySmall,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onSurface
)
}
Row(modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp)) {
Text(
text = "$key:",
modifier = Modifier.width(100.dp),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = value,
style = MaterialTheme.typography.bodySmall,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onSurface
)
}
}
// --- Log Components (Terminal Style - intentionally distinct) ---
@Composable
private fun LogHeader(onClear: () -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = Dimens.SpacingXS),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = Dimens.SpacingXS),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text("EVENT LOG", style = MaterialTheme.typography.labelSmall, fontWeight = FontWeight.Bold)
TextButton(
onClick = onClear,
contentPadding = PaddingValues(0.dp),
modifier = Modifier.height(24.dp)
) {
Text("EVENT LOG", style = MaterialTheme.typography.labelSmall, fontWeight = FontWeight.Bold)
TextButton(
onClick = onClear,
contentPadding = PaddingValues(0.dp),
modifier = Modifier.height(24.dp)
) {
Text("CLEAR", style = MaterialTheme.typography.labelSmall)
}
Text("CLEAR", style = MaterialTheme.typography.labelSmall)
}
}
}
@Composable
private fun LogConsole(logs: List<LogEntry>) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFF1E1E1E)) // Always dark for terminal
.padding(Dimens.SpacingXS),
reverseLayout = false
) {
items(logs) { log ->
val color = if (log.isError) Color(0xFFFF5555) else Color(0xFF55FF55)
Text(
text = "[${log.timestamp}] [${log.source}] ${log.message}",
color = color,
fontSize = 11.sp,
fontFamily = FontFamily.Monospace,
lineHeight = 14.sp
)
}
LazyColumn(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFF1E1E1E)) // Always dark for terminal
.padding(Dimens.SpacingXS),
reverseLayout = false
) {
items(logs) { log ->
val color = if (log.isError) Color(0xFFFF5555) else Color(0xFF55FF55)
Text(
text = "[${log.timestamp}] [${log.source}] ${log.message}",
color = color,
fontSize = 11.sp,
fontFamily = FontFamily.Monospace,
lineHeight = 14.sp
)
}
}
}
@Composable
private fun PingStatusBar(lastSync: String?) {
Surface(
color = MaterialTheme.colorScheme.primaryContainer,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = lastSync ?: "Ready",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier.padding(horizontal = Dimens.SpacingS, vertical = 2.dp)
)
}
Surface(
color = MaterialTheme.colorScheme.primaryContainer,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = lastSync ?: "Ready",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier.padding(horizontal = Dimens.SpacingS, vertical = 2.dp)
)
}
}
@@ -16,10 +16,10 @@ import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime
data class LogEntry(
val timestamp: String,
val source: String,
val message: String,
val isError: Boolean = false
val timestamp: String,
val source: String,
val message: String,
val isError: Boolean = false
)
data class PingUiState(
@@ -43,7 +43,9 @@ class PingViewModel(
private fun addLog(source: String, message: String, isError: Boolean = false) {
val now = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())
val timeString = "${now.hour.toString().padStart(2, '0')}:${now.minute.toString().padStart(2, '0')}:${now.second.toString().padStart(2, '0')}"
val timeString = "${now.hour.toString().padStart(2, '0')}:${now.minute.toString().padStart(2, '0')}:${
now.second.toString().padStart(2, '0')
}"
val entry = LogEntry(timeString, source, message, isError)
uiState = uiState.copy(logs = listOf(entry) + uiState.logs) // Prepend for newest first
}