Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 09bcf7c

Browse files
committed
show less/more + display error
1 parent 840df63 commit 09bcf7c

File tree

8 files changed

+94
-52
lines changed

8 files changed

+94
-52
lines changed

.swiftlint.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
disabled_rules:
2-
- todo
2+
- todo
3+
- trailing_comma

Desktop/AgentRow.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import SwiftUI
22

3-
struct AgentRow: Identifiable {
3+
struct AgentRow: Identifiable, Equatable {
44
let id: UUID
55
let name: String
66
let status: Color
@@ -55,11 +55,11 @@ struct AgentRowView: View {
5555
.padding(3)
5656
}.foregroundStyle(copyIsSelected ? Color.white : .primary)
5757
.imageScale(.small)
58-
.background(copyIsSelected ? Color.accentColor.opacity(0.8) : .clear)
59-
.clipShape(.rect(cornerRadius: 4))
60-
.onHover { hovering in copyIsSelected = hovering }
61-
.buttonStyle(.plain)
62-
.padding(.trailing, 5)
58+
.background(copyIsSelected ? Color.accentColor.opacity(0.8) : .clear)
59+
.clipShape(.rect(cornerRadius: 4))
60+
.onHover { hovering in copyIsSelected = hovering }
61+
.buttonStyle(.plain)
62+
.padding(.trailing, 5)
6363
}
6464
}
6565
}

Desktop/CoderVPN.swift

+16-5
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,20 @@ protocol CoderVPN: ObservableObject {
88
}
99

1010
enum CoderVPNState: Equatable {
11-
case disabled
12-
case connecting
13-
case disconnecting
14-
case connected
15-
case failed(String)
11+
case disabled
12+
case connecting
13+
case disconnecting
14+
case connected
15+
case failed(CoderVPNError)
16+
}
17+
18+
enum CoderVPNError: Error {
19+
case exampleError
20+
21+
var description: String {
22+
switch self {
23+
case .exampleError:
24+
return "This is a long error to test the UI with long errors"
25+
}
26+
}
1627
}

Desktop/Preview Content/PreviewVPN.swift

+34-25
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,48 @@ class PreviewVPN: Desktop.CoderVPN {
77
AgentRow(id: UUID(), name: "testing-a-very-long-name", status: .green, copyableDNS: "asdf.coder"),
88
AgentRow(id: UUID(), name: "opensrc", status: .yellow, copyableDNS: "asdf.coder"),
99
AgentRow(id: UUID(), name: "gvisor", status: .gray, copyableDNS: "asdf.coder"),
10-
AgentRow(id: UUID(), name: "example", status: .gray, copyableDNS: "asdf.coder")
10+
AgentRow(id: UUID(), name: "example", status: .gray, copyableDNS: "asdf.coder"),
11+
AgentRow(id: UUID(), name: "dogfood2", status: .red, copyableDNS: "asdf.coder"),
12+
AgentRow(id: UUID(), name: "testing-a-very-long-name", status: .green, copyableDNS: "asdf.coder"),
13+
AgentRow(id: UUID(), name: "opensrc", status: .yellow, copyableDNS: "asdf.coder"),
14+
AgentRow(id: UUID(), name: "gvisor", status: .gray, copyableDNS: "asdf.coder"),
15+
AgentRow(id: UUID(), name: "example", status: .gray, copyableDNS: "asdf.coder"),
1116
]
12-
func start() async {
13-
await MainActor.run {
14-
state = .connecting
15-
}
16-
do {
17-
try await Task.sleep(nanoseconds: 1_000_000_000)
18-
} catch {
19-
await MainActor.run {
20-
state = .failed("Timed out starting CoderVPN")
21-
}
22-
return
23-
}
24-
await MainActor.run {
25-
state = .connected
26-
}
27-
}
17+
let shouldFail: Bool
2818

