Skip to content

Commit f6365aa

Browse files
committed
Switch to use Tab/TabContent instead
1 parent 758b91f commit f6365aa

File tree

1 file changed

+167
-164
lines changed

1 file changed

+167
-164
lines changed

webview-ui/src/components/cloud/CloudView.tsx

Lines changed: 167 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { ToggleSwitch } from "@/components/ui/toggle-switch"
1111
import { renderCloudBenefitsContent } from "./CloudUpsellDialog"
1212
import { TriangleAlert } from "lucide-react"
1313
import { cn } from "@/lib/utils"
14+
import { Tab, TabContent, TabHeader } from "../common/Tab"
15+
import { Button } from "@/components/ui/button"
1416

1517
// Define the production URL constant locally to avoid importing from cloud package in tests
1618
const PRODUCTION_ROO_CODE_API_URL = "https://app.roocode.com"
@@ -153,186 +155,187 @@ export const CloudView = ({ userInfo, isAuthenticated, cloudApiUrl, onDone }: Cl
153155
}
154156

155157
return (
156-
<div className="flex flex-col h-full p-4">
157-
<div className="flex justify-between items-center mb-6">
158-
<h1 className="text-xl font-medium text-vscode-foreground">{isAuthenticated && t("cloud:title")}</h1>
159-
<VSCodeButton appearance="secondary" onClick={onDone}>
160-
{t("settings:common.done")}
161-
</VSCodeButton>
162-
</div>
163-
{isAuthenticated ? (
164-
<>
165-
{userInfo && (
166-
<div className="flex flex-col items-center mb-6">
167-
<div className="w-16 h-16 mb-3 rounded-full overflow-hidden">
168-
{userInfo?.picture ? (
169-
<img
170-
src={userInfo.picture}
171-
alt={t("cloud:profilePicture")}
172-
className="w-full h-full object-cover"
173-
/>
174-
) : (
175-
<div className="w-full h-full flex items-center justify-center bg-vscode-button-background text-vscode-button-foreground text-xl">
176-
{userInfo?.name?.charAt(0) || userInfo?.email?.charAt(0) || "?"}
177-
</div>
178-
)}
179-
</div>
180-
{userInfo.name && (
181-
<h2 className="text-lg font-medium text-vscode-foreground my-0">{userInfo.name}</h2>
182-
)}
183-
{userInfo?.email && (
184-
<p className="text-sm text-vscode-descriptionForeground my-0">{userInfo?.email}</p>
185-
)}
186-
{userInfo?.organizationName && (
187-
<div className="flex items-center gap-2 text-sm text-vscode-descriptionForeground mt-2">
188-
{userInfo.organizationImageUrl && (
158+
<Tab>
159+
<TabHeader className="flex justify-between items-center">
160+
<h3 className="text-vscode-foreground m-0">{isAuthenticated && t("cloud:title")}</h3>
161+
<Button onClick={onDone}>{t("settings:common.done")}</Button>
162+
</TabHeader>
163+
164+
<TabContent>
165+
{isAuthenticated ? (
166+
<>
167+
{userInfo && (
168+
<div className="flex flex-col items-center mb-6">
169+
<div className="w-16 h-16 mb-3 rounded-full overflow-hidden">
170+
{userInfo?.picture ? (
189171
<img
190-
src={userInfo.organizationImageUrl}
191-
alt={userInfo.organizationName}
192-
className="w-4 h-4 rounded object-cover"
172+
src={userInfo.picture}
173+
alt={t("cloud:profilePicture")}
174+
className="w-full h-full object-cover"
193175
/>
176+
) : (
177+
<div className="w-full h-full flex items-center justify-center bg-vscode-button-background text-vscode-button-foreground text-xl">
178+
{userInfo?.name?.charAt(0) || userInfo?.email?.charAt(0) || "?"}
179+
</div>
194180
)}
195-
<span>{userInfo.organizationName}</span>
196181
</div>
197-
)}
198-
</div>
199-
)}
200-
201-
{/* Task Sync Toggle - Always shown when authenticated */}
202-
<div className="border-t border-vscode-widget-border pt-4 mt-4">
203-
<div className="flex items-center gap-3 mb-2">
204-
<ToggleSwitch
205-
checked={taskSyncEnabled}
206-
onChange={handleTaskSyncToggle}
207-
size="medium"
208-
aria-label={t("cloud:taskSync")}
209-
data-testid="task-sync-toggle"
210-
disabled={!!userInfo?.organizationId}
211-
/>
212-
<span className="font-medium text-vscode-foreground">{t("cloud:taskSync")}</span>
213-
</div>
214-
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-4 ml-8">
215-
{t("cloud:taskSyncDescription")}
216-
</div>
217-
{userInfo?.organizationId && (
218-
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-4 ml-8 italic">
219-
{t("cloud:taskSyncManagedByOrganization")}
182+
{userInfo.name && (
183+
<h2 className="text-lg font-medium text-vscode-foreground my-0">{userInfo.name}</h2>
184+
)}
185+
{userInfo?.email && (
186+
<p className="text-sm text-vscode-descriptionForeground my-0">{userInfo?.email}</p>
187+
)}
188+
{userInfo?.organizationName && (
189+
<div className="flex items-center gap-2 text-sm text-vscode-descriptionForeground mt-2">
190+
{userInfo.organizationImageUrl && (
191+
<img
192+
src={userInfo.organizationImageUrl}
193+
alt={userInfo.organizationName}
194+
className="w-4 h-4 rounded object-cover"
195+
/>
196+
)}
197+
<span>{userInfo.organizationName}</span>
198+
</div>
199+
)}
220200
</div>
221201
)}
222202

223-
{/* Remote Control Toggle - Only shown when both extensionBridgeEnabled and featureRoomoteControlEnabled are true */}
224-
{userInfo?.extensionBridgeEnabled && featureRoomoteControlEnabled && (
225-
<>
226-
<div className="flex items-center gap-3 mb-2">
227-
<ToggleSwitch
228-
checked={remoteControlEnabled}
229-
onChange={handleRemoteControlToggle}
230-
size="medium"
231-
aria-label={t("cloud:remoteControl")}
232-
data-testid="remote-control-toggle"
233-
disabled={!taskSyncEnabled}
234-
/>
235-
<span className="font-medium text-vscode-foreground">
236-
{t("cloud:remoteControl")}
237-
</span>
238-
</div>
239-
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-4 ml-8">
240-
{t("cloud:remoteControlDescription")}
241-
{!taskSyncEnabled && (
242-
<div className="text-vscode-errorForeground mt-2">
243-
{t("cloud:remoteControlRequiresTaskSync")}
244-
</div>
245-
)}
203+
{/* Task Sync Toggle - Always shown when authenticated */}
204+
<div className="border-t border-vscode-widget-border pt-4 mt-4">
205+
<div className="flex items-center gap-3 mb-2">
206+
<ToggleSwitch
207+
checked={taskSyncEnabled}
208+
onChange={handleTaskSyncToggle}
209+
size="medium"
210+
aria-label={t("cloud:taskSync")}
211+
data-testid="task-sync-toggle"
212+
disabled={!!userInfo?.organizationId}
213+
/>
214+
<span className="font-medium text-vscode-foreground">{t("cloud:taskSync")}</span>
215+
</div>
216+
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-4 ml-8">
217+
{t("cloud:taskSyncDescription")}
218+
</div>
219+
{userInfo?.organizationId && (
220+
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-4 ml-8 italic">
221+
{t("cloud:taskSyncManagedByOrganization")}
246222
</div>
247-
</>
248-
)}
223+
)}
249224

250-
{/* Info text about usage metrics */}
251-
<div className="text-vscode-descriptionForeground text-sm mt-4 mb-4 ml-8 italic">
252-
{t("cloud:usageMetricsAlwaysReported")}
253-
</div>
225+
{/* Remote Control Toggle - Only shown when both extensionBridgeEnabled and featureRoomoteControlEnabled are true */}
226+
{userInfo?.extensionBridgeEnabled && featureRoomoteControlEnabled && (
227+
<>
228+
<div className="flex items-center gap-3 mb-2">
229+
<ToggleSwitch
230+
checked={remoteControlEnabled}
231+
onChange={handleRemoteControlToggle}
232+
size="medium"
233+
aria-label={t("cloud:remoteControl")}
234+
data-testid="remote-control-toggle"
235+
disabled={!taskSyncEnabled}
236+
/>
237+
<span className="font-medium text-vscode-foreground">
238+
{t("cloud:remoteControl")}
239+
</span>
240+
</div>
241+
<div className="text-vscode-descriptionForeground text-sm mt-1 mb-4 ml-8">
242+
{t("cloud:remoteControlDescription")}
243+
{!taskSyncEnabled && (
244+
<div className="text-vscode-errorForeground mt-2">
245+
{t("cloud:remoteControlRequiresTaskSync")}
246+
</div>
247+
)}
248+
</div>
249+
</>
250+
)}
254251

255-
<hr className="border-vscode-widget-border mb-4" />
256-
</div>
252+
{/* Info text about usage metrics */}
253+
<div className="text-vscode-descriptionForeground text-sm mt-4 mb-4 ml-8 italic">
254+
{t("cloud:usageMetricsAlwaysReported")}
255+
</div>
257256

258-
<div className="flex flex-col gap-2 mt-4">
259-
<VSCodeButton appearance="secondary" onClick={handleVisitCloudWebsite} className="w-full">
260-
{t("cloud:visitCloudWebsite")}
261-
</VSCodeButton>
262-
<VSCodeButton appearance="secondary" onClick={handleLogoutClick} className="w-full">
263-
{t("cloud:logOut")}
264-
</VSCodeButton>
265-
</div>
266-
</>
267-
) : (
268-
<>
269-
<div className="flex flex-col items-start gap-4 px-8">
270-
<div className={cn(authInProgress && "opacity-50")}>{renderCloudBenefitsContent(t)}</div>
257+
<hr className="border-vscode-widget-border mb-4" />
258+
</div>
271259

272-
{!authInProgress && (
273-
<VSCodeButton appearance="primary" onClick={handleConnectClick} className="w-full">
274-
{t("cloud:connect")}
260+
<div className="flex flex-col gap-2 mt-4">
261+
<VSCodeButton appearance="secondary" onClick={handleVisitCloudWebsite} className="w-full">
262+
{t("cloud:visitCloudWebsite")}
275263
</VSCodeButton>
276-
)}
264+
<VSCodeButton appearance="secondary" onClick={handleLogoutClick} className="w-full">
265+
{t("cloud:logOut")}
266+
</VSCodeButton>
267+
</div>
268+
</>
269+
) : (
270+
<>
271+
<div className="flex flex-col items-start gap-4 px-8">
272+
<div className={cn(authInProgress && "opacity-50")}>{renderCloudBenefitsContent(t)}</div>
277273

278-
{/* Manual entry section */}
279-
{authInProgress && !showManualEntry && (
280-
// Timeout message with "Having trouble?" link
281-
<div className="flex flex-col items-start gap-1">
282-
<div className="flex items-center gap-2 text-base text-vscode-descriptionForeground">
283-
<VSCodeProgressRing className="size-3 text-vscode-foreground" />
284-
{t("cloud:authWaiting")}
274+
{!authInProgress && (
275+
<VSCodeButton appearance="primary" onClick={handleConnectClick} className="w-full">
276+
{t("cloud:connect")}
277+
</VSCodeButton>
278+
)}
279+
280+
{/* Manual entry section */}
281+
{authInProgress && !showManualEntry && (
282+
// Timeout message with "Having trouble?" link
283+
<div className="flex flex-col items-start gap-1">
284+
<div className="flex items-center gap-2 text-base text-vscode-descriptionForeground">
285+
<VSCodeProgressRing className="size-3 text-vscode-foreground" />
286+
{t("cloud:authWaiting")}
287+
</div>
288+
{!showManualEntry && (
289+
<button
290+
onClick={handleShowManualEntry}
291+
className="text-base ml-5 text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground underline cursor-pointer bg-transparent border-none p-0">
292+
{t("cloud:havingTrouble")}
293+
</button>
294+
)}
285295
</div>
286-
{!showManualEntry && (
287-
<button
288-
onClick={handleShowManualEntry}
289-
className="text-base ml-5 text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground underline cursor-pointer bg-transparent border-none p-0">
290-
{t("cloud:havingTrouble")}
291-
</button>
292-
)}
293-
</div>
294-
)}
296+
)}
295297

296-
{showManualEntry && (
297-
// Manual URL entry form
298-
<div className="space-y-2 max-w-72">
299-
<p className="text-base text-vscode-descriptionForeground">
300-
{t("cloud:pasteCallbackUrl")}
301-
</p>
302-
<VSCodeTextField
303-
ref={manualUrlInputRef as any}
304-
value={manualUrl}
305-
onChange={handleManualUrlChange}
306-
onKeyDown={handleKeyDown}
307-
placeholder="vscode://RooVeterinaryInc.roo-cline/auth/clerk/callback?state=..."
308-
className="w-full"
309-
/>
310-
<p className="mt-1">
311-
or{" "}
312-
<button
313-
onClick={handleReset}
314-
className="text-base text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground underline cursor-pointer bg-transparent border-none p-0">
315-
{t("cloud:startOver")}
316-
</button>
317-
</p>
318-
</div>
319-
)}
320-
</div>
321-
</>
322-
)}
323-
{cloudApiUrl && cloudApiUrl !== PRODUCTION_ROO_CODE_API_URL && (
324-
<div className="ml-8 mt-6 flex justify-start">
325-
<div className="inline-flex items-center gap-2 text-xs">
326-
<TriangleAlert className="size-4 text-vscode-descriptionForeground" />
327-
<span className="text-vscode-foreground/75">{t("cloud:cloudUrlPillLabel")}: </span>
328-
<button
329-
onClick={handleOpenCloudUrl}
330-
className="text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground underline cursor-pointer bg-transparent border-none p-0">
331-
{cloudApiUrl}
332-
</button>
298+
{showManualEntry && (
299+
// Manual URL entry form
300+
<div className="space-y-2 max-w-72">
301+
<p className="text-base text-vscode-descriptionForeground">
302+
{t("cloud:pasteCallbackUrl")}
303+
</p>
304+
<VSCodeTextField
305+
ref={manualUrlInputRef as any}
306+
value={manualUrl}
307+
onChange={handleManualUrlChange}
308+
onKeyDown={handleKeyDown}
309+
placeholder="vscode://RooVeterinaryInc.roo-cline/auth/clerk/callback?state=..."
310+
className="w-full"
311+
/>
312+
<p className="mt-1">
313+
or{" "}
314+
<button
315+
onClick={handleReset}
316+
className="text-base text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground underline cursor-pointer bg-transparent border-none p-0">
317+
{t("cloud:startOver")}
318+
</button>
319+
</p>
320+
</div>
321+
)}
322+
</div>
323+
</>
324+
)}
325+
{cloudApiUrl && cloudApiUrl !== PRODUCTION_ROO_CODE_API_URL && (
326+
<div className="ml-8 mt-6 flex justify-start">
327+
<div className="inline-flex items-center gap-2 text-xs">
328+
<TriangleAlert className="size-4 text-vscode-descriptionForeground" />
329+
<span className="text-vscode-foreground/75">{t("cloud:cloudUrlPillLabel")}: </span>
330+
<button
331+
onClick={handleOpenCloudUrl}
332+
className="text-vscode-textLink-foreground hover:text-vscode-textLink-activeForeground underline cursor-pointer bg-transparent border-none p-0">
333+
{cloudApiUrl}
334+
</button>
335+
</div>
333336
</div>
334-
</div>
335-
)}
336-
</div>
337+
)}
338+
</TabContent>
339+
</Tab>
337340
)
338341
}

0 commit comments

Comments
 (0)