summaryrefslogtreecommitdiffhomepage
path: root/packages/console/app/src
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-10-02 13:58:38 -0400
committerFrank <[email protected]>2025-10-02 13:58:40 -0400
commita45fa7a93c7864ef7eed792949755b334a9b2524 (patch)
tree00fedb5631806de856ecf9e5b49c997521d9d31d /packages/console/app/src
parentae15c914556a51c042f37284d52945d6c480b37f (diff)
downloadopencode-a45fa7a93c7864ef7eed792949755b334a9b2524.tar.gz
opencode-a45fa7a93c7864ef7eed792949755b334a9b2524.zip
wip: zen
Diffstat (limited to 'packages/console/app/src')
-rw-r--r--packages/console/app/src/context/auth.ts1
-rw-r--r--packages/console/app/src/routes/workspace/[id].tsx18
-rw-r--r--packages/console/app/src/routes/workspace/member-section.tsx127
3 files changed, 28 insertions, 118 deletions
diff --git a/packages/console/app/src/context/auth.ts b/packages/console/app/src/context/auth.ts
index 7097787fb..079f05c9c 100644
--- a/packages/console/app/src/context/auth.ts
+++ b/packages/console/app/src/context/auth.ts
@@ -79,7 +79,6 @@ export const getActor = async (workspace?: string): Promise<Actor.Info> => {
properties: {
userID: result.user.id,
workspaceID: result.user.workspaceID,
- role: result.user.role,
},
}
}
diff --git a/packages/console/app/src/routes/workspace/[id].tsx b/packages/console/app/src/routes/workspace/[id].tsx
index df05b14b1..ad1f47bd4 100644
--- a/packages/console/app/src/routes/workspace/[id].tsx
+++ b/packages/console/app/src/routes/workspace/[id].tsx
@@ -10,24 +10,14 @@ import { Show } from "solid-js"
import { createAsync, query, useParams } from "@solidjs/router"
import { Actor } from "@opencode/console-core/actor.js"
import { withActor } from "~/context/auth.withActor"
-import { and, Database, eq } from "@opencode/console-core/drizzle/index.js"
-import { UserTable } from "@opencode/console-core/schema/user.sql.js"
+import { User } from "@opencode/console-core/user.js"
const getUser = query(async (workspaceID: string) => {
"use server"
return withActor(async () => {
- const actor = Actor.use()
- const isAdmin = await (async () => {
- if (actor.type !== "user") return false
- const role = await Database.use((tx) =>
- tx
- .select({ role: UserTable.role })
- .from(UserTable)
- .where(and(eq(UserTable.workspaceID, workspaceID), eq(UserTable.id, actor.properties.userID))),
- ).then((x) => x[0]?.role)
- return role === "admin"
- })()
- return { isAdmin }
+ const actor = Actor.assert("user")
+ const user = await User.fromID(actor.properties.userID)
+ return { isAdmin: user?.role === "admin" }
}, workspaceID)
}, "user.get")
diff --git a/packages/console/app/src/routes/workspace/member-section.tsx b/packages/console/app/src/routes/workspace/member-section.tsx
index 0e3a101fd..7dc893346 100644
--- a/packages/console/app/src/routes/workspace/member-section.tsx
+++ b/packages/console/app/src/routes/workspace/member-section.tsx
@@ -3,46 +3,18 @@ import { createEffect, createSignal, For, Show } from "solid-js"
import { withActor } from "~/context/auth.withActor"
import { createStore } from "solid-js/store"
import styles from "./member-section.module.css"
-import { and, Database, eq, isNull, sql } from "@opencode/console-core/drizzle/index.js"
-import { UserTable, UserRole } from "@opencode/console-core/schema/user.sql.js"
-import { Identifier } from "@opencode/console-core/identifier.js"
+import { UserRole } from "@opencode/console-core/schema/user.sql.js"
import { Actor } from "@opencode/console-core/actor.js"
-import { AWS } from "@opencode/console-core/aws.js"
-
-const assertAdmin = async (workspaceID: string) => {
- const actor = Actor.use()
- if (actor.type !== "user") throw new Error(`Expected admin user, got ${actor.type}`)
- const user = await Database.use((tx) =>
- tx
- .select()
- .from(UserTable)
- .where(and(eq(UserTable.workspaceID, workspaceID), eq(UserTable.id, actor.properties.userID))),
- ).then((x) => x[0])
- if (user?.role !== "admin") throw new Error(`Expected admin user, got ${user?.role}`)
- return actor
-}
-
-const assertNotSelf = (id: string) => {
- const actor = Actor.use()
- if (actor.type === "user" && actor.properties.userID === id) {
- throw new Error(`Expected not self actor, got self actor`)
- }
- return actor
-}
+import { User } from "@opencode/console-core/user.js"
const listMembers = query(async (workspaceID: string) => {
"use server"
return withActor(async () => {
- const actor = await assertAdmin(workspaceID)
- return Database.use((tx) =>
- tx
- .select()
- .from(UserTable)
- .where(and(eq(UserTable.workspaceID, workspaceID), isNull(UserTable.timeDeleted))),
- ).then((members) => ({
- members,
+ const actor = Actor.assert("user")
+ return {
+ members: await User.list(),
currentUserID: actor.properties.userID,
- }))
+ }
}, workspaceID)
}, "member.list")
@@ -55,43 +27,13 @@ const inviteMember = action(async (form: FormData) => {
const role = form.get("role")?.toString() as (typeof UserRole)[number]
if (!role) return { error: "Role is required" }
return json(
- await withActor(async () => {
- await assertAdmin(workspaceID)
- return Database.use((tx) =>
- tx
- .insert(UserTable)
- .values({
- id: Identifier.create("user"),
- name: "",
- email,
- workspaceID,
- role,
- })
+ await withActor(
+ () =>
+ User.invite({ email, role })
.then((data) => ({ error: undefined, data }))
- .then(async (data) => {
- const { render } = await import("@jsx-email/render")
- const { InviteEmail } = await import("@opencode/console-mail/InviteEmail.jsx")
- await AWS.sendEmail({
- to: email,
- subject: `You've been invited to join the ${workspaceID} workspace on OpenCode Zen`,
- body: render(
- // @ts-ignore
- InviteEmail({
- assetsUrl: `https://opencode.ai/email`,
- workspace: workspaceID,
- }),
- ),
- })
- return data
- })
- .catch((e) => {
- let error = e.message
- if (error.match(/Duplicate entry '.*' for key 'user.user_email'/))
- error = "A user with this email has already been invited."
- return { error }
- }),
- )
- }, workspaceID),
+ .catch((e) => ({ error: e.message as string })),
+ workspaceID,
+ ),
{ revalidate: listMembers.key },
)
}, "member.create")
@@ -103,29 +45,13 @@ const removeMember = action(async (form: FormData) => {
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
return json(
- await withActor(async () => {
- await assertAdmin(workspaceID)
- assertNotSelf(id)
- return Database.transaction(async (tx) => {
- const email = await tx
- .select({ email: UserTable.email })
- .from(UserTable)
- .where(and(eq(UserTable.id, id), eq(UserTable.workspaceID, workspaceID)))
- .execute()
- .then((rows) => rows[0].email)
- if (!email) return { error: "User not found" }
- await tx
- .update(UserTable)
- .set({
- oldEmail: email,
- email: null,
- timeDeleted: sql`now()`,
- })
- .where(and(eq(UserTable.id, id), eq(UserTable.workspaceID, workspaceID)))
- })
- .then(() => ({ error: undefined }))
- .catch((e) => ({ error: e.message as string }))
- }, workspaceID),
+ await withActor(
+ () =>
+ User.remove(id)
+ .then((data) => ({ error: undefined, data }))
+ .catch((e) => ({ error: e.message as string })),
+ workspaceID,
+ ),
{ revalidate: listMembers.key },
)
}, "member.remove")
@@ -139,18 +65,13 @@ const updateMemberRole = action(async (form: FormData) => {
const role = form.get("role")?.toString() as (typeof UserRole)[number]
if (!role) return { error: "Role is required" }
return json(
- await withActor(async () => {
- await assertAdmin(workspaceID)
- if (role === "member") assertNotSelf(id)
- return Database.use((tx) =>
- tx
- .update(UserTable)
- .set({ role })
- .where(and(eq(UserTable.id, id), eq(UserTable.workspaceID, workspaceID)))
+ await withActor(
+ () =>
+ User.updateRole({ id, role })
.then((data) => ({ error: undefined, data }))
.catch((e) => ({ error: e.message as string })),
- )
- }, workspaceID),
+ workspaceID,
+ ),
{ revalidate: listMembers.key },
)
}, "member.updateRole")