Format notification log exports

This commit is contained in:
ajp_anton
2026-07-23 09:47:50 +00:00
parent 23aa3282dd
commit 4345ecbf2f
@@ -0,0 +1,43 @@
package se.ajpanton.notificationlog.export
import se.ajpanton.notificationlog.model.NotificationLogEntry
import se.ajpanton.notificationlog.settings.LogField
import se.ajpanton.notificationlog.settings.LogViewSettings
import se.ajpanton.notificationlog.settings.TimestampZone
import java.text.DateFormat
import java.util.Date
import java.util.TimeZone
object LogExporter {
fun csv(entries: List<NotificationLogEntry>, settings: LogViewSettings): String =
rows(entries, settings).joinToString("\n") { row -> row.joinToString(",") { csvValue(it) } }
fun formatted(entries: List<NotificationLogEntry>, settings: LogViewSettings): String {
val rows = rows(entries, settings)
val widths = rows.fold(emptyList<Int>()) { current, row -> row.mapIndexed { i, value -> maxOf(current.getOrElse(i) { 0 }, value.length) } }
return rows.joinToString("\n") { row -> row.mapIndexed { i, value -> value.padEnd(widths[i]) }.joinToString(" ") }
}
fun html(entries: List<NotificationLogEntry>, settings: LogViewSettings): String = buildString {
append("<!doctype html><meta charset=\"utf-8\"><table><thead><tr>")
settings.order.filter { it in settings.visibleFields }.forEach { append("<th>${escape(header(it))}</th>") }
append("</tr></thead><tbody>")
rows(entries, settings).forEach { row -> append("<tr>"); row.forEach { append("<td>${escape(it)}</td>") }; append("</tr>") }
append("</tbody></table>")
}
private fun rows(entries: List<NotificationLogEntry>, settings: LogViewSettings) = listOf(
settings.order.filter { it in settings.visibleFields }.map(::header),
) + entries.sortedByDescending { it.recordedAtEpochMillis }.map { entry ->
settings.order.filter { it in settings.visibleFields }.map { field -> when (field) {
LogField.TIMESTAMP -> timestamp(entry.recordedAtEpochMillis, settings.timestampZone)
LogField.APP_NAME -> entry.appName; LogField.PACKAGE_NAME -> entry.packageName
LogField.ACTION -> entry.action.name.lowercase().replace('_', ' ')
LogField.CONTENTS -> entry.contents ?: ""
} }
}
private fun header(field: LogField) = field.name.lowercase().replace('_', ' ')
private fun timestamp(value: Long, zone: TimestampZone): String = DateFormat.getDateTimeInstance().apply { if (zone == TimestampZone.UTC) timeZone = TimeZone.getTimeZone("UTC") }.format(Date(value))
private fun csvValue(value: String) = "\"${value.replace("\"", "\"\"")}\""
private fun escape(value: String) = value.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;")
}