125 lines
4.0 KiB
TypeScript
125 lines
4.0 KiB
TypeScript
import { json, action, useParams, useSubmission, createAsync, query } from "@solidjs/router"
|
|
import { createEffect, Show } from "solid-js"
|
|
import { createStore } from "solid-js/store"
|
|
import { withActor } from "~/context/auth.withActor"
|
|
import { Workspace } from "@opencode-ai/console-core/workspace.js"
|
|
import styles from "./settings-section.module.css"
|
|
import { Database, eq } from "@opencode-ai/console-core/drizzle/index.js"
|
|
import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js"
|
|
|
|
const getWorkspaceInfo = query(async (workspaceID: string) => {
|
|
"use server"
|
|
return withActor(
|
|
() =>
|
|
Database.use((tx) =>
|
|
tx
|
|
.select({
|
|
id: WorkspaceTable.id,
|
|
name: WorkspaceTable.name,
|
|
slug: WorkspaceTable.slug,
|
|
})
|
|
.from(WorkspaceTable)
|
|
.where(eq(WorkspaceTable.id, workspaceID))
|
|
.then((rows) => rows[0] || null),
|
|
),
|
|
workspaceID,
|
|
)
|
|
}, "workspace.get")
|
|
|
|
const updateWorkspace = action(async (form: FormData) => {
|
|
"use server"
|
|
const name = form.get("name")?.toString().trim()
|
|
if (!name) return { error: "Workspace name is required." }
|
|
if (name.length > 255) return { error: "Name must be 255 characters or less." }
|
|
const workspaceID = form.get("workspaceID")?.toString()
|
|
if (!workspaceID) return { error: "Workspace ID is required." }
|
|
return json(
|
|
await withActor(
|
|
() =>
|
|
Workspace.update({ name })
|
|
.then(() => ({ error: undefined }))
|
|
.catch((e) => ({ error: e.message as string })),
|
|
workspaceID,
|
|
),
|
|
)
|
|
}, "workspace.update")
|
|
|
|
export function SettingsSection() {
|
|
const params = useParams()
|
|
const workspaceInfo = createAsync(() => getWorkspaceInfo(params.id))
|
|
const submission = useSubmission(updateWorkspace)
|
|
const [store, setStore] = createStore({ show: false })
|
|
|
|
let input: HTMLInputElement
|
|
|
|
createEffect(() => {
|
|
if (!submission.pending && submission.result && !submission.result.error) {
|
|
hide()
|
|
}
|
|
})
|
|
|
|
function show() {
|
|
while (true) {
|
|
submission.clear()
|
|
if (!submission.result) break
|
|
}
|
|
setStore("show", true)
|
|
input.focus()
|
|
}
|
|
|
|
function hide() {
|
|
setStore("show", false)
|
|
}
|
|
|
|
return (
|
|
<section class={styles.root}>
|
|
<div data-slot="section-title">
|
|
<h2>Settings</h2>
|
|
<p>Update your workspace name and preferences.</p>
|
|
</div>
|
|
<div data-slot="section-content">
|
|
<div data-slot="setting">
|
|
<div data-slot="setting-info">
|
|
<h3>Workspace Name</h3>
|
|
<p data-slot="current-value">{workspaceInfo()?.name}</p>
|
|
</div>
|
|
<Show
|
|
when={!store.show}
|
|
fallback={
|
|
<form action={updateWorkspace} method="post" data-slot="create-form">
|
|
<div data-slot="input-container">
|
|
<input
|
|
required
|
|
ref={(r) => (input = r)}
|
|
data-component="input"
|
|
name="name"
|
|
type="text"
|
|
placeholder="Workspace name"
|
|
value={workspaceInfo()?.name ?? "Default"}
|
|
/>
|
|
<Show when={submission.result && submission.result.error}>
|
|
{(err) => <div data-slot="form-error">{err()}</div>}
|
|
</Show>
|
|
</div>
|
|
<input type="hidden" name="workspaceID" value={params.id} />
|
|
<div data-slot="form-actions">
|
|
<button type="reset" data-color="ghost" onClick={() => hide()}>
|
|
Cancel
|
|
</button>
|
|
<button type="submit" data-color="primary" disabled={submission.pending}>
|
|
{submission.pending ? "Updating..." : "Update"}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
}
|
|
>
|
|
<button data-color="primary" onClick={() => show()}>
|
|
Edit Name
|
|
</button>
|
|
</Show>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|