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 "d", "ssl"
switch "d", "client"
switch "d", "ImGuiTextSelect"

View File

@@ -52,6 +52,9 @@ proc main() =
continue
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
]#
@@ -61,8 +64,8 @@ proc main() =
# Receive and parse websocket response message
let event = recvEvent(ws.receiveMessage().get())
case event.eventType:
of CLIENT_PROFILE:
profile = parseString(event.data["profile"].getStr())
# of CLIENT_PROFILE:
# profile = parsetoml.parseString(event.data["profile"].getStr())
of CLIENT_LISTENER_ADD:
let listener = event.data.to(UIListener)
@@ -74,6 +77,17 @@ proc main() =
dump agent.agentId
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:
discard
@@ -89,7 +103,6 @@ proc main() =
else: discard
# 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 showListeners: listenersTable.draw(addr showListeners, ws)
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
consoles = newConsoleTable
igShowDemoWindow(nil)
# igShowDemoWindow(nil)
# render
app.render()

View File

@@ -43,20 +43,23 @@ proc draw*(component: DockspaceComponent, showComponent: ptr bool, views: Table[
# Setup default docking layout
var dockspaceId = igGetID_Str("Dockspace")
if igDockBuilderGetNode(dockspaceId) == nil:
igDockBuilderRemoveNode(dockspaceId)
igDockBuilderAddNode(dockspaceId, ImGuiDockNodeFlags_DockSpace.int32)
igDockBuilderSetNodeSize(dockspaceId, vp.WorkSize)
discard igDockBuilderSplitNode(dockspaceId, ImGuiDir_Down, 0.8f, dockBottom, dockTop)
discard igDockBuilderSplitNode(dockTop[], ImGuiDir_Right, 0.4f, dockTopRight, dockTopLeft)
if not component.initialized:
if igDockBuilderGetNode(dockspaceId) == nil:
igDockBuilderRemoveNode(dockspaceId)
igDockBuilderAddNode(dockspaceId, ImGuiDockNodeFlags_DockSpace.int32)
igDockBuilderSetNodeSize(dockspaceId, vp.WorkSize)
igDockBuilderDockWindow("Sessions [Table View]", dockTopLeft[])
igDockBuilderDockWindow("Listeners", dockBottom[])
igDockBuilderDockWindow("Eventlog", dockTopRight[])
igDockBuilderDockWindow("Dear ImGui Demo", dockTopRight[])
discard igDockBuilderSplitNode(dockspaceId, ImGuiDir_Down, 0.8f, dockBottom, dockTop)
discard igDockBuilderSplitNode(dockTop[], ImGuiDir_Right, 0.4f, dockTopRight, dockTopLeft)
igDockBuilderFinish(dockspaceId)
igDockBuilderDockWindow("Sessions [Table View]", dockTopLeft[])
igDockBuilderDockWindow("Listeners", dockBottom[])
igDockBuilderDockWindow("Eventlog", dockTopRight[])
igDockBuilderDockWindow("Dear ImGui Demo", dockTopRight[])
igDockBuilderFinish(dockspaceId)
component.initialized = true
# Create dockspace
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 ./console
@@ -52,13 +52,14 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
ImGui_TableFlags_SizingStretchSame.int32
)
let cols: int32 = 8
let cols: int32 = 9
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("Address", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Username", 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("Process", 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()))
ImGuiSelectionBasicStorage_ApplyRequests(component.selection, multiSelectIO)
for row in 0 ..< component.agents.len():
for row, agent in component.agents:
igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f)
let agent = component.agents[row]
if igTableSetColumnIndex(0):
# Enable multi-select functionality
@@ -92,12 +92,14 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
if igTableSetColumnIndex(3):
igText(agent.hostname)
if igTableSetColumnIndex(4):
igText(agent.os)
igText(if agent.domain.isEmptyOrWhitespace(): "-" else: agent.domain)
if igTableSetColumnIndex(5):
igText(agent.process)
igText(agent.os)
if igTableSetColumnIndex(6):
igText($agent.pid)
igText(agent.process)
if igTableSetColumnIndex(7):
igText($agent.pid)
if igTableSetColumnIndex(8):
let duration = now() - agent.latestCheckin.fromUnix().utc()
let totalSeconds = duration.inSeconds
@@ -121,9 +123,9 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
if igMenuItem("Remove", nil, false, true):
# Update agents table with only non-selected ones
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)):
newAgents.add(component.agents[i])
newAgents.add(agent)
component.agents = newAgents
ImGuiSelectionBasicStorage_Clear(component.selection)