import QtQuick import qs.Commons import qs.Ui // BrokenSessions.qml - Sessions that a switch cut short. Shown in the list, because the point is to be noticed without going looking. // // One stage of the claude-mode panel. Panel.qml hands itself in as `panel` // and owns all the state and actions; this file only draws them. Column { id: stage required property var panel width: parent.width visible: stage.panel.stage === "list" && (stage.panel.broken.length > 0 || stage.panel.ignored.length > 0) spacing: Style.space(4) PanelSeparator { width: parent.width } Text { width: parent.width visible: stage.panel.broken.length > 0 text: stage.panel.broken.length === 1 ? "1 session cannot be resumed" : stage.panel.broken.length + " sessions cannot be resumed" color: stage.panel.urgentColor wrapMode: Text.WordWrap font.family: stage.panel.uiFont font.pixelSize: Style.space(11) font.bold: true } Repeater { model: stage.panel.stage === "list" ? stage.panel.broken : [] Item { id: brokenRow required property var modelData width: stage.width height: Style.space(26) Column { anchors.left: parent.left anchors.right: ignoreBtn.left anchors.rightMargin: Style.space(6) anchors.verticalCenter: parent.verticalCenter spacing: 0 Text { width: parent.width text: String(brokenRow.modelData.sessionId).substring(0, 8) + " · " + stage.panel.projectLabel(brokenRow.modelData.project) color: Color.popups.text elide: Text.ElideMiddle font.family: stage.panel.uiFont font.pixelSize: Style.space(10) } Text { width: parent.width text: brokenRow.modelData.dropLines + " turn lines after the last good message" color: Color.muted elide: Text.ElideRight font.family: stage.panel.uiFont font.pixelSize: Style.space(9) } } PillButton { fontFamily: stage.panel.uiFont; id: ignoreBtn anchors.right: repairBtn.left anchors.rightMargin: Style.space(5) anchors.verticalCenter: parent.verticalCenter label: "Ignore" onTriggered: stage.panel.setIgnored(brokenRow.modelData, true) } PillButton { fontFamily: stage.panel.uiFont; id: repairBtn anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter label: "Repair" onTriggered: stage.panel.askRepair(brokenRow.modelData) } } } // ---- Hidden: dismissed here, or broken but untouched for longer than // the age limit. Collapsed, because the point of hiding them was that // they stop taking up attention - but never gone without a trace. Item { width: parent.width height: Style.space(20) visible: stage.panel.ignored.length > 0 Text { id: hiddenLabel anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter text: "hidden (" + stage.panel.ignored.length + ")" color: hiddenArea.containsMouse ? Color.popups.text : Color.muted font.family: stage.panel.uiFont font.pixelSize: Style.space(10) } Text { anchors.left: hiddenLabel.right anchors.leftMargin: Style.space(4) anchors.verticalCenter: parent.verticalCenter text: String.fromCodePoint(stage.panel.hiddenExpanded ? 0xF0140 : 0xF0142) color: hiddenLabel.color font.family: stage.panel.uiFont font.pixelSize: Style.space(11) } MouseArea { id: hiddenArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: stage.panel.hiddenExpanded = !stage.panel.hiddenExpanded } } Column { width: parent.width visible: stage.panel.hiddenExpanded && stage.panel.ignored.length > 0 spacing: Style.space(3) Text { visible: stage.panel.dismissedList.length > 0 text: "Ignored (" + stage.panel.dismissedList.length + ")" color: Color.popups.text font.family: stage.panel.uiFont font.pixelSize: Style.space(10) font.bold: true } Repeater { model: stage.panel.hiddenExpanded ? stage.panel.dismissedList.slice(0, stage.panel.hiddenCap) : [] Item { id: dismissedRow required property var modelData width: stage.width height: Style.space(26) Text { anchors.left: parent.left anchors.right: restoreBtn.left anchors.rightMargin: Style.space(6) anchors.verticalCenter: parent.verticalCenter text: String(dismissedRow.modelData.sessionId).substring(0, 8) + " · " + stage.panel.projectLabel(dismissedRow.modelData.project) color: Color.muted elide: Text.ElideMiddle font.family: stage.panel.uiFont font.pixelSize: Style.space(10) } PillButton { fontFamily: stage.panel.uiFont; id: restoreBtn anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter label: "Restore" onTriggered: stage.panel.setIgnored(dismissedRow.modelData, false) } } } Text { visible: stage.panel.dismissedList.length > stage.panel.hiddenCap text: "… and " + (stage.panel.dismissedList.length - stage.panel.hiddenCap) + " more · claude-mode repair-session --ignored" color: Color.muted font.family: stage.panel.uiFont font.pixelSize: Style.space(9) } Text { visible: stage.panel.staleList.length > 0 text: "Older than " + stage.panel.ageDays + " days (" + stage.panel.staleList.length + ")" color: Color.popups.text font.family: stage.panel.uiFont font.pixelSize: Style.space(10) font.bold: true } Repeater { model: stage.panel.hiddenExpanded ? stage.panel.staleList.slice(0, stage.panel.hiddenCap) : [] Text { required property var modelData width: stage.width text: String(modelData.sessionId).substring(0, 8) + " · " + Math.floor((Date.now() / 1000 - Number(modelData.mtime)) / 86400) + "d" + " · " + stage.panel.projectLabel(modelData.project) color: Color.muted elide: Text.ElideMiddle font.family: stage.panel.uiFont font.pixelSize: Style.space(10) } } Text { width: parent.width visible: stage.panel.staleList.length > 0 text: (stage.panel.staleList.length > stage.panel.hiddenCap ? "… and " + (stage.panel.staleList.length - stage.panel.hiddenCap) + " more. " : "") + "Not counted because nothing has touched them since. " + "claude-mode repair-session --all --max-age 0 lists them." color: Color.muted opacity: 0.85 wrapMode: Text.WordWrap font.family: stage.panel.uiFont font.pixelSize: Style.space(9) } } }