7 changed files with 10 additions and 64 deletions

No files matched your search

+1 -2
View File
@@ -13,7 +13,7 @@ plugins {
alias(libs.plugins.buildconfig) alias(libs.plugins.buildconfig)
} }
version = PhoebenchVersion(1, 2, 2, "csv-export") version = PhoebenchVersion(1, 2, 1, "autoscroll")
if((version as PhoebenchVersion) < (rootProject.version as PhoebenchVersion)) if((version as PhoebenchVersion) < (rootProject.version as PhoebenchVersion))
throw GradleException("UI Clients version must be at least as high as protocol/common version") throw GradleException("UI Clients version must be at least as high as protocol/common version")
@@ -96,7 +96,6 @@ kotlin {
implementation(libs.lucide) implementation(libs.lucide)
implementation(libs.koala) implementation(libs.koala)
implementation(libs.kolor) implementation(libs.kolor)
implementation(libs.filekit)
} }
desktopMain.dependencies { desktopMain.dependencies {
implementation(compose.desktop.currentOs) implementation(compose.desktop.currentOs)
@@ -37,6 +37,4 @@ expect fun <T> drag(data: T, serializer: KSerializer<T>): DragAndDropTransferDat
inline fun <reified T> drop(data: DragAndDropEvent): T? = drop(data, serializer<T>()) inline fun <reified T> drop(data: DragAndDropEvent): T? = drop(data, serializer<T>())
expect fun <T> drop(data: DragAndDropEvent, serializer: KSerializer<T>): T? expect fun <T> drop(data: DragAndDropEvent, serializer: KSerializer<T>): T?
expect suspend fun onDownload(contents: String, nameHint: String, extension: String)
@@ -1,5 +1,6 @@
package com.jaytux.phoebench.clients.data package com.jaytux.phoebench.clients.data
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@@ -12,7 +13,6 @@ import com.jaytux.phoebench.clients.hexString
import com.jaytux.phoebench.clients.immutable import com.jaytux.phoebench.clients.immutable
import com.jaytux.phoebench.clients.insort import com.jaytux.phoebench.clients.insort
import com.jaytux.phoebench.clients.insortIdx import com.jaytux.phoebench.clients.insortIdx
import com.jaytux.phoebench.clients.onDownload
import com.jaytux.phoebench.clients.replace import com.jaytux.phoebench.clients.replace
import com.jaytux.phoebench.clients.withScope import com.jaytux.phoebench.clients.withScope
import com.jaytux.phoebench.common.BenchmarkResponse import com.jaytux.phoebench.common.BenchmarkResponse
@@ -21,7 +21,7 @@ import com.jaytux.phoebench.common.VersionResponse
import com.jaytux.phoebench.common.ProjectEvent import com.jaytux.phoebench.common.ProjectEvent
import com.jaytux.phoebench.common.ServerMonitorEvent import com.jaytux.phoebench.common.ServerMonitorEvent
import com.jaytux.phoebench.common.TimeUnit import com.jaytux.phoebench.common.TimeUnit
import io.ktor.http.quote import com.jaytux.phoebench.common.fold
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlin.time.Clock import kotlin.time.Clock
import kotlin.time.Instant import kotlin.time.Instant
@@ -322,31 +322,4 @@ class ProjectVM(
fun clearMonitor() = withScope { fun clearMonitor() = withScope {
_repo.deleteMonitorLogs().snackOnError() _repo.deleteMonitorLogs().snackOnError()
} }
fun triggerCsvDownload() = withScope {
data class CsvEntry(val id: Uuid, val bench: Uuid, val benchName: String, val runner: Uuid, val runnerName: String, val runnerHex: String, val input: String, val hardware: String, val timing: List<Float>)
val benchmarks = _benchmarks.value.flatMap { bench ->
bench.entries.map {
CsvEntry(
id = it.id, bench = bench.id, benchName = bench.name,
runner = it.label.id, runnerName = it.label.name, runnerHex = it.label.colorStr,
input = it.input, hardware = it.hardware, timing = it.measurements
)
}
}
val dataCount = benchmarks.maxOf { it.timing.size }
val header = listOf("id", "benchmark-id", "benchmark-name", "runner-id", "runner-name", "runner-hex", "input", "hardware") + List(dataCount) { "entry-$it" }
val body = benchmarks.map {
listOf(
it.id.toHexDashString(), it.bench.toHexDashString(), it.benchName.quote(),
it.runner.toHexDashString(), it.runnerName.quote(), it.runnerHex,
it.input.quote(), it.hardware.quote()
) + List(dataCount) { i -> it.timing.getOrNull(i)?.toString() ?: "" }
}
val csv = "${header.joinToString(",")}\n${body.joinToString("\n"){ it.joinToString(",") }}"
onDownload(csv, name.value ?: "PhoeBench-project", "csv")
}
} }
@@ -80,10 +80,8 @@ fun ProjectView(id: Uuid, forceBack: () -> Unit) {
IconButton({ vm.openMonitor() }) { IconButton({ vm.openMonitor() }) {
Icon(Lucide.SquareTerminal, "Open monitor") Icon(Lucide.SquareTerminal, "Open monitor")
} }
IconButton({ vm.triggerCsvDownload() }) {
Icon(Lucide.FileDown, "Download CSV")
}
} }
} }
owner?.let { Text("${if(public) "Public" else "Private"} project by user $it") } owner?.let { Text("${if(public) "Public" else "Private"} project by user $it") }
Spacer(Modifier.height(15.dp)) Spacer(Modifier.height(15.dp))
@@ -6,10 +6,6 @@ import androidx.compose.ui.draganddrop.*
import androidx.compose.ui.platform.ClipEntry import androidx.compose.ui.platform.ClipEntry
import com.github.javakeyring.Keyring import com.github.javakeyring.Keyring
import com.jaytux.phoebench.clients.ui.DefaultServerSelect import com.jaytux.phoebench.clients.ui.DefaultServerSelect
import io.github.vinceglb.filekit.FileKit
import io.github.vinceglb.filekit.dialogs.FileKitDialogException
import io.github.vinceglb.filekit.dialogs.openFileSaver
import io.github.vinceglb.filekit.writeString
import io.ktor.client.* import io.ktor.client.*
import io.ktor.client.engine.okhttp.* import io.ktor.client.engine.okhttp.*
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
@@ -81,14 +77,4 @@ actual fun <T> drag(data: T, serializer: KSerializer<T>): DragAndDropTransferDat
actual fun <T> drop(data: DragAndDropEvent, serializer: KSerializer<T>): T? = actual fun <T> drop(data: DragAndDropEvent, serializer: KSerializer<T>): T? =
if(data.awtTransferable.isDataFlavorSupported(DataFlavor.stringFlavor)) if(data.awtTransferable.isDataFlavorSupported(DataFlavor.stringFlavor))
Json.decodeFromString(serializer, data.awtTransferable.getTransferData(DataFlavor.stringFlavor) as String) Json.decodeFromString(serializer, data.awtTransferable.getTransferData(DataFlavor.stringFlavor) as String)
else null else null
actual suspend fun onDownload(contents: String, nameHint: String, extension: String) {
try {
val file = FileKit.openFileSaver(suggestedName = nameHint, defaultExtension = extension)
file?.writeString(contents)
}
catch(e: FileKitDialogException) {
SnackProvider.get().send("Failed to save CSV: ${e.message}")
}
}
@@ -7,8 +7,6 @@ import androidx.compose.ui.draganddrop.DragAndDropTransferData
import androidx.compose.ui.draganddrop.domDataTransferOrNull import androidx.compose.ui.draganddrop.domDataTransferOrNull
import androidx.compose.ui.platform.ClipEntry import androidx.compose.ui.platform.ClipEntry
import com.jaytux.phoebench.clients.ui.constantServerSelect import com.jaytux.phoebench.clients.ui.constantServerSelect
import io.github.vinceglb.filekit.FileKit
import io.github.vinceglb.filekit.download
import io.ktor.client.* import io.ktor.client.*
import io.ktor.client.engine.js.* import io.ktor.client.engine.js.*
import kotlinx.browser.window import kotlinx.browser.window
@@ -95,8 +93,4 @@ actual fun <T> drag(data: T, serializer: KSerializer<T>): DragAndDropTransferDat
actual fun <T> drop(data: DragAndDropEvent, serializer: KSerializer<T>): T? = actual fun <T> drop(data: DragAndDropEvent, serializer: KSerializer<T>): T? =
data.transferData?.domDataTransferOrNull?.getData("application/json")?.let { data.transferData?.domDataTransferOrNull?.getData("application/json")?.let {
Json.decodeFromString(serializer, it) Json.decodeFromString(serializer, it)
} }
actual suspend fun onDownload(contents: String, nameHint: String, extension: String) {
FileKit.download(contents.encodeToByteArray(), fileName = "$nameHint.$extension")
}
+3 -5
View File
@@ -8,13 +8,13 @@ ksoup = "0.2.6"
sqlite = "3.53.2.0" sqlite = "3.53.2.0"
mariadb = "3.5.9" mariadb = "3.5.9"
androidx-lifecycle = "2.10.0" androidx-lifecycle = "2.10.0"
compose-multiplatform = "1.12.2" compose-multiplatform = "1.11.1"
kotlin = "2.4.10" kotlin = "2.4.10"
kotlinx-coroutines = "1.11.0" kotlinx-coroutines = "1.11.0"
ktor = "3.5.1" ktor = "3.5.1"
spring-sec = "7.1.0" spring-sec = "7.1.0"
atomic = "0.33.0" atomic = "0.33.0"
datetime = "0.8.0" datetime = "0.8.0-0.6.x-compat"
material = "1.9.0" material = "1.9.0"
java-keystore = "1.0.4" java-keystore = "1.0.4"
lucide = "2.2.1" lucide = "2.2.1"
@@ -22,9 +22,8 @@ koala-plot = "0.12.0"
kolor-picker = "2.1.0" kolor-picker = "2.1.0"
shadow = "9.3.0" shadow = "9.3.0"
clikt = "5.0.3" clikt = "5.0.3"
buildconfig = "6.1.2" buildconfig = "6.0.10"
process = "1.5.1" process = "1.5.1"
filekit = "0.17.0"
[libraries] [libraries]
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
@@ -92,7 +91,6 @@ java-keystore = { module = "com.github.javakeyring:java-keyring", version.ref =
clikt = { module = "com.github.ajalt.clikt:clikt", version.ref = "clikt" } clikt = { module = "com.github.ajalt.clikt:clikt", version.ref = "clikt" }
process = { module = "com.github.pgreze:kotlin-process", version.ref = "process" } process = { module = "com.github.pgreze:kotlin-process", version.ref = "process" }
filekit = { module = "io.github.vinceglb:filekit-dialogs-compose", version.ref = "filekit" }
[plugins] [plugins]
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" } composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }