Fixed the docking problems by having each agent dock once to the bottom or to the node where the "Listeners" table is shown when they get added.

This commit is contained in:
Jakob Friedl
2025-09-26 13:24:35 +02:00
parent 166cadcb56
commit d477cbd70d
4 changed files with 46 additions and 27 deletions

View File

@@ -1,5 +1,6 @@
switch "o", "bin/client" switch "o", "bin/client"
switch "d", "ssl"
switch "d", "client" switch "d", "client"
switch "d", "ImGuiTextSelect" switch "d", "ImGuiTextSelect"

View File

@@ -52,6 +52,9 @@ proc main() =
continue continue
newFrame() newFrame()
# Initialize dockspace and docking layout
dockspace.draw(addr showConquest, views, addr dockTop, addr dockBottom, addr dockTopLeft, addr dockTopRight)
#[ #[
WebSocket communication with the team server WebSocket communication with the team server
]# ]#
@@ -61,8 +64,8 @@ proc main() =
# Receive and parse websocket response message # Receive and parse websocket response message
let event = recvEvent(ws.receiveMessage().get()) let event = recvEvent(ws.receiveMessage().get())
case event.eventType: case event.eventType:
of CLIENT_PROFILE: # of CLIENT_PROFILE:
profile = parseString(event.data["profile"].getStr()) # profile = parsetoml.parseString(event.data["profile"].getStr())
of CLIENT_LISTENER_ADD: of CLIENT_LISTENER_ADD:
let listener = event.data.to(UIListener) let listener = event.data.to(UIListener)
@@ -74,6 +77,17 @@ proc main() =
dump agent.agentId dump agent.agentId
sessionsTable.agents.add(agent) sessionsTable.agents.add(agent)
# Initialize position of console windows to bottom by drawing them once when they are added
var agentConsole = Console(agent)
consoles[agent.agentId] = agentConsole
let listenersWindow = igFindWindowByName("Listeners")
if listenersWindow != nil and listenersWindow.DockNode != nil:
igSetNextWindowDockID(listenersWindow.DockNode.ID, ImGuiCond_FirstUseEver.int32)
else:
igSetNextWindowDockID(dockBottom, ImGuiCond_FirstUseEver.int32)
consoles[agent.agentId].draw(ws)
consoles[agent.agentId].showConsole = false
of CLIENT_AGENT_CHECKIN: of CLIENT_AGENT_CHECKIN:
discard discard
@@ -89,7 +103,6 @@ proc main() =
else: discard else: discard
# Draw/update UI components/views # Draw/update UI components/views
dockspace.draw(addr showConquest, views, addr dockTop, addr dockBottom, addr dockTopLeft, addr dockTopRight)
if showSessionsTable: sessionsTable.draw(addr showSessionsTable) if showSessionsTable: sessionsTable.draw(addr showSessionsTable)
if showListeners: listenersTable.draw(addr showListeners, ws) if showListeners: listenersTable.draw(addr showListeners, ws)
if showEventlog: eventlog.draw(addr showEventlog) if showEventlog: eventlog.draw(addr showEventlog)
@@ -107,7 +120,7 @@ proc main() =
# This is done to ensure that closed console windows can be opened again # This is done to ensure that closed console windows can be opened again
consoles = newConsoleTable consoles = newConsoleTable
igShowDemoWindow(nil) # igShowDemoWindow(nil)
# render # render
app.render() app.render()

View File

