From af90702515102c64fdbdab79ecc6ab46929088c6 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Mon, 4 May 2026 16:47:08 +0530
Subject: [PATCH 1/4] feat(composio): add optional identity fields to
ComposioConnection (#1153)
Adds optional accountEmail/workspace/username fields, non-breaking. Future
backend versions can populate these for friendly account display.
Co-authored-by: oxoxDev <164490987+oxoxDev@users.noreply.github.com>
---
app/src/lib/composio/types.ts | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/app/src/lib/composio/types.ts b/app/src/lib/composio/types.ts
index 30aa67fcde..f614a8634a 100644
--- a/app/src/lib/composio/types.ts
+++ b/app/src/lib/composio/types.ts
@@ -16,6 +16,11 @@ export interface ComposioConnection {
status: string;
/** ISO timestamp (backend passthrough). */
createdAt?: string;
+
+ /** Optional friendly identity fields populated by later backend versions. */
+ accountEmail?: string;
+ workspace?: string;
+ username?: string;
}
export interface ComposioConnectionsResponse {
From bd7a3d52605e319586331c5c21920963e6c4fb81 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Mon, 4 May 2026 16:47:08 +0530
Subject: [PATCH 2/4] refactor(composio): hide raw connection ID, derive
friendly label (#1153)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Replace raw '(id: ca_…)' span with a label derived from
accountEmail/workspace/username (priority order). Collapses cleanly when no
identity field is present.
Co-authored-by: oxoxDev <164490987+oxoxDev@users.noreply.github.com>
---
app/src/components/composio/ComposioConnectModal.tsx | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/app/src/components/composio/ComposioConnectModal.tsx b/app/src/components/composio/ComposioConnectModal.tsx
index 0c49201b8f..afc62f73a9 100644
--- a/app/src/components/composio/ComposioConnectModal.tsx
+++ b/app/src/components/composio/ComposioConnectModal.tsx
@@ -32,6 +32,10 @@ import { openUrl } from '../../utils/openUrl';
import type { ComposioToolkitMeta } from './toolkitMeta';
import TriggerToggles from './TriggerToggles';
+function deriveConnectionLabel(c: ComposioConnection): string | null {
+ return c.accountEmail ?? c.workspace ?? c.username ?? null;
+}
+
type Phase = 'idle' | 'authorizing' | 'waiting' | 'connected' | 'disconnecting' | 'error';
interface ComposioConnectModalProps {
@@ -392,9 +396,9 @@ export default function ComposioConnectModal({
{toolkit.name} is connected.
- {activeConnection && (
+ {activeConnection && deriveConnectionLabel(activeConnection) && (
- (id: {activeConnection.id})
+ ({deriveConnectionLabel(activeConnection)})
)}
From 6258a3850cee59d920b0784de163296c9860fd34 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Mon, 4 May 2026 16:47:08 +0530
Subject: [PATCH 3/4] test(composio): add ComposioConnectModal hide-id render
assertions (#1153)
Asserts no ca_ substring in DOM, friendly identity renders when populated,
priority order accountEmail > workspace > username.
Co-authored-by: oxoxDev <164490987+oxoxDev@users.noreply.github.com>
---
.../composio/ComposioConnectModal.test.tsx | 100 ++++++++++++++++++
1 file changed, 100 insertions(+)
create mode 100644 app/src/components/composio/ComposioConnectModal.test.tsx
diff --git a/app/src/components/composio/ComposioConnectModal.test.tsx b/app/src/components/composio/ComposioConnectModal.test.tsx
new file mode 100644
index 0000000000..969dc84728
--- /dev/null
+++ b/app/src/components/composio/ComposioConnectModal.test.tsx
@@ -0,0 +1,100 @@
+import { render, screen } from '@testing-library/react';
+import { describe, expect, it, vi } from 'vitest';
+
+import { type ComposioConnection } from '../../lib/composio/types';
+import ComposioConnectModal from './ComposioConnectModal';
+import { composioToolkitMeta } from './toolkitMeta';
+
+vi.mock('../../lib/composio/composioApi', () => ({
+ authorize: vi.fn(),
+ deleteConnection: vi.fn(),
+ getUserScopes: vi.fn(() => Promise.resolve({ read: true, write: true, admin: false })),
+ listConnections: vi.fn(),
+ setUserScopes: vi.fn(),
+}));
+
+vi.mock('../../utils/openUrl', () => ({ openUrl: vi.fn() }));
+
+// Mock TriggerToggles because it does its own API calls
+vi.mock('./TriggerToggles', () => ({ default: () => }));
+
+const mockToolkit = composioToolkitMeta('gmail');
+
+describe('', () => {
+ it('hides raw connection ID and "id:" label in connected phase', () => {
+ const connection: ComposioConnection = { id: 'ca_xyz', toolkit: 'gmail', status: 'ACTIVE' };
+
+ render(
+ {}} />
+ );
+
+ // Should be in 'connected' phase because connection.status is 'ACTIVE'
+ expect(screen.getByText(/Gmail is connected/)).toBeInTheDocument();
+ expect(screen.queryByText(/ca_xyz/)).not.toBeInTheDocument();
+ expect(screen.queryByText(/id:/)).not.toBeInTheDocument();
+ });
+
+ it('renders accountEmail when provided', () => {
+ const connection: ComposioConnection = {
+ id: 'ca_xyz',
+ toolkit: 'gmail',
+ status: 'ACTIVE',
+ accountEmail: 'foo@bar.com',
+ };
+
+ render(
+ {}} />
+ );
+
+ expect(screen.getByText('(foo@bar.com)')).toBeInTheDocument();
+ });
+
+ it('renders workspace when accountEmail is missing', () => {
+ const connection: ComposioConnection = {
+ id: 'ca_xyz',
+ toolkit: 'gmail',
+ status: 'ACTIVE',
+ workspace: 'Acme',
+ };
+
+ render(
+ {}} />
+ );
+
+ expect(screen.getByText('(Acme)')).toBeInTheDocument();
+ });
+
+ it('renders username when email and workspace are missing', () => {
+ const connection: ComposioConnection = {
+ id: 'ca_xyz',
+ toolkit: 'gmail',
+ status: 'ACTIVE',
+ username: 'oxox',
+ };
+
+ render(
+ {}} />
+ );
+
+ expect(screen.getByText('(oxox)')).toBeInTheDocument();
+ });
+
+ it('prioritizes accountEmail over workspace and username', () => {
+ const connection: ComposioConnection = {
+ id: 'ca_xyz',
+ toolkit: 'gmail',
+ status: 'ACTIVE',
+ accountEmail: 'foo@bar.com',
+ workspace: 'Acme',
+ username: 'oxox',
+ };
+
+ render(
+ {}} />
+ );
+
+ expect(screen.getByText('(foo@bar.com)')).toBeInTheDocument();
+ expect(screen.queryByText('(Acme)')).not.toBeInTheDocument();
+ expect(screen.queryByText('(oxox)')).not.toBeInTheDocument();
+ });
+});
From 7b7d2b736819cb13cc3576b15b007cd792d7f7de Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Mon, 4 May 2026 18:56:41 +0530
Subject: [PATCH 4/4] fix(composio): trim + skip blank identity values in
deriveConnectionLabel (#1153)
CodeRabbit feedback: ?? only catches null/undefined, so an empty-string
accountEmail blocked fallback to workspace/username. Iterate the
candidates, trim each, and return the first non-blank value.
Co-authored-by: oxoxDev <164490987+oxoxDev@users.noreply.github.com>
---
app/src/components/composio/ComposioConnectModal.tsx | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/app/src/components/composio/ComposioConnectModal.tsx b/app/src/components/composio/ComposioConnectModal.tsx
index afc62f73a9..846c5072b5 100644
--- a/app/src/components/composio/ComposioConnectModal.tsx
+++ b/app/src/components/composio/ComposioConnectModal.tsx
@@ -33,7 +33,11 @@ import type { ComposioToolkitMeta } from './toolkitMeta';
import TriggerToggles from './TriggerToggles';
function deriveConnectionLabel(c: ComposioConnection): string | null {
- return c.accountEmail ?? c.workspace ?? c.username ?? null;
+ for (const value of [c.accountEmail, c.workspace, c.username]) {
+ const normalized = value?.trim();
+ if (normalized) return normalized;
+ }
+ return null;
}
type Phase = 'idle' | 'authorizing' | 'waiting' | 'connected' | 'disconnecting' | 'error';