|
1 | 1 | import { type MetaFunction } from "@remix-run/react"; |
2 | 2 | import { type LoaderFunctionArgs } from "@remix-run/server-runtime"; |
3 | | -import { Area, AreaChart, ResponsiveContainer } from "recharts"; |
| 3 | +import { Bar, BarChart, ResponsiveContainer } from "recharts"; |
4 | 4 | import { typedjson, useTypedLoaderData } from "remix-typedjson"; |
5 | 5 | import { PromptsNone } from "~/components/BlankStatePanels"; |
6 | 6 | import { MainCenteredContainer, PageBody, PageContainer } from "~/components/layout/AppLayout"; |
7 | 7 | import { TruncatedCopyableValue } from "~/components/primitives/TruncatedCopyableValue"; |
8 | | -import { Badge } from "~/components/primitives/Badge"; |
9 | 8 | import { DateTime } from "~/components/primitives/DateTime"; |
10 | 9 | import { NavBar, PageTitle } from "~/components/primitives/PageHeader"; |
11 | 10 | import { |
@@ -87,51 +86,57 @@ export default function PromptsPage() { |
87 | 86 | <TableHeader> |
88 | 87 | <TableRow> |
89 | 88 | <TableHeaderCell>ID</TableHeaderCell> |
90 | | - <TableHeaderCell>Prompt</TableHeaderCell> |
| 89 | + <TableHeaderCell>Slug</TableHeaderCell> |
| 90 | + <TableHeaderCell>Description</TableHeaderCell> |
91 | 91 | <TableHeaderCell>Model</TableHeaderCell> |
92 | | - <TableHeaderCell>Current</TableHeaderCell> |
| 92 | + <TableHeaderCell>Version</TableHeaderCell> |
93 | 93 | <TableHeaderCell>Usage (24h)</TableHeaderCell> |
94 | 94 | <TableHeaderCell alignment="right">Last updated</TableHeaderCell> |
95 | 95 | </TableRow> |
96 | 96 | </TableHeader> |
97 | 97 | <TableBody> |
98 | 98 | {prompts.length === 0 ? ( |
99 | | - <TableBlankRow colSpan={6}>No prompts found</TableBlankRow> |
| 99 | + <TableBlankRow colSpan={7}>No prompts found</TableBlankRow> |
100 | 100 | ) : ( |
101 | 101 | prompts.map((prompt) => { |
102 | 102 | const path = `${v3PromptsPath(organization, project, environment)}/${prompt.slug}`; |
| 103 | + const activeVersion = prompt.overrideVersion ?? prompt.currentVersion; |
| 104 | + const isOverride = !!prompt.overrideVersion; |
103 | 105 |
|
104 | 106 | return ( |
105 | 107 | <TableRow key={prompt.id}> |
106 | 108 | <TableCell to={path} isTabbableCell> |
107 | 109 | <TruncatedCopyableValue value={prompt.friendlyId} /> |
108 | 110 | </TableCell> |
109 | 111 | <TableCell to={path}> |
110 | | - <div className="flex flex-col"> |
111 | | - <div className="flex items-center gap-1.5"> |
112 | | - <span className="text-text-bright">{prompt.slug}</span> |
113 | | - {prompt.hasOverride && ( |
114 | | - <Badge variant="extra-small" className="border-amber-500/30 text-amber-400"> |
115 | | - override |
116 | | - </Badge> |
117 | | - )} |
118 | | - </div> |
119 | | - {prompt.description && ( |
120 | | - <span className="text-xs text-text-dimmed">{prompt.description}</span> |
121 | | - )} |
122 | | - </div> |
| 112 | + <span className="text-text-bright">{prompt.slug}</span> |
| 113 | + </TableCell> |
| 114 | + <TableCell to={path}> |
| 115 | + {prompt.description ? ( |
| 116 | + <span className="text-text-dimmed" title={prompt.description.length > 80 ? prompt.description : undefined}> |
| 117 | + {prompt.description.length > 80 |
| 118 | + ? prompt.description.slice(0, 80) + "..." |
| 119 | + : prompt.description} |
| 120 | + </span> |
| 121 | + ) : ( |
| 122 | + <span className="text-charcoal-500">-</span> |
| 123 | + )} |
123 | 124 | </TableCell> |
124 | 125 | <TableCell to={path}> |
125 | 126 | <span className="text-text-dimmed"> |
126 | 127 | {prompt.defaultModel ?? <span className="text-charcoal-500">-</span>} |
127 | 128 | </span> |
128 | 129 | </TableCell> |
129 | 130 | <TableCell to={path}> |
130 | | - {prompt.currentVersion ? ( |
| 131 | + {activeVersion ? ( |
131 | 132 | <div className="flex items-center gap-1.5"> |
132 | | - <div className="size-1.5 rounded-full bg-green-500" /> |
| 133 | + <div |
| 134 | + className={`size-1.5 rounded-full ${ |
| 135 | + isOverride ? "bg-amber-400" : "bg-green-500" |
| 136 | + }`} |
| 137 | + /> |
133 | 138 | <span className="text-text-bright"> |
134 | | - v{prompt.currentVersion.version} |
| 139 | + v{activeVersion.version} |
135 | 140 | </span> |
136 | 141 | </div> |
137 | 142 | ) : ( |
@@ -167,22 +172,14 @@ function UsageSparkline({ data }: { data?: number[] }) { |
167 | 172 | <div className="flex items-center gap-2"> |
168 | 173 | <div className="h-6 w-16"> |
169 | 174 | <ResponsiveContainer width="100%" height="100%"> |
170 | | - <AreaChart data={chartData} margin={{ top: 1, right: 0, bottom: 1, left: 0 }}> |
171 | | - <defs> |
172 | | - <linearGradient id="sparkFill" x1="0" y1="0" x2="0" y2="1"> |
173 | | - <stop offset="0%" stopColor="#3b82f6" stopOpacity={0.3} /> |
174 | | - <stop offset="100%" stopColor="#3b82f6" stopOpacity={0} /> |
175 | | - </linearGradient> |
176 | | - </defs> |
177 | | - <Area |
178 | | - type="monotone" |
| 175 | + <BarChart data={chartData} margin={{ top: 1, right: 0, bottom: 1, left: 0 }}> |
| 176 | + <Bar |
179 | 177 | dataKey="value" |
180 | | - stroke="#3b82f6" |
181 | | - strokeWidth={1.5} |
182 | | - fill="url(#sparkFill)" |
| 178 | + fill="#3b82f6" |
| 179 | + radius={[1, 1, 0, 0]} |
183 | 180 | isAnimationActive={false} |
184 | 181 | /> |
185 | | - </AreaChart> |
| 182 | + </BarChart> |
186 | 183 | </ResponsiveContainer> |
187 | 184 | </div> |
188 | 185 | <span className="text-xs tabular-nums text-text-dimmed">{total.toLocaleString()}</span> |
|
0 commit comments