Skip to content

Commit 4e98801

Browse files
authored
Merge pull request #452 from cloudflare/main
Release
2 parents 345a0ea + 89c5f3a commit 4e98801

6 files changed

Lines changed: 97 additions & 61 deletions

File tree

src/components/cloudflare-account-selector.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,17 @@ import { Switch } from '@/components/ui/switch';
1111
import { toast } from 'sonner';
1212
import { apiClient } from '@/lib/api-client';
1313
import { CloudflareLogo } from '@cloudflare/kumo';
14-
import { Loader2, CheckCircle2, AlertCircle, MoreVertical, ExternalLink, LogOut, RefreshCw } from 'lucide-react';
14+
import {
15+
Loader2,
16+
CheckCircle2,
17+
AlertCircle,
18+
MoreVertical,
19+
RefreshCw,
20+
} from 'lucide-react';
1521
import { useLimitsContext } from '@/contexts/limits-context';
1622
import { CloudflareLogoThemed } from './shared/CloudflareLogoThemed';
1723
import { startCloudflareConnect } from '@/lib/cloudflare-connect';
24+
import { ArrowSquareOutIcon, SignOutIcon } from '@phosphor-icons/react';
1825

1926
interface CloudflareAccount {
2027
id: string;
@@ -309,17 +316,17 @@ export function CloudflareAccountSelector() {
309316
<DropdownMenu.Content align="end">
310317
{gatewayDashUrl && (
311318
<DropdownMenu.Item
319+
icon={ArrowSquareOutIcon}
312320
onClick={() => window.open(gatewayDashUrl, '_blank', 'noopener,noreferrer')}
313321
>
314-
<ExternalLink className="size-4" />
315322
View gateway
316323
</DropdownMenu.Item>
317324
)}
318325
<DropdownMenu.Item
326+
icon={SignOutIcon}
319327
onClick={handleDisconnect}
320328
variant="danger"
321329
>
322-
<LogOut className="size-4" />
323330
Disconnect
324331
</DropdownMenu.Item>
325332
</DropdownMenu.Content>

src/components/monaco-editor/monaco-editor.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ self.MonacoEnvironment = {
3030
},
3131
};
3232

33+
/** Resolve Monaco language id, including markdown when only a path is known. */
34+
function resolveLanguage(
35+
language: string | undefined,
36+
path: string | undefined,
37+
): string {
38+
if (language && language !== 'plaintext') {
39+
return language;
40+
}
41+
if (path) {
42+
const ext = path.split('.').pop()?.toLowerCase();
43+
if (ext === 'md' || ext === 'markdown') return 'markdown';
44+
if (ext === 'mdx') return 'mdx';
45+
}
46+
return language || 'typescript';
47+
}
48+
3349
monaco.editor.defineTheme('vesper', vesperTheme);
3450

3551
monaco.editor.defineTheme('vibesdk', {
@@ -247,7 +263,7 @@ export const MonacoEditor = memo<MonacoEditorProps>(function MonacoEditor({
247263
...restOptions
248264
} = options;
249265

250-
const initialLanguage = language || 'typescript';
266+
const initialLanguage = resolveLanguage(language, pathRef.current);
251267
const initialValue = value ?? '';
252268
const model = getOrCreateModel(
253269
initialValue,
@@ -320,7 +336,7 @@ export const MonacoEditor = memo<MonacoEditorProps>(function MonacoEditor({
320336
if (!editor.current) return;
321337

322338
const nextValue = createOptions.value ?? '';
323-
const nextLanguage = createOptions.language || 'typescript';
339+
const nextLanguage = resolveLanguage(createOptions.language, path);
324340
const pathChanged = path !== prevPath.current;
325341
const valueChanged = nextValue !== prevValue.current;
326342

@@ -550,8 +566,8 @@ export const MonacoDiffEditor = memo<MonacoDiffEditorProps>(
550566

551567
useEffect(() => {
552568
if (!diffEditor.current) return;
553-
const lang = language || 'plaintext';
554-
const prevOriginal = originalModel.current;
569+
const lang = resolveLanguage(language, path);
570+
const prevOriginal = originalModel.current;
555571
const prevModified = modifiedModel.current;
556572
const original = monaco.editor.createModel(
557573
originalValue,

src/routes/chat/components/database-viewer.tsx

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ export function DatabaseViewer({ agentId, enabled }: DatabaseViewerProps) {
7272
};
7373

7474
return (
75-
<div className="flex-1 flex flex-col overflow-hidden bg-kumo-base text-text-primary">
76-
<div className="flex items-center gap-2 px-3 py-2 border-b border-bg-2 bg-bg-4/40">
75+
<div className="flex-1 flex flex-col min-h-0 min-w-0 overflow-hidden bg-kumo-base text-text-primary">
76+
<div className="flex shrink-0 items-center gap-2 px-3 py-2 border-b border-bg-2 bg-bg-4/40">
7777
<DatabaseIcon className="size-4 text-text-50/70" />
7878
<span className="text-xs font-mono text-text-50/70">App database</span>
7979
<span className="text-xs text-text-50/40 ml-2">read-only</span>
@@ -98,13 +98,13 @@ export function DatabaseViewer({ agentId, enabled }: DatabaseViewerProps) {
9898
</div>
9999

100100
{error && (
101-
<div className="px-3 py-2 text-xs text-red-400 bg-red-500/10 border-b border-red-500/20">
101+
<div className="shrink-0 px-3 py-2 text-xs text-red-400 bg-red-500/10 border-b border-red-500/20">
102102
{error}
103103
</div>
104104
)}
105105

106-
<div className="flex-1 flex overflow-hidden">
107-
<div className="w-56 border-r border-bg-2 overflow-y-auto bg-bg-4/20 flex flex-col">
106+
<div className="flex-1 flex min-h-0 min-w-0 overflow-hidden">
107+
<div className="w-56 shrink-0 border-r border-bg-2 overflow-y-auto bg-bg-4/20 flex flex-col min-h-0">
108108
<div className="px-3 py-2 text-[10px] uppercase tracking-wider text-text-50/40 font-mono">
109109
Tables
110110
</div>
@@ -123,80 +123,87 @@ export function DatabaseViewer({ agentId, enabled }: DatabaseViewerProps) {
123123
key={t.name}
124124
onClick={() => selectTable(t.name)}
125125
className={cn(
126-
'flex items-center justify-between px-3 py-1.5 text-xs font-mono text-left hover:bg-kumo-elevated transition-colors',
126+
'flex items-center justify-between px-3 py-1.5 text-xs font-mono text-left hover:bg-kumo-elevated transition-colors min-w-0',
127127
selectedTable === t.name && 'bg-kumo-elevated text-text-primary',
128128
)}
129129
>
130130
<span className="truncate">{t.name}</span>
131-
<span className="text-text-50/40 ml-2">{t.rowCount}</span>
131+
<span className="text-text-50/40 ml-2 shrink-0">{t.rowCount}</span>
132132
</button>
133133
))}
134134
</div>
135135

136-
<div className="flex-1 flex flex-col overflow-hidden">
136+
<div className="flex-1 flex flex-col min-h-0 min-w-0 overflow-hidden">
137137
{!selectedTable && (
138138
<div className="flex-1 flex items-center justify-center text-text-50/50 text-sm">
139139
Select a table to view rows
140140
</div>
141141
)}
142142
{selectedTable && (
143143
<>
144-
<div className="flex-1 overflow-auto">
145-
{loadingQuery && !queryResult && (
146-
<div className="p-4 text-xs text-text-50/50">Loading rows…</div>
147-
)}
148-
{queryResult && queryResult.rows.length === 0 && (
149-
<div className="p-4 text-xs text-text-50/50">No rows.</div>
150-
)}
151-
{queryResult && queryResult.rows.length > 0 && (
152-
<table className="w-full text-xs font-mono">
153-
<thead className="sticky top-0 bg-bg-4 border-b border-bg-2">
154-
<tr>
155-
{queryResult.columns.map((col) => (
144+
<div className="relative flex-1 min-h-0 min-w-0">
145+
<div className="absolute inset-0 overflow-auto">
146+
{loadingQuery && !queryResult && (
147+
<div className="p-4 text-xs text-text-50/50">Loading rows…</div>
148+
)}
149+
{queryResult && queryResult.rows.length === 0 && (
150+
<div className="p-4 text-xs text-text-50/50">No rows.</div>
151+
)}
152+
{queryResult && queryResult.rows.length > 0 && (
153+
<table className="w-max min-w-full text-xs font-mono border-collapse">
154+
<thead className="sticky top-0 z-10 bg-bg-4 border-b border-bg-2">
155+
<tr>
156+
{queryResult.columns.map((col) => (
156157
<th
157158
key={col}
158159
onClick={() => onColumnHeaderClick(col)}
159-
className="px-3 py-1.5 text-left font-medium text-text-50/70 cursor-pointer select-none hover:bg-kumo-elevated"
160+
className="px-3 py-1.5 text-left font-medium text-text-50/70 cursor-pointer select-none hover:bg-kumo-elevated whitespace-nowrap max-w-64"
160161
>
161-
{col}
162-
{orderBy === col && (
163-
<span className="ml-1 text-text-primary">
164-
{orderDir === 'asc' ? '↑' : '↓'}
165-
</span>
166-
)}
162+
<span className="block truncate max-w-64">
163+
{col}
164+
{orderBy === col && (
165+
<span className="ml-1 text-text-primary">
166+
{orderDir === 'asc' ? '↑' : '↓'}
167+
</span>
168+
)}
169+
</span>
167170
</th>
168-
))}
169-
</tr>
170-
</thead>
171-
<tbody>
172-
{queryResult.rows.map((row, i) => (
173-
<tr
174-
key={i}
175-
className="border-b border-bg-2/50 hover:bg-kumo-elevated/30"
176-
>
177-
{queryResult.columns.map((col) => (
178-
<td key={col} className="px-3 py-1.5 align-top">
171+
))}
172+
</tr>
173+
</thead>
174+
<tbody>
175+
{queryResult.rows.map((row, i) => (
176+
<tr
177+
key={i}
178+
className="border-b border-bg-2/50 hover:bg-kumo-elevated/30"
179+
>
180+
{queryResult.columns.map((col) => (
181+
<td
182+
key={col}
183+
className="px-3 py-1.5 align-top max-w-64 overflow-hidden whitespace-nowrap"
184+
>
179185
<CellValue
180186
value={row[col]}
181187
onExpand={(v) =>
182188
setExpandedCell({ column: col, value: v })
183189
}
184190
/>
185191
</td>
186-
))}
187-
</tr>
188-
))}
189-
</tbody>
190-
</table>
191-
)}
192+
))}
193+
</tr>
194+
))}
195+
</tbody>
196+
</table>
197+
)}
198+
</div>
192199
</div>
193200
{queryResult && (
194-
<div className="flex items-center gap-3 px-3 py-2 border-t border-bg-2 bg-bg-4/40 text-xs">
195-
<span className="text-text-50/60">
201+
<div className="flex items-center gap-3 px-3 py-2 border-t border-bg-2 bg-bg-4/40 text-xs shrink-0 min-w-0">
202+
<span className="text-text-50/60 shrink-0">
196203
{queryResult.totalCount.toLocaleString()} rows
197204
</span>
198205
<span className="text-text-50/30">·</span>
199-
<span className="text-text-50/60">
206+
<span className="text-text-50/60 shrink-0">
200207
Page {page + 1} / {totalPages}
201208
</span>
202209
<button
@@ -213,7 +220,7 @@ export function DatabaseViewer({ agentId, enabled }: DatabaseViewerProps) {
213220
>
214221
<ChevronRight className="size-3.5" />
215222
</button>
216-
<div className="ml-auto flex items-center gap-1">
223+
<div className="ml-auto flex items-center gap-1 shrink-0">
217224
<span className="text-text-50/50">per page</span>
218225
<select
219226
value={pageSize}
@@ -294,11 +301,11 @@ function CellValue({
294301
}
295302
if (typeof value === 'string') {
296303
if (value.length <= MAX_INLINE_CELL_LEN) {
297-
return <span className="break-all">{value}</span>;
304+
return <span className="truncate max-w-64 inline-block align-bottom" title={value}>{value}</span>;
298305
}
299306
return (
300307
<button
301-
className="text-left text-text-primary/80 hover:text-text-primary underline-offset-2 hover:underline truncate block w-full"
308+
className="text-left text-text-primary/80 hover:text-text-primary underline-offset-2 hover:underline truncate max-w-64 inline-block align-bottom"
302309
onClick={() => onExpand(value)}
303310
title="Click to view full value"
304311
>
@@ -308,12 +315,13 @@ function CellValue({
308315
}
309316
const repr = typeof value === 'object' ? JSON.stringify(value) : String(value);
310317
if (repr.length <= MAX_INLINE_CELL_LEN) {
311-
return <span>{repr}</span>;
318+
return <span className="truncate max-w-64 inline-block align-bottom" title={repr}>{repr}</span>;
312319
}
313320
return (
314321
<button
315-
className="text-left text-text-primary/80 hover:text-text-primary underline-offset-2 hover:underline truncate block w-full"
322+
className="text-left text-text-primary/80 hover:text-text-primary underline-offset-2 hover:underline truncate max-w-64 inline-block align-bottom"
316323
onClick={() => onExpand(value)}
324+
title="Click to view full value"
317325
>
318326
{repr.slice(0, MAX_INLINE_CELL_LEN)}
319327
</button>

src/routes/chat/components/main-content-panel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ export function MainContentPanel(props: MainContentPanelProps) {
450450

451451
return (
452452
<motion.div
453-
className="flex-1 flex flex-col overflow-hidden"
453+
className="flex-1 flex flex-col min-h-0 min-w-0 overflow-hidden"
454454
initial={{ opacity: 0, scale: 0.84 }}
455455
animate={{ opacity: 1, scale: 1 }}
456456
transition={{ duration: 0.3, ease: 'easeInOut' }}

src/routes/chat/components/view-container.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ interface ViewContainerProps {
66

77
export function ViewContainer({ children }: ViewContainerProps) {
88
return (
9-
<div className="flex-1 flex flex-col bg-kumo-base overflow-hidden border-l">
9+
<div className="flex-1 flex flex-col min-h-0 min-w-0 bg-kumo-base overflow-hidden border-l">
1010
{children}
1111
</div>
1212
);

src/utils/string.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ export const getFileType = (path: string): string => {
1515
return 'html';
1616
case 'json':
1717
return 'json';
18+
case 'md':
19+
case 'markdown':
20+
return 'markdown';
21+
case 'mdx':
22+
return 'mdx';
1823
default:
1924
return 'plaintext';
2025
}

0 commit comments

Comments
 (0)