Skip to content

Commit 0770674

Browse files
committed
feat(web): add docsUrl for providers to install from
1 parent 46ea594 commit 0770674

3 files changed

Lines changed: 45 additions & 4 deletions

File tree

apps/web/src/components/chat/ProviderHealthBanner.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { type ServerProviderStatus } from "@t3tools/contracts";
22
import { memo } from "react";
33
import { Alert, AlertDescription, AlertTitle } from "../ui/alert";
44
import { CircleAlertIcon } from "lucide-react";
5+
import { PROVIDER_OPTIONS } from "~/session-logic";
6+
import { ensureSentenceEnds } from "~/lib/utils";
57

68
export const ProviderHealthBanner = memo(function ProviderHealthBanner({
79
status,
@@ -17,6 +19,8 @@ export const ProviderHealthBanner = memo(function ProviderHealthBanner({
1719
? `${status.provider} provider is unavailable.`
1820
: `${status.provider} provider has limited availability.`;
1921

22+
const opts = PROVIDER_OPTIONS.find((opt) => opt.value === status.provider);
23+
2024
return (
2125
<div className="pt-3 mx-auto max-w-3xl">
2226
<Alert variant={status.status === "error" ? "error" : "warning"}>
@@ -25,7 +29,20 @@ export const ProviderHealthBanner = memo(function ProviderHealthBanner({
2529
{status.provider === "codex" ? "Codex provider status" : `${status.provider} status`}
2630
</AlertTitle>
2731
<AlertDescription className="line-clamp-3" title={status.message ?? defaultMessage}>
28-
{status.message ?? defaultMessage}
32+
{ensureSentenceEnds(status.message ?? defaultMessage)}
33+
{opts?.docsUrl ? (
34+
<>
35+
{" "}
36+
<a
37+
className="underline underline-offset-4 text-foreground hover:text-primary"
38+
href={opts.docsUrl}
39+
target="_blank"
40+
rel="noreferrer"
41+
>
42+
Installation Guide
43+
</a>
44+
</>
45+
) : null}
2946
</AlertDescription>
3047
</Alert>
3148
</div>

apps/web/src/lib/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,11 @@ export const newProjectId = (): ProjectId => ProjectId.makeUnsafe(randomUUID());
3030
export const newThreadId = (): ThreadId => ThreadId.makeUnsafe(randomUUID());
3131

3232
export const newMessageId = (): MessageId => MessageId.makeUnsafe(randomUUID());
33+
34+
export const ensureSentenceEnds = (value: string): string => {
35+
const trimmed = value.trim();
36+
if ([".", "!", "?"].includes(trimmed.at(-1) ?? "")) {
37+
return trimmed;
38+
}
39+
return `${trimmed}.`;
40+
};

apps/web/src/session-logic.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,26 @@ export const PROVIDER_OPTIONS: Array<{
2424
value: ProviderPickerKind;
2525
label: string;
2626
available: boolean;
27+
docsUrl: string | null;
2728
}> = [
28-
{ value: "codex", label: "Codex", available: true },
29-
{ value: "claudeCode", label: "Claude Code", available: false },
30-
{ value: "cursor", label: "Cursor", available: false },
29+
{
30+
value: "codex",
31+
label: "Codex",
32+
available: true,
33+
docsUrl: "https://developers.openai.com/codex/cli/#cli-setup",
34+
},
35+
{
36+
value: "claudeCode",
37+
label: "Claude Code",
38+
available: false,
39+
docsUrl: "https://code.claude.com/docs/en/quickstart#step-1-install-claude-code",
40+
},
41+
{
42+
value: "cursor",
43+
label: "Cursor",
44+
available: false,
45+
docsUrl: "https://cursor.com/docs/cli/installation#installation",
46+
},
3147
];
3248

3349
export interface WorkLogEntry {

0 commit comments

Comments
 (0)