Panel.qml keeps the state, the CLI calls and the stage switch (889 lines, was 2360); each stage is its own file taking the panel as a required property. The omarchy installer copies every QML/JS file and clears stale ones. tests/static.sh filters qmllint on [syntax], not the word error. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
219 lines
6.9 KiB
QML
219 lines
6.9 KiB
QML
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)
|
|
}
|
|
}
|
|
}
|