gui: procs output panel resizable and toggle-able

- SplitView allows dragging the divider between process list and output
- Show/Hide Output button toggles output panel visibility
- View Output and double-click auto-show the panel if hidden
This commit is contained in:
Levi Neely 2026-10-09 09:43:25 +02:00
parent 9b8715d625
commit cc56fda862
1 changed files with 122 additions and 104 deletions

View File

@ -14,6 +14,7 @@ Window {
property var procs: [] property var procs: []
property string outputText: "" property string outputText: ""
property int selectedPid: -1 property int selectedPid: -1
property bool outputVisible: true
// Track the session we're displaying (synced from main window) // Track the session we're displaying (synced from main window)
property string currentSessionId: ollie.activeSessionId property string currentSessionId: ollie.activeSessionId
@ -106,113 +107,123 @@ Window {
} }
} }
// Process list // Resizable split between process list and output
ListView { SplitView {
id: procList
Layout.fillWidth: true
Layout.preferredHeight: 180
Layout.minimumHeight: 100
model: procs
clip: true
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
delegate: Rectangle {
width: procList.width
height: 44
color: selectedPid === modelData.pid ? palette.highlight : (index % 2 ? palette.alternateBase : palette.base)
MouseArea {
anchors.fill: parent
onClicked: selectedPid = modelData.pid
onDoubleClicked: {
selectedPid = modelData.pid
var out = ollie.procOutput(currentSessionId, currentAgentId, selectedPid)
outputText = out.length > 0 ? out : "(no output)"
}
}
RowLayout {
anchors.fill: parent
anchors.margins: 8
spacing: 12
// Status indicator
Rectangle {
width: 10
height: 10
radius: 5
color: modelData.status === "running" ? "#4CAF50" : (modelData.exitCode === 0 ? "#9E9E9E" : "#F44336")
}
// PID
Label {
text: modelData.pid
font.family: "monospace"
Layout.preferredWidth: 50
}
// Tool
Label {
text: modelData.tool
font.weight: Font.Medium
Layout.preferredWidth: 80
elide: Text.ElideRight
}
// Command
Label {
text: modelData.cmd
Layout.fillWidth: true
elide: Text.ElideMiddle
opacity: 0.8
}
// Runtime
Label {
text: formatRuntime(modelData.runtime)
font.family: "monospace"
Layout.preferredWidth: 55
horizontalAlignment: Text.AlignRight
}
// Exit code (if exited)
Label {
visible: modelData.status !== "running"
text: modelData.exitCode === 0 ? "✓" : "exit " + modelData.exitCode
font.family: "monospace"
color: modelData.exitCode === 0 ? "#4CAF50" : "#F44336"
Layout.preferredWidth: 45
}
}
}
Label {
anchors.centerIn: parent
visible: procs.length === 0
text: currentSessionId ? "No background processes" : "No session selected"
opacity: 0.5
}
}
// Output pane (always visible)
GroupBox {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.minimumHeight: 100 orientation: Qt.Vertical
title: selectedPid > 0 ? "Output (PID " + selectedPid + ")" : "Output"
ScrollView { // Process list
anchors.fill: parent ListView {
TextArea { id: procList
id: outputArea SplitView.fillWidth: true
text: outputText SplitView.minimumHeight: 80
readOnly: true SplitView.preferredHeight: 180
font.family: "monospace" model: procs
font.pointSize: 11 clip: true
wrapMode: TextEdit.Wrap
selectByMouse: true ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
placeholderText: "Select a process and click View Output"
delegate: Rectangle {
width: procList.width
height: 44
color: selectedPid === modelData.pid ? palette.highlight : (index % 2 ? palette.alternateBase : palette.base)
MouseArea {
anchors.fill: parent
onClicked: selectedPid = modelData.pid
onDoubleClicked: {
selectedPid = modelData.pid
var out = ollie.procOutput(currentSessionId, currentAgentId, selectedPid)
outputText = out.length > 0 ? out : "(no output)"
outputVisible = true
}
}
RowLayout {
anchors.fill: parent
anchors.margins: 8
spacing: 12
// Status indicator
Rectangle {
width: 10
height: 10
radius: 5
color: modelData.status === "running" ? "#4CAF50" : (modelData.exitCode === 0 ? "#9E9E9E" : "#F44336")
}
// PID
Label {
text: modelData.pid
font.family: "monospace"
Layout.preferredWidth: 50
}
// Tool
Label {
text: modelData.tool
font.weight: Font.Medium
Layout.preferredWidth: 80
elide: Text.ElideRight
}
// Command
Label {
text: modelData.cmd
Layout.fillWidth: true
elide: Text.ElideMiddle
opacity: 0.8
}
// Runtime
Label {
text: formatRuntime(modelData.runtime)
font.family: "monospace"
Layout.preferredWidth: 55
horizontalAlignment: Text.AlignRight
}
// Exit code (if exited)
Label {
visible: modelData.status !== "running"
text: modelData.exitCode === 0 ? "✓" : "exit " + modelData.exitCode
font.family: "monospace"
color: modelData.exitCode === 0 ? "#4CAF50" : "#F44336"
Layout.preferredWidth: 45
}
}
}
Label {
anchors.centerIn: parent
visible: procs.length === 0
text: currentSessionId ? "No background processes" : "No session selected"
opacity: 0.5
}
}
// Output pane (toggle-able)
GroupBox {
id: outputPane
visible: outputVisible
SplitView.fillWidth: true
SplitView.fillHeight: true
SplitView.minimumHeight: 60
title: selectedPid > 0 ? "Output (PID " + selectedPid + ")" : "Output"
ScrollView {
anchors.fill: parent
TextArea {
id: outputArea
text: outputText
readOnly: true
font.family: "monospace"
font.pointSize: 11
wrapMode: TextEdit.Wrap
selectByMouse: true
placeholderText: "Select a process and click View Output"
}
} }
} }
} }
@ -236,9 +247,16 @@ Window {
outputText = "" outputText = ""
var out = ollie.procOutput(currentSessionId, currentAgentId, selectedPid) var out = ollie.procOutput(currentSessionId, currentAgentId, selectedPid)
outputText = out.length > 0 ? out : "(no output)" outputText = out.length > 0 ? out : "(no output)"
outputVisible = true
} }
} }
Button {
text: outputVisible ? "Hide Output" : "Show Output"
icon.name: outputVisible ? "go-up" : "go-down"
onClicked: outputVisible = !outputVisible
}
Item { Layout.fillWidth: true } Item { Layout.fillWidth: true }
Button { Button {