@deck-ui/connections 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@deck-ui/connections",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "main": "src/index.ts",
6
+ "types": "src/index.ts",
7
+ "files": ["src"],
8
+ "peerDependencies": {
9
+ "react": "^19.0.0",
10
+ "react-dom": "^19.0.0",
11
+ "@deck-ui/core": "^0.1.0"
12
+ },
13
+ "dependencies": {
14
+ "lucide-react": "^0.577.0"
15
+ },
16
+ "scripts": {
17
+ "typecheck": "tsc --noEmit"
18
+ }
19
+ }
@@ -0,0 +1,47 @@
1
+ import { Check } from "lucide-react";
2
+ import { useState } from "react";
3
+ import type { Connection } from "./types";
4
+
5
+ interface ConnectionRowProps {
6
+ connection: Connection;
7
+ }
8
+
9
+ export function ConnectionRow({ connection }: ConnectionRowProps) {
10
+ const [imgError, setImgError] = useState(false);
11
+ const initial = connection.display_name.charAt(0).toUpperCase();
12
+
13
+ return (
14
+ <div className="flex items-center gap-3.5 px-1 py-3">
15
+ {/* App icon */}
16
+ {!imgError ? (
17
+ <img
18
+ src={connection.logo_url}
19
+ alt={connection.display_name}
20
+ className="size-10 rounded-[10px] object-contain shrink-0"
21
+ onError={() => setImgError(true)}
22
+ />
23
+ ) : (
24
+ <div className="size-10 rounded-[10px] bg-[#e8e8e8] flex items-center justify-center shrink-0">
25
+ <span className="text-sm font-semibold text-[#5d5d5d]">
26
+ {initial}
27
+ </span>
28
+ </div>
29
+ )}
30
+
31
+ {/* Text */}
32
+ <div className="flex-1 min-w-0">
33
+ <p className="text-[13px] font-medium text-[#0d0d0d] truncate">
34
+ {connection.display_name}
35
+ </p>
36
+ <p className="text-[12px] text-[#8e8e8e] truncate">
37
+ {connection.email ?? connection.description}
38
+ </p>
39
+ </div>
40
+
41
+ {/* Connected indicator */}
42
+ <div className="size-5 rounded-full bg-emerald-50 flex items-center justify-center shrink-0">
43
+ <Check className="size-3 text-emerald-600" strokeWidth={2.5} />
44
+ </div>
45
+ </div>
46
+ );
47
+ }
@@ -0,0 +1,170 @@
1
+ import { ExternalLink, Loader2, RefreshCw } from "lucide-react";
2
+ import { ConnectionRow } from "./connection-row";
3
+ import type { Connection, ConnectionsResult } from "./types";
4
+
5
+ export interface ConnectionsViewProps {
6
+ result: ConnectionsResult | null;
7
+ loading: boolean;
8
+ onRetry: () => void;
9
+ onManage: () => void;
10
+ }
11
+
12
+ export function ConnectionsView({
13
+ result,
14
+ loading,
15
+ onRetry,
16
+ onManage,
17
+ }: ConnectionsViewProps) {
18
+ const items: Connection[] =
19
+ result?.status === "ok" ? result.connections : [];
20
+
21
+ return (
22
+ <div className="flex-1 flex flex-col min-h-0 overflow-auto">
23
+ <div className="max-w-3xl mx-auto w-full px-6 py-8">
24
+ {/* Header -- only when there are connections */}
25
+ {!loading && items.length > 0 && (
26
+ <div className="flex items-start justify-between mb-6">
27
+ <div>
28
+ <h1 className="text-xl font-semibold text-[#0d0d0d] tracking-tight">
29
+ Connected apps
30
+ </h1>
31
+ <p className="text-[13px] text-[#8e8e8e] mt-1">
32
+ Services Houston can use across all your projects
33
+ </p>
34
+ </div>
35
+ <button
36
+ onClick={onManage}
37
+ className="inline-flex items-center gap-1.5 h-8 px-4 rounded-full bg-[#0d0d0d] text-white text-xs font-medium hover:bg-[#424242] transition-colors duration-200 shrink-0"
38
+ >
39
+ Manage connections
40
+ <ExternalLink className="size-3" />
41
+ </button>
42
+ </div>
43
+ )}
44
+
45
+ {/* Loading */}
46
+ {loading && (
47
+ <div className="flex flex-col items-center justify-center py-24 gap-3">
48
+ <Loader2 className="size-5 text-[#b4b4b4] animate-spin" />
49
+ <p className="text-[13px] text-[#8e8e8e]">
50
+ Checking your connections...
51
+ </p>
52
+ </div>
53
+ )}
54
+
55
+ {/* Not configured */}
56
+ {!loading && result?.status === "not_configured" && (
57
+ <div className="flex flex-col items-center justify-center py-24 gap-4">
58
+ <div className="space-y-2 text-center max-w-md">
59
+ <h1 className="text-2xl font-semibold text-foreground tracking-tight">
60
+ Connect your apps
61
+ </h1>
62
+ <p className="text-sm text-[#5d5d5d]">
63
+ Set up Composio so Houston can use Gmail, Slack, Google Drive,
64
+ and 100+ other services on your behalf.
65
+ </p>
66
+ </div>
67
+ <button
68
+ onClick={onManage}
69
+ className="inline-flex items-center gap-1.5 h-9 px-4 rounded-full bg-[#0d0d0d] text-white text-sm font-medium hover:bg-[#424242] transition-colors duration-200"
70
+ >
71
+ Set up connections
72
+ <ExternalLink className="size-3.5" />
73
+ </button>
74
+ </div>
75
+ )}
76
+
77
+ {/* Needs auth */}
78
+ {!loading && result?.status === "needs_auth" && (
79
+ <div className="flex flex-col items-center justify-center py-24 gap-4">
80
+ <div className="space-y-2 text-center max-w-md">
81
+ <h1 className="text-2xl font-semibold text-foreground tracking-tight">
82
+ Composio needs authentication
83
+ </h1>
84
+ <p className="text-sm text-[#5d5d5d]">
85
+ Open Claude Code in your terminal and type{" "}
86
+ <code className="px-1.5 py-0.5 bg-[#f4f4f4] rounded text-[13px]">
87
+ /mcp
88
+ </code>{" "}
89
+ to complete the OAuth setup for Composio.
90
+ </p>
91
+ </div>
92
+ <button
93
+ onClick={onRetry}
94
+ className="inline-flex items-center gap-1.5 h-9 px-4 rounded-full bg-[#0d0d0d] text-white text-sm font-medium hover:bg-[#424242] transition-colors duration-200"
95
+ >
96
+ <RefreshCw className="size-3.5" />
97
+ Retry
98
+ </button>
99
+ </div>
100
+ )}
101
+
102
+ {/* Error */}
103
+ {!loading && result?.status === "error" && (
104
+ <div className="flex flex-col items-center justify-center py-24 gap-4">
105
+ <div className="space-y-2 text-center max-w-md">
106
+ <h1 className="text-2xl font-semibold text-foreground tracking-tight">
107
+ Couldn't load connections
108
+ </h1>
109
+ <p className="text-sm text-[#5d5d5d]">
110
+ Composio is set up but we couldn't fetch your connections. This
111
+ can happen if your authentication expired or the service is
112
+ temporarily unavailable.
113
+ </p>
114
+ <p className="text-xs text-[#8e8e8e] font-mono mt-2">
115
+ {result.message}
116
+ </p>
117
+ </div>
118
+ <div className="flex items-center gap-2">
119
+ <button
120
+ onClick={onRetry}
121
+ className="inline-flex items-center gap-1.5 h-9 px-4 rounded-full bg-[#0d0d0d] text-white text-sm font-medium hover:bg-[#424242] transition-colors duration-200"
122
+ >
123
+ <RefreshCw className="size-3.5" />
124
+ Retry
125
+ </button>
126
+ <button
127
+ onClick={onManage}
128
+ className="inline-flex items-center gap-1.5 h-9 px-4 rounded-full border border-black/15 bg-white text-[#0d0d0d] text-sm font-medium hover:bg-gray-50 transition-colors duration-200"
129
+ >
130
+ Reconnect
131
+ <ExternalLink className="size-3.5" />
132
+ </button>
133
+ </div>
134
+ </div>
135
+ )}
136
+
137
+ {/* Empty -- configured, no active connections */}
138
+ {!loading && result?.status === "ok" && items.length === 0 && (
139
+ <div className="flex flex-col items-center justify-center py-24 gap-4">
140
+ <div className="space-y-2 text-center max-w-md">
141
+ <h1 className="text-2xl font-semibold text-foreground tracking-tight">
142
+ No apps connected yet
143
+ </h1>
144
+ <p className="text-sm text-[#5d5d5d]">
145
+ Connect Gmail, Slack, Google Drive, and 100+ other services so
146
+ Houston can use them across all your projects.
147
+ </p>
148
+ </div>
149
+ <button
150
+ onClick={onManage}
151
+ className="inline-flex items-center gap-1.5 h-9 px-4 rounded-full bg-[#0d0d0d] text-white text-sm font-medium hover:bg-[#424242] transition-colors duration-200"
152
+ >
153
+ Add a connection
154
+ <ExternalLink className="size-3.5" />
155
+ </button>
156
+ </div>
157
+ )}
158
+
159
+ {/* Connection grid */}
160
+ {!loading && items.length > 0 && (
161
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-x-6">
162
+ {items.map((conn) => (
163
+ <ConnectionRow key={conn.toolkit} connection={conn} />
164
+ ))}
165
+ </div>
166
+ )}
167
+ </div>
168
+ </div>
169
+ );
170
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export { ConnectionsView } from "./connections-view";
2
+ export type { ConnectionsViewProps } from "./connections-view";
3
+
4
+ export { ConnectionRow } from "./connection-row";
5
+
6
+ export type { Connection, ConnectionsResult } from "./types";
package/src/styles.css ADDED
@@ -0,0 +1,2 @@
1
+ /* @deck-ui/connections — Tell Tailwind to scan this package's components */
2
+ @source ".";
package/src/types.ts ADDED
@@ -0,0 +1,14 @@
1
+ export interface Connection {
2
+ toolkit: string;
3
+ display_name: string;
4
+ description: string;
5
+ email: string | null;
6
+ logo_url: string;
7
+ connected_at: string | null;
8
+ }
9
+
10
+ export type ConnectionsResult =
11
+ | { status: "not_configured" }
12
+ | { status: "needs_auth" }
13
+ | { status: "error"; message: string }
14
+ | { status: "ok"; connections: Connection[] };