Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Sources/AppleDockerApp/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum SidebarItem: String, CaseIterable, Identifiable {
case volumes = "Volumes"
case networks = "Networks"
case compose = "Compose"
case editor = "Editor"
case activity = "Activity Monitor"
case settings = "Settings"

Expand All @@ -30,6 +31,7 @@ enum SidebarItem: String, CaseIterable, Identifiable {
case .volumes: "externaldrive"
case .networks: "network"
case .compose: "square.stack.3d.up"
case .editor: "doc.plaintext"
case .activity: "waveform.path.ecg"
case .settings: "gearshape"
}
Expand Down Expand Up @@ -121,6 +123,8 @@ private struct RootView: View {
NetworkListView()
case .compose:
ComposeView()
case .editor:
ComposeEditorView()
case .activity:
ActivityMonitorView()
case .settings:
Expand Down
36 changes: 27 additions & 9 deletions Sources/AppleDockerApp/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ final class AppState {
/// History of image builds, shown in the Builds tab (most recent first).
var buildHistory: [BuildRecord] = []
/// Persistent terminal sessions, keyed by container ID. Kept here so the
/// terminal survives tab switches.
var terminalSessions: [String: ContainerTerminalSession] = [:]
/// terminal survives tab switches. Each container may have multiple sessions.
var terminalSessions: [String: [ContainerTerminalSession]] = [:]

// MARK: - Build tracking

Expand Down Expand Up @@ -357,17 +357,35 @@ final class AppState {

// MARK: - Terminal sessions

/// Return the persistent terminal session for a container, creating it on
/// first use.
func terminalSession(for containerID: String) -> ContainerTerminalSession {
if let session = terminalSessions[containerID] {
return session
/// Return the list of terminal sessions for a container, creating a
/// default first session if none exist yet.
func terminalSessions(for containerID: String) -> [ContainerTerminalSession] {
if let sessions = terminalSessions[containerID], !sessions.isEmpty {
return sessions
}
let session = ContainerTerminalSession(containerID: containerID)
terminalSessions[containerID] = session
let session = ContainerTerminalSession(containerID: containerID, sessionLabel: "Session 1")
terminalSessions[containerID] = [session]
return [session]
}

/// Add a new terminal session for a container and return it.
@discardableResult
func addTerminalSession(for containerID: String) -> ContainerTerminalSession {
let existing = terminalSessions[containerID] ?? []
let label = "Session \(existing.count + 1)"
let session = ContainerTerminalSession(containerID: containerID, sessionLabel: label)
terminalSessions[containerID] = existing + [session]
return session
}

/// Remove a terminal session for a container.
func removeTerminalSession(_ session: ContainerTerminalSession) {
guard var sessions = terminalSessions[session.containerID] else { return }
sessions.removeAll { $0 === session }
session.disconnect()
terminalSessions[session.containerID] = sessions
}

// MARK: - Container actions

func startContainer(_ id: String) async {
Expand Down
Loading