gui: fix session tree view delegate crashes and scrollable input

- Guard delegate against undefined properties during initial render
- Use || 0 fallbacks for optional model properties
- Remove broken ScrollBar.vertical.value assignment (not assignable)
- Fix Keys.onReturnPressed to use explicit function(event) parameter
- Call buildSessionTree() on Component.onCompleted
This commit is contained in:
Levi Neely 2026-08-01 11:48:59 +02:00
parent 3cedf602be
commit 69458631dc
1 changed files with 40 additions and 41 deletions

View File

@ -73,11 +73,13 @@ ApplicationWindow {
}
function buildSessionTree() {
console.log("buildSessionTree: sessions count = " + ollie.sessions.length)
sessionTreeModel.clear()
var sessions = ollie.sessions
for (var i = 0; i < sessions.length; ++i) {
var sess = sessions[i].toMap()
var sess = sessions[i]
var sid = sess.id || ""
console.log(" session[" + i + "] = " + sid)
// Auto-expand active session
var expanded = (sid === ollie.activeSessionId)
// Add session node
@ -91,19 +93,25 @@ ApplicationWindow {
displayName: sid
})
// Fetch agents and add them
var agents = ollie.getAgents(sid)
for (var j = 0; j < agents.length; ++j) {
var aid = agents[j]
sessionTreeModel.append({
type: "agent",
parentId: sid,
agentId: aid,
level: 1,
state: "idle",
displayName: "Agent " + aid
})
try {
var agents = ollie.getAgents(sid)
console.log(" agents for " + sid + ": " + agents.length)
for (var j = 0; j < agents.length; ++j) {
var aid = agents[j]
sessionTreeModel.append({
type: "agent",
parentId: sid,
agentId: aid,
level: 1,
state: "idle",
displayName: "Agent " + aid
})
}
} catch(e) {
console.log(" error getting agents for " + sid + ": " + e)
}
}
console.log(" total tree items: " + sessionTreeModel.count)
}
function toggleExpand(index) {
@ -131,6 +139,7 @@ ApplicationWindow {
chatModel.trimFront(30)
}
scrollTimer.start()
buildSessionTree()
}
Connections {
@ -305,54 +314,47 @@ ApplicationWindow {
delegate: ItemDelegate {
width: sessionList.width
// Guard against undefined during initial render
height: {
if (modelData.type === "agent" && !parentSessionExpanded(modelData.parentId))
if (!type) return 0
if (type === "agent" && !parentSessionExpanded(parentId))
return 0
return 28
}
visible: height > 0
property var _parentItem: null
contentItem: RowLayout {
anchors.fill: parent
spacing: 0
// Expand/collapse indicator
// Indent + expand/collapse indicator
Label {
Layout.leftPadding: modelData.level * 16 + 4
Layout.preferredWidth: 16
text: modelData.type === "session" ? (modelData.expanded ? "▼" : "▶") : ""
Layout.preferredWidth: (level || 0) * 16 + 16
text: type === "session" ? (expanded ? "▼" : "▶") : ""
font.pixelSize: theme.fontSize > 0 ? theme.fontSize * 0.7 : 10
color: theme.textColor
opacity: 0.6
}
// Icon/type indicator
Label {
Layout.preferredWidth: 16
text: modelData.type === "session" ? "📁" : "🤖"
font.pixelSize: theme.fontSize > 0 ? theme.fontSize * 0.8 : 11
verticalAlignment: Text.AlignVCenter
}
// Name
Label {
Layout.fillWidth: true
text: modelData.displayName || ""
text: displayName || ""
color: theme.textColor
font.pointSize: theme.fontSize > 0 ? theme.fontSize : Qt.application.font.pointSize
verticalAlignment: Text.AlignVCenter
leftPadding: 4
}
// State dot
Rectangle {
Layout.preferredWidth: 8
Layout.preferredHeight: 8
Layout.alignment: Qt.AlignVCenter
radius: 4
anchors.verticalCenter: parent.verticalCenter
color: {
var s = modelData.state || "idle"
var s = state || "idle"
if (s === "idle") return "#4caf50"
if (s.startsWith("calling")) return "#ff9800"
return "#2196f3"
@ -361,19 +363,19 @@ ApplicationWindow {
}
onClicked: {
if (modelData.type === "session") {
if (type === "session") {
toggleExpand(index)
} else if (modelData.type === "agent") {
activateAgent(modelData.parentId, modelData.agentId)
} else if (type === "agent") {
activateAgent(parentId, agentId)
}
}
highlighted: (modelData.type === "agent" && modelData.agentId === ollie.activeAgentId && modelData.parentId === ollie.activeSessionId)
highlighted: (type === "agent" && agentId === ollie.activeAgentId && parentId === ollie.activeSessionId)
function parentSessionExpanded(parentId) {
function parentSessionExpanded(pid) {
for (var i = 0; i < sessionTreeModel.count; ++i) {
var item = sessionTreeModel.get(i)
if (item.id === parentId && item.type === "session")
if (item.id === pid && item.type === "session")
return item.expanded
}
return false
@ -554,6 +556,7 @@ ApplicationWindow {
spacing: 4
ScrollView {
id: promptScroll
Layout.fillWidth: true
Layout.maximumHeight: 200
Layout.preferredHeight: Math.min(promptInput.contentHeight + 16, 200)
@ -565,11 +568,7 @@ ApplicationWindow {
placeholderText: ollie.activeSessionId ? "Message..." : "No session"
enabled: ollie.activeSessionId !== ""
wrapMode: TextEdit.Wrap
onTextChanged: {
// Auto-scroll to bottom as content grows
textCursor.position = text.length
}
Keys.onReturnPressed: {
Keys.onReturnPressed: function(event) {
if (event.modifiers & Qt.ShiftModifier) {
event.accepted = false
} else {