gui: add pending bypass indicator to agent tree
Track multiple concurrent pending bypasses per agent in C++ backend: - Add m_pendingBypasses QHash<QString,QSet<QString>> keyed by session:agent - Add pendingBypassCount(sessionId, agentId) Q_INVOKABLE - Add pendingBypassCountChanged(sessionId, agentId) signal - Update resolveBypass to take agentId and remove from tracking set SessionTree.qml: show ⚠ indicator left of agent name when the agent has pending bypass requests. Uses Connections to refresh on signal. ChatPane.qml: pass agentId to resolveBypass calls.
This commit is contained in:
parent
f9e6785add
commit
150ca5dfdd
|
|
@ -188,7 +188,7 @@ Item {
|
|||
highlighted: true
|
||||
onClicked: {
|
||||
if (chatPane.pendingBypass) {
|
||||
ollie.resolveBypass(chatPane.pendingBypass.sessionId, chatPane.pendingBypass.id, true)
|
||||
ollie.resolveBypass(chatPane.pendingBypass.sessionId, chatPane.pendingBypass.agentId, chatPane.pendingBypass.id, true)
|
||||
chatPane.pendingBypass = null
|
||||
chatPane.hasPendingBypass = false
|
||||
}
|
||||
|
|
@ -199,7 +199,7 @@ Item {
|
|||
text: "Deny"
|
||||
onClicked: {
|
||||
if (chatPane.pendingBypass) {
|
||||
ollie.resolveBypass(chatPane.pendingBypass.sessionId, chatPane.pendingBypass.id, false)
|
||||
ollie.resolveBypass(chatPane.pendingBypass.sessionId, chatPane.pendingBypass.agentId, chatPane.pendingBypass.id, false)
|
||||
chatPane.pendingBypass = null
|
||||
chatPane.hasPendingBypass = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,6 +229,26 @@ Item {
|
|||
visible: type === "session"
|
||||
}
|
||||
|
||||
// Pending bypass indicator (agent rows only)
|
||||
Label {
|
||||
id: bypassIndicator
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.rightMargin: 4
|
||||
text: "⚠"
|
||||
color: "#e6a700"
|
||||
font.pixelSize: theme.fontSize > 0 ? theme.fontSize : 12
|
||||
visible: type === "agent" && ollie.pendingBypassCount(parentId || "", agentId || "") > 0
|
||||
|
||||
Connections {
|
||||
target: ollie
|
||||
function onPendingBypassCountChanged(sid, aid) {
|
||||
if (type === "agent" && sid === parentId && aid === agentId) {
|
||||
bypassIndicator.visible = ollie.pendingBypassCount(parentId || "", agentId || "") > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Name area
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -243,6 +243,12 @@ void Ollie9pClient::handleEvent(const QString &eventLine)
|
|||
QString cmd = payload.mid(tab1 + 1, tab2 - tab1 - 1).toString();
|
||||
cmd.replace(QLatin1String("\\n"), QLatin1String("\n")); // unescape newlines
|
||||
const QString cwd = payload.mid(tab2 + 1).toString();
|
||||
|
||||
// Track pending bypass
|
||||
const QString key = agentKey(sessionId.toString(), agentId.toString());
|
||||
m_pendingBypasses[key].insert(id);
|
||||
emit pendingBypassCountChanged(sessionId.toString(), agentId.toString());
|
||||
|
||||
emit bypassRequested(sessionId.toString(), agentId.toString(), id, cmd, cwd);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -260,6 +266,12 @@ QString Ollie9pClient::agentState(const QString &sessionId, const QString &agent
|
|||
return m_agentStateValues.value(agentKey(sessionId, agentId), "idle");
|
||||
}
|
||||
|
||||
int Ollie9pClient::pendingBypassCount(const QString &sessionId, const QString &agentId) const
|
||||
{
|
||||
const QString key = agentKey(sessionId, agentId);
|
||||
return m_pendingBypasses.value(key).size();
|
||||
}
|
||||
|
||||
void Ollie9pClient::refreshSessions()
|
||||
{
|
||||
if (!m_daemonConnected) return;
|
||||
|
|
@ -764,7 +776,7 @@ bool Ollie9pClient::renameAgent(const QString &sessionId, const QString &agentId
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Ollie9pClient::resolveBypass(const QString &sessionId, const QString &id, bool approve)
|
||||
bool Ollie9pClient::resolveBypass(const QString &sessionId, const QString &agentId, const QString &id, bool approve)
|
||||
{
|
||||
if (sessionId.isEmpty() || id.isEmpty()) return false;
|
||||
if (!m_9p || !m_9p->isConnected()) return false;
|
||||
|
|
@ -772,6 +784,16 @@ bool Ollie9pClient::resolveBypass(const QString &sessionId, const QString &id, b
|
|||
QString path = "session/" + sessionId + "/bypass";
|
||||
QString data = id + (approve ? " approve" : " deny");
|
||||
if (m_9p->write(path, data.toUtf8())) {
|
||||
// Remove from pending bypasses
|
||||
const QString key = agentKey(sessionId, agentId);
|
||||
if (m_pendingBypasses.contains(key)) {
|
||||
m_pendingBypasses[key].remove(id);
|
||||
if (m_pendingBypasses[key].isEmpty()) {
|
||||
m_pendingBypasses.remove(key);
|
||||
}
|
||||
emit pendingBypassCountChanged(sessionId, agentId);
|
||||
emit bypassResolved(sessionId, agentId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
qDebug() << "resolveBypass failed:" << m_9p->lastError();
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ public:
|
|||
bool daemonConnected() const { return m_daemonConnected; }
|
||||
Q_INVOKABLE QString agentState(const QString &sessionId, const QString &agentId) const;
|
||||
Q_INVOKABLE QString sessionConnectionColor(const QString &sessionId) const;
|
||||
Q_INVOKABLE int pendingBypassCount(const QString &sessionId, const QString &agentId) const;
|
||||
Q_INVOKABLE void setCurrentBackend(const QString &backend) {
|
||||
if (m_currentBackend == backend) return;
|
||||
m_currentBackend = backend;
|
||||
|
|
@ -90,7 +91,7 @@ public:
|
|||
Q_INVOKABLE bool killAgent(const QString &sessionId, const QString &agentId);
|
||||
Q_INVOKABLE bool renameSession(const QString &sessionId, const QString &newName);
|
||||
Q_INVOKABLE bool renameAgent(const QString &sessionId, const QString &agentId, const QString &newName);
|
||||
Q_INVOKABLE bool resolveBypass(const QString &sessionId, const QString &id, bool approve);
|
||||
Q_INVOKABLE bool resolveBypass(const QString &sessionId, const QString &agentId, const QString &id, bool approve);
|
||||
Q_INVOKABLE QString lastError() const { return m_9p ? m_9p->lastError() : QString(); }
|
||||
|
||||
signals:
|
||||
|
|
@ -101,6 +102,8 @@ signals:
|
|||
void agentStateChanged(const QString &sessionId, const QString &agentId, const QString &state);
|
||||
void chatReceived(const QString &text);
|
||||
void bypassRequested(const QString &sessionId, const QString &agentId, const QString &id, const QString &cmd, const QString &cwd);
|
||||
void bypassResolved(const QString &sessionId, const QString &agentId);
|
||||
void pendingBypassCountChanged(const QString &sessionId, const QString &agentId);
|
||||
void rootBackendsLoadedChanged();
|
||||
void availableBackendsChanged();
|
||||
void rootAgentsLoadedChanged();
|
||||
|
|
@ -146,6 +149,9 @@ private:
|
|||
|
||||
// Agent state cache — updated via delta events
|
||||
QHash<QString, QString> m_agentStateValues;
|
||||
|
||||
// Pending bypass requests per agent: agentKey -> set of bypass IDs
|
||||
QHash<QString, QSet<QString>> m_pendingBypasses;
|
||||
|
||||
// Native streaming readers
|
||||
Lib9pStreamer *m_chat = nullptr; // Guarded — reads agent chat log
|
||||
|
|
|
|||
Loading…
Reference in New Issue