@chaaskit/client 0.1.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/dist/favicon.svg +11 -0
- package/dist/index.html +17 -0
- package/dist/lib/LoadingSkeletons-IcIC2JPq.js +132 -0
- package/dist/lib/LoadingSkeletons-IcIC2JPq.js.map +1 -0
- package/dist/lib/ServerThemeProvider-DNF0LAyk.js +42 -0
- package/dist/lib/ServerThemeProvider-DNF0LAyk.js.map +1 -0
- package/dist/lib/extensions.js +10 -0
- package/dist/lib/extensions.js.map +1 -0
- package/dist/lib/favicon.svg +11 -0
- package/dist/lib/index.js +74126 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/logo.svg +12 -0
- package/dist/lib/routes/AcceptInviteRoute.js +19 -0
- package/dist/lib/routes/AcceptInviteRoute.js.map +1 -0
- package/dist/lib/routes/AdminDashboardRoute.js +19 -0
- package/dist/lib/routes/AdminDashboardRoute.js.map +1 -0
- package/dist/lib/routes/AdminTeamRoute.js +19 -0
- package/dist/lib/routes/AdminTeamRoute.js.map +1 -0
- package/dist/lib/routes/AdminTeamsRoute.js +19 -0
- package/dist/lib/routes/AdminTeamsRoute.js.map +1 -0
- package/dist/lib/routes/AdminUsersRoute.js +19 -0
- package/dist/lib/routes/AdminUsersRoute.js.map +1 -0
- package/dist/lib/routes/ApiKeysRoute.js +19 -0
- package/dist/lib/routes/ApiKeysRoute.js.map +1 -0
- package/dist/lib/routes/AutomationsRoute.js +19 -0
- package/dist/lib/routes/AutomationsRoute.js.map +1 -0
- package/dist/lib/routes/ChatRoute.js +19 -0
- package/dist/lib/routes/ChatRoute.js.map +1 -0
- package/dist/lib/routes/DocumentsRoute.js +19 -0
- package/dist/lib/routes/DocumentsRoute.js.map +1 -0
- package/dist/lib/routes/OAuthConsentRoute.js +19 -0
- package/dist/lib/routes/OAuthConsentRoute.js.map +1 -0
- package/dist/lib/routes/PricingRoute.js +19 -0
- package/dist/lib/routes/PricingRoute.js.map +1 -0
- package/dist/lib/routes/PrivacyRoute.js +19 -0
- package/dist/lib/routes/PrivacyRoute.js.map +1 -0
- package/dist/lib/routes/TeamSettingsRoute.js +19 -0
- package/dist/lib/routes/TeamSettingsRoute.js.map +1 -0
- package/dist/lib/routes/TermsRoute.js +19 -0
- package/dist/lib/routes/TermsRoute.js.map +1 -0
- package/dist/lib/routes/VerifyEmailRoute.js +19 -0
- package/dist/lib/routes/VerifyEmailRoute.js.map +1 -0
- package/dist/lib/routes.js +79 -0
- package/dist/lib/routes.js.map +1 -0
- package/dist/lib/ssr-utils.js +29 -0
- package/dist/lib/ssr-utils.js.map +1 -0
- package/dist/lib/ssr.js +60 -0
- package/dist/lib/ssr.js.map +1 -0
- package/dist/lib/styles.css +2410 -0
- package/dist/lib/useExtensions-B5nX_8XD.js +155 -0
- package/dist/lib/useExtensions-B5nX_8XD.js.map +1 -0
- package/dist/logo.svg +12 -0
- package/package.json +84 -0
- package/src/components/AgentSelector.tsx +90 -0
- package/src/components/BranchModal.tsx +129 -0
- package/src/components/ClientOnly.tsx +27 -0
- package/src/components/ExportMenu.tsx +122 -0
- package/src/components/LoadingSkeletons.tsx +110 -0
- package/src/components/MCPCredentialsSection.tsx +309 -0
- package/src/components/MentionChip.tsx +149 -0
- package/src/components/MentionDropdown.tsx +175 -0
- package/src/components/MentionInput.tsx +293 -0
- package/src/components/MessageItem.tsx +300 -0
- package/src/components/MessageList.tsx +159 -0
- package/src/components/OAuthAppsSection.tsx +124 -0
- package/src/components/ProjectFolder.tsx +141 -0
- package/src/components/ProjectModal.tsx +296 -0
- package/src/components/SSRMessageList.tsx +153 -0
- package/src/components/SearchModal.tsx +173 -0
- package/src/components/SettingsModal.tsx +412 -0
- package/src/components/ShareModal.tsx +280 -0
- package/src/components/Sidebar.tsx +491 -0
- package/src/components/TeamSwitcher.tsx +273 -0
- package/src/components/ToolCallDisplay.tsx +473 -0
- package/src/components/ToolConfirmationModal.tsx +130 -0
- package/src/components/UsageChart.tsx +177 -0
- package/src/components/content/CodeBlock.tsx +69 -0
- package/src/components/content/MarkdownRenderer.tsx +64 -0
- package/src/components/content/SSRMarkdownRenderer.tsx +158 -0
- package/src/contexts/AuthContext.tsx +119 -0
- package/src/contexts/ConfigContext.tsx +214 -0
- package/src/contexts/ProjectContext.tsx +167 -0
- package/src/contexts/ServerConfigProvider.tsx +41 -0
- package/src/contexts/ServerThemeProvider.tsx +47 -0
- package/src/contexts/TeamContext.tsx +255 -0
- package/src/contexts/ThemeContext.tsx +113 -0
- package/src/extensions/index.ts +15 -0
- package/src/extensions/registry.ts +187 -0
- package/src/extensions/useExtensions.ts +52 -0
- package/src/hooks/useAppPath.ts +34 -0
- package/src/hooks/useBasePath.ts +13 -0
- package/src/hooks/useKeyboardShortcuts.ts +50 -0
- package/src/hooks/useMentionSearch.ts +106 -0
- package/src/index.tsx +116 -0
- package/src/layouts/MainLayout.tsx +98 -0
- package/src/pages/AcceptInvitePage.tsx +175 -0
- package/src/pages/AdminDashboardPage.tsx +362 -0
- package/src/pages/AdminTeamPage.tsx +304 -0
- package/src/pages/AdminTeamsPage.tsx +242 -0
- package/src/pages/AdminUsersPage.tsx +385 -0
- package/src/pages/ApiKeysPage.tsx +449 -0
- package/src/pages/ChatPage.tsx +310 -0
- package/src/pages/DocumentsPage.tsx +577 -0
- package/src/pages/LoginPage.tsx +232 -0
- package/src/pages/OAuthConsentPage.tsx +234 -0
- package/src/pages/PricingPage.tsx +314 -0
- package/src/pages/PrivacyPage.tsx +65 -0
- package/src/pages/RegisterPage.tsx +153 -0
- package/src/pages/ScheduledPromptsPage.tsx +702 -0
- package/src/pages/SharedThreadPage.tsx +116 -0
- package/src/pages/TeamSettingsPage.tsx +1085 -0
- package/src/pages/TermsPage.tsx +82 -0
- package/src/pages/VerifyEmailPage.tsx +202 -0
- package/src/routes/AcceptInviteRoute.tsx +24 -0
- package/src/routes/AdminDashboardRoute.tsx +24 -0
- package/src/routes/AdminTeamRoute.tsx +24 -0
- package/src/routes/AdminTeamsRoute.tsx +24 -0
- package/src/routes/AdminUsersRoute.tsx +24 -0
- package/src/routes/ApiKeysRoute.tsx +24 -0
- package/src/routes/AutomationsRoute.tsx +24 -0
- package/src/routes/ChatRoute.tsx +28 -0
- package/src/routes/DocumentsRoute.tsx +24 -0
- package/src/routes/OAuthConsentRoute.tsx +24 -0
- package/src/routes/PricingRoute.tsx +24 -0
- package/src/routes/PrivacyRoute.tsx +24 -0
- package/src/routes/TeamSettingsRoute.tsx +24 -0
- package/src/routes/TermsRoute.tsx +24 -0
- package/src/routes/VerifyEmailRoute.tsx +24 -0
- package/src/routes/index.ts +57 -0
- package/src/ssr-utils.tsx +84 -0
- package/src/ssr.ts +123 -0
- package/src/stores/chatStore.ts +670 -0
- package/src/styles/index.css +254 -0
- package/src/utils/api.ts +78 -0
- package/src/vite-env.d.ts +13 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import { Share2, Copy, Check, Trash2, X, Link, Clock, Loader2 } from 'lucide-react';
|
|
4
|
+
import { useConfig } from '../contexts/ConfigContext';
|
|
5
|
+
|
|
6
|
+
interface ShareInfo {
|
|
7
|
+
shareId: string;
|
|
8
|
+
url: string;
|
|
9
|
+
expiresAt: string | null;
|
|
10
|
+
createdAt: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ShareModalProps {
|
|
14
|
+
threadId: string;
|
|
15
|
+
threadTitle: string;
|
|
16
|
+
isOpen: boolean;
|
|
17
|
+
onClose: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function ShareModal({ threadId, threadTitle, isOpen, onClose }: ShareModalProps) {
|
|
21
|
+
const config = useConfig();
|
|
22
|
+
const [shares, setShares] = useState<ShareInfo[]>([]);
|
|
23
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
24
|
+
const [isCreating, setIsCreating] = useState(false);
|
|
25
|
+
const [copiedId, setCopiedId] = useState<string | null>(null);
|
|
26
|
+
const [expiresIn, setExpiresIn] = useState<string>('never');
|
|
27
|
+
const [error, setError] = useState<string | null>(null);
|
|
28
|
+
|
|
29
|
+
const expirationOptions = config.sharing?.expirationOptions || ['1h', '24h', '7d', '30d', 'never'];
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (isOpen) {
|
|
33
|
+
loadShares();
|
|
34
|
+
}
|
|
35
|
+
}, [isOpen, threadId]);
|
|
36
|
+
|
|
37
|
+
async function loadShares() {
|
|
38
|
+
setIsLoading(true);
|
|
39
|
+
setError(null);
|
|
40
|
+
try {
|
|
41
|
+
const response = await fetch(`/api/share/thread/${threadId}`, {
|
|
42
|
+
credentials: 'include',
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error('Failed to load shares');
|
|
46
|
+
}
|
|
47
|
+
const data = await response.json();
|
|
48
|
+
setShares(data.shares);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
setError('Failed to load existing shares');
|
|
51
|
+
console.error(err);
|
|
52
|
+
} finally {
|
|
53
|
+
setIsLoading(false);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function handleCreateShare() {
|
|
58
|
+
setIsCreating(true);
|
|
59
|
+
setError(null);
|
|
60
|
+
try {
|
|
61
|
+
const response = await fetch(`/api/share/${threadId}`, {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: { 'Content-Type': 'application/json' },
|
|
64
|
+
credentials: 'include',
|
|
65
|
+
body: JSON.stringify({ expiresIn }),
|
|
66
|
+
});
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
const data = await response.json();
|
|
69
|
+
throw new Error(data.error || 'Failed to create share link');
|
|
70
|
+
}
|
|
71
|
+
const data = await response.json();
|
|
72
|
+
setShares((prev) => [
|
|
73
|
+
{
|
|
74
|
+
shareId: data.shareId,
|
|
75
|
+
url: data.url,
|
|
76
|
+
expiresAt: data.expiresAt,
|
|
77
|
+
createdAt: new Date().toISOString(),
|
|
78
|
+
},
|
|
79
|
+
...prev,
|
|
80
|
+
]);
|
|
81
|
+
// Auto-copy the new link
|
|
82
|
+
await copyToClipboard(data.url, data.shareId);
|
|
83
|
+
} catch (err) {
|
|
84
|
+
setError(err instanceof Error ? err.message : 'Failed to create share link');
|
|
85
|
+
} finally {
|
|
86
|
+
setIsCreating(false);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function handleDeleteShare(shareId: string) {
|
|
91
|
+
try {
|
|
92
|
+
const response = await fetch(`/api/share/${shareId}`, {
|
|
93
|
+
method: 'DELETE',
|
|
94
|
+
credentials: 'include',
|
|
95
|
+
});
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
throw new Error('Failed to delete share');
|
|
98
|
+
}
|
|
99
|
+
setShares((prev) => prev.filter((s) => s.shareId !== shareId));
|
|
100
|
+
} catch (err) {
|
|
101
|
+
setError('Failed to delete share link');
|
|
102
|
+
console.error(err);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function copyToClipboard(url: string, shareId: string) {
|
|
107
|
+
try {
|
|
108
|
+
await navigator.clipboard.writeText(url);
|
|
109
|
+
setCopiedId(shareId);
|
|
110
|
+
setTimeout(() => setCopiedId(null), 2000);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.error('Failed to copy:', err);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function formatExpiration(expiresAt: string | null): string {
|
|
117
|
+
if (!expiresAt) return 'Never expires';
|
|
118
|
+
const date = new Date(expiresAt);
|
|
119
|
+
const now = new Date();
|
|
120
|
+
const diff = date.getTime() - now.getTime();
|
|
121
|
+
|
|
122
|
+
if (diff < 0) return 'Expired';
|
|
123
|
+
if (diff < 60 * 60 * 1000) {
|
|
124
|
+
const mins = Math.round(diff / (60 * 1000));
|
|
125
|
+
return `Expires in ${mins} min${mins !== 1 ? 's' : ''}`;
|
|
126
|
+
}
|
|
127
|
+
if (diff < 24 * 60 * 60 * 1000) {
|
|
128
|
+
const hours = Math.round(diff / (60 * 60 * 1000));
|
|
129
|
+
return `Expires in ${hours} hour${hours !== 1 ? 's' : ''}`;
|
|
130
|
+
}
|
|
131
|
+
const days = Math.round(diff / (24 * 60 * 60 * 1000));
|
|
132
|
+
return `Expires in ${days} day${days !== 1 ? 's' : ''}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function formatExpirationLabel(option: string): string {
|
|
136
|
+
const labels: Record<string, string> = {
|
|
137
|
+
'1h': '1 hour',
|
|
138
|
+
'24h': '24 hours',
|
|
139
|
+
'7d': '7 days',
|
|
140
|
+
'30d': '30 days',
|
|
141
|
+
'never': 'Never',
|
|
142
|
+
};
|
|
143
|
+
return labels[option] || option;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!isOpen) return null;
|
|
147
|
+
|
|
148
|
+
const sharingEnabled = config.sharing?.enabled;
|
|
149
|
+
const scope = config.sharing?.scope || 'public';
|
|
150
|
+
|
|
151
|
+
return createPortal(
|
|
152
|
+
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
|
153
|
+
{/* Backdrop */}
|
|
154
|
+
<div className="absolute inset-0 bg-black/50" onClick={onClose} />
|
|
155
|
+
|
|
156
|
+
{/* Modal */}
|
|
157
|
+
<div className="relative w-full max-w-md rounded-xl bg-background p-4 shadow-2xl">
|
|
158
|
+
<div className="mb-4 flex items-center justify-between">
|
|
159
|
+
<div className="flex items-center gap-2">
|
|
160
|
+
<Share2 size={20} className="text-primary" />
|
|
161
|
+
<h3 className="text-lg font-semibold text-text-primary">Share Conversation</h3>
|
|
162
|
+
</div>
|
|
163
|
+
<button
|
|
164
|
+
onClick={onClose}
|
|
165
|
+
className="rounded p-1 text-text-muted hover:bg-background-secondary hover:text-text-primary"
|
|
166
|
+
>
|
|
167
|
+
<X size={20} />
|
|
168
|
+
</button>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{!sharingEnabled ? (
|
|
172
|
+
<p className="text-sm text-text-secondary">
|
|
173
|
+
Sharing is currently disabled.
|
|
174
|
+
</p>
|
|
175
|
+
) : (
|
|
176
|
+
<>
|
|
177
|
+
<p className="mb-4 text-sm text-text-secondary">
|
|
178
|
+
{scope === 'team'
|
|
179
|
+
? 'Create a link to share this conversation with your team members.'
|
|
180
|
+
: 'Create a public link to share this conversation with anyone.'}
|
|
181
|
+
</p>
|
|
182
|
+
|
|
183
|
+
{/* Error */}
|
|
184
|
+
{error && (
|
|
185
|
+
<div className="mb-4 rounded-lg border border-error/30 bg-error/10 p-3 text-sm text-error">
|
|
186
|
+
{error}
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
189
|
+
|
|
190
|
+
{/* Create new share */}
|
|
191
|
+
<div className="mb-4 rounded-lg border border-border p-3">
|
|
192
|
+
<div className="mb-3 flex items-center gap-3">
|
|
193
|
+
<div className="flex-1">
|
|
194
|
+
<label className="mb-1 block text-xs font-medium text-text-secondary">
|
|
195
|
+
Link expires in
|
|
196
|
+
</label>
|
|
197
|
+
<select
|
|
198
|
+
value={expiresIn}
|
|
199
|
+
onChange={(e) => setExpiresIn(e.target.value)}
|
|
200
|
+
className="w-full rounded-md border border-input-border bg-input-background px-3 py-1.5 text-sm text-text-primary focus:border-primary focus:outline-none"
|
|
201
|
+
>
|
|
202
|
+
{expirationOptions.map((option) => (
|
|
203
|
+
<option key={option} value={option}>
|
|
204
|
+
{formatExpirationLabel(option)}
|
|
205
|
+
</option>
|
|
206
|
+
))}
|
|
207
|
+
</select>
|
|
208
|
+
</div>
|
|
209
|
+
<button
|
|
210
|
+
onClick={handleCreateShare}
|
|
211
|
+
disabled={isCreating}
|
|
212
|
+
className="mt-5 flex items-center gap-2 rounded-lg bg-primary px-4 py-1.5 text-sm font-medium text-white hover:bg-primary-hover disabled:opacity-50"
|
|
213
|
+
>
|
|
214
|
+
{isCreating ? (
|
|
215
|
+
<Loader2 size={16} className="animate-spin" />
|
|
216
|
+
) : (
|
|
217
|
+
<Link size={16} />
|
|
218
|
+
)}
|
|
219
|
+
Create Link
|
|
220
|
+
</button>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
|
|
224
|
+
{/* Existing shares */}
|
|
225
|
+
<div>
|
|
226
|
+
<h4 className="mb-2 text-sm font-medium text-text-primary">Active Links</h4>
|
|
227
|
+
{isLoading ? (
|
|
228
|
+
<div className="flex items-center justify-center py-4">
|
|
229
|
+
<Loader2 size={20} className="animate-spin text-text-muted" />
|
|
230
|
+
</div>
|
|
231
|
+
) : shares.length === 0 ? (
|
|
232
|
+
<p className="py-4 text-center text-sm text-text-muted">
|
|
233
|
+
No active share links
|
|
234
|
+
</p>
|
|
235
|
+
) : (
|
|
236
|
+
<div className="max-h-48 space-y-2 overflow-y-auto">
|
|
237
|
+
{shares.map((share) => (
|
|
238
|
+
<div
|
|
239
|
+
key={share.shareId}
|
|
240
|
+
className="flex items-center gap-2 rounded-lg border border-border p-2"
|
|
241
|
+
>
|
|
242
|
+
<div className="min-w-0 flex-1">
|
|
243
|
+
<p className="truncate text-xs font-mono text-text-secondary">
|
|
244
|
+
{share.url}
|
|
245
|
+
</p>
|
|
246
|
+
<p className="mt-0.5 flex items-center gap-1 text-xs text-text-muted">
|
|
247
|
+
<Clock size={10} />
|
|
248
|
+
{formatExpiration(share.expiresAt)}
|
|
249
|
+
</p>
|
|
250
|
+
</div>
|
|
251
|
+
<button
|
|
252
|
+
onClick={() => copyToClipboard(share.url, share.shareId)}
|
|
253
|
+
className="rounded p-1.5 text-text-muted hover:bg-background-secondary hover:text-text-primary"
|
|
254
|
+
title="Copy link"
|
|
255
|
+
>
|
|
256
|
+
{copiedId === share.shareId ? (
|
|
257
|
+
<Check size={16} className="text-success" />
|
|
258
|
+
) : (
|
|
259
|
+
<Copy size={16} />
|
|
260
|
+
)}
|
|
261
|
+
</button>
|
|
262
|
+
<button
|
|
263
|
+
onClick={() => handleDeleteShare(share.shareId)}
|
|
264
|
+
className="rounded p-1.5 text-text-muted hover:bg-error/10 hover:text-error"
|
|
265
|
+
title="Revoke link"
|
|
266
|
+
>
|
|
267
|
+
<Trash2 size={16} />
|
|
268
|
+
</button>
|
|
269
|
+
</div>
|
|
270
|
+
))}
|
|
271
|
+
</div>
|
|
272
|
+
)}
|
|
273
|
+
</div>
|
|
274
|
+
</>
|
|
275
|
+
)}
|
|
276
|
+
</div>
|
|
277
|
+
</div>,
|
|
278
|
+
document.body
|
|
279
|
+
);
|
|
280
|
+
}
|