summaryrefslogtreecommitdiffhomepage
path: root/packages/console/app/src/routes/workspace
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-10-07 09:17:05 -0400
committerFrank <[email protected]>2025-10-07 09:17:08 -0400
commit6c99b833e443ba1531845a7fcf4f74247a0837bc (patch)
tree8ad2e4c1bc3b67f44019d5dcbccc54b3fe2d0959 /packages/console/app/src/routes/workspace
parentcd3780b7f5b46f03b121dff6172adb445bd748e5 (diff)
downloadopencode-6c99b833e443ba1531845a7fcf4f74247a0837bc.tar.gz
opencode-6c99b833e443ba1531845a7fcf4f74247a0837bc.zip
wip: zen
Diffstat (limited to 'packages/console/app/src/routes/workspace')
-rw-r--r--packages/console/app/src/routes/workspace/member-section.tsx83
1 files changed, 71 insertions, 12 deletions
diff --git a/packages/console/app/src/routes/workspace/member-section.tsx b/packages/console/app/src/routes/workspace/member-section.tsx
index 9fc57621c..ddaac7348 100644
--- a/packages/console/app/src/routes/workspace/member-section.tsx
+++ b/packages/console/app/src/routes/workspace/member-section.tsx
@@ -56,25 +56,36 @@ const removeMember = action(async (form: FormData) => {
)
}, "member.remove")
-const updateMemberRole = action(async (form: FormData) => {
+const updateMember = action(async (form: FormData) => {
"use server"
+ console.log("!@#!@ Form data entries:")
+ for (const [key, value] of form.entries()) {
+ console.log(`!@#!@ ${key}:`, value)
+ }
+
const id = form.get("id")?.toString()
if (!id) return { error: "ID is required" }
const workspaceID = form.get("workspaceID")?.toString()
if (!workspaceID) return { error: "Workspace ID is required" }
const role = form.get("role")?.toString() as (typeof UserRole)[number]
if (!role) return { error: "Role is required" }
+ const limit = form.get("limit")?.toString()
+ const monthlyLimit = limit && limit.trim() !== "" ? parseInt(limit) : null
+ if (monthlyLimit !== null && monthlyLimit < 0) return { error: "Set a valid monthly limit" }
+
+ console.log({ id, role, monthlyLimit, limit })
+
return json(
await withActor(
() =>
- User.updateRole({ id, role })
+ User.update({ id, role, monthlyLimit })
.then((data) => ({ error: undefined, data }))
.catch((e) => ({ error: e.message as string })),
workspaceID,
),
{ revalidate: listMembers.key },
)
-}, "member.updateRole")
+}, "member.update")
export function MemberCreateForm() {
const params = useParams()
@@ -155,7 +166,7 @@ export function MemberCreateForm() {
function MemberRow(props: { member: any; workspaceID: string; currentUserID: string | null }) {
const [editing, setEditing] = createSignal(false)
- const submission = useSubmission(updateMemberRole)
+ const submission = useSubmission(updateMember)
const isCurrentUser = () => props.currentUserID === props.member.id
createEffect(() => {
@@ -164,6 +175,29 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
}
})
+ function getUsageDisplay() {
+ const currentUsage = (() => {
+ const dateLastUsed = props.member.timeMonthlyUsageUpdated
+ if (!dateLastUsed) return 0
+
+ const current = new Date().toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ timeZone: "UTC",
+ })
+ const lastUsed = dateLastUsed.toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ timeZone: "UTC",
+ })
+ if (current !== lastUsed) return 0
+ return ((props.member.monthlyUsage ?? 0) / 100000000).toFixed(2)
+ })()
+
+ const limit = props.member.monthlyLimit ? `$${props.member.monthlyLimit}` : "no limit"
+ return `$${currentUsage} / ${limit}`
+ }
+
return (
<Show
when={editing()}
@@ -171,6 +205,7 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
<tr>
<td data-slot="member-email">{props.member.accountEmail ?? props.member.email}</td>
<td data-slot="member-role">{props.member.role}</td>
+ <td data-slot="member-usage">{getUsageDisplay()}</td>
<Show when={!props.member.timeSeen} fallback={<td data-slot="member-joined"></td>}>
<td data-slot="member-joined">invited</td>
</Show>
@@ -190,12 +225,21 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
}
>
<tr>
- <td colspan="4">
- <form action={updateMemberRole} method="post">
+ <td colspan="5">
+ <form action={updateMember} method="post">
<div data-slot="edit-member-email">{props.member.accountEmail ?? props.member.email}</div>
<input type="hidden" name="id" value={props.member.id} />
<input type="hidden" name="workspaceID" value={props.workspaceID} />
- <Show when={!isCurrentUser()} fallback={<div data-slot="current-user-role">Role: {props.member.role}</div>}>
+
+ <Show
+ when={!isCurrentUser()}
+ fallback={
+ <>
+ <div data-slot="current-user-role">Role: {props.member.role}</div>
+ <input type="hidden" name="role" value={props.member.role} />
+ </>
+ }
+ >
<div data-slot="role-selector">
<label>
<input type="radio" name="role" value="admin" checked={props.member.role === "admin"} />
@@ -213,18 +257,32 @@ function MemberRow(props: { member: any; workspaceID: string; currentUserID: str
</label>
</div>
</Show>
+
+ <div data-slot="limit-selector">
+ <label>
+ <strong>Monthly Limit</strong>
+ <input
+ type="number"
+ name="limit"
+ value={props.member.monthlyLimit ?? ""}
+ placeholder="No limit"
+ min="0"
+ />
+ <p>Set a monthly spending limit for this user</p>
+ </label>
+ </div>
+
<Show when={submission.result && submission.result.error}>
{(err) => <div data-slot="form-error">{err()}</div>}
</Show>
+
<div data-slot="form-actions">
<button type="button" data-color="ghost" onClick={() => setEditing(false)}>
Cancel
</button>
- <Show when={!isCurrentUser()}>
- <button type="submit" data-color="primary" disabled={submission.pending}>
- {submission.pending ? "Saving..." : "Save"}
- </button>
- </Show>
+ <button type="submit" data-color="primary" disabled={submission.pending}>
+ {submission.pending ? "Saving..." : "Save"}
+ </button>
</div>
</form>
</td>
@@ -258,6 +316,7 @@ export function MemberSection() {
<tr>
<th>Email</th>
<th>Role</th>
+ <th>Usage</th>
<th></th>
<th></th>
</tr>