Read a session's transcript as the file it is
The conversation on screen is a drawing of the record, and when the two disagree -- or when something in the record is what has gone wrong -- there was no way to see the record itself from the phone. View raw in the session settings dialog opens the file explorer on the transcript, which is its third caller and needed no new screen: the file name and path in the header, a back button, and the lines as code. The session says where the file is, because only the backend knows, and it names this backend's machine rather than the session's -- for a remote session those are two different filesystems. Back from the file lands in the session's own directory, where the log and the process record are. The paragraph under Reload goes, and both buttons move to a line of their own: two buttons and a measurement do not fit a phone's width.
This commit is contained in:
1 parent
049780fda6
commit
66b3403a71
8 files changed
+123
-12
No files matched your search
@@ -243,8 +243,17 @@ data class SessionSummary(
|
||||
val lastActivity: Double,
|
||||
/** Latest measured number of live background tasks; zero also covers older servers. */
|
||||
val backgroundTasks: Int,
|
||||
/**
|
||||
* Where the transcript file itself is, for reading the record rather than the conversation
|
||||
* drawn from it. Null from a server that does not say, and from one whose own machine is not in
|
||||
* its config -- there is then nothing that could read the file, and no way in is offered.
|
||||
*/
|
||||
val transcriptFile: FileOnMachine?,
|
||||
)
|
||||
|
||||
/** A file somewhere the explorer can be pointed at: which machine, and the path on it. */
|
||||
data class FileOnMachine(val machine: String, val machineName: String, val path: String)
|
||||
|
||||
private fun parseSession(session: JSONObject) =
|
||||
SessionSummary(
|
||||
id = session.getString("id"),
|
||||
@@ -277,6 +286,14 @@ private fun parseSession(session: JSONObject) =
|
||||
status = session.getString("status"),
|
||||
lastActivity = session.getDouble("lastActivity"),
|
||||
backgroundTasks = session.optInt("backgroundTasks", 0),
|
||||
transcriptFile =
|
||||
session.optJSONObject("transcriptFile")?.let { file ->
|
||||
FileOnMachine(
|
||||
machine = file.getString("machine"),
|
||||
machineName = file.getString("machineName"),
|
||||
path = file.getString("path"),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
fun fetchSessions(settings: ServerSettings): List<SessionSummary> =
|
||||
|
||||
@@ -56,6 +56,20 @@ data class FilesTarget(
|
||||
val file: String? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
* The explorer opened on one file, wherever that file is.
|
||||
*
|
||||
* Its directory is what the reader lands in on the way back, which for a session's transcript is
|
||||
* that session's own directory -- the log, the process record and the rest of what it wrote.
|
||||
*/
|
||||
fun fileTarget(file: FileOnMachine) =
|
||||
FilesTarget(
|
||||
machine = file.machine,
|
||||
machineName = file.machineName,
|
||||
start = parentOf(file.path) ?: "/",
|
||||
file = file.path,
|
||||
)
|
||||
|
||||
/** The explorer target for this session's machine, optionally opened on [file]. */
|
||||
fun SessionSummary.filesTarget(file: String? = null) =
|
||||
FilesTarget(
|
||||
|
||||
@@ -2507,6 +2507,16 @@ fun SessionScreen(
|
||||
// The purge finishes before the epoch moves, because the relaunched opening effect
|
||||
// reads the same directory and would otherwise draw what is about to be deleted. The
|
||||
// epoch is what makes the rest a cold open.
|
||||
// The explorer, opened on the transcript file: the record itself, in the screen this
|
||||
// app already has for reading a file on a machine. Nothing is offered where the server
|
||||
// does not say where the file is.
|
||||
onViewRaw =
|
||||
summary.transcriptFile?.let { file ->
|
||||
{
|
||||
settingsOpen = false
|
||||
onFiles(fileTarget(file))
|
||||
}
|
||||
},
|
||||
onReload = {
|
||||
settingsOpen = false
|
||||
scope.launch {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.example.aiapp
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -99,6 +100,11 @@ fun SessionSettingsDialog(
|
||||
*/
|
||||
cachedBytes: Long?,
|
||||
onReload: () -> Unit,
|
||||
/**
|
||||
* Opens the transcript file itself in the explorer. Null from a server that does not say where
|
||||
* it is, which draws no button rather than one that cannot work.
|
||||
*/
|
||||
onViewRaw: (() -> Unit)?,
|
||||
onDismiss: () -> Unit,
|
||||
/**
|
||||
* Copies what this session costs to draw. Built by the session screen, because everything it
|
||||
@@ -524,21 +530,24 @@ fun SessionSettingsDialog(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.width(12.dp))
|
||||
}
|
||||
// Both on a line of their own under what they act on, rather than crowded against
|
||||
// the size on the line above: two buttons and a measurement do not fit the width
|
||||
// of a phone, and the one that would lose is the number.
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.End,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
// The record as it is on disk, for the question the drawn conversation cannot
|
||||
// answer -- which is most of what anybody opens this dialog to debug.
|
||||
onViewRaw?.let { TextButton(onClick = it) { Text("View raw") } }
|
||||
Spacer(Modifier.width(8.dp))
|
||||
// Enabled whether or not anything is cached: "what I see disagrees with the
|
||||
// machine" is a state an empty cache can be in too, and a control that comes
|
||||
// and goes makes its own presence the signal.
|
||||
TextButton(onClick = onReload) { Text("Reload") }
|
||||
}
|
||||
// Captioned, unlike the controls above it, for the same reason Move is: what it
|
||||
// costs is not visible, and neither is the case it exists for.
|
||||
Text(
|
||||
"Reload throws away this phone's copy and fetches the transcript from the " +
|
||||
"server again. Use it when what is shown here disagrees with the file " +
|
||||
"on the machine.",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
error?.let {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text(
|
||||
|
||||
Reference in new issue
Block a user