feat(zns-import): DAT-Dateisupport hinzugefügt, Fehlerbehebung und UI-Anpassungen
Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
@@ -62,3 +62,12 @@ Parameter sind hiermit fixiert und umgesetzt.
|
||||
`management.endpoint.health.probes.enabled: true`).
|
||||
* **Optimierung**: Healthcheck in `dc-backend.yaml` auf `wget --no-verbose` umgestellt für bessere
|
||||
Diagnosemöglichkeiten.
|
||||
|
||||
### Nachtrag: 2026-04-16 15:30 - Connectivity & Serialization Fixes
|
||||
|
||||
* **Connectivity**: `ConnectivityTracker` wurde auf den korrekten Health-Pfad `/api/ping/health` umgestellt. Der Footer
|
||||
zeigt nun korrekt den Online-Status ("Cloud synchronisiert") an.
|
||||
* **Serialization**: Behebung des Fehlers `Serializer for class 'JobIdResponse' is not found`. Die DTO-Klasse wurde im
|
||||
Frontend in `ImportStartResponse` umbenannt (passend zum Backend) und die Sichtbarkeit auf `public` erhöht.
|
||||
* **Flexibilität**: Der ZNS-Importer unterstützt nun sowohl `.zip` als auch `.dat` Dateien (z.B. direkte
|
||||
`VEREIN01.dat`). Die UI (`pickZnsFile`) und das ViewModel wurden entsprechend erweitert.
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ class ConnectivityTracker : KoinComponent {
|
||||
|
||||
private suspend fun checkConnection(): Boolean {
|
||||
return try {
|
||||
val response = client.get(NetworkConfig.baseUrl.trimEnd('/') + "/ping")
|
||||
val response = client.get(NetworkConfig.baseUrl.trimEnd('/') + "/api/ping/health")
|
||||
response.status.value in 200..299
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
|
||||
+11
-5
@@ -24,7 +24,7 @@ import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
|
||||
@Serializable
|
||||
internal data class JobIdResponse(val jobId: String)
|
||||
data class ImportStartResponse(val jobId: String)
|
||||
|
||||
@Serializable
|
||||
internal data class JobStatusResponse(
|
||||
@@ -57,8 +57,12 @@ class ZnsImportViewModel(
|
||||
override fun startImport(mode: String) {
|
||||
val filePath = state.selectedFilePath ?: return
|
||||
val file = File(filePath)
|
||||
if (!file.exists() || !file.name.endsWith(".zip", ignoreCase = true)) {
|
||||
state = state.copy(errorMessage = "Bitte eine gültige .zip-Datei auswählen.")
|
||||
if (!file.exists() || !(file.name.endsWith(".zip", ignoreCase = true) || file.name.endsWith(
|
||||
".dat",
|
||||
ignoreCase = true
|
||||
))
|
||||
) {
|
||||
state = state.copy(errorMessage = "Bitte eine gültige .zip oder .dat-Datei auswählen.")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -72,15 +76,17 @@ class ZnsImportViewModel(
|
||||
val response: HttpResponse = httpClient.post("${NetworkConfig.baseUrl}/api/v1/import/zns") {
|
||||
parameter("mode", mode)
|
||||
if (token != null) header(HttpHeaders.Authorization, "Bearer $token")
|
||||
val contentType =
|
||||
if (file.name.endsWith(".zip", ignoreCase = true)) "application/zip" else "application/octet-stream"
|
||||
setBody(MultiPartFormDataContent(formData {
|
||||
append("file", file.readBytes(), Headers.build {
|
||||
append(HttpHeaders.ContentDisposition, "filename=\"${file.name}\"")
|
||||
append(HttpHeaders.ContentType, "application/zip")
|
||||
append(HttpHeaders.ContentType, contentType)
|
||||
})
|
||||
}))
|
||||
}
|
||||
if (response.status == HttpStatusCode.Accepted) {
|
||||
val body = json.decodeFromString<JobIdResponse>(response.bodyAsText())
|
||||
val body = json.decodeFromString<ImportStartResponse>(response.bodyAsText())
|
||||
state = state.copy(isUploading = false, jobId = body.jobId, jobStatus = "AUSSTEHEND")
|
||||
startPolling(body.jobId)
|
||||
} else {
|
||||
|
||||
+10
-6
@@ -1587,7 +1587,11 @@ fun ZnsImportWizardSection(
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Icon(Icons.Default.CloudUpload, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
|
||||
Text("ZNS-Stammdaten Import (ZIP)", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
"ZNS-Stammdaten Import (ZIP/DAT)",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (state.isFinished || state.errorMessage != null) {
|
||||
TextButton(onClick = onReset) {
|
||||
@@ -1609,14 +1613,14 @@ fun ZnsImportWizardSection(
|
||||
value = state.selectedFilePath ?: "",
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
placeholder = { Text("ZNS.zip auswählen...") },
|
||||
placeholder = { Text("ZNS-Datei auswählen (.zip, .dat)...") },
|
||||
modifier = Modifier.weight(1f),
|
||||
singleLine = true,
|
||||
textStyle = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
Button(
|
||||
onClick = {
|
||||
val path = pickZipFile()
|
||||
val path = pickZnsFile()
|
||||
if (path != null) onFileSelect(path)
|
||||
},
|
||||
enabled = !state.isUploading
|
||||
@@ -1714,10 +1718,10 @@ fun ZnsImportWizardSection(
|
||||
}
|
||||
}
|
||||
|
||||
private fun pickZipFile(): String? {
|
||||
private fun pickZnsFile(): String? {
|
||||
val chooser = JFileChooser()
|
||||
chooser.dialogTitle = "ZNS.zip auswählen"
|
||||
chooser.fileFilter = FileNameExtensionFilter("ZIP-Archiv (*.zip)", "zip")
|
||||
chooser.dialogTitle = "ZNS-Datei auswählen"
|
||||
chooser.fileFilter = FileNameExtensionFilter("ZNS Dateien (*.zip, *.dat)", "zip", "dat")
|
||||
chooser.isAcceptAllFileFilterUsed = false
|
||||
val result = chooser.showOpenDialog(null)
|
||||
return if (result == JFileChooser.APPROVE_OPTION) chooser.selectedFile.absolutePath else null
|
||||
|
||||
Reference in New Issue
Block a user