mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-13 07:12:00 +01:00
feat(apps): confirm connections and cache MCP actions
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
e6a7728087
commit
84c2b30358
5 files changed
+153
-27
No files matched your search
@@ -25,6 +25,7 @@ const listUserDirectoryMock = vi.hoisted(() => vi.fn());
|
||||
const getSessionMock = vi.hoisted(() => vi.fn());
|
||||
const mockNavigate = vi.hoisted(() => vi.fn());
|
||||
const mockParams = vi.hoisted(() => ({ connectionId: "conn-1", tab: "setup" as string | undefined }));
|
||||
const mockSearchParams = vi.hoisted(() => ({ value: new URLSearchParams() }));
|
||||
const navigateComponentMock = vi.hoisted(() => vi.fn());
|
||||
const navigateTopLevelMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
@@ -80,7 +81,7 @@ vi.mock("@/lib/browserNavigation", () => ({
|
||||
vi.mock("@/lib/router", () => ({
|
||||
useParams: () => mockParams,
|
||||
useNavigate: () => mockNavigate,
|
||||
useSearchParams: () => [new URLSearchParams(), vi.fn()],
|
||||
useSearchParams: () => [mockSearchParams.value, vi.fn()],
|
||||
Navigate: ({ to, replace }: { to: string; replace?: boolean }) => {
|
||||
navigateComponentMock({ to, replace });
|
||||
return <div data-navigate-to={to} />;
|
||||
@@ -189,6 +190,7 @@ describe("AppDetail", () => {
|
||||
document.body.appendChild(container);
|
||||
mockParams.connectionId = "conn-1";
|
||||
mockParams.tab = "setup";
|
||||
mockSearchParams.value = new URLSearchParams();
|
||||
getConnectionMock.mockResolvedValue(connection());
|
||||
getConnectionInstallsMock.mockResolvedValue({ connectionId: "conn-1", installs: [] });
|
||||
listGalleryMock.mockResolvedValue({
|
||||
@@ -398,6 +400,20 @@ describe("AppDetail", () => {
|
||||
expect(container.querySelector(".animate-spin")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("confirms a successful connection on Test and clears the one-time URL flag", async () => {
|
||||
mockParams.tab = "test";
|
||||
mockSearchParams.value = new URLSearchParams("success=1");
|
||||
|
||||
await renderAppDetail();
|
||||
|
||||
expect(pushToastMock).toHaveBeenCalledWith({
|
||||
title: "GitHub connected",
|
||||
body: "The connection is ready. You can test an action below.",
|
||||
tone: "success",
|
||||
});
|
||||
expect(mockNavigate).toHaveBeenCalledWith("/apps/conn-1/test", { replace: true });
|
||||
});
|
||||
|
||||
it("hides secret URL parameters in setup technical details", async () => {
|
||||
mockParams.tab = "setup";
|
||||
getConnectionMock.mockResolvedValue(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { Check, Loader2, Pencil } from "lucide-react";
|
||||
import type {
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
humanizeConnectionDisplayName,
|
||||
isToolConnectionAttentionHealth as isAttentionHealthStatus,
|
||||
} from "@paperclipai/shared";
|
||||
import { Navigate, useParams, useNavigate } from "@/lib/router";
|
||||
import { Navigate, useParams, useNavigate, useSearchParams } from "@/lib/router";
|
||||
import { useCompany } from "@/context/CompanyContext";
|
||||
import { useBreadcrumbs } from "@/context/BreadcrumbContext";
|
||||
import { useToast } from "@/context/ToastContext";
|
||||
@@ -62,6 +62,7 @@ export { DangerZone, connectionAddress, connectionTransportLabel };
|
||||
export function AppDetail() {
|
||||
const { connectionId = "", tab } = useParams<{ connectionId: string; tab?: string }>();
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const queryClient = useQueryClient();
|
||||
const { pushToast } = useToast();
|
||||
const { selectedCompany, selectedCompanyId } = useCompany();
|
||||
@@ -138,6 +139,23 @@ export function AppDetail() {
|
||||
const appName = connection
|
||||
? connectionDisplayNameForOwner(connection, baseAppName, owner)
|
||||
: "App";
|
||||
const successNoticeShownFor = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
activeTab !== "test"
|
||||
|| searchParams.get("success") !== "1"
|
||||
|| !connection
|
||||
|| successNoticeShownFor.current === connection.id
|
||||
) return;
|
||||
successNoticeShownFor.current = connection.id;
|
||||
pushToast({
|
||||
title: `${appName} connected`,
|
||||
body: "The connection is ready. You can test an action below.",
|
||||
tone: "success",
|
||||
});
|
||||
navigate(appTabHref(connection.id, "test"), { replace: true });
|
||||
}, [activeTab, appName, connection, navigate, pushToast, searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeTab) return;
|
||||
|
||||
Reference in new issue
Block a user