From c6c153de95668b6e3a3e08e122cad06b8e0f40e6 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 12 Sep 2025 14:22:40 -0400 Subject: [PATCH] wip: zen --- cloud/app/src/routes/workspace/[id].css | 14 +++++++++++ cloud/app/src/routes/workspace/[id].tsx | 33 ++++++++++++++++++++----- cloud/core/src/key.ts | 6 ++++- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/cloud/app/src/routes/workspace/[id].css b/cloud/app/src/routes/workspace/[id].css index 2d9b0e63..6cf8a0cf 100644 --- a/cloud/app/src/routes/workspace/[id].css +++ b/cloud/app/src/routes/workspace/[id].css @@ -115,11 +115,18 @@ [data-component="api-keys-section"] { [data-slot="create-form"] { display: flex; + flex-direction: column; gap: var(--space-3); padding: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--border-radius-sm); + [data-slot="input-container"] { + display: flex; + flex-direction: column; + gap: var(--space-1); + } + @media (max-width: 30rem) { gap: var(--space-2); } @@ -148,6 +155,13 @@ display: flex; gap: var(--space-2); } + + [data-slot="form-error"] { + color: var(--color-danger); + font-size: var(--font-size-sm); + margin-top: var(--space-1); + line-height: 1.4; + } } [data-slot="api-keys-table"] { diff --git a/cloud/app/src/routes/workspace/[id].tsx b/cloud/app/src/routes/workspace/[id].tsx index 222e51a1..39db5cc4 100644 --- a/cloud/app/src/routes/workspace/[id].tsx +++ b/cloud/app/src/routes/workspace/[id].tsx @@ -49,7 +49,13 @@ const createKey = action(async (form: FormData) => { const workspaceID = form.get("workspaceID")?.toString() if (!workspaceID) return { error: "Workspace ID is required" } return json( - withActor(() => Key.create({ name }), workspaceID), + withActor( + () => + Key.create({ name }) + .then((data) => ({ data })) + .catch((e) => ({ error: e.message })), + workspaceID, + ), { revalidate: listKeys.key }, ) }, "key.create") @@ -185,19 +191,27 @@ function KeySection() { function KeyCreateForm() { const params = useParams() const submission = useSubmission(createKey) - const [store, setStore] = createStore({ - show: false, - }) + const [store, setStore] = createStore({ show: false }) let input: HTMLInputElement createEffect(() => { - if (!submission.pending && submission.result) { + // @ts-expect-error + if (!submission.pending && submission.result?.data) { hide() } }) function show() { + // submission.clear() does not clear the result in some cases, ie. + // 1. Create key with empty name => error shows + // 2. Put in a key name and creates the key => form hides + // 3. Click add key button again => form shows with the same error if + // submission.clear() is called only once + for (let i = 0; i < 3; i++) { + submission.clear() + if (!submission.result) break + } setStore("show", true) input.focus() } @@ -216,7 +230,14 @@ function KeyCreateForm() { } >
- (input = r)} data-component="input" name="name" type="text" placeholder="Enter key name" /> +
+ (input = r)} data-component="input" name="name" type="text" placeholder="Enter key name" /> + {/* @ts-expect-error */} + + {/* @ts-expect-error */} +
{submission.result.error}
+
+