mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-05-07 16:08:58 +02:00
Certificate UI/Import (#798)
* Sketching out. * WIP * WIP * Dump * Apply stash * Merge + WIP * UI * More WIP * Agent config * UI cleanup * Restore dirty files * XPC * Edit/delete * UI fixes * Cleanup * Change id for OpenSSHCertificate to hex of md5 * Fix runtime warning for confirmation dialog * Mark strings as reviewed * Cleanup * Fix agent tests
This commit is contained in:
@@ -1,25 +1,32 @@
|
||||
import SwiftUI
|
||||
import SecretKit
|
||||
import SSHProtocolKit
|
||||
|
||||
struct StoreListView: View {
|
||||
|
||||
@Binding var activeSecret: AnySecret?
|
||||
enum StoreListSelection: Hashable {
|
||||
case secret(AnySecret)
|
||||
case certificate(OpenSSHCertificate)
|
||||
}
|
||||
|
||||
@Binding var selection: StoreListSelection?
|
||||
|
||||
@Environment(\.secretStoreList) private var storeList
|
||||
@Environment(\.certificateStore) private var certificateStore
|
||||
|
||||
private func secretDeleted(secret: AnySecret) {
|
||||
activeSecret = nextDefaultSecret
|
||||
selection = nextDefaultSecret.map(StoreListSelection.secret)
|
||||
}
|
||||
|
||||
private func secretRenamed(secret: AnySecret) {
|
||||
// Pull new version from store, so we get all updated attributes
|
||||
activeSecret = nil
|
||||
activeSecret = storeList.allSecrets.first(where: { $0.id == secret.id })
|
||||
selection = nil
|
||||
selection = storeList.allSecrets.first(where: { $0.id == secret.id }).map(StoreListSelection.secret)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationSplitView {
|
||||
List(selection: $activeSecret) {
|
||||
List(selection: $selection) {
|
||||
ForEach(storeList.stores) { store in
|
||||
if store.isAvailable {
|
||||
Section(header: Text(store.name)) {
|
||||
@@ -30,29 +37,51 @@ struct StoreListView: View {
|
||||
deletedSecret: secretDeleted,
|
||||
renamedSecret: secretRenamed,
|
||||
)
|
||||
.tag(StoreListSelection.secret(secret))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !certificateStore.certificates.isEmpty {
|
||||
Section("Certificates") {
|
||||
ForEach(certificateStore.certificates) { certificate in
|
||||
CertificateListItemView(
|
||||
certificate: certificate,
|
||||
deletedCertificate: { _ in },
|
||||
renamedCertificate: { _ in }
|
||||
)
|
||||
.tag(StoreListSelection.certificate(certificate))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} detail: {
|
||||
if let activeSecret {
|
||||
SecretDetailView(secret: activeSecret)
|
||||
} else if let nextDefaultSecret {
|
||||
// This just means onAppear hasn't executed yet.
|
||||
// Do this to avoid a blip.
|
||||
SecretDetailView(secret: nextDefaultSecret)
|
||||
} else {
|
||||
if let modifiable = storeList.modifiableStore, modifiable.isAvailable {
|
||||
EmptyStoreView(store: modifiable)
|
||||
switch selection {
|
||||
case .secret(let secret):
|
||||
SecretDetailView(secret: secret, certificates: certificateStore.certificates(for: secret)) {
|
||||
selection = .certificate($0)
|
||||
}
|
||||
case .certificate(let certificate):
|
||||
CertificateDetailView(certificate: certificate)
|
||||
case nil:
|
||||
if let nextDefaultSecret {
|
||||
// This just means onAppear hasn't executed yet.
|
||||
// Do this to avoid a blip.
|
||||
SecretDetailView(secret: nextDefaultSecret, certificates: certificateStore.certificates(for: nextDefaultSecret)) {
|
||||
selection = .certificate($0)
|
||||
}
|
||||
} else {
|
||||
EmptyStoreView(store: storeList.stores.first(where: \.isAvailable))
|
||||
if let modifiable = storeList.modifiableStore, modifiable.isAvailable {
|
||||
EmptyStoreView(store: modifiable)
|
||||
} else {
|
||||
EmptyStoreView(store: storeList.stores.first(where: \.isAvailable))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationSplitViewStyle(.balanced)
|
||||
.onAppear {
|
||||
activeSecret = nextDefaultSecret
|
||||
selection = nextDefaultSecret.map(StoreListSelection.secret)
|
||||
}
|
||||
.frame(minWidth: 100, idealWidth: 240)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user