fix(settings): API key create/delete need Outline's web session, not this app
Same limitation as Passkeys — apiKeys.create/apiKeys.delete need Outline's cookie+CSRF web session, not this app's Bearer-token auth. "New API Key…" and the per-row trash button now show an explanatory popup instead of attempting a request that doesn't work. The real create sheet, reveal-once flow, delete confirmation, and their backing functions are untouched and still fully built/tested at the OutlineKit layer — only the two trigger points were redirected, each marked with a TODO pointing back to how to re-enable them (swap the button action back) once there's a supported native auth path or Outline adds Bearer support for these two endpoints.
This commit is contained in:
@@ -53,6 +53,7 @@ struct SettingsView: View {
|
|||||||
@State private var didCopyRevealedKey = false
|
@State private var didCopyRevealedKey = false
|
||||||
@State private var apiKeyPendingDeletion: OutlineAPIKey?
|
@State private var apiKeyPendingDeletion: OutlineAPIKey?
|
||||||
@State private var deletingApiKeyId: String?
|
@State private var deletingApiKeyId: String?
|
||||||
|
@State private var isShowingApiKeyWebOnlyNotice = false
|
||||||
|
|
||||||
/// Full Local Sync and cache-clearing both need a real connection to be
|
/// Full Local Sync and cache-clearing both need a real connection to be
|
||||||
/// safe — clearing while offline (or letting Full Local Sync think it
|
/// safe — clearing while offline (or letting Full Local Sync think it
|
||||||
@@ -772,8 +773,14 @@ struct SettingsView: View {
|
|||||||
Text("Personal keys")
|
Text("Personal keys")
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
Spacer()
|
Spacer()
|
||||||
Button("New API Key…") { isShowingCreateApiKey = true }
|
// TODO: apiKeys.create needs Outline's cookie+CSRF web
|
||||||
.disabled(!isEffectivelyOnline)
|
// session, not this app's Bearer-token auth — confirmed
|
||||||
|
// this app's requests to it don't work. Swap this back to
|
||||||
|
// `isShowingCreateApiKey = true` (the real create sheet
|
||||||
|
// below is fully built and untouched) once there's a
|
||||||
|
// supported native auth path, or Outline adds Bearer
|
||||||
|
// support for this endpoint.
|
||||||
|
Button("New API Key…") { isShowingApiKeyWebOnlyNotice = true }
|
||||||
}
|
}
|
||||||
.frame(maxWidth: 480)
|
.frame(maxWidth: 480)
|
||||||
|
|
||||||
@@ -807,6 +814,11 @@ struct SettingsView: View {
|
|||||||
Text("Any scripts or integrations using \"\(name)\" will stop working immediately.")
|
Text("Any scripts or integrations using \"\(name)\" will stop working immediately.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.alert("Manage API Keys on the Web", isPresented: $isShowingApiKeyWebOnlyNotice) {
|
||||||
|
Button("OK") {}
|
||||||
|
} message: {
|
||||||
|
Text("Creating and deleting personal API keys currently requires Outline's web app, the same way Passkeys does — this app can only display your existing keys for now. We may add this here in the future if Outline supports it or we add the right kind of authentication.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shown exactly once, immediately after creation — Outline never
|
/// Shown exactly once, immediately after creation — Outline never
|
||||||
@@ -967,19 +979,28 @@ struct SettingsView: View {
|
|||||||
if deletingApiKeyId == key.id {
|
if deletingApiKeyId == key.id {
|
||||||
ProgressView().controlSize(.small)
|
ProgressView().controlSize(.small)
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: apiKeys.delete — same web-session-only limitation
|
||||||
|
// as create above, see that comment. Swap back to
|
||||||
|
// `apiKeyPendingDeletion = key` (the real confirmation
|
||||||
|
// dialog + deleteApiKey(_:) below are fully built and
|
||||||
|
// untouched) once native auth can actually call it.
|
||||||
Button {
|
Button {
|
||||||
apiKeyPendingDeletion = key
|
isShowingApiKeyWebOnlyNotice = true
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "trash")
|
Image(systemName: "trash")
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.foregroundStyle(.red)
|
.foregroundStyle(.red)
|
||||||
.disabled(!isEffectivelyOnline)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: not currently reachable from the UI — apiKeys.create needs
|
||||||
|
// Outline's cookie+CSRF web session, confirmed this app's Bearer-token
|
||||||
|
// requests to it don't work. Kept intact (and covered by OutlineKit
|
||||||
|
// tests) for when native auth can support it; see the "New API Key…"
|
||||||
|
// button's own TODO for the reconnect point.
|
||||||
private func createApiKey() async {
|
private func createApiKey() async {
|
||||||
guard let apiClient = session.apiClient else { return }
|
guard let apiClient = session.apiClient else { return }
|
||||||
let trimmedName = newApiKeyName.trimmingCharacters(in: .whitespacesAndNewlines)
|
let trimmedName = newApiKeyName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
@@ -1007,6 +1028,9 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: not currently reachable from the UI — same apiKeys.delete
|
||||||
|
// web-session-only limitation as createApiKey() above. Kept intact
|
||||||
|
// for the same reason; see the trash button's own TODO.
|
||||||
private func deleteApiKey(_ key: OutlineAPIKey) async {
|
private func deleteApiKey(_ key: OutlineAPIKey) async {
|
||||||
guard let apiClient = session.apiClient else { return }
|
guard let apiClient = session.apiClient else { return }
|
||||||
apiKeyPendingDeletion = nil
|
apiKeyPendingDeletion = nil
|
||||||
|
|||||||
Reference in New Issue
Block a user