mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-21 01:34:22 +01:00
wip: zen
This commit is contained in:
@@ -7,6 +7,11 @@ import { createStore } from "solid-js/store"
|
|||||||
import { formatDateUTC, formatDateForTable } from "./common"
|
import { formatDateUTC, formatDateForTable } from "./common"
|
||||||
import styles from "./key-section.module.css"
|
import styles from "./key-section.module.css"
|
||||||
import { Actor } from "@opencode-ai/console-core/actor.js"
|
import { Actor } from "@opencode-ai/console-core/actor.js"
|
||||||
|
import { and, Database, eq, isNull, sql } from "@opencode-ai/console-core/drizzle/index.js"
|
||||||
|
import { KeyTable } from "@opencode-ai/console-core/schema/key.sql.js"
|
||||||
|
import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js"
|
||||||
|
import { AccountTable } from "@opencode-ai/console-core/schema/account.sql.js"
|
||||||
|
import { User } from "@opencode-ai/console-core/user.js"
|
||||||
|
|
||||||
const removeKey = action(async (form: FormData) => {
|
const removeKey = action(async (form: FormData) => {
|
||||||
"use server"
|
"use server"
|
||||||
@@ -108,11 +113,6 @@ export function KeySection() {
|
|||||||
const params = useParams()
|
const params = useParams()
|
||||||
const keys = createAsync(() => listKeys(params.id))
|
const keys = createAsync(() => listKeys(params.id))
|
||||||
|
|
||||||
function formatKey(key: string) {
|
|
||||||
if (key.length <= 11) return key
|
|
||||||
return `${key.slice(0, 7)}...${key.slice(-4)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section class={styles.root}>
|
<section class={styles.root}>
|
||||||
<div data-slot="section-title">
|
<div data-slot="section-title">
|
||||||
@@ -134,7 +134,8 @@ export function KeySection() {
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Key</th>
|
<th>Key</th>
|
||||||
<th>Created</th>
|
<th>Created By</th>
|
||||||
|
<th>Last Used</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -147,24 +148,27 @@ export function KeySection() {
|
|||||||
<tr>
|
<tr>
|
||||||
<td data-slot="key-name">{key.name}</td>
|
<td data-slot="key-name">{key.name}</td>
|
||||||
<td data-slot="key-value">
|
<td data-slot="key-value">
|
||||||
<button
|
<Show when={key.key} fallback={<span>{key.keyDisplay}</span>}>
|
||||||
data-color="ghost"
|
<button
|
||||||
disabled={copied()}
|
data-color="ghost"
|
||||||
onClick={async () => {
|
disabled={copied()}
|
||||||
await navigator.clipboard.writeText(key.key)
|
onClick={async () => {
|
||||||
setCopied(true)
|
await navigator.clipboard.writeText(key.key!)
|
||||||
setTimeout(() => setCopied(false), 1000)
|
setCopied(true)
|
||||||
}}
|
setTimeout(() => setCopied(false), 1000)
|
||||||
title="Copy API key"
|
}}
|
||||||
>
|
title="Copy API key"
|
||||||
<span>{formatKey(key.key)}</span>
|
>
|
||||||
<Show when={copied()} fallback={<IconCopy style={{ width: "14px", height: "14px" }} />}>
|
<span>{key.keyDisplay}</span>
|
||||||
<IconCheck style={{ width: "14px", height: "14px" }} />
|
<Show when={copied()} fallback={<IconCopy style={{ width: "14px", height: "14px" }} />}>
|
||||||
</Show>
|
<IconCheck style={{ width: "14px", height: "14px" }} />
|
||||||
</button>
|
</Show>
|
||||||
|
</button>
|
||||||
|
</Show>
|
||||||
</td>
|
</td>
|
||||||
<td data-slot="key-date" title={formatDateUTC(key.timeCreated)}>
|
<td data-slot="key-user-email">{key.email}</td>
|
||||||
{formatDateForTable(key.timeCreated)}
|
<td data-slot="key-last-used" title={key.timeUsed ? formatDateUTC(key.timeUsed) : undefined}>
|
||||||
|
{key.timeUsed ? formatDateForTable(key.timeUsed) : "-"}
|
||||||
</td>
|
</td>
|
||||||
<td data-slot="key-actions">
|
<td data-slot="key-actions">
|
||||||
<form action={removeKey} method="post">
|
<form action={removeKey} method="post">
|
||||||
|
|||||||
@@ -4,19 +4,45 @@ import { Actor } from "./actor"
|
|||||||
import { and, Database, eq, isNull, sql } from "./drizzle"
|
import { and, Database, eq, isNull, sql } from "./drizzle"
|
||||||
import { Identifier } from "./identifier"
|
import { Identifier } from "./identifier"
|
||||||
import { KeyTable } from "./schema/key.sql"
|
import { KeyTable } from "./schema/key.sql"
|
||||||
|
import { AccountTable } from "./schema/account.sql"
|
||||||
|
import { UserTable } from "./schema/user.sql"
|
||||||
|
import { User } from "./user"
|
||||||
|
|
||||||
export namespace Key {
|
export namespace Key {
|
||||||
export const list = async () => {
|
export const list = fn(z.void(), async () => {
|
||||||
const workspace = Actor.workspace()
|
const userID = Actor.assert("user").properties.userID
|
||||||
|
const user = await User.fromID(userID)
|
||||||
const keys = await Database.use((tx) =>
|
const keys = await Database.use((tx) =>
|
||||||
tx
|
tx
|
||||||
.select()
|
.select({
|
||||||
|
id: KeyTable.id,
|
||||||
|
name: KeyTable.name,
|
||||||
|
key: KeyTable.key,
|
||||||
|
timeUsed: KeyTable.timeUsed,
|
||||||
|
userID: KeyTable.userID,
|
||||||
|
email: AccountTable.email,
|
||||||
|
})
|
||||||
.from(KeyTable)
|
.from(KeyTable)
|
||||||
.where(and(eq(KeyTable.workspaceID, workspace), isNull(KeyTable.timeDeleted)))
|
.innerJoin(UserTable, and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID)))
|
||||||
.orderBy(sql`${KeyTable.timeCreated} DESC`),
|
.innerJoin(AccountTable, eq(UserTable.accountID, AccountTable.id))
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
...[
|
||||||
|
eq(KeyTable.workspaceID, Actor.workspace()),
|
||||||
|
isNull(KeyTable.timeDeleted),
|
||||||
|
...(user.role === "admin" ? [] : [eq(KeyTable.userID, userID)]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.orderBy(sql`${KeyTable.name} DESC`),
|
||||||
)
|
)
|
||||||
return keys
|
// only return value for user's keys
|
||||||
}
|
return keys.map((key) => ({
|
||||||
|
...key,
|
||||||
|
key: key.userID === userID ? key.key : undefined,
|
||||||
|
keyDisplay: `${key.key.slice(0, 7)}...${key.key.slice(-4)}`,
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
export const create = fn(
|
export const create = fn(
|
||||||
z.object({
|
z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user