Skip to content

Commit db26f63

Browse files
committed
feat: prompts list redesign with separate columns, bar sparklines, version/override display, breadcrumb fix
1 parent 86beeb9 commit db26f63

File tree

3 files changed

+37
-36
lines changed
  • apps/webapp/app
    • presenters/v3
    • routes
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index

3 files changed

+37
-36
lines changed

apps/webapp/app/presenters/v3/PromptPresenter.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export class PromptPresenter extends BasePresenter {
8282
tags: p.tags,
8383
defaultModel: effectiveModel,
8484
currentVersion: currentVersion ? { version: currentVersion.version } : null,
85+
overrideVersion: overrideVersion ? { version: overrideVersion.version } : null,
8586
hasOverride,
8687
updatedAt: p.updatedAt,
8788
};

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ import { MetricWidget } from "~/routes/resources.metric";
6969
import { InfoPanel } from "~/components/primitives/InfoPanel";
7070
import { InlineCode } from "~/components/code/InlineCode";
7171
import { TextLink } from "~/components/primitives/TextLink";
72-
import { EnvironmentParamSchema, v3RunSpanPath } from "~/utils/pathBuilder";
72+
import { EnvironmentParamSchema, v3PromptsPath, v3RunSpanPath } from "~/utils/pathBuilder";
7373
import { z } from "zod";
7474

7575
const ParamSchema = EnvironmentParamSchema.extend({
@@ -434,6 +434,9 @@ export default function PromptDetailPage() {
434434
possibleOperations,
435435
possibleProviders,
436436
} = useTypedLoaderData<typeof loader>();
437+
const organization = useOrganization();
438+
const project = useProject();
439+
const environment = useEnvironment();
437440
const fetcher = useFetcher();
438441
const { value: searchValue, replace: replaceSearch } = useSearchParams();
439442

@@ -486,7 +489,7 @@ export default function PromptDetailPage() {
486489
</span>
487490
</div>
488491
}
489-
backButton={{ to: "..", text: "Prompts" }}
492+
backButton={{ to: v3PromptsPath(organization, project, environment), text: "Prompts" }}
490493
/>
491494
<PageAccessories>
492495
<div className="flex items-center gap-2">

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsx

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { type MetaFunction } from "@remix-run/react";
22
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
3-
import { Area, AreaChart, ResponsiveContainer } from "recharts";
3+
import { Bar, BarChart, ResponsiveContainer } from "recharts";
44
import { typedjson, useTypedLoaderData } from "remix-typedjson";
55
import { PromptsNone } from "~/components/BlankStatePanels";
66
import { MainCenteredContainer, PageBody, PageContainer } from "~/components/layout/AppLayout";
77
import { TruncatedCopyableValue } from "~/components/primitives/TruncatedCopyableValue";
8-
import { Badge } from "~/components/primitives/Badge";
98
import { DateTime } from "~/components/primitives/DateTime";
109
import { NavBar, PageTitle } from "~/components/primitives/PageHeader";
1110
import {
@@ -87,51 +86,57 @@ export default function PromptsPage() {
8786
<TableHeader>
8887
<TableRow>
8988
<TableHeaderCell>ID</TableHeaderCell>
90-
<TableHeaderCell>Prompt</TableHeaderCell>
89+
<TableHeaderCell>Slug</TableHeaderCell>
90+
<TableHeaderCell>Description</TableHeaderCell>
9191
<TableHeaderCell>Model</TableHeaderCell>
92-
<TableHeaderCell>Current</TableHeaderCell>
92+
<TableHeaderCell>Version</TableHeaderCell>
9393
<TableHeaderCell>Usage (24h)</TableHeaderCell>
9494
<TableHeaderCell alignment="right">Last updated</TableHeaderCell>
9595
</TableRow>
9696
</TableHeader>
9797
<TableBody>
9898
{prompts.length === 0 ? (
99-
<TableBlankRow colSpan={6}>No prompts found</TableBlankRow>
99+
<TableBlankRow colSpan={7}>No prompts found</TableBlankRow>
100100
) : (
101101
prompts.map((prompt) => {
102102
const path = `${v3PromptsPath(organization, project, environment)}/${prompt.slug}`;
103+
const activeVersion = prompt.overrideVersion ?? prompt.currentVersion;
104+
const isOverride = !!prompt.overrideVersion;
103105

104106
return (
105107
<TableRow key={prompt.id}>
106108
<TableCell to={path} isTabbableCell>
107109
<TruncatedCopyableValue value={prompt.friendlyId} />
108110
</TableCell>
109111
<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+
)}
123124
</TableCell>
124125
<TableCell to={path}>
125126
<span className="text-text-dimmed">
126127
{prompt.defaultModel ?? <span className="text-charcoal-500">-</span>}
127128
</span>
128129
</TableCell>
129130
<TableCell to={path}>
130-
{prompt.currentVersion ? (
131+
{activeVersion ? (
131132
<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+
/>
133138
<span className="text-text-bright">
134-
v{prompt.currentVersion.version}
139+
v{activeVersion.version}
135140
</span>
136141
</div>
137142
) : (
@@ -167,22 +172,14 @@ function UsageSparkline({ data }: { data?: number[] }) {
167172
<div className="flex items-center gap-2">
168173
<div className="h-6 w-16">
169174
<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
179177
dataKey="value"
180-
stroke="#3b82f6"
181-
strokeWidth={1.5}
182-
fill="url(#sparkFill)"
178+
fill="#3b82f6"
179+
radius={[1, 1, 0, 0]}
183180
isAnimationActive={false}
184181
/>
185-
</AreaChart>
182+
</BarChart>
186183
</ResponsiveContainer>
187184
</div>
188185
<span className="text-xs tabular-nums text-text-dimmed">{total.toLocaleString()}</span>

0 commit comments

Comments
 (0)