Unified · Split
| @@ -1,5 +1,6 @@ | |||
| 1 | import { useState } from "react"; | 1 | import { useState } from "react"; |
| 2 | import { useAtomSet, useAtomValue } from "@effect/atom-react"; | 2 | import { useAtomSet, useAtomValue } from "@effect/atom-react"; |
| 3 | import * as Exit from "effect/Exit"; | ||
| 3 | import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; | 4 | import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; |
| 4 | import { ReactivityKey } from "@executor-js/react/api/reactivity-keys"; | 5 | import { ReactivityKey } from "@executor-js/react/api/reactivity-keys"; |
| 5 | import { useScope } from "@executor-js/react/api/scope-context"; | 6 | import { useScope } from "@executor-js/react/api/scope-context"; |
| @@ -62,15 +63,15 @@ function VaultPicker(props: { · 56 unmodified lines | |||
| 62 | isLoading: true, | 63 | isLoading: true, |
| 63 | error: null, | 64 | error: null, |
| 64 | }), | 65 | }), |
| 65 | onError: (error) => ({ | 66 | onError: () => ({ |
| 66 | vaults: [] as { id: string; name: string }[], | 67 | vaults: [] as { id: string; name: string }[], |
| 67 | isLoading: false, | 68 | isLoading: false, |
| 68 | error: error.message, | 69 | error: "Failed to list vaults", |
| 69 | }), | 70 | }), |
| 70 | onDefect: (defect) => ({ | 71 | onDefect: () => ({ |
| 71 | vaults: [] as { id: string; name: string }[], | 72 | vaults: [] as { id: string; name: string }[], |
| 72 | isLoading: false, | 73 | isLoading: false, |
| 73 | error: defect instanceof Error ? defect.message : "Failed to list vaults", | 74 | error: "Failed to list vaults", |
| 74 | }), | 75 | }), |
| 75 | onSuccess: ({ value }) => { | 76 | onSuccess: ({ value }) => { |
| 76 | const v = value.vaults; | 77 | const v = value.vaults; |
| @@ -142,7 +143,7 @@ function ConfigDialog(props: { · 65 unmodified lines | |||
| 142 | const [error, setError] = useState<string | null>(null); | 143 | const [error, setError] = useState<string | null>(null); |
| 143 | 144 | ||
| 144 | const scopeId = useScope(); | 145 | const scopeId = useScope(); |
| 145 | const doConfigure = useAtomSet(configureOnePassword, { mode: "promise" }); | 146 | const doConfigure = useAtomSet(configureOnePassword, { mode: "promiseExit" }); |
| 146 | 147 | ||
| 147 | const reset = () => { | 148 | const reset = () => { |
| 148 | if (!isEdit) { | 149 | if (!isEdit) { |
| @@ -159,23 +160,25 @@ function ConfigDialog(props: { · 10 unmodified lines | |||
| 159 | if (!accountName.trim() || !vaultId.trim()) return; | 160 | if (!accountName.trim() || !vaultId.trim()) return; |
| 160 | setSaving(true); | 161 | setSaving(true); |
| 161 | setError(null); | 162 | setError(null); |
| 162 | try { | ||
| 163 | const auth = | ||
| 164 | authKind === "desktop-app" | ||
| 165 | ? { kind: "desktop-app" as const, accountName: accountName.trim() } | ||
| 166 | : { kind: "service-account" as const, tokenSecretId: accountName.trim() }; | ||
| 167 | 163 | ||
| 168 | await doConfigure({ | 164 | const auth = |
| 169 | params: { scopeId }, | 165 | authKind === "desktop-app" |
| 170 | payload: { auth, vaultId: vaultId.trim(), name: vaultName.trim() || "1Password" }, | 166 | ? { kind: "desktop-app" as const, accountName: accountName.trim() } |
| 171 | reactivityKeys: [ReactivityKey.secrets], | 167 | : { kind: "service-account" as const, tokenSecretId: accountName.trim() }; |
| 172 | }); | 168 | |
| 173 | props.onOpenChange(false); | 169 | const exit = await doConfigure({ |
| 174 | reset(); | 170 | params: { scopeId }, |
| 175 | } catch (e) { | 171 | payload: { auth, vaultId: vaultId.trim(), name: vaultName.trim() || "1Password" }, |
| 176 | setError(e instanceof Error ? e.message : "Failed to save configuration"); | 172 | reactivityKeys: [ReactivityKey.secrets], |
| 173 | }); | ||
| 174 | if (Exit.isFailure(exit)) { | ||
| 175 | setError("Failed to save configuration"); | ||
| 177 | setSaving(false); | 176 | setSaving(false); |
| 177 | return; | ||
| 178 | } | 178 | } |
| 179 | |||
| 180 | props.onOpenChange(false); | ||
| 181 | reset(); | ||
| 179 | }; | 182 | }; |
| 180 | 183 | ||
| 181 | return ( | 184 | return ( |
| @@ -298,14 +301,10 @@ export default function OnePasswordSettings() { · 116 unmodified lines | |||
| 298 | const [configOpen, setConfigOpen] = useState(false); | 301 | const [configOpen, setConfigOpen] = useState(false); |
| 299 | const scopeId = useScope(); | 302 | const scopeId = useScope(); |
| 300 | const configResult = useAtomValue(onepasswordConfigAtom(scopeId)); | 303 | const configResult = useAtomValue(onepasswordConfigAtom(scopeId)); |
| 301 | const doRemove = useAtomSet(removeOnePasswordConfig, { mode: "promise" }); | 304 | const doRemove = useAtomSet(removeOnePasswordConfig, { mode: "promiseExit" }); |
| 302 | 305 | ||
| 303 | const handleRemove = async () => { | 306 | const handleRemove = async () => { |
| 304 | try { | 307 | await doRemove({ params: { scopeId }, reactivityKeys: [ReactivityKey.secrets] }); |
| 305 | await doRemove({ params: { scopeId }, reactivityKeys: [ReactivityKey.secrets] }); | ||
| 306 | } catch { | ||
| 307 | /* TODO: toast */ | ||
| 308 | } | ||
| 309 | }; | 308 | }; |
| 310 | 309 | ||
| 311 | const config: OnePasswordConfig | null = AsyncResult.match( | 310 | const config: OnePasswordConfig | null = AsyncResult.match( |