Compare commits
56 Commits
prompt-con
...
pause-cham
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
816b41adad | ||
|
|
868d7084f0 | ||
|
|
f6f04e537e | ||
|
|
4feb3e5829 | ||
|
|
c62ced867a | ||
|
|
7bb414026e | ||
|
|
1b2b6c1456 | ||
|
|
760bfbbe32 | ||
|
|
3424aa36ba | ||
|
|
ded86cba08 | ||
|
|
65a0f9065f | ||
|
|
2861c64428 | ||
|
|
ca33bb0b08 | ||
|
|
72e680e77c | ||
|
|
5dd7e67396 | ||
|
|
fd286f6874 | ||
|
|
7a4aa5f0aa | ||
|
|
cb791e3c73 | ||
|
|
a2c322ff43 | ||
|
|
a2ace63f25 | ||
|
|
41d06596cb | ||
|
|
49c68fdbf2 | ||
|
|
6188f55569 | ||
|
|
ea91d692d3 | ||
|
|
ae7acbfdd4 | ||
|
|
b9396e63cc | ||
|
|
753a48f6e9 | ||
|
|
bd7c8b43b0 | ||
|
|
a1249f17c9 | ||
|
|
6f8db40f74 | ||
|
|
8c5345a291 | ||
|
|
f47010a6e7 | ||
|
|
6d32f1c06e | ||
|
|
8fed9730da | ||
|
|
0f9a83cf45 | ||
|
|
9f17d98736 | ||
|
|
74029e5478 | ||
|
|
d220cd30e8 | ||
|
|
c0f10cd522 | ||
|
|
dc497dbd99 | ||
|
|
f8f855adf4 | ||
|
|
8f49bace53 | ||
|
|
c9f59bfb79 | ||
|
|
57166e96b4 | ||
|
|
1a838824ae | ||
|
|
6b304f8456 | ||
|
|
a53d70d8b2 | ||
|
|
109a9ddb1e | ||
|
|
7f8b574c9f | ||
|
|
9e859c199e | ||
|
|
deabbb094b | ||
|
|
7637b94ea7 | ||
|
|
721f1726eb | ||
|
|
cfeb4dfa92 | ||
|
|
21ef67ed4c | ||
|
|
7707d451e0 |
@@ -6,6 +6,10 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: app
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run-checks:
|
run-checks:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -31,3 +31,6 @@ NEXT_PUBLIC_HOST="http://localhost:3000"
|
|||||||
# Next Auth Github Provider
|
# Next Auth Github Provider
|
||||||
GITHUB_CLIENT_ID="your_client_id"
|
GITHUB_CLIENT_ID="your_client_id"
|
||||||
GITHUB_CLIENT_SECRET="your_secret"
|
GITHUB_CLIENT_SECRET="your_secret"
|
||||||
|
|
||||||
|
OPENPIPE_BASE_URL="http://localhost:3000/api"
|
||||||
|
OPENPIPE_API_KEY="your_key"
|
||||||
0
.gitignore → app/.gitignore
vendored
@@ -12,8 +12,10 @@ declare module "nextjs-routes" {
|
|||||||
|
|
||||||
export type Route =
|
export type Route =
|
||||||
| StaticRoute<"/account/signin">
|
| StaticRoute<"/account/signin">
|
||||||
|
| DynamicRoute<"/api/[...trpc]", { "trpc": string[] }>
|
||||||
| DynamicRoute<"/api/auth/[...nextauth]", { "nextauth": string[] }>
|
| DynamicRoute<"/api/auth/[...nextauth]", { "nextauth": string[] }>
|
||||||
| StaticRoute<"/api/experiments/og-image">
|
| StaticRoute<"/api/experiments/og-image">
|
||||||
|
| StaticRoute<"/api/openapi">
|
||||||
| StaticRoute<"/api/sentry-example-api">
|
| StaticRoute<"/api/sentry-example-api">
|
||||||
| DynamicRoute<"/api/trpc/[trpc]", { "trpc": string }>
|
| DynamicRoute<"/api/trpc/[trpc]", { "trpc": string }>
|
||||||
| DynamicRoute<"/data/[id]", { "id": string }>
|
| DynamicRoute<"/data/[id]", { "id": string }>
|
||||||
@@ -21,6 +23,8 @@ declare module "nextjs-routes" {
|
|||||||
| DynamicRoute<"/experiments/[id]", { "id": string }>
|
| DynamicRoute<"/experiments/[id]", { "id": string }>
|
||||||
| StaticRoute<"/experiments">
|
| StaticRoute<"/experiments">
|
||||||
| StaticRoute<"/">
|
| StaticRoute<"/">
|
||||||
|
| StaticRoute<"/logged-calls">
|
||||||
|
| StaticRoute<"/project/settings">
|
||||||
| StaticRoute<"/sentry-example-page">
|
| StaticRoute<"/sentry-example-page">
|
||||||
| StaticRoute<"/world-champs">
|
| StaticRoute<"/world-champs">
|
||||||
| StaticRoute<"/world-champs/signup">;
|
| StaticRoute<"/world-champs/signup">;
|
||||||
@@ -23,6 +23,7 @@ ARG NEXT_PUBLIC_SOCKET_URL
|
|||||||
ARG NEXT_PUBLIC_HOST
|
ARG NEXT_PUBLIC_HOST
|
||||||
ARG NEXT_PUBLIC_SENTRY_DSN
|
ARG NEXT_PUBLIC_SENTRY_DSN
|
||||||
ARG SENTRY_AUTH_TOKEN
|
ARG SENTRY_AUTH_TOKEN
|
||||||
|
ARG NEXT_PUBLIC_FF_SHOW_LOGGED_CALLS
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
7
app/openapitools.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||||
|
"spaces": 2,
|
||||||
|
"generator-cli": {
|
||||||
|
"version": "6.6.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
"postinstall": "prisma generate",
|
"postinstall": "prisma generate",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"codegen": "tsx src/codegen/export-openai-types.ts",
|
"codegen": "tsx src/server/scripts/client-codegen.ts",
|
||||||
"seed": "tsx prisma/seed.ts",
|
"seed": "tsx prisma/seed.ts",
|
||||||
"check": "concurrently 'pnpm lint' 'pnpm tsc' 'pnpm prettier . --check'",
|
"check": "concurrently 'pnpm lint' 'pnpm tsc' 'pnpm prettier . --check'",
|
||||||
"test": "pnpm vitest --no-threads"
|
"test": "pnpm vitest --no-threads"
|
||||||
@@ -50,6 +50,7 @@
|
|||||||
"chroma-js": "^2.4.2",
|
"chroma-js": "^2.4.2",
|
||||||
"concurrently": "^8.2.0",
|
"concurrently": "^8.2.0",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
"crypto-random-string": "^5.0.0",
|
||||||
"dayjs": "^1.11.8",
|
"dayjs": "^1.11.8",
|
||||||
"dedent": "^1.0.1",
|
"dedent": "^1.0.1",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
@@ -62,12 +63,16 @@
|
|||||||
"json-schema-to-typescript": "^13.0.2",
|
"json-schema-to-typescript": "^13.0.2",
|
||||||
"json-stringify-pretty-compact": "^4.0.0",
|
"json-stringify-pretty-compact": "^4.0.0",
|
||||||
"jsonschema": "^1.4.1",
|
"jsonschema": "^1.4.1",
|
||||||
|
"kysely": "^0.26.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"lucide-react": "^0.265.0",
|
||||||
"next": "^13.4.2",
|
"next": "^13.4.2",
|
||||||
"next-auth": "^4.22.1",
|
"next-auth": "^4.22.1",
|
||||||
"next-query-params": "^4.2.3",
|
"next-query-params": "^4.2.3",
|
||||||
|
"nextjs-cors": "^2.1.2",
|
||||||
"nextjs-routes": "^2.0.1",
|
"nextjs-routes": "^2.0.1",
|
||||||
"openai": "4.0.0-beta.7",
|
"openai": "4.0.0-beta.7",
|
||||||
|
"pg": "^8.11.2",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "^8.0.0",
|
||||||
"posthog-js": "^1.75.3",
|
"posthog-js": "^1.75.3",
|
||||||
"posthog-node": "^3.1.1",
|
"posthog-node": "^3.1.1",
|
||||||
@@ -83,10 +88,12 @@
|
|||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"react-textarea-autosize": "^8.5.0",
|
"react-textarea-autosize": "^8.5.0",
|
||||||
"recast": "^0.23.3",
|
"recast": "^0.23.3",
|
||||||
|
"recharts": "^2.7.2",
|
||||||
"replicate": "^0.12.3",
|
"replicate": "^0.12.3",
|
||||||
"socket.io": "^4.7.1",
|
"socket.io": "^4.7.1",
|
||||||
"socket.io-client": "^4.7.1",
|
"socket.io-client": "^4.7.1",
|
||||||
"superjson": "1.12.2",
|
"superjson": "1.12.2",
|
||||||
|
"trpc-openapi": "^1.2.0",
|
||||||
"tsx": "^3.12.7",
|
"tsx": "^3.12.7",
|
||||||
"type-fest": "^4.0.0",
|
"type-fest": "^4.0.0",
|
||||||
"use-query-params": "^2.2.1",
|
"use-query-params": "^2.2.1",
|
||||||
@@ -106,6 +113,7 @@
|
|||||||
"@types/json-schema": "^7.0.12",
|
"@types/json-schema": "^7.0.12",
|
||||||
"@types/lodash-es": "^4.17.8",
|
"@types/lodash-es": "^4.17.8",
|
||||||
"@types/node": "^18.16.0",
|
"@types/node": "^18.16.0",
|
||||||
|
"@types/pg": "^8.10.2",
|
||||||
"@types/pluralize": "^0.0.30",
|
"@types/pluralize": "^0.0.30",
|
||||||
"@types/prismjs": "^1.26.0",
|
"@types/prismjs": "^1.26.0",
|
||||||
"@types/react": "^18.2.6",
|
"@types/react": "^18.2.6",
|
||||||
982
pnpm-lock.yaml → app/pnpm-lock.yaml
generated
@@ -0,0 +1,90 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "LoggedCall" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"startTime" TIMESTAMP(3) NOT NULL,
|
||||||
|
"cacheHit" BOOLEAN NOT NULL,
|
||||||
|
"modelResponseId" UUID NOT NULL,
|
||||||
|
"organizationId" UUID NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "LoggedCall_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "LoggedCallModelResponse" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"reqPayload" JSONB NOT NULL,
|
||||||
|
"respStatus" INTEGER,
|
||||||
|
"respPayload" JSONB,
|
||||||
|
"error" TEXT,
|
||||||
|
"startTime" TIMESTAMP(3) NOT NULL,
|
||||||
|
"endTime" TIMESTAMP(3) NOT NULL,
|
||||||
|
"cacheKey" TEXT,
|
||||||
|
"durationMs" INTEGER,
|
||||||
|
"inputTokens" INTEGER,
|
||||||
|
"outputTokens" INTEGER,
|
||||||
|
"finishReason" TEXT,
|
||||||
|
"completionId" TEXT,
|
||||||
|
"totalCost" DECIMAL(18,12),
|
||||||
|
"originalLoggedCallId" UUID NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "LoggedCallModelResponse_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "LoggedCallTag" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"value" TEXT,
|
||||||
|
"loggedCallId" UUID NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "LoggedCallTag_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "ApiKey" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"apiKey" TEXT NOT NULL,
|
||||||
|
"organizationId" UUID NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "ApiKey_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "LoggedCall_startTime_idx" ON "LoggedCall"("startTime");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "LoggedCallModelResponse_originalLoggedCallId_key" ON "LoggedCallModelResponse"("originalLoggedCallId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "LoggedCallModelResponse_cacheKey_idx" ON "LoggedCallModelResponse"("cacheKey");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "LoggedCallTag_name_idx" ON "LoggedCallTag"("name");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "LoggedCallTag_name_value_idx" ON "LoggedCallTag"("name", "value");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "ApiKey_apiKey_key" ON "ApiKey"("apiKey");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "LoggedCall" ADD CONSTRAINT "LoggedCall_modelResponseId_fkey" FOREIGN KEY ("modelResponseId") REFERENCES "LoggedCallModelResponse"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "LoggedCall" ADD CONSTRAINT "LoggedCall_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "LoggedCallModelResponse" ADD CONSTRAINT "LoggedCallModelResponse_originalLoggedCallId_fkey" FOREIGN KEY ("originalLoggedCallId") REFERENCES "LoggedCall"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "LoggedCallTag" ADD CONSTRAINT "LoggedCallTag_loggedCallId_fkey" FOREIGN KEY ("loggedCallId") REFERENCES "LoggedCall"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "ApiKey" ADD CONSTRAINT "ApiKey_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Organization" ADD COLUMN "name" TEXT NOT NULL DEFAULT 'Project 1';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "LoggedCall" ALTER COLUMN "modelResponseId" DROP NOT NULL;
|
||||||
@@ -200,16 +200,21 @@ model DatasetEntry {
|
|||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO rename Organization to Project
|
||||||
model Organization {
|
model Organization {
|
||||||
id String @id @default(uuid()) @db.Uuid
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
name String @default("Project 1")
|
||||||
|
|
||||||
personalOrgUserId String? @unique @db.Uuid
|
personalOrgUserId String? @unique @db.Uuid
|
||||||
PersonalOrgUser User? @relation(fields: [personalOrgUserId], references: [id], onDelete: Cascade)
|
personalOrgUser User? @relation(fields: [personalOrgUserId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
organizationUsers OrganizationUser[]
|
organizationUsers OrganizationUser[]
|
||||||
experiments Experiment[]
|
experiments Experiment[]
|
||||||
datasets Dataset[]
|
datasets Dataset[]
|
||||||
|
loggedCalls LoggedCall[]
|
||||||
|
apiKeys ApiKey[]
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OrganizationUserRole {
|
enum OrganizationUserRole {
|
||||||
@@ -249,6 +254,99 @@ model WorldChampEntrant {
|
|||||||
@@unique([userId])
|
@@unique([userId])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model LoggedCall {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
|
||||||
|
startTime DateTime
|
||||||
|
|
||||||
|
// True if this call was served from the cache, false otherwise
|
||||||
|
cacheHit Boolean
|
||||||
|
|
||||||
|
// A LoggedCall is always associated with a LoggedCallModelResponse. If this
|
||||||
|
// is a cache miss, we create a new LoggedCallModelResponse.
|
||||||
|
// If it's a cache hit, it's a pre-existing LoggedCallModelResponse.
|
||||||
|
modelResponseId String? @db.Uuid
|
||||||
|
modelResponse LoggedCallModelResponse? @relation(fields: [modelResponseId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
// The responses created by this LoggedCall. Will be empty if this LoggedCall was a cache hit.
|
||||||
|
createdResponses LoggedCallModelResponse[] @relation(name: "ModelResponseOriginalCall")
|
||||||
|
|
||||||
|
organizationId String @db.Uuid
|
||||||
|
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
tags LoggedCallTag[]
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
@@index([startTime])
|
||||||
|
}
|
||||||
|
|
||||||
|
model LoggedCallModelResponse {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
|
||||||
|
reqPayload Json
|
||||||
|
|
||||||
|
// The HTTP status returned by the model provider
|
||||||
|
respStatus Int?
|
||||||
|
respPayload Json?
|
||||||
|
|
||||||
|
// Should be null if the request was successful, and some string if the request failed.
|
||||||
|
error String?
|
||||||
|
|
||||||
|
startTime DateTime
|
||||||
|
endTime DateTime
|
||||||
|
|
||||||
|
// Note: the function to calculate the cacheKey should include the project
|
||||||
|
// ID so we don't share cached responses between projects, which could be an
|
||||||
|
// attack vector. Also, we should only set the cacheKey on the model if the
|
||||||
|
// request was successful.
|
||||||
|
cacheKey String?
|
||||||
|
|
||||||
|
// Derived fields
|
||||||
|
durationMs Int?
|
||||||
|
inputTokens Int?
|
||||||
|
outputTokens Int?
|
||||||
|
finishReason String?
|
||||||
|
completionId String?
|
||||||
|
totalCost Decimal? @db.Decimal(18, 12)
|
||||||
|
|
||||||
|
// The LoggedCall that created this LoggedCallModelResponse
|
||||||
|
originalLoggedCallId String @unique @db.Uuid
|
||||||
|
originalLoggedCall LoggedCall @relation(name: "ModelResponseOriginalCall", fields: [originalLoggedCallId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
loggedCalls LoggedCall[]
|
||||||
|
|
||||||
|
@@index([cacheKey])
|
||||||
|
}
|
||||||
|
|
||||||
|
model LoggedCallTag {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
name String
|
||||||
|
value String?
|
||||||
|
|
||||||
|
loggedCallId String @db.Uuid
|
||||||
|
loggedCall LoggedCall @relation(fields: [loggedCallId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@index([name])
|
||||||
|
@@index([name, value])
|
||||||
|
}
|
||||||
|
|
||||||
|
model ApiKey {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
|
||||||
|
name String
|
||||||
|
apiKey String @unique
|
||||||
|
|
||||||
|
organizationId String @db.Uuid
|
||||||
|
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
model Account {
|
model Account {
|
||||||
id String @id @default(uuid()) @db.Uuid
|
id String @id @default(uuid()) @db.Uuid
|
||||||
userId String @db.Uuid
|
userId String @db.Uuid
|
||||||
410
app/prisma/seedDashboard.ts
Normal file
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 704 B After Width: | Height: | Size: 704 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 858 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
40
app/src/components/CopiableCode.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { HStack, Icon, IconButton, Tooltip, Text } from "@chakra-ui/react";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { MdContentCopy } from "react-icons/md";
|
||||||
|
import { useHandledAsyncCallback } from "~/utils/hooks";
|
||||||
|
|
||||||
|
const CopiableCode = ({ code }: { code: string }) => {
|
||||||
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
|
const [copyToClipboard] = useHandledAsyncCallback(async () => {
|
||||||
|
await navigator.clipboard.writeText(code);
|
||||||
|
setCopied(true);
|
||||||
|
}, [code]);
|
||||||
|
return (
|
||||||
|
<HStack
|
||||||
|
backgroundColor="blackAlpha.800"
|
||||||
|
color="white"
|
||||||
|
borderRadius={4}
|
||||||
|
padding={3}
|
||||||
|
w="full"
|
||||||
|
justifyContent="space-between"
|
||||||
|
>
|
||||||
|
<Text fontFamily="inconsolata" fontWeight="bold" letterSpacing={0.5}>
|
||||||
|
{code}
|
||||||
|
</Text>
|
||||||
|
<Tooltip closeOnClick={false} label={copied ? "Copied!" : "Copy to clipboard"}>
|
||||||
|
<IconButton
|
||||||
|
aria-label="Copy"
|
||||||
|
icon={<Icon as={MdContentCopy} boxSize={5} />}
|
||||||
|
size="xs"
|
||||||
|
colorScheme="white"
|
||||||
|
variant="ghost"
|
||||||
|
onClick={copyToClipboard}
|
||||||
|
onMouseLeave={() => setCopied(false)}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</HStack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CopiableCode;
|
||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { BsTrash } from "react-icons/bs";
|
import { BsTrash } from "react-icons/bs";
|
||||||
|
import { useAppStore } from "~/state/store";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
import { useExperiment, useHandledAsyncCallback } from "~/utils/hooks";
|
import { useExperiment, useHandledAsyncCallback } from "~/utils/hooks";
|
||||||
|
|
||||||
@@ -23,6 +24,8 @@ export const DeleteButton = () => {
|
|||||||
const utils = api.useContext();
|
const utils = api.useContext();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const closeDrawer = useAppStore((s) => s.closeDrawer);
|
||||||
|
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const cancelRef = useRef<HTMLButtonElement>(null);
|
const cancelRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
@@ -31,6 +34,8 @@ export const DeleteButton = () => {
|
|||||||
await mutation.mutateAsync({ id: experiment.data.id });
|
await mutation.mutateAsync({ id: experiment.data.id });
|
||||||
await utils.experiments.list.invalidate();
|
await utils.experiments.list.invalidate();
|
||||||
await router.push({ pathname: "/experiments" });
|
await router.push({ pathname: "/experiments" });
|
||||||
|
closeDrawer();
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
}, [mutation, experiment.data?.id, router]);
|
}, [mutation, experiment.data?.id, router]);
|
||||||
|
|
||||||
@@ -18,13 +18,13 @@ export const CellOptions = ({
|
|||||||
const modalDisclosure = useDisclosure();
|
const modalDisclosure = useDisclosure();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HStack justifyContent="flex-end" w="full">
|
<HStack justifyContent="flex-end" w="full" spacing={1}>
|
||||||
{cell && (
|
{cell && (
|
||||||
<>
|
<>
|
||||||
<Tooltip label="See Prompt">
|
<Tooltip label="See Prompt">
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="See Prompt"
|
aria-label="See Prompt"
|
||||||
icon={<Icon as={BsInfoCircle} boxSize={4} />}
|
icon={<Icon as={BsInfoCircle} boxSize={3.5} />}
|
||||||
onClick={modalDisclosure.onOpen}
|
onClick={modalDisclosure.onOpen}
|
||||||
size="xs"
|
size="xs"
|
||||||
colorScheme="gray"
|
colorScheme="gray"
|
||||||
26
app/src/components/StatsCard.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { VStack, HStack, type StackProps, Text, Divider } from "@chakra-ui/react";
|
||||||
|
import Link, { type LinkProps } from "next/link";
|
||||||
|
|
||||||
|
const StatsCard = ({
|
||||||
|
title,
|
||||||
|
href,
|
||||||
|
children,
|
||||||
|
...rest
|
||||||
|
}: { title: string; href: string } & StackProps & LinkProps) => {
|
||||||
|
return (
|
||||||
|
<VStack flex={1} borderWidth={1} padding={4} borderRadius={4} borderColor="gray.300" {...rest}>
|
||||||
|
<HStack w="full" justifyContent="space-between">
|
||||||
|
<Text fontSize="md" fontWeight="bold">
|
||||||
|
{title}
|
||||||
|
</Text>
|
||||||
|
<Link href={href}>
|
||||||
|
<Text color="blue">View all</Text>
|
||||||
|
</Link>
|
||||||
|
</HStack>
|
||||||
|
<Divider />
|
||||||
|
{children}
|
||||||
|
</VStack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StatsCard;
|
||||||