Files
applecontainercompose/Sources/ContentView.swift
T
2026-11-08 17:28:29 +00:00

78 lines
4.2 KiB
Swift

import SwiftUI
struct ContentView: View {
@EnvironmentObject private var model: ComposeModel
var body: some View {
NavigationSplitView {
VStack(alignment: .leading, spacing: 12) {
HStack {
Image(systemName: "shippingbox.fill").foregroundStyle(.blue)
Text("Services").font(.headline)
Spacer()
Text("\(model.services.count)").foregroundStyle(.secondary)
}.padding(.horizontal)
List(selection: $model.selectedService) {
ForEach(model.services) { service in
VStack(alignment: .leading, spacing: 4) {
Text(service.id).font(.headline)
Text(service.image).font(.caption).foregroundStyle(.secondary).lineLimit(1)
}.padding(.vertical, 4).tag(service.id)
}
}
Text(model.projectURL?.lastPathComponent ?? "No project opened")
.font(.caption).foregroundStyle(.secondary).lineLimit(1).padding()
}
.navigationSplitViewColumnWidth(min: 220, ideal: 265)
} detail: {
VStack(alignment: .leading, spacing: 14) {
HStack {
VStack(alignment: .leading, spacing: 4) {
Text("Apple Container Compose").font(.title2.bold())
Text(model.projectURL?.deletingLastPathComponent().path ?? "Open a Compose project to get started")
.font(.caption).foregroundStyle(.secondary).textSelection(.enabled)
}
Spacer()
Text(model.status).foregroundStyle(.secondary)
}
if let service = model.services.first(where: { $0.id == model.selectedService }) {
GroupBox("Selected service") {
VStack(alignment: .leading, spacing: 6) {
LabeledContent("Name", value: service.id)
LabeledContent("Image", value: service.image)
LabeledContent("Ports", value: service.ports.joined(separator: ", ").isEmpty ? "None" : service.ports.joined(separator: ", "))
LabeledContent("Depends on", value: service.dependencies.joined(separator: ", ").isEmpty ? "None" : service.dependencies.joined(separator: ", "))
}.frame(maxWidth: .infinity, alignment: .leading).padding(5)
}
}
HStack {
Text("Command output").font(.headline)
Spacer()
Button("Clear") { model.clearLog() }
}
ScrollView {
Text(model.output).font(.system(size: 12, design: .monospaced))
.frame(maxWidth: .infinity, alignment: .leading)
.textSelection(.enabled).padding(12)
}
.background(.black.opacity(0.87), in: RoundedRectangle(cornerRadius: 9))
.foregroundStyle(.green)
}.padding(20)
}
.toolbar {
ToolbarItemGroup {
Button("Open YAML", systemImage: "folder") { model.openProject() }
Button("Up", systemImage: "play.fill") { model.perform("up") }.disabled(model.busy || model.projectURL == nil)
Button("Down", systemImage: "stop.fill") { model.perform("down") }.disabled(model.busy || model.projectURL == nil)
Button("Restart", systemImage: "arrow.clockwise") { model.perform("restart") }.disabled(model.busy || model.projectURL == nil)
Button("Status", systemImage: "list.bullet.rectangle") { model.perform("ps") }.disabled(model.busy || model.projectURL == nil)
Button("Logs", systemImage: "text.alignleft") { model.perform("logs") }.disabled(model.busy || model.projectURL == nil)
Menu("More") {
Button("Pull Images") { model.perform("pull") }
Button("Build Images") { model.perform("build") }
Button("Check Runtime") { model.checkRuntime() }
}
}
}
}
}