Skip to content

Commit dea0478

Browse files
committed
add TextField to store OpenAI key
1 parent 192e32c commit dea0478

7 files changed

Lines changed: 122 additions & 75 deletions

File tree

Core/Sources/HostApp/Benchmark/DI/BenchmarkModule.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
protocol BenchmarkModuleType {
22
func provide() -> BenchmarkViewModel
3-
func provide() -> OutputConfigurationViewModel
3+
func provide() -> ConfigurationViewModel
44
func provide() -> AddDirectoryViewModel
55
}
66

@@ -31,8 +31,8 @@ class BenchmarkModule: BenchmarkModuleType {
3131
)
3232
}
3333

34-
func provide() -> OutputConfigurationViewModel {
35-
OutputConfigurationViewModel(
34+
func provide() -> ConfigurationViewModel {
35+
ConfigurationViewModel(
3636
benchmarkSettingsRepository: component()
3737
)
3838
}

Core/Sources/HostApp/Benchmark/Data/Repository/LocalBenchmarkSettingsRepository.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class LocalBenchmarkSettingsRepository: BenchmarkSettingsRepository {
55
private let localStorageManager: LocalStorageManager
66
private let benchmarkDirectoriesKey = "benchmarkDirectories"
77
private let benchmarkOutputDirectoryKey = "benchmarkOutputDirectory"
8+
private let openAIKeyDefaultsKey = "openAIKey"
89

910
private var defaultOutputDirectory: URL {
1011
FileManager.default.homeDirectoryForCurrentUser
@@ -21,6 +22,11 @@ class LocalBenchmarkSettingsRepository: BenchmarkSettingsRepository {
2122
benchmarkOutputDirectory.eraseToAnyPublisher()
2223
}
2324

25+
private let currentOpenAIKey: CurrentValueSubject<String, Never> = CurrentValueSubject("")
26+
var openAIKey: AnyPublisher<String, Never> {
27+
currentOpenAIKey.eraseToAnyPublisher()
28+
}
29+
2430
init(localStorageManager: LocalStorageManager) {
2531
self.localStorageManager = localStorageManager
2632
if let benchmarkDirectories = try? retrieveBenchmarkDirectories() {
@@ -29,6 +35,9 @@ class LocalBenchmarkSettingsRepository: BenchmarkSettingsRepository {
2935
if let outputDirectory = try? loadBenchmarkOutputDirectory() {
3036
benchmarkOutputDirectory.send(outputDirectory)
3137
}
38+
if let openAIKey = try? loadOpenAIKey() {
39+
currentOpenAIKey.send("")
40+
}
3241
}
3342

3443
func saveBenchmarkDirectory(_ directory: BenchmarkDirectory) throws {
@@ -69,6 +78,15 @@ class LocalBenchmarkSettingsRepository: BenchmarkSettingsRepository {
6978

7079
private func deleteBenchmarkOutputDirectory() {
7180
}
81+
82+
private func loadOpenAIKey() throws -> String? {
83+
return try? localStorageManager.load(key: openAIKeyDefaultsKey)
84+
}
85+
86+
func saveOpenAIKey(_ key: String) throws {
87+
try localStorageManager.save(codable: key, key: openAIKeyDefaultsKey)
88+
currentOpenAIKey.send(key)
89+
}
7290
}
7391

7492
extension Array where Element == BenchmarkDirectory {

Core/Sources/HostApp/Benchmark/Domain/Repository/BenchmarkSettingsRepository.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ protocol BenchmarkSettingsRepository {
66
func saveBenchmarkDirectory(_ directory: BenchmarkDirectory) throws
77
func deleteBenchmarkDirectory(_ directory: BenchmarkDirectory) throws
88
func saveBenchmarkOutputDirectory(_ directory: String) throws
9+
var openAIKey: AnyPublisher<String, Never> { get }
10+
func saveOpenAIKey(_ key: String) throws
911
}

Core/Sources/HostApp/Benchmark/Presentation/View/BenchmarkView.swift

Lines changed: 70 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,37 @@ struct BenchmarkView: View {
2020
.font(.title)
2121
.frame(maxWidth: .infinity, alignment: .leading)
2222
Toggle("Multi File Context Enabled", isOn: $viewModel.isMultiFileContextEnabled)
23-
OutputConfigurationButtonView(module: module)
23+
ConfigurationButtonView(module: module)
2424
}
2525
.padding(.vertical)
26-
VStack {
27-
ForEach(viewModel.benchmarkDirectories, id: \.self) { directory in
28-
HStack {
29-
DirectoryNameView(directory: directory)
30-
.frame(maxWidth: .infinity, alignment: .leading)
31-
Button {
32-
Task {
33-
try? await viewModel.runBenchmark(for: directory)
26+
ForEach(viewModel.benchmarkDirectories, id: \.self) { directory in
27+
VStack {
28+
VStack(alignment: .leading, spacing: 10) {
29+
HStack {
30+
DirectoryNameView(directory: directory)
31+
.frame(maxWidth: .infinity, alignment: .leading)
32+
Button {
33+
Task {
34+
try? await viewModel.runBenchmark(for: directory)
35+
}
36+
} label: {
37+
Image(systemName: "play")
38+
}
39+
Button {
40+
NSWorkspace.shared.open(directory.url)
41+
} label: {
42+
Image(systemName: "folder")
43+
}
44+
Button {
45+
viewModel.deleteDirectory(directory)
46+
} label: {
47+
Image(systemName: "trash")
48+
.foregroundColor(.red)
3449
}
35-
} label: {
36-
Image(systemName: "play")
37-
}
38-
Button {
39-
NSWorkspace.shared.open(directory.url)
40-
} label: {
41-
Image(systemName: "folder")
42-
}
43-
Button {
44-
viewModel.deleteDirectory(directory)
45-
} label: {
46-
Image(systemName: "trash")
47-
.foregroundColor(.red)
4850
}
4951
}
5052
}
53+
taskList(directory: directory)
5154
}
5255
AddDirectoryButtonView(module: module)
5356
.padding(.vertical, 10)
@@ -56,55 +59,56 @@ struct BenchmarkView: View {
5659
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
5760
.padding()
5861
}
59-
VStack(alignment: .leading, spacing: 12) {
60-
if viewModel.taskStates.isEmpty {
61-
Text("💤 No benchmarks running right now.")
62-
.foregroundColor(.secondary)
63-
} else {
64-
VStack(alignment: .leading, spacing: 8) {
65-
Text("📋 Task Status")
66-
.font(.headline)
67-
ScrollView {
68-
LazyVStack(alignment: .leading, spacing: 8) {
69-
ForEach(Array(viewModel.taskStates.enumerated()), id: \.offset) { index, taskStatus in
70-
HStack {
71-
Text("Task \(index + 1)")
72-
.frame(maxWidth: .infinity, alignment: .leading)
73-
74-
Group {
75-
switch taskStatus {
76-
case .notStarted:
77-
Text("🕒")
78-
.accessibilityLabel("Not started")
79-
case .running:
80-
ProgressView()
81-
.scaleEffect(0.6)
82-
.accessibilityLabel("Running")
83-
case .success:
84-
Text("")
85-
.accessibilityLabel("Success")
86-
case .failure:
87-
Text("")
88-
.accessibilityLabel("Failed")
89-
}
90-
}
91-
.frame(width: 24, height: 24, alignment: .center)
92-
}
93-
.padding(.vertical, 2)
94-
}
62+
}
63+
.onAppear {
64+
viewModel.loadBenchmarkDirectories()
65+
}
66+
}
67+
68+
func taskList(directory: BenchmarkDirectory) -> some View {
69+
VStack(alignment: .leading, spacing: 8) {
70+
// Text("📋 Task Status")
71+
// .font(.headline)
72+
LazyVStack(alignment: .leading, spacing: 8) {
73+
ForEach(Array(viewModel.taskStates.enumerated()), id: \.offset) { index, taskStatus in
74+
HStack {
75+
Button {
76+
Task {
77+
await viewModel.runTask(index: index, in: directory)
78+
}
79+
} label: {
80+
Image(systemName: "play")
81+
}
82+
83+
Text("Task \(index + 1)")
84+
.frame(maxWidth: .infinity, alignment: .leading)
85+
86+
Group {
87+
switch taskStatus {
88+
case .notStarted:
89+
Text("")
90+
.accessibilityLabel("Not started")
91+
case .scheduled:
92+
Text("🕒")
93+
.accessibilityLabel("Scheduled")
94+
case .running:
95+
ProgressView()
96+
.scaleEffect(0.6)
97+
.accessibilityLabel("Running")
98+
case .success:
99+
Text("")
100+
.accessibilityLabel("Success")
101+
case .failure:
102+
Text("")
103+
.accessibilityLabel("Failed")
95104
}
96105
}
106+
.frame(width: 24, height: 24, alignment: .center)
97107
}
98-
.frame(height: taskStatusInfoHeight)
108+
.padding(.vertical, 2)
99109
}
100110
}
101-
.frame(maxWidth: .infinity, minHeight: taskStatusInfoHeight, alignment: .leading)
102-
.padding()
103-
.background(Color(.windowBackgroundColor))
104-
.cornerRadius(8)
105-
}
106-
.onAppear {
107-
viewModel.loadBenchmarkDirectories()
108111
}
112+
.padding(.leading, 20)
109113
}
110114
}

Core/Sources/HostApp/Benchmark/Presentation/View/OutputConfigurationButtonView.swift renamed to Core/Sources/HostApp/Benchmark/Presentation/View/ConfigurationButtonView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import SwiftUI
22

3-
struct OutputConfigurationButtonView: View {
3+
struct ConfigurationButtonView: View {
44
private let module: BenchmarkModuleType
55
@State private var isShowingSheet = false
66

@@ -12,10 +12,10 @@ struct OutputConfigurationButtonView: View {
1212
Button {
1313
isShowingSheet.toggle()
1414
} label : {
15-
Label("Configure Output", systemImage: "gear")
15+
Label("Configure", systemImage: "gear")
1616
}
1717
.sheet(isPresented: $isShowingSheet) {
18-
OutputConfigurationView(module: module)
18+
ConfigurationView(module: module)
1919
}
2020
}
2121
}

Core/Sources/HostApp/Benchmark/Presentation/View/OutputConfigurationView.swift renamed to Core/Sources/HostApp/Benchmark/Presentation/View/ConfigurationView.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import SwiftUI
22

3-
struct OutputConfigurationView: View {
3+
struct ConfigurationView: View {
44
@State private var currentOutputDirectory: String = ""
5-
@StateObject var viewModel: OutputConfigurationViewModel
5+
@State private var currentOpenAIKey: String = ""
6+
@StateObject var viewModel: ConfigurationViewModel
67
@Environment(\.dismiss) private var dismiss
78

89
private let labelWidth: CGFloat = 120
@@ -13,6 +14,13 @@ struct OutputConfigurationView: View {
1314

1415
var body: some View {
1516
VStack {
17+
HStack(alignment: .top) {
18+
Text("OpenAI API Key:")
19+
.frame(width: labelWidth, alignment: .leading)
20+
TextField("Key", text: $currentOpenAIKey, prompt: Text("Key"))
21+
.textFieldStyle(PlainTextFieldStyle())
22+
}
23+
.padding([.top, .horizontal])
1624
HStack(alignment: .top) {
1725
Text("Output Directory:")
1826
.frame(width: labelWidth, alignment: .leading)
@@ -34,13 +42,15 @@ struct OutputConfigurationView: View {
3442
}
3543
Button("Save") {
3644
viewModel.saveOutputDirectory(currentOutputDirectory)
45+
viewModel.saveOpenAIKey(currentOpenAIKey)
3746
dismiss()
3847
}
3948
}
4049
.padding([.horizontal, .bottom])
4150
}
4251
.onAppear {
4352
currentOutputDirectory = viewModel.outputDirectory
53+
currentOpenAIKey = viewModel.openAIKey
4454
}
4555
}
4656

Core/Sources/HostApp/Benchmark/Presentation/ViewModel/OutputConfigurationViewModel.swift renamed to Core/Sources/HostApp/Benchmark/Presentation/ViewModel/ConfigurationViewModel.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import Combine
22
import Toast
33

4-
class OutputConfigurationViewModel: ObservableObject {
4+
class ConfigurationViewModel: ObservableObject {
55
@Published var outputDirectory: String = ""
6+
@Published var openAIKey: String = ""
67
private var cancellables = Set<AnyCancellable>()
78
private var toast: ToastController { ToastControllerDependencyKey.liveValue }
89

@@ -13,6 +14,9 @@ class OutputConfigurationViewModel: ObservableObject {
1314
benchmarkSettingsRepository.outputDirectory
1415
.assign(to: \.outputDirectory, on: self)
1516
.store(in: &cancellables)
17+
benchmarkSettingsRepository.openAIKey
18+
.assign(to: \.openAIKey, on: self)
19+
.store(in: &cancellables)
1620
}
1721

1822
func saveOutputDirectory(_ directory: String) {
@@ -23,5 +27,14 @@ class OutputConfigurationViewModel: ObservableObject {
2327
toast.toast(content: "Failed changing output directory.", level: .error)
2428
}
2529
}
30+
31+
func saveOpenAIKey(_ key: String) {
32+
do {
33+
try benchmarkSettingsRepository.saveOpenAIKey(key)
34+
toast.toast(content: "OpenAI Key changed.", level: .info)
35+
} catch {
36+
toast.toast(content: "Failed changing OpenAI Key.", level: .error)
37+
}
38+
}
2639
}
2740

0 commit comments

Comments
 (0)