@@ -43,6 +43,8 @@ proc draw*(component: DockspaceComponent, showComponent: ptr bool, views: Table[
# Setup default docking layout # Setup default docking layout
var dockspaceId = igGetID_Str("Dockspace") var dockspaceId = igGetID_Str("Dockspace")
if not component.initialized:
if igDockBuilderGetNode(dockspaceId) == nil: if igDockBuilderGetNode(dockspaceId) == nil:
igDockBuilderRemoveNode(dockspaceId) igDockBuilderRemoveNode(dockspaceId)
igDockBuilderAddNode(dockspaceId, ImGuiDockNodeFlags_DockSpace.int32) igDockBuilderAddNode(dockspaceId, ImGuiDockNodeFlags_DockSpace.int32)
@@ -57,6 +59,7 @@ proc draw*(component: DockspaceComponent, showComponent: ptr bool, views: Table[
igDockBuilderDockWindow("Dear ImGui Demo", dockTopRight[]) igDockBuilderDockWindow("Dear ImGui Demo", dockTopRight[])
igDockBuilderFinish(dockspaceId) igDockBuilderFinish(dockspaceId)
component.initialized = true
# Create dockspace # Create dockspace
igDockSpace(dockspaceId, vec2(0.0f, 0.0f), component.dockspaceFlags, component.windowClass) igDockSpace(dockspaceId, vec2(0.0f, 0.0f), component.dockspaceFlags, component.windowClass)

View File

@@ -1,4 +1,4 @@
import times, tables, strformat import times, tables, strformat, strutils
import imguin/[cimgui, glfw_opengl, simple] import imguin/[cimgui, glfw_opengl, simple]
import ./console import ./console
@@ -52,13 +52,14 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
ImGui_TableFlags_SizingStretchSame.int32 ImGui_TableFlags_SizingStretchSame.int32
) )
let cols: int32 = 8 let cols: int32 = 9
if igBeginTable("Sessions", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f): if igBeginTable("Sessions", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f):
igTableSetupColumn("AgentID", ImGuiTableColumnFlags_NoReorder.int32 or ImGuiTableColumnFlags_NoHide.int32, 0.0f, 0) igTableSetupColumn("AgentID", ImGuiTableColumnFlags_NoReorder.int32 or ImGuiTableColumnFlags_NoHide.int32, 0.0f, 0)
igTableSetupColumn("Address", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("Address", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Username", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("Username", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Hostname", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("Hostname", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Domain", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("OS", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("OS", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Process", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("Process", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("PID", ImGuiTableColumnFlags_None.int32, 0.0f, 0) igTableSetupColumn("PID", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
@@ -70,10 +71,9 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
var multiSelectIO = igBeginMultiSelect(ImGuiMultiSelectFlags_ClearOnEscape.int32 or ImGuiMultiSelectFlags_BoxSelect1d.int32, component.selection[].Size, int32(component.agents.len())) var multiSelectIO = igBeginMultiSelect(ImGuiMultiSelectFlags_ClearOnEscape.int32 or ImGuiMultiSelectFlags_BoxSelect1d.int32, component.selection[].Size, int32(component.agents.len()))
ImGuiSelectionBasicStorage_ApplyRequests(component.selection, multiSelectIO) ImGuiSelectionBasicStorage_ApplyRequests(component.selection, multiSelectIO)
for row in 0 ..< component.agents.len(): for row, agent in component.agents:
igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f) igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f)
let agent = component.agents[row]
if igTableSetColumnIndex(0): if igTableSetColumnIndex(0):
# Enable multi-select functionality # Enable multi-select functionality
@@ -92,12 +92,14 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
if igTableSetColumnIndex(3): if igTableSetColumnIndex(3):
igText(agent.hostname) igText(agent.hostname)
if igTableSetColumnIndex(4): if igTableSetColumnIndex(4):
igText(agent.os) igText(if agent.domain.isEmptyOrWhitespace(): "-" else: agent.domain)
if igTableSetColumnIndex(5): if igTableSetColumnIndex(5):
igText(agent.process) igText(agent.os)
if igTableSetColumnIndex(6): if igTableSetColumnIndex(6):
igText($agent.pid) igText(agent.process)
if igTableSetColumnIndex(7): if igTableSetColumnIndex(7):
igText($agent.pid)
if igTableSetColumnIndex(8):
let duration = now() - agent.latestCheckin.fromUnix().utc() let duration = now() - agent.latestCheckin.fromUnix().utc()
let totalSeconds = duration.inSeconds let totalSeconds = duration.inSeconds
@@ -121,9 +123,9 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
if igMenuItem("Remove", nil, false, true): if igMenuItem("Remove", nil, false, true):
# Update agents table with only non-selected ones # Update agents table with only non-selected ones
var newAgents: seq[UIAgent] = @[] var newAgents: seq[UIAgent] = @[]
for i in 0 ..< component.agents.len(): for i, agent in component.agents:
if not ImGuiSelectionBasicStorage_Contains(component.selection, cast[ImGuiID](i)): if not ImGuiSelectionBasicStorage_Contains(component.selection, cast[ImGuiID](i)):
newAgents.add(component.agents[i]) newAgents.add(agent)
component.agents = newAgents component.agents = newAgents
ImGuiSelectionBasicStorage_Clear(component.selection) ImGuiSelectionBasicStorage_Clear(component.selection)