mirror of
https://github.com/cline/cline.git
synced 2026-10-24 02:02:27 +08:00
fix(desktop): build Account view links from the sidecar's Cline app and the loaded user
This commit is contained in:
@@ -24,7 +24,7 @@ beforeEach(() => {
|
||||
invoke.mockReset();
|
||||
openExternalUrl.mockReset();
|
||||
useAccount.mockReturnValue({
|
||||
privacySettingsUrl: undefined,
|
||||
clineAppBaseUrl: undefined,
|
||||
refreshAccount: vi.fn(),
|
||||
});
|
||||
container = document.createElement("div");
|
||||
@@ -243,8 +243,11 @@ describe("AccountView signed-out state", () => {
|
||||
});
|
||||
|
||||
describe("AccountView privacy settings", () => {
|
||||
async function renderSignedInWithPrivacyLink(privacySettingsUrl?: string) {
|
||||
useAccount.mockReturnValue({ privacySettingsUrl, refreshAccount: vi.fn() });
|
||||
async function renderSignedInWithPrivacyLink(dataPrivacyPath?: string) {
|
||||
useAccount.mockReturnValue({
|
||||
clineAppBaseUrl: "https://staging-app.cline.bot",
|
||||
refreshAccount: vi.fn(),
|
||||
});
|
||||
invoke.mockImplementation(
|
||||
async (_command: string, args?: Record<string, unknown>) => {
|
||||
switch (args?.operation) {
|
||||
@@ -256,6 +259,7 @@ describe("AccountView privacy settings", () => {
|
||||
createdAt: "2024-01-01T00:00:00Z",
|
||||
updatedAt: "2024-01-01T00:00:00Z",
|
||||
organizations: [],
|
||||
dataPrivacyPath,
|
||||
};
|
||||
case "fetchBalance":
|
||||
return { balance: 5_000_000 };
|
||||
@@ -274,6 +278,11 @@ describe("AccountView privacy settings", () => {
|
||||
});
|
||||
}
|
||||
|
||||
const dashboardButton = () =>
|
||||
container.querySelector<HTMLButtonElement>(
|
||||
'button[title="Open dashboard"]',
|
||||
);
|
||||
|
||||
const privacySettingsButton = () =>
|
||||
container.querySelector<HTMLButtonElement>(
|
||||
'button[title="Privacy settings"]',
|
||||
@@ -282,21 +291,23 @@ describe("AccountView privacy settings", () => {
|
||||
it("hides the action when there is no privacy settings link", async () => {
|
||||
await renderSignedInWithPrivacyLink(undefined);
|
||||
|
||||
expect(
|
||||
container.querySelector('button[title="Open dashboard"]'),
|
||||
).not.toBeNull();
|
||||
expect(dashboardButton()).not.toBeNull();
|
||||
expect(privacySettingsButton()).toBeNull();
|
||||
});
|
||||
|
||||
it("opens the privacy settings link from the account context", async () => {
|
||||
await renderSignedInWithPrivacyLink(
|
||||
"https://staging-app.cline.bot/dashboard/account?tab=privacy&client=desktop",
|
||||
);
|
||||
it("opens privacy settings and the dashboard on the sidecar's Cline app", async () => {
|
||||
await renderSignedInWithPrivacyLink("/dashboard/account?tab=privacy");
|
||||
|
||||
await act(async () => privacySettingsButton()?.click());
|
||||
await act(async () => dashboardButton()?.click());
|
||||
|
||||
expect(openExternalUrl).toHaveBeenCalledWith(
|
||||
expect(openExternalUrl).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
"https://staging-app.cline.bot/dashboard/account?tab=privacy&client=desktop",
|
||||
);
|
||||
expect(openExternalUrl).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
"https://staging-app.cline.bot/dashboard",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import type {
|
||||
ClineAccountUsageTransaction,
|
||||
ClineAccountUser,
|
||||
} from "@cline/core";
|
||||
import { getClinePrivacySettingsUrl } from "@cline/shared/browser";
|
||||
import {
|
||||
AlertCircle,
|
||||
Building,
|
||||
@@ -165,10 +166,20 @@ export function AccountView() {
|
||||
const [activeTab, setActiveTab] = useState<"overview" | "usage" | "billing">(
|
||||
"overview",
|
||||
);
|
||||
const { privacySettingsUrl, refreshAccount } = useAccount();
|
||||
const { clineAppBaseUrl, refreshAccount } = useAccount();
|
||||
|
||||
// Overview data
|
||||
const [user, setUser] = useState<ClineAccountUser | null>(null);
|
||||
const dashboardUrl = clineAppBaseUrl
|
||||
? `${clineAppBaseUrl}/dashboard`
|
||||
: DASHBOARD_URL;
|
||||
const privacySettingsUrl = clineAppBaseUrl
|
||||
? getClinePrivacySettingsUrl(
|
||||
user?.dataPrivacyPath,
|
||||
clineAppBaseUrl,
|
||||
"desktop",
|
||||
)
|
||||
: undefined;
|
||||
const [balance, setBalance] = useState<ClineAccountBalance | null>(null);
|
||||
const [organizationBalance, setOrganizationBalance] =
|
||||
useState<ClineAccountOrganizationBalance | null>(null);
|
||||
@@ -663,7 +674,7 @@ export function AccountView() {
|
||||
<button
|
||||
type="button"
|
||||
title="Open dashboard"
|
||||
onClick={() => void openExternalUrl(DASHBOARD_URL)}
|
||||
onClick={() => void openExternalUrl(dashboardUrl)}
|
||||
className="rounded-md p-1.5 text-muted-foreground hover:bg-surface-hover hover:text-foreground"
|
||||
>
|
||||
<ExternalLink className="h-4 w-4" />
|
||||
|
||||
@@ -27,6 +27,7 @@ type AccountContextValue = {
|
||||
accountReady: boolean;
|
||||
organizations: ClineAccountOrganization[];
|
||||
activeOrganization: ClineAccountOrganization | null;
|
||||
clineAppBaseUrl: string | undefined;
|
||||
privacySettingsUrl: string | undefined;
|
||||
refreshAccount: () => Promise<void>;
|
||||
};
|
||||
@@ -36,6 +37,7 @@ const AccountContext = createContext<AccountContextValue>({
|
||||
accountReady: false,
|
||||
organizations: [],
|
||||
activeOrganization: null,
|
||||
clineAppBaseUrl: undefined,
|
||||
privacySettingsUrl: undefined,
|
||||
refreshAccount: async () => undefined,
|
||||
});
|
||||
@@ -161,6 +163,7 @@ export function AccountProvider({ children }: { children: React.ReactNode }) {
|
||||
organizations,
|
||||
activeOrganization:
|
||||
organizations.find((organization) => organization.active) ?? null,
|
||||
clineAppBaseUrl,
|
||||
privacySettingsUrl: clineAppBaseUrl
|
||||
? getClinePrivacySettingsUrl(
|
||||
user?.dataPrivacyPath,
|
||||
|
||||
Reference in New Issue
Block a user