29-
func stop() async {
19+
init(shouldFail: Bool = false) {
20+
self.shouldFail = shouldFail
21+
}
22+
23+
private func setState(_ newState: Desktop.CoderVPNState) async {
3024
await MainActor.run {
31-
state = .disconnecting
25+
self.state = newState
3226
}
27+
}
28+
29+
func start() async {
30+
await setState(.connecting)
3331
do {
34-
try await Task.sleep(nanoseconds: 1_000_000_000) // Simulate network delay
32+
try await Task.sleep(nanoseconds: 1000000000)
3533
} catch {
36-
await MainActor.run {
37-
state = .failed("Timed out stopping CoderVPN")
38-
}
34+
await setState(.failed(.exampleError))
3935
return
4036
}
41-
await MainActor.run {
42-
state = .disabled
37+
if shouldFail {
38+
await setState(.failed(.exampleError))
39+
} else {
40+
await setState(.connected)
41+
}
42+
}
43+
44+
func stop() async {
45+
await setState(.disconnecting)
46+
do {
47+
try await Task.sleep(nanoseconds: 1000000000) // Simulate network delay
48+
} catch {
49+
await setState(.failed(.exampleError))
50+
return
4351
}
52+
await setState(.disabled)
4453
}
4554
}

Desktop/VPNMenu.swift

+35-10
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,27 @@ import SwiftUI
22

33
struct VPNMenu<VPN: CoderVPN>: View {
44
@ObservedObject var vpnService: VPN
5+
@State var viewAll = false
6+
7+
private let defaultVisibleRows = 5
58

69
var body: some View {
710
// Main stack
8-
VStack(alignment: .leading) {
11+
VStackLayout(alignment: .leading) {
912
// CoderVPN Stack
1013
VStack(alignment: .leading, spacing: 10) {
1114
HStack {
1215
Toggle(isOn: Binding(
1316
get: { self.vpnService.state == .connected || self.vpnService.state == .connecting },
1417
set: { isOn in Task {
15-
if isOn { await self.vpnService.start() } else { await self.vpnService.stop() }
16-
}
18+
if isOn { await self.vpnService.start() } else { await self.vpnService.stop() }
19+
}
1720
}
1821
)) {
1922
Text("CoderVPN")
2023
.frame(maxWidth: .infinity, alignment: .leading)
2124
}.toggleStyle(.switch)
22-
.disabled(self.vpnService.state == .connecting || self.vpnService.state == .disconnecting)
25+
.disabled(self.vpnService.state == .connecting || self.vpnService.state == .disconnecting)
2326
}
2427
Divider()
2528
Text("Workspace Agents")
@@ -35,12 +38,34 @@ struct VPNMenu<VPN: CoderVPN>: View {
3538
).padding()
3639
Spacer()
3740
}
41+
} else if case let .failed(vpnErr) = self.vpnService.state {
42+
Text("\(vpnErr.description)")
43+
.font(.headline)
44+
.foregroundColor(.red)
45+
.multilineTextAlignment(.center)
46+
.fixedSize(horizontal: false, vertical: true)
47+
.padding(.horizontal, 15)
48+
.padding(.top, 5)
49+
.frame(maxWidth: .infinity)
3850
}
3951
}.padding([.horizontal, .top], 15)
52+
// Workspaces List
4053
if self.vpnService.state == .connected {
41-
ForEach(self.vpnService.data) { workspace in
54+
let visibleData = viewAll ? vpnService.data : Array(vpnService.data.prefix(defaultVisibleRows))
55+
ForEach(visibleData) { workspace in
4256
AgentRowView(workspace: workspace).padding(.horizontal, 5)
4357
}
58+
if vpnService.data.count > defaultVisibleRows {
59+
Button(action: {
60+
viewAll.toggle()
61+
}, label: {
62+
Text(viewAll ? "Show Less" : "Show All")
63+
.font(.headline)
64+
.foregroundColor(.gray)
65+
.padding(.horizontal, 15)
66+
.padding(.top, 5)
67+
}).buttonStyle(.plain)
68+
}
4469
}
4570
// Trailing stack
4671
VStack(alignment: .leading, spacing: 3) {
@@ -49,29 +74,29 @@ struct VPNMenu<VPN: CoderVPN>: View {
4974
Text("Create workspace")
5075
EmptyView()
5176
} action: {
52-
// TODO
77+
// TODO:
5378
}
5479
Divider().padding([.horizontal], 10).padding(.vertical, 4)
5580
ButtonRowView {
5681
Text("About")
5782
} action: {
58-
// TODO
83+
// TODO:
5984
}
6085
ButtonRowView {
6186
Text("Preferences")
6287
} action: {
63-
// TODO
88+
// TODO:
6489
}
6590
ButtonRowView {
6691
Text("Sign out")
6792
} action: {
68-
// TODO
93+
// TODO:
6994
}
7095
}.padding([.horizontal, .bottom], 5)
7196
}.padding(.bottom, 5)
7297
}
7398
}
7499

75100
#Preview {
76-
VPNMenu(vpnService: PreviewVPN()).frame(width: 256)
101+
VPNMenu(vpnService: PreviewVPN(shouldFail: true)).frame(width: 256)
77102
}

DesktopTests/DesktopTests.swift

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import Testing
21
@testable import Desktop
2+
import Testing
33

44
struct DesktopTests {
5-
65
@Test func example() async throws {
76
// Write your test here and use APIs like `#expect(...)` to check expected conditions.
87
}
9-
108
}

DesktopUITests/DesktopUITests.swift

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import XCTest
22

33
final class DesktopUITests: XCTestCase {
4-
54
override func setUpWithError() throws {
65
// Put setup code here. This method is called before the invocation of each test method in the class.
76

DesktopUITests/DesktopUITestsLaunchTests.swift

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import XCTest
22

33
final class DesktopUITestsLaunchTests: XCTestCase {
4-
54
override class var runsForEachTargetApplicationUIConfiguration: Bool {
65
true
76
}

0 commit comments

Comments
 (0)