@arbidocs/react 0.4.4 → 0.4.6
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/README.md +23 -0
- package/dist/artifacts/index.cjs +458 -0
- package/dist/artifacts/index.cjs.map +1 -0
- package/dist/artifacts/index.d.cts +276 -0
- package/dist/artifacts/index.d.ts +276 -0
- package/dist/artifacts/index.js +434 -0
- package/dist/artifacts/index.js.map +1 -0
- package/dist/artifacts/redline-core.cjs +20 -0
- package/dist/artifacts/redline-core.cjs.map +1 -0
- package/dist/artifacts/redline-core.d.cts +36 -0
- package/dist/artifacts/redline-core.d.ts +36 -0
- package/dist/artifacts/redline-core.js +3 -0
- package/dist/artifacts/redline-core.js.map +1 -0
- package/dist/{chunk-MIJRORQL.js → chunk-2ACHNDO6.js} +10 -304
- package/dist/chunk-2ACHNDO6.js.map +1 -0
- package/dist/chunk-CBJ3WOGD.cjs +317 -0
- package/dist/chunk-CBJ3WOGD.cjs.map +1 -0
- package/dist/{chunk-EJ2BMHYK.js → chunk-FSMIN5VX.js} +4 -3
- package/dist/chunk-FSMIN5VX.js.map +1 -0
- package/dist/{chunk-JKO3NR5L.js → chunk-HDCRPPBW.js} +5 -23
- package/dist/chunk-HDCRPPBW.js.map +1 -0
- package/dist/chunk-J4MX2W4H.js +26 -0
- package/dist/chunk-J4MX2W4H.js.map +1 -0
- package/dist/chunk-KWCHIAQ5.js +290 -0
- package/dist/chunk-KWCHIAQ5.js.map +1 -0
- package/dist/{chunk-6ALMBER7.js → chunk-N5SVBDLC.js} +4 -9
- package/dist/chunk-N5SVBDLC.js.map +1 -0
- package/dist/{chunk-RZQACYNQ.cjs → chunk-OBNTJEEO.cjs} +14 -20
- package/dist/chunk-OBNTJEEO.cjs.map +1 -0
- package/dist/chunk-OI55JRKT.cjs +334 -0
- package/dist/chunk-OI55JRKT.cjs.map +1 -0
- package/dist/{chunk-BXP6S34V.cjs → chunk-PGLV23SB.cjs} +13 -12
- package/dist/chunk-PGLV23SB.cjs.map +1 -0
- package/dist/chunk-RIHMIEXM.js +320 -0
- package/dist/chunk-RIHMIEXM.js.map +1 -0
- package/dist/chunk-RKWNX32A.js +299 -0
- package/dist/chunk-RKWNX32A.js.map +1 -0
- package/dist/chunk-S6A6FSG7.cjs +13 -0
- package/dist/chunk-S6A6FSG7.cjs.map +1 -0
- package/dist/chunk-SN5YV6FF.js +11 -0
- package/dist/chunk-SN5YV6FF.js.map +1 -0
- package/dist/{chunk-7IOCMCC5.cjs → chunk-TMPDW7J5.cjs} +3 -23
- package/dist/chunk-TMPDW7J5.cjs.map +1 -0
- package/dist/chunk-VJWAP2HJ.cjs +303 -0
- package/dist/chunk-VJWAP2HJ.cjs.map +1 -0
- package/dist/{chunk-ORKGCXG3.cjs → chunk-Z5YCRJY3.cjs} +125 -429
- package/dist/chunk-Z5YCRJY3.cjs.map +1 -0
- package/dist/chunk-ZMTLGO3K.cjs +29 -0
- package/dist/chunk-ZMTLGO3K.cjs.map +1 -0
- package/dist/index-CC6CvXEs.d.cts +1366 -0
- package/dist/index-CC6CvXEs.d.ts +1366 -0
- package/dist/index.cjs +1159 -722
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +588 -28
- package/dist/index.d.ts +588 -28
- package/dist/index.js +645 -310
- package/dist/index.js.map +1 -1
- package/dist/shell/index.cjs +8 -7
- package/dist/shell/index.js +3 -2
- package/dist/ui/index.cjs +158 -152
- package/dist/ui/index.d.cts +24 -1324
- package/dist/ui/index.d.ts +24 -1324
- package/dist/ui/index.js +4 -2
- package/dist/viewers/index.cjs +9 -8
- package/dist/viewers/index.cjs.map +1 -1
- package/dist/viewers/index.js +3 -2
- package/dist/viewers/index.js.map +1 -1
- package/package.json +19 -3
- package/dist/chunk-6ALMBER7.js.map +0 -1
- package/dist/chunk-7IOCMCC5.cjs.map +0 -1
- package/dist/chunk-BXP6S34V.cjs.map +0 -1
- package/dist/chunk-EJ2BMHYK.js.map +0 -1
- package/dist/chunk-JKO3NR5L.js.map +0 -1
- package/dist/chunk-MIJRORQL.js.map +0 -1
- package/dist/chunk-ORKGCXG3.cjs.map +0 -1
- package/dist/chunk-RZQACYNQ.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
import {
|
|
4
|
-
export { AgentBadge, AiMarkdown, ArbiBotHeadIcon, AudIcon, Avatar, AvatarFallback, AvatarImage, BASE_COLORS, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DictateProvider, DocumentCard, DocumentEntity, ENTITY_MAPPINGS, EmlIcon, EntityIcon, EntityPill, FILE_TYPE_COLORS, HoverCard, HoverCardContent, HoverCardTrigger, IconToggle, ImgIcon, InlineMicButton, Input, Label, MarkMenu,
|
|
5
|
-
import {
|
|
6
|
-
export {
|
|
7
|
-
import {
|
|
8
|
-
export {
|
|
1
|
+
import { useDocuments, useConversations, useAssistantQuery, useConversationThreads, arbiQueryKeys, useWorkspaces, useParsedDocument, useTags, useActivity, useThumbnails } from './chunk-KWCHIAQ5.js';
|
|
2
|
+
export { DEFAULT_USD_PER_CREDIT, arbiQueryKeys, creditsToUsd, formatCredits, isUsageMetered, useActivity, useAgents, useAssistantQuery, useConfigs, useConversationThreads, useConversations, useDeleteAgents, useDocuments, useFacts, useHealth, useParsedDocument, useProjectInvoices, useProjectUsage, useProjects, useProjectsUsage, useSessions, useTags, useTasks, useThumbnails, useUserUsageToday, useWorkspaces } from './chunk-KWCHIAQ5.js';
|
|
3
|
+
import { MarkMenu, AiMarkdown, Card, Button, Badge, TagEntity, Input, FILE_TYPE_COLORS, getEntityIcon, UserEntity, getEntityColorStyles, AgentBadge, Textarea, Label, Slider, Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DocumentEntity, DocumentCard, useAudioRecorder, MicWaveformIndicator, IconToggle, classifyMediaError, formatElapsed, PassageCard } from './chunk-2ACHNDO6.js';
|
|
4
|
+
export { AgentBadge, AiMarkdown, ArbiBotHeadIcon, AudIcon, Avatar, AvatarFallback, AvatarImage, BASE_COLORS, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DictateProvider, DocumentCard, DocumentEntity, ENTITY_MAPPINGS, EmlIcon, EntityIcon, EntityPill, FILE_TYPE_COLORS, HoverCard, HoverCardContent, HoverCardTrigger, IconToggle, ImgIcon, InlineMicButton, Input, Label, MarkMenu, MicRecordingOverlay, MicWaveformIndicator, NEUTRAL_GRAY, PLACEHOLDER_COLOR, PassageCard, PdfIcon, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, PresenceLabel, Progress, ProjectEntity, RadioGroup, RadioGroupItem, RagDot, RelevanceDot, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Slider, StatusPill, Switch, TAG_TYPE_ICONS, TAG_TYPE_LABELS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagEntity, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserEntity, UserMenu, VISIBILITY_ICONS, VidIcon, VisibilityIcon, badgeVariants, buttonVariants, cardVariants, configureEntityRegistry, configureRagLabels, configureStatusRegistry, formatElapsed, getDocIcon, getEntityColor, getEntityColorStyles, getEntityIcon, getEntityLabel, getStatusVariant, getTagTypeIcon, getTagTypeLabel, getWorkspaceColor, toggleVariants, useAudioRecorder } from './chunk-2ACHNDO6.js';
|
|
5
|
+
import { normalizeCitationMarkup, MarkdownRenderer } from './chunk-RIHMIEXM.js';
|
|
6
|
+
export { MarkdownRenderer, MarkdownStreamingContext, markdownBaseComponents, normalizeCitationMarkup, splitMarkdownBlocks, trimOpenCitation } from './chunk-RIHMIEXM.js';
|
|
7
|
+
import { formatRelativeTime } from './chunk-FSMIN5VX.js';
|
|
8
|
+
export { DEFAULT_NOTIFY_TONE, NotificationBell, Toaster, formatRelativeTime, notify, seedNotifications, selectUnread, toast, useNotify } from './chunk-FSMIN5VX.js';
|
|
9
|
+
import { ScrollArea, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from './chunk-N5SVBDLC.js';
|
|
10
|
+
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ScrollArea, ScrollBar } from './chunk-N5SVBDLC.js';
|
|
11
|
+
import { cn } from './chunk-SN5YV6FF.js';
|
|
12
|
+
export { cn } from './chunk-SN5YV6FF.js';
|
|
13
|
+
import { AudioViewer, ImageViewer, VideoViewer } from './chunk-HDCRPPBW.js';
|
|
14
|
+
import { useArbi } from './chunk-J4MX2W4H.js';
|
|
15
|
+
export { ArbiProvider, useArbi } from './chunk-J4MX2W4H.js';
|
|
9
16
|
import React, { memo, useState, createContext, useMemo, useCallback, useEffect, useRef, useLayoutEffect, useContext, useId, Fragment as Fragment$1 } from 'react';
|
|
10
|
-
import {
|
|
17
|
+
import { resolveCitations, summarizeCitations, connectWithReconnect } from '@arbidocs/sdk/browser';
|
|
18
|
+
export { Arbi, ArbiError } from '@arbidocs/sdk/browser';
|
|
11
19
|
import { Link, Trash2, CheckCheck, Check, Loader2, AlertTriangle, ShieldCheck, Copy, Sparkles, FileText, GitCompareArrows, Download, Image as Image$1, Search, CornerDownLeft, X, ArrowLeft, Send, Tags, Crown, Info, Activity, Gauge, Gift, PartyPopper, UserCheck, MessageCircleMore, FileX2, FileCheck2, Pencil, FolderPlus, SquareArrowOutUpRight, MessagesSquare, ArrowRight, MoreHorizontal, SquarePen, Mic, Pause, Play, Square, RotateCcw, Camera, Circle } from 'lucide-react';
|
|
12
20
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
13
|
-
import {
|
|
14
|
-
export { Arbi, ArbiError } from '@arbidocs/sdk/browser';
|
|
15
|
-
import { isMessageType } from '@arbidocs/client';
|
|
21
|
+
import { isMessageType, passwordChangeErrorMessage } from '@arbidocs/client';
|
|
16
22
|
export { isMessageType } from '@arbidocs/client';
|
|
17
23
|
import { create } from 'zustand';
|
|
24
|
+
import { useQueryClient, useMutation, useQuery } from '@tanstack/react-query';
|
|
18
25
|
import { diffWords } from 'diff';
|
|
19
26
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
20
27
|
import { createPortal } from 'react-dom';
|
|
@@ -23,274 +30,28 @@ import Cropper from 'react-easy-crop';
|
|
|
23
30
|
import { AgGridReact } from 'ag-grid-react';
|
|
24
31
|
import { ModuleRegistry, AllCommunityModule } from 'ag-grid-community';
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
function formatCredits(credits, options = {}) {
|
|
29
|
-
const { unit = true, locale = "en-US" } = options;
|
|
30
|
-
const whole = Math.round(Number.isFinite(credits) ? credits : 0);
|
|
31
|
-
const digits = whole.toLocaleString(locale);
|
|
32
|
-
return unit ? `${digits} ${whole === 1 ? "credit" : "credits"}` : digits;
|
|
33
|
-
}
|
|
34
|
-
function creditsToUsd(credits, usdPerCredit = DEFAULT_USD_PER_CREDIT) {
|
|
35
|
-
return credits * usdPerCredit;
|
|
36
|
-
}
|
|
37
|
-
function isUsageMetered(usage, subscription) {
|
|
38
|
-
const empty = usage.total_spend === 0 && usage.total_tokens === 0 && usage.total_requests === 0;
|
|
39
|
-
return !(empty && subscription === "dev");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// src/hooks.ts
|
|
43
|
-
var arbiQueryKeys = {
|
|
44
|
-
workspaces: () => ["arbi", "workspaces"],
|
|
45
|
-
documents: (workspaceId) => ["arbi", "documents", workspaceId],
|
|
46
|
-
conversations: (workspaceId) => ["arbi", "conversations", workspaceId],
|
|
47
|
-
tags: (workspaceId) => ["arbi", "tags", workspaceId],
|
|
48
|
-
thumbnails: (docIds) => ["arbi", "thumbnails", [...docIds].sort().join(",")],
|
|
49
|
-
parsedDoc: (docId, stage) => ["arbi", "parsedDoc", docId, stage],
|
|
50
|
-
agents: () => ["arbi", "agents"],
|
|
51
|
-
sessions: () => ["arbi", "sessions"],
|
|
52
|
-
health: () => ["arbi", "health"],
|
|
53
|
-
tasks: () => ["arbi", "tasks"],
|
|
54
|
-
facts: (workspaceId) => ["arbi", "facts", workspaceId],
|
|
55
|
-
configs: () => ["arbi", "configs"],
|
|
56
|
-
activity: () => ["arbi", "activity"],
|
|
57
|
-
projects: () => ["arbi", "projects"],
|
|
58
|
-
projectUsage: (projectExtId, monthsBack) => ["arbi", "projectUsage", projectExtId, monthsBack],
|
|
59
|
-
projectInvoices: (projectExtId) => ["arbi", "projectInvoices", projectExtId],
|
|
60
|
-
userUsageToday: () => ["arbi", "userUsageToday"],
|
|
61
|
-
contacts: () => ["arbi", "contacts"],
|
|
62
|
-
skills: () => ["arbi", "skills"],
|
|
63
|
-
taskRuns: (taskId) => ["arbi", "taskRuns", taskId],
|
|
64
|
-
/** An agent's pinned config; `undefined` = the library default config. */
|
|
65
|
-
agentConfig: (agentExtId) => ["arbi", "agentConfig", agentExtId ?? "default"],
|
|
66
|
-
agentWorkspaces: (agentExtId) => ["arbi", "agentWorkspaces", agentExtId],
|
|
67
|
-
models: () => ["arbi", "models"]
|
|
68
|
-
};
|
|
69
|
-
function useWorkspaces(options) {
|
|
70
|
-
const arbi = useArbi();
|
|
71
|
-
return useQuery({
|
|
72
|
-
queryKey: arbiQueryKeys.workspaces(),
|
|
73
|
-
queryFn: () => arbi.workspaces.list(),
|
|
74
|
-
enabled: options?.enabled ?? arbi.isLoggedIn
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
function useDocuments(workspaceId, options) {
|
|
78
|
-
const arbi = useArbi();
|
|
79
|
-
return useQuery({
|
|
80
|
-
queryKey: arbiQueryKeys.documents(workspaceId ?? ""),
|
|
81
|
-
queryFn: () => arbi.documents.list(),
|
|
82
|
-
enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
function useConversations(workspaceId, options) {
|
|
86
|
-
const arbi = useArbi();
|
|
87
|
-
return useQuery({
|
|
88
|
-
queryKey: arbiQueryKeys.conversations(workspaceId ?? ""),
|
|
89
|
-
queryFn: () => arbi.conversations.list(),
|
|
90
|
-
enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
function useTags(workspaceId, options) {
|
|
94
|
-
const arbi = useArbi();
|
|
95
|
-
return useQuery({
|
|
96
|
-
queryKey: arbiQueryKeys.tags(workspaceId ?? ""),
|
|
97
|
-
queryFn: () => arbi.tags.list(),
|
|
98
|
-
enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
function useThumbnails(docIds, options) {
|
|
102
|
-
const arbi = useArbi();
|
|
103
|
-
return useQuery({
|
|
104
|
-
queryKey: arbiQueryKeys.thumbnails(docIds),
|
|
105
|
-
queryFn: () => arbi.documents.getThumbnails(docIds),
|
|
106
|
-
enabled: (options?.enabled ?? true) && docIds.length > 0 && arbi.hasWorkspace,
|
|
107
|
-
staleTime: 5 * 6e4
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
function useParsedDocument(docId, stage = "final", options) {
|
|
111
|
-
const arbi = useArbi();
|
|
112
|
-
return useQuery({
|
|
113
|
-
queryKey: arbiQueryKeys.parsedDoc(docId ?? "", stage),
|
|
114
|
-
queryFn: () => arbi.documents.getParsedContent(docId, stage),
|
|
115
|
-
enabled: (options?.enabled ?? true) && !!docId && arbi.hasWorkspace
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
function useAssistantQuery() {
|
|
119
|
-
const arbi = useArbi();
|
|
120
|
-
return useMutation({
|
|
121
|
-
mutationFn: ({ question, ...options }) => arbi.assistant.query(question, options)
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
function useAgents(options) {
|
|
125
|
-
const arbi = useArbi();
|
|
126
|
-
return useQuery({
|
|
127
|
-
queryKey: arbiQueryKeys.agents(),
|
|
128
|
-
queryFn: () => arbi.agents.list(),
|
|
129
|
-
enabled: options?.enabled ?? arbi.isLoggedIn
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
function useDeleteAgents() {
|
|
133
|
-
const arbi = useArbi();
|
|
134
|
-
return useMutation({
|
|
135
|
-
mutationFn: ({ agentExtIds }) => arbi.agents.delete(agentExtIds)
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
function useSessions(options) {
|
|
139
|
-
const arbi = useArbi();
|
|
140
|
-
return useQuery({
|
|
141
|
-
queryKey: arbiQueryKeys.sessions(),
|
|
142
|
-
queryFn: () => arbi.sessions.list(),
|
|
143
|
-
enabled: options?.enabled ?? arbi.isLoggedIn
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
function useHealth(options) {
|
|
147
|
-
const arbi = useArbi();
|
|
148
|
-
return useQuery({
|
|
149
|
-
queryKey: arbiQueryKeys.health(),
|
|
150
|
-
queryFn: () => arbi.health.check(),
|
|
151
|
-
enabled: options?.enabled
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
function useTasks(options) {
|
|
155
|
-
const arbi = useArbi();
|
|
156
|
-
return useQuery({
|
|
157
|
-
queryKey: arbiQueryKeys.tasks(),
|
|
158
|
-
queryFn: () => arbi.tasks.list(),
|
|
159
|
-
enabled: options?.enabled ?? arbi.isLoggedIn
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
function useFacts(workspaceId, options) {
|
|
163
|
-
const arbi = useArbi();
|
|
164
|
-
return useQuery({
|
|
165
|
-
queryKey: arbiQueryKeys.facts(workspaceId ?? ""),
|
|
166
|
-
queryFn: () => arbi.facts.list({ pinnedOnly: options?.pinnedOnly }),
|
|
167
|
-
enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
function useConfigs(options) {
|
|
171
|
-
const arbi = useArbi();
|
|
172
|
-
return useQuery({
|
|
173
|
-
queryKey: arbiQueryKeys.configs(),
|
|
174
|
-
queryFn: () => arbi.agentConfig.list(),
|
|
175
|
-
enabled: options?.enabled ?? arbi.isLoggedIn
|
|
176
|
-
});
|
|
33
|
+
function previewText(content) {
|
|
34
|
+
return content.replace(/\s+/g, " ").trim().replace(/^(?:(?:[-*•>]|#{1,6})\s+)+/, "");
|
|
177
35
|
}
|
|
178
|
-
function
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
function useProjects(options) {
|
|
187
|
-
const arbi = useArbi();
|
|
188
|
-
return useQuery({
|
|
189
|
-
queryKey: arbiQueryKeys.projects(),
|
|
190
|
-
queryFn: () => arbi.projects.list(),
|
|
191
|
-
enabled: options?.enabled ?? arbi.isLoggedIn
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
function useProjectUsage(projectExtId, monthsBack = 0, options) {
|
|
195
|
-
const arbi = useArbi();
|
|
196
|
-
const usage = useQuery({
|
|
197
|
-
queryKey: arbiQueryKeys.projectUsage(projectExtId ?? "", monthsBack),
|
|
198
|
-
queryFn: () => arbi.projects.usage(projectExtId, monthsBack),
|
|
199
|
-
enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn
|
|
200
|
-
});
|
|
201
|
-
const projects = useProjects({ enabled: !!projectExtId && (options?.enabled ?? true) });
|
|
202
|
-
const subscription = projects.data?.find((p) => p.external_id === projectExtId)?.subscription;
|
|
203
|
-
const metered = usage.data ? isUsageMetered(usage.data, subscription) : void 0;
|
|
204
|
-
return { ...usage, metered };
|
|
205
|
-
}
|
|
206
|
-
function useProjectsUsage(projectExtIds, monthsBack = 0, options) {
|
|
207
|
-
const arbi = useArbi();
|
|
208
|
-
const enabled = (options?.enabled ?? true) && arbi.isLoggedIn;
|
|
209
|
-
const projects = useProjects({ enabled: enabled && projectExtIds.length > 0 });
|
|
210
|
-
const results = useQueries({
|
|
211
|
-
queries: projectExtIds.map((id) => ({
|
|
212
|
-
queryKey: arbiQueryKeys.projectUsage(id, monthsBack),
|
|
213
|
-
queryFn: () => arbi.projects.usage(id, monthsBack),
|
|
214
|
-
enabled: enabled && !!id
|
|
215
|
-
}))
|
|
216
|
-
});
|
|
217
|
-
const signature = results.map((r) => `${r.status}:${r.dataUpdatedAt ?? 0}`).join("|") + `#${projects.dataUpdatedAt}`;
|
|
218
|
-
return useMemo(() => {
|
|
219
|
-
const dailyMap = /* @__PURE__ */ new Map();
|
|
220
|
-
const modelMap = /* @__PURE__ */ new Map();
|
|
221
|
-
let totalCredits = 0;
|
|
222
|
-
let anyData = false;
|
|
223
|
-
let anyMetered = false;
|
|
224
|
-
let totalTokens = 0;
|
|
225
|
-
let totalRequests = 0;
|
|
226
|
-
results.forEach((r, i) => {
|
|
227
|
-
const d = r.data;
|
|
228
|
-
if (!d) return;
|
|
229
|
-
anyData = true;
|
|
230
|
-
const subscription = projects.data?.find(
|
|
231
|
-
(p) => p.external_id === projectExtIds[i]
|
|
232
|
-
)?.subscription;
|
|
233
|
-
if (isUsageMetered(d, subscription)) anyMetered = true;
|
|
234
|
-
totalCredits += d.total_spend ?? 0;
|
|
235
|
-
totalTokens += d.total_tokens ?? 0;
|
|
236
|
-
totalRequests += d.total_requests ?? 0;
|
|
237
|
-
for (const day of d.daily ?? []) {
|
|
238
|
-
const cur = dailyMap.get(day.date) ?? {
|
|
239
|
-
date: day.date,
|
|
240
|
-
credits: 0,
|
|
241
|
-
totalTokens: 0,
|
|
242
|
-
apiRequests: 0
|
|
243
|
-
};
|
|
244
|
-
cur.credits += day.spend ?? 0;
|
|
245
|
-
cur.totalTokens += day.total_tokens ?? 0;
|
|
246
|
-
cur.apiRequests += day.api_requests ?? 0;
|
|
247
|
-
dailyMap.set(day.date, cur);
|
|
248
|
-
}
|
|
249
|
-
for (const [model, mg] of Object.entries(d.model_groups ?? {})) {
|
|
250
|
-
const cur = modelMap.get(model) ?? {
|
|
251
|
-
model,
|
|
252
|
-
credits: 0,
|
|
253
|
-
totalTokens: 0,
|
|
254
|
-
promptTokens: 0,
|
|
255
|
-
completionTokens: 0,
|
|
256
|
-
successfulRequests: 0
|
|
257
|
-
};
|
|
258
|
-
cur.credits += mg.spend ?? 0;
|
|
259
|
-
cur.totalTokens += mg.total_tokens ?? 0;
|
|
260
|
-
cur.promptTokens += mg.prompt_tokens ?? 0;
|
|
261
|
-
cur.completionTokens += mg.completion_tokens ?? 0;
|
|
262
|
-
cur.successfulRequests += mg.successful_requests ?? 0;
|
|
263
|
-
modelMap.set(model, cur);
|
|
264
|
-
}
|
|
265
|
-
});
|
|
36
|
+
function toChatCitations(source) {
|
|
37
|
+
if (!source?.tools) return [];
|
|
38
|
+
const resolved = resolveCitations(source);
|
|
39
|
+
const summaries = summarizeCitations(resolved);
|
|
40
|
+
return resolved.map((r, i) => {
|
|
41
|
+
const summary = summaries[i];
|
|
266
42
|
return {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
43
|
+
num: r.citationNum,
|
|
44
|
+
statement: summary.statement,
|
|
45
|
+
documentTitle: summary.docTitle,
|
|
46
|
+
page: summary.pageNumber,
|
|
47
|
+
passages: r.chunks.map((chunk) => ({
|
|
48
|
+
id: chunk.metadata.chunk_ext_id,
|
|
49
|
+
documentId: chunk.metadata.doc_ext_id ?? null,
|
|
50
|
+
documentTitle: chunk.metadata.doc_title ?? summary.docTitle,
|
|
51
|
+
page: chunk.metadata.page_number ?? null,
|
|
52
|
+
text: previewText(chunk.content)
|
|
53
|
+
}))
|
|
277
54
|
};
|
|
278
|
-
}, [signature]);
|
|
279
|
-
}
|
|
280
|
-
function useProjectInvoices(projectExtId, options) {
|
|
281
|
-
const arbi = useArbi();
|
|
282
|
-
return useQuery({
|
|
283
|
-
queryKey: arbiQueryKeys.projectInvoices(projectExtId ?? ""),
|
|
284
|
-
queryFn: () => arbi.projects.invoices(projectExtId),
|
|
285
|
-
enabled: (options?.enabled ?? true) && !!projectExtId && arbi.isLoggedIn
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
function useUserUsageToday(options) {
|
|
289
|
-
const arbi = useArbi();
|
|
290
|
-
return useQuery({
|
|
291
|
-
queryKey: arbiQueryKeys.userUsageToday(),
|
|
292
|
-
queryFn: () => arbi.user.usageToday(),
|
|
293
|
-
enabled: options?.enabled ?? arbi.isLoggedIn
|
|
294
55
|
});
|
|
295
56
|
}
|
|
296
57
|
|
|
@@ -298,11 +59,38 @@ function useUserUsageToday(options) {
|
|
|
298
59
|
var counter = 0;
|
|
299
60
|
var nextId = (prefix) => `${prefix}-${Date.now().toString(36)}-${(counter++).toString(36)}`;
|
|
300
61
|
var emptyThread = () => ({
|
|
301
|
-
|
|
62
|
+
key: nextId("thread"),
|
|
63
|
+
conversationId: null,
|
|
302
64
|
title: "",
|
|
303
65
|
messages: [],
|
|
304
|
-
responseId: null
|
|
66
|
+
responseId: null,
|
|
67
|
+
isLoaded: true
|
|
305
68
|
});
|
|
69
|
+
var storedThread = (conversationId) => ({
|
|
70
|
+
key: conversationId,
|
|
71
|
+
conversationId,
|
|
72
|
+
title: "",
|
|
73
|
+
messages: [],
|
|
74
|
+
responseId: null,
|
|
75
|
+
isLoaded: false
|
|
76
|
+
});
|
|
77
|
+
var publicId = (t) => t.conversationId ?? t.key;
|
|
78
|
+
function messagesFromHistory(history) {
|
|
79
|
+
return history.filter((m) => m.role !== "system" && m.content.trim() !== "").map((m) => {
|
|
80
|
+
if (m.role === "user") {
|
|
81
|
+
return { id: m.external_id, role: "user", content: m.content, status: "complete" };
|
|
82
|
+
}
|
|
83
|
+
const citations = toChatCitations({ tools: m.tools });
|
|
84
|
+
return {
|
|
85
|
+
id: m.external_id,
|
|
86
|
+
role: "assistant",
|
|
87
|
+
content: m.content,
|
|
88
|
+
status: m.status === "failed" ? "error" : "complete",
|
|
89
|
+
...m.status === "failed" ? { error: "The assistant request failed." } : {},
|
|
90
|
+
...citations.length > 0 ? { citations } : {}
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
}
|
|
306
94
|
function titleFromQuestion(question, maxLength = 48) {
|
|
307
95
|
const flat = question.replace(/\s+/g, " ").trim();
|
|
308
96
|
if (flat.length <= maxLength) return flat;
|
|
@@ -312,29 +100,88 @@ function titleFromQuestion(question, maxLength = 48) {
|
|
|
312
100
|
return `${words.replace(/[\s,;:.\-–—]+$/, "")}\u2026`;
|
|
313
101
|
}
|
|
314
102
|
var messageOf = (e, fallback) => e instanceof Error ? e.message : fallback;
|
|
103
|
+
var isAbort = (e) => e instanceof DOMException && e.name === "AbortError";
|
|
104
|
+
var TITLE_REFRESH_DELAYS_MS = [2500, 6e3, 12e3];
|
|
315
105
|
function useArbiChat(options = {}) {
|
|
316
106
|
const { workspaceId, model, titleLength = 48 } = options;
|
|
317
107
|
const arbi = useArbi();
|
|
318
108
|
const { data: docs = [], isLoading: isLoadingDocuments, refetch } = useDocuments(workspaceId);
|
|
109
|
+
const {
|
|
110
|
+
data: stored = [],
|
|
111
|
+
isLoading: isLoadingThreads,
|
|
112
|
+
refetch: refetchConversations
|
|
113
|
+
} = useConversations(workspaceId);
|
|
319
114
|
const query = useAssistantQuery();
|
|
320
115
|
const { mutateAsync } = query;
|
|
321
116
|
const [threads, setThreads] = useState(() => [emptyThread()]);
|
|
322
|
-
const [
|
|
117
|
+
const [activeKey, setActiveKey] = useState(() => threads[0].key);
|
|
323
118
|
const [deselected, setDeselected] = useState(/* @__PURE__ */ new Set());
|
|
324
119
|
const [isRunning, setIsRunning] = useState(false);
|
|
325
120
|
const [isUploading, setIsUploading] = useState(false);
|
|
326
121
|
const [uploadError, setUploadError] = useState(null);
|
|
122
|
+
const [historyError, setHistoryError] = useState(null);
|
|
123
|
+
const abortRef = useRef(null);
|
|
124
|
+
const timersRef = useRef([]);
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
const timers = timersRef.current;
|
|
127
|
+
return () => timers.forEach(clearTimeout);
|
|
128
|
+
}, []);
|
|
327
129
|
const scopeRef = useRef(workspaceId);
|
|
328
130
|
useEffect(() => {
|
|
329
131
|
if (scopeRef.current === workspaceId) return;
|
|
330
132
|
scopeRef.current = workspaceId;
|
|
331
133
|
const fresh = emptyThread();
|
|
332
134
|
setThreads([fresh]);
|
|
333
|
-
|
|
135
|
+
setActiveKey(fresh.key);
|
|
334
136
|
setDeselected(/* @__PURE__ */ new Set());
|
|
335
137
|
setUploadError(null);
|
|
138
|
+
setHistoryError(null);
|
|
336
139
|
}, [workspaceId]);
|
|
337
|
-
const active = threads.find((t) => t.
|
|
140
|
+
const active = threads.find((t) => t.key === activeKey) ?? threads[0];
|
|
141
|
+
const threadEntries = useMemo(() => {
|
|
142
|
+
const storedIds = new Set(stored.map((c) => c.external_id));
|
|
143
|
+
const byConversation = new Map(
|
|
144
|
+
threads.filter((t) => t.conversationId).map((t) => [t.conversationId, t])
|
|
145
|
+
);
|
|
146
|
+
const fresh = threads.filter((t) => !t.conversationId);
|
|
147
|
+
const justSaved = threads.filter((t) => t.conversationId && !storedIds.has(t.conversationId));
|
|
148
|
+
const persisted = [...stored].filter((c) => c.message_count > 0 || byConversation.has(c.external_id)).sort((a, b) => b.updated_at.localeCompare(a.updated_at)).map((c) => {
|
|
149
|
+
const local = byConversation.get(c.external_id);
|
|
150
|
+
return {
|
|
151
|
+
key: local?.key ?? c.external_id,
|
|
152
|
+
id: c.external_id,
|
|
153
|
+
title: c.title || local?.title || ""
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
return [
|
|
157
|
+
...fresh.map((t) => ({ key: t.key, id: publicId(t), title: t.title })),
|
|
158
|
+
...justSaved.map((t) => ({ key: t.key, id: publicId(t), title: t.title })),
|
|
159
|
+
...persisted
|
|
160
|
+
];
|
|
161
|
+
}, [threads, stored]);
|
|
162
|
+
const needsLoad = !!active.conversationId && !active.isLoaded;
|
|
163
|
+
const loaded = useConversationThreads(workspaceId, active.conversationId ?? void 0, {
|
|
164
|
+
enabled: needsLoad
|
|
165
|
+
});
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
const data = loaded.data;
|
|
168
|
+
if (!needsLoad || !data || data.conversation_ext_id !== active.conversationId) return;
|
|
169
|
+
const primary = [...data.threads].sort((a, b) => b.history.length - a.history.length)[0];
|
|
170
|
+
setThreads(
|
|
171
|
+
(all) => all.map(
|
|
172
|
+
(t) => t.key === active.key ? {
|
|
173
|
+
...t,
|
|
174
|
+
isLoaded: true,
|
|
175
|
+
messages: messagesFromHistory(primary?.history ?? []),
|
|
176
|
+
responseId: primary?.leaf_message_ext_id ?? null
|
|
177
|
+
} : t
|
|
178
|
+
)
|
|
179
|
+
);
|
|
180
|
+
}, [loaded.data, needsLoad, active.conversationId, active.key]);
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
if (loaded.error)
|
|
183
|
+
setHistoryError(messageOf(loaded.error, "The conversation could not be loaded."));
|
|
184
|
+
}, [loaded.error]);
|
|
338
185
|
const selectedIds = useMemo(
|
|
339
186
|
() => docs.map((d) => d.external_id).filter((id) => !!id && !deselected.has(id)),
|
|
340
187
|
[docs, deselected]
|
|
@@ -348,16 +195,23 @@ function useArbiChat(options = {}) {
|
|
|
348
195
|
[docs, deselected]
|
|
349
196
|
);
|
|
350
197
|
const patchThread = useCallback(
|
|
351
|
-
(
|
|
198
|
+
(key, patch) => setThreads((all) => all.map((t) => t.key === key ? patch(t) : t)),
|
|
352
199
|
[]
|
|
353
200
|
);
|
|
354
201
|
const patchMessage = useCallback(
|
|
355
|
-
(
|
|
202
|
+
(threadKey, messageId, patch) => patchThread(threadKey, (t) => ({
|
|
356
203
|
...t,
|
|
357
204
|
messages: t.messages.map((m) => m.id === messageId ? { ...m, ...patch } : m)
|
|
358
205
|
})),
|
|
359
206
|
[patchThread]
|
|
360
207
|
);
|
|
208
|
+
const refreshTitles = useCallback(() => {
|
|
209
|
+
void refetchConversations();
|
|
210
|
+
timersRef.current.forEach(clearTimeout);
|
|
211
|
+
timersRef.current = TITLE_REFRESH_DELAYS_MS.map(
|
|
212
|
+
(delay) => setTimeout(() => void refetchConversations(), delay)
|
|
213
|
+
);
|
|
214
|
+
}, [refetchConversations]);
|
|
361
215
|
const ask = useCallback(
|
|
362
216
|
async (thread, text) => {
|
|
363
217
|
const userMessage = {
|
|
@@ -372,11 +226,13 @@ function useArbiChat(options = {}) {
|
|
|
372
226
|
content: "",
|
|
373
227
|
status: "streaming"
|
|
374
228
|
};
|
|
375
|
-
patchThread(thread.
|
|
229
|
+
patchThread(thread.key, (t) => ({
|
|
376
230
|
...t,
|
|
377
231
|
title: t.title || titleFromQuestion(text, titleLength),
|
|
378
232
|
messages: [...t.messages, userMessage, answer]
|
|
379
233
|
}));
|
|
234
|
+
const controller = new AbortController();
|
|
235
|
+
abortRef.current = controller;
|
|
380
236
|
setIsRunning(true);
|
|
381
237
|
let buffer = "";
|
|
382
238
|
let steps = 0;
|
|
@@ -387,15 +243,34 @@ function useArbiChat(options = {}) {
|
|
|
387
243
|
docIds: selectedIds,
|
|
388
244
|
previousResponseId: thread.responseId,
|
|
389
245
|
model,
|
|
246
|
+
signal: controller.signal,
|
|
247
|
+
onStreamStart: (data) => {
|
|
248
|
+
if (data.assistant_message_ext_id) {
|
|
249
|
+
patchThread(thread.key, (t) => ({
|
|
250
|
+
...t,
|
|
251
|
+
responseId: data.assistant_message_ext_id ?? t.responseId
|
|
252
|
+
}));
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
onUserMessage: (ev) => {
|
|
256
|
+
patchThread(thread.key, (t) => ({
|
|
257
|
+
...t,
|
|
258
|
+
conversationId: t.conversationId ?? ev.conversation_ext_id
|
|
259
|
+
}));
|
|
260
|
+
},
|
|
261
|
+
onMetadata: (meta) => {
|
|
262
|
+
const citations = toChatCitations(meta);
|
|
263
|
+
if (citations.length > 0) patchMessage(thread.key, answer.id, { citations });
|
|
264
|
+
},
|
|
390
265
|
onToken: (token) => {
|
|
391
266
|
buffer += token;
|
|
392
|
-
patchMessage(thread.
|
|
267
|
+
patchMessage(thread.key, answer.id, { content: buffer });
|
|
393
268
|
},
|
|
394
269
|
onOutputItemDone: (ev) => {
|
|
395
270
|
const type = ev.item.type;
|
|
396
271
|
if (type === "function_call" || type === "reasoning") {
|
|
397
272
|
steps += 1;
|
|
398
|
-
patchMessage(thread.
|
|
273
|
+
patchMessage(thread.key, answer.id, { stepCount: steps });
|
|
399
274
|
}
|
|
400
275
|
},
|
|
401
276
|
onError: (message) => {
|
|
@@ -405,37 +280,50 @@ function useArbiChat(options = {}) {
|
|
|
405
280
|
const finalText = result.text || buffer;
|
|
406
281
|
const failure = streamError || result.errors[0] || null;
|
|
407
282
|
if (failure && !finalText) {
|
|
408
|
-
patchMessage(thread.
|
|
283
|
+
patchMessage(thread.key, answer.id, { status: "error", error: failure });
|
|
409
284
|
} else {
|
|
410
|
-
|
|
285
|
+
const citations = toChatCitations(result.metadata);
|
|
286
|
+
patchMessage(thread.key, answer.id, {
|
|
411
287
|
status: "complete",
|
|
412
288
|
content: finalText,
|
|
413
|
-
stepCount: result.agentSteps.length || steps || void 0
|
|
289
|
+
stepCount: result.agentSteps.length || steps || void 0,
|
|
290
|
+
...citations.length > 0 ? { citations } : {}
|
|
414
291
|
});
|
|
415
|
-
patchThread(thread.
|
|
292
|
+
patchThread(thread.key, (t) => ({
|
|
416
293
|
...t,
|
|
417
294
|
responseId: result.assistantMessageExtId ?? t.responseId
|
|
418
295
|
}));
|
|
419
296
|
}
|
|
420
297
|
} catch (e) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
298
|
+
if (controller.signal.aborted || isAbort(e)) {
|
|
299
|
+
patchMessage(thread.key, answer.id, {
|
|
300
|
+
status: "complete",
|
|
301
|
+
content: buffer,
|
|
302
|
+
stopped: true
|
|
303
|
+
});
|
|
304
|
+
} else {
|
|
305
|
+
patchMessage(thread.key, answer.id, {
|
|
306
|
+
status: "error",
|
|
307
|
+
error: messageOf(e, "The assistant request failed.")
|
|
308
|
+
});
|
|
309
|
+
}
|
|
425
310
|
} finally {
|
|
311
|
+
if (abortRef.current === controller) abortRef.current = null;
|
|
426
312
|
setIsRunning(false);
|
|
313
|
+
refreshTitles();
|
|
427
314
|
}
|
|
428
315
|
},
|
|
429
|
-
[mutateAsync, patchMessage, patchThread, selectedIds, model, titleLength]
|
|
316
|
+
[mutateAsync, patchMessage, patchThread, refreshTitles, selectedIds, model, titleLength]
|
|
430
317
|
);
|
|
431
318
|
const send = useCallback(
|
|
432
319
|
async (text) => {
|
|
433
320
|
const trimmed = text.trim();
|
|
434
|
-
if (!trimmed || isRunning) return;
|
|
321
|
+
if (!trimmed || isRunning || !active.isLoaded) return;
|
|
435
322
|
await ask(active, trimmed);
|
|
436
323
|
},
|
|
437
324
|
[active, ask, isRunning]
|
|
438
325
|
);
|
|
326
|
+
const stop = useCallback(() => abortRef.current?.abort(), []);
|
|
439
327
|
const lastMessage = active.messages[active.messages.length - 1];
|
|
440
328
|
const error = lastMessage?.status === "error" ? lastMessage.error ?? null : null;
|
|
441
329
|
const retry = useCallback(async () => {
|
|
@@ -445,23 +333,54 @@ function useArbiChat(options = {}) {
|
|
|
445
333
|
const question = messages[messages.length - 2];
|
|
446
334
|
if (failed?.status !== "error" || question?.role !== "user") return;
|
|
447
335
|
const trimmed = { ...active, messages: messages.slice(0, -2) };
|
|
448
|
-
patchThread(active.
|
|
336
|
+
patchThread(active.key, () => trimmed);
|
|
449
337
|
await ask(trimmed, question.content);
|
|
450
338
|
}, [active, ask, isRunning, patchThread]);
|
|
451
339
|
const newThread = useCallback(() => {
|
|
452
|
-
|
|
340
|
+
setHistoryError(null);
|
|
341
|
+
const blank = threads.find((t) => !t.conversationId && t.messages.length === 0);
|
|
342
|
+
if (blank) {
|
|
343
|
+
setActiveKey(blank.key);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
453
346
|
const fresh = emptyThread();
|
|
454
347
|
setThreads((all) => [fresh, ...all]);
|
|
455
|
-
|
|
456
|
-
}, [
|
|
348
|
+
setActiveKey(fresh.key);
|
|
349
|
+
}, [threads]);
|
|
350
|
+
const selectThread = useCallback(
|
|
351
|
+
(id) => {
|
|
352
|
+
const entry = threadEntries.find((e) => e.id === id);
|
|
353
|
+
if (!entry) return;
|
|
354
|
+
setHistoryError(null);
|
|
355
|
+
setThreads((all) => all.some((t) => t.key === entry.key) ? all : [...all, storedThread(id)]);
|
|
356
|
+
setActiveKey(entry.key);
|
|
357
|
+
},
|
|
358
|
+
[threadEntries]
|
|
359
|
+
);
|
|
457
360
|
const deleteThread = useCallback(
|
|
458
361
|
(id) => {
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
362
|
+
const entry = threadEntries.find((e) => e.id === id);
|
|
363
|
+
if (!entry) return;
|
|
364
|
+
const remove = () => {
|
|
365
|
+
const rest = threads.filter((t) => t.key !== entry.key);
|
|
366
|
+
const next = rest.length > 0 ? rest : [emptyThread()];
|
|
367
|
+
setThreads(next);
|
|
368
|
+
if (entry.key === active.key) setActiveKey(next[0].key);
|
|
369
|
+
};
|
|
370
|
+
const local = threads.find((t) => t.key === entry.key);
|
|
371
|
+
const conversationId = local ? local.conversationId : id;
|
|
372
|
+
if (!conversationId) return remove();
|
|
373
|
+
void (async () => {
|
|
374
|
+
try {
|
|
375
|
+
await arbi.conversations.delete(conversationId);
|
|
376
|
+
remove();
|
|
377
|
+
await refetchConversations();
|
|
378
|
+
} catch (e) {
|
|
379
|
+
setHistoryError(messageOf(e, "The conversation could not be deleted."));
|
|
380
|
+
}
|
|
381
|
+
})();
|
|
463
382
|
},
|
|
464
|
-
[threads,
|
|
383
|
+
[threadEntries, threads, active.key, arbi, refetchConversations]
|
|
465
384
|
);
|
|
466
385
|
const toggleDocument = useCallback((id) => {
|
|
467
386
|
setDeselected((prev) => {
|
|
@@ -489,18 +408,22 @@ function useArbiChat(options = {}) {
|
|
|
489
408
|
[arbi, refetch]
|
|
490
409
|
);
|
|
491
410
|
return {
|
|
492
|
-
threads:
|
|
493
|
-
activeThreadId: active
|
|
411
|
+
threads: threadEntries.map(({ id, title }) => ({ id, title })),
|
|
412
|
+
activeThreadId: publicId(active),
|
|
494
413
|
messages: active.messages,
|
|
495
414
|
isRunning,
|
|
496
415
|
error,
|
|
416
|
+
isLoadingThread: needsLoad && !historyError,
|
|
417
|
+
isLoadingThreads,
|
|
418
|
+
historyError,
|
|
497
419
|
documents,
|
|
498
420
|
isLoadingDocuments,
|
|
499
421
|
isUploading,
|
|
500
422
|
uploadError,
|
|
501
423
|
send,
|
|
502
424
|
retry,
|
|
503
|
-
|
|
425
|
+
stop,
|
|
426
|
+
selectThread,
|
|
504
427
|
newThread,
|
|
505
428
|
deleteThread,
|
|
506
429
|
toggleDocument,
|
|
@@ -1107,6 +1030,418 @@ function useRemoveContacts() {
|
|
|
1107
1030
|
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.contacts() })
|
|
1108
1031
|
});
|
|
1109
1032
|
}
|
|
1033
|
+
function toProfileView(profile) {
|
|
1034
|
+
return {
|
|
1035
|
+
...profile,
|
|
1036
|
+
fullName: [profile.givenName, profile.familyName].map((part) => part?.trim()).filter(Boolean).join(" ")
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
function useProfile(options) {
|
|
1040
|
+
const arbi = useArbi();
|
|
1041
|
+
return useQuery({
|
|
1042
|
+
queryKey: arbiQueryKeys.profile(),
|
|
1043
|
+
queryFn: () => {
|
|
1044
|
+
const profile = arbi.user.profile();
|
|
1045
|
+
return profile ? toProfileView(profile) : null;
|
|
1046
|
+
},
|
|
1047
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn,
|
|
1048
|
+
staleTime: Infinity
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
function useUpdateProfile() {
|
|
1052
|
+
const arbi = useArbi();
|
|
1053
|
+
const qc = useQueryClient();
|
|
1054
|
+
return useMutation({
|
|
1055
|
+
mutationFn: async (vars) => {
|
|
1056
|
+
await arbi.profile.update({
|
|
1057
|
+
...vars.givenName !== void 0 && { given_name: vars.givenName.trim() },
|
|
1058
|
+
...vars.familyName !== void 0 && { family_name: vars.familyName.trim() },
|
|
1059
|
+
...vars.picture !== void 0 && { picture: vars.picture }
|
|
1060
|
+
});
|
|
1061
|
+
const profile = arbi.user.profile();
|
|
1062
|
+
return profile ? toProfileView(profile) : null;
|
|
1063
|
+
},
|
|
1064
|
+
onSuccess: (profile) => {
|
|
1065
|
+
qc.setQueryData(arbiQueryKeys.profile(), profile);
|
|
1066
|
+
return qc.invalidateQueries({ queryKey: arbiQueryKeys.workspaces() });
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
function useNameEditor({ givenName, familyName, save }) {
|
|
1071
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
1072
|
+
const [given, setGiven] = useState("");
|
|
1073
|
+
const [family, setFamily] = useState("");
|
|
1074
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
1075
|
+
const [error, setError] = useState(null);
|
|
1076
|
+
const onStartEdit = useCallback(() => {
|
|
1077
|
+
setGiven(givenName ?? "");
|
|
1078
|
+
setFamily(familyName ?? "");
|
|
1079
|
+
setError(null);
|
|
1080
|
+
setIsEditing(true);
|
|
1081
|
+
}, [givenName, familyName]);
|
|
1082
|
+
const onSave = useCallback(() => {
|
|
1083
|
+
const trimmedGiven = given.trim();
|
|
1084
|
+
if (!trimmedGiven) return;
|
|
1085
|
+
setIsSaving(true);
|
|
1086
|
+
setError(null);
|
|
1087
|
+
void Promise.resolve().then(() => save({ givenName: trimmedGiven, familyName: family.trim() })).then(() => setIsEditing(false)).catch((e) => setError(e)).finally(() => setIsSaving(false));
|
|
1088
|
+
}, [given, family, save]);
|
|
1089
|
+
return {
|
|
1090
|
+
isEditing,
|
|
1091
|
+
givenName: given,
|
|
1092
|
+
familyName: family,
|
|
1093
|
+
onGivenNameChange: setGiven,
|
|
1094
|
+
onFamilyNameChange: setFamily,
|
|
1095
|
+
onStartEdit,
|
|
1096
|
+
onSave,
|
|
1097
|
+
onCancel: () => setIsEditing(false),
|
|
1098
|
+
isSaving,
|
|
1099
|
+
error
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
var MAX_AVATAR_FILE_BYTES = 5 * 1024 * 1024;
|
|
1103
|
+
function useAvatarCrop({
|
|
1104
|
+
upload,
|
|
1105
|
+
onProblem,
|
|
1106
|
+
maxBytes = MAX_AVATAR_FILE_BYTES
|
|
1107
|
+
}) {
|
|
1108
|
+
const [pendingImage, setPendingImage] = useState(null);
|
|
1109
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
1110
|
+
const onFileChosen = useCallback(
|
|
1111
|
+
(file) => {
|
|
1112
|
+
if (!file.type.startsWith("image/")) return onProblem?.("not-image");
|
|
1113
|
+
if (file.size > maxBytes) return onProblem?.("too-large");
|
|
1114
|
+
const reader = new FileReader();
|
|
1115
|
+
reader.onload = () => setPendingImage(reader.result);
|
|
1116
|
+
reader.onerror = () => onProblem?.("unreadable");
|
|
1117
|
+
reader.readAsDataURL(file);
|
|
1118
|
+
},
|
|
1119
|
+
[maxBytes, onProblem]
|
|
1120
|
+
);
|
|
1121
|
+
const onCropComplete = useCallback(
|
|
1122
|
+
(result) => {
|
|
1123
|
+
setPendingImage(null);
|
|
1124
|
+
setIsUploading(true);
|
|
1125
|
+
void Promise.resolve().then(() => upload(result.dataUrl)).catch(() => {
|
|
1126
|
+
}).finally(() => setIsUploading(false));
|
|
1127
|
+
},
|
|
1128
|
+
[upload]
|
|
1129
|
+
);
|
|
1130
|
+
return {
|
|
1131
|
+
onFileChosen,
|
|
1132
|
+
pendingImage,
|
|
1133
|
+
onCropComplete,
|
|
1134
|
+
onCropCancel: () => setPendingImage(null),
|
|
1135
|
+
isUploading
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
function useRequestEmailChange() {
|
|
1139
|
+
const arbi = useArbi();
|
|
1140
|
+
return useMutation({
|
|
1141
|
+
mutationFn: (newEmail) => arbi.account.requestEmailChange(newEmail)
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
function useConfirmEmailChange() {
|
|
1145
|
+
const arbi = useArbi();
|
|
1146
|
+
const qc = useQueryClient();
|
|
1147
|
+
return useMutation({
|
|
1148
|
+
mutationFn: ({ newEmail, code }) => arbi.account.confirmEmailChange(newEmail, code),
|
|
1149
|
+
onSuccess: () => {
|
|
1150
|
+
const profile = arbi.user.profile();
|
|
1151
|
+
qc.setQueryData(arbiQueryKeys.profile(), profile ? toProfileView(profile) : null);
|
|
1152
|
+
}
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
function useEmailChange({
|
|
1156
|
+
requestCode,
|
|
1157
|
+
confirm,
|
|
1158
|
+
cooldownSeconds: cooldownLength = 30
|
|
1159
|
+
}) {
|
|
1160
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
1161
|
+
const [step, setStep] = useState("enter");
|
|
1162
|
+
const [newEmail, setNewEmail] = useState("");
|
|
1163
|
+
const [code, setCode] = useState("");
|
|
1164
|
+
const [cooldown, setCooldown] = useState(0);
|
|
1165
|
+
const [isSending, setIsSending] = useState(false);
|
|
1166
|
+
const [isConfirming, setIsConfirming] = useState(false);
|
|
1167
|
+
const [error, setError] = useState(null);
|
|
1168
|
+
useEffect(() => {
|
|
1169
|
+
if (cooldown <= 0) return;
|
|
1170
|
+
const timer = setTimeout(() => setCooldown((c) => c - 1), 1e3);
|
|
1171
|
+
return () => clearTimeout(timer);
|
|
1172
|
+
}, [cooldown]);
|
|
1173
|
+
const reset = useCallback(() => {
|
|
1174
|
+
setIsOpen(false);
|
|
1175
|
+
setStep("enter");
|
|
1176
|
+
setNewEmail("");
|
|
1177
|
+
setCode("");
|
|
1178
|
+
setError(null);
|
|
1179
|
+
}, []);
|
|
1180
|
+
const onSendCode = useCallback(() => {
|
|
1181
|
+
const email = newEmail.trim();
|
|
1182
|
+
if (!email) return;
|
|
1183
|
+
setIsSending(true);
|
|
1184
|
+
setError(null);
|
|
1185
|
+
void Promise.resolve().then(() => requestCode(email)).then(() => {
|
|
1186
|
+
setStep("verify");
|
|
1187
|
+
setCooldown(cooldownLength);
|
|
1188
|
+
}).catch((e) => setError(e)).finally(() => setIsSending(false));
|
|
1189
|
+
}, [newEmail, requestCode, cooldownLength]);
|
|
1190
|
+
const onConfirm = useCallback(() => {
|
|
1191
|
+
const email = newEmail.trim();
|
|
1192
|
+
const entered = code.trim();
|
|
1193
|
+
if (!email || !entered) return;
|
|
1194
|
+
setIsConfirming(true);
|
|
1195
|
+
setError(null);
|
|
1196
|
+
void Promise.resolve().then(() => confirm({ newEmail: email, code: entered })).then(reset).catch((e) => setError(e)).finally(() => setIsConfirming(false));
|
|
1197
|
+
}, [newEmail, code, confirm, reset]);
|
|
1198
|
+
return {
|
|
1199
|
+
isOpen,
|
|
1200
|
+
onStart: () => setIsOpen(true),
|
|
1201
|
+
step,
|
|
1202
|
+
newEmail,
|
|
1203
|
+
onNewEmailChange: setNewEmail,
|
|
1204
|
+
onSendCode,
|
|
1205
|
+
isSending,
|
|
1206
|
+
code,
|
|
1207
|
+
onCodeChange: setCode,
|
|
1208
|
+
onConfirm,
|
|
1209
|
+
isConfirming,
|
|
1210
|
+
cooldownSeconds: cooldown,
|
|
1211
|
+
onCancel: reset,
|
|
1212
|
+
error
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
function usePasswordChange() {
|
|
1216
|
+
const arbi = useArbi();
|
|
1217
|
+
return useMutation({
|
|
1218
|
+
mutationFn: (vars) => arbi.account.changePassword(vars)
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
var DEFAULT_PASSWORD_CHANGE_FORM_MESSAGES = {
|
|
1222
|
+
required: "All fields are required",
|
|
1223
|
+
mismatch: "New passwords do not match",
|
|
1224
|
+
sameAsCurrent: "New password must be different from current password",
|
|
1225
|
+
wrongCurrent: "Current password is incorrect.",
|
|
1226
|
+
wrongRecoveryKey: "Recovery key did not match this account. Try a different recovery file."
|
|
1227
|
+
};
|
|
1228
|
+
function usePasswordChangeForm({
|
|
1229
|
+
recoveryMode = false,
|
|
1230
|
+
getUnmetRequirement,
|
|
1231
|
+
submit,
|
|
1232
|
+
onClose,
|
|
1233
|
+
onRecoveryComplete,
|
|
1234
|
+
messages
|
|
1235
|
+
}) {
|
|
1236
|
+
const m = useMemo(() => ({ ...DEFAULT_PASSWORD_CHANGE_FORM_MESSAGES, ...messages }), [messages]);
|
|
1237
|
+
const [currentPassword, setCurrentPassword] = useState("");
|
|
1238
|
+
const [newPassword, setNewPassword] = useState("");
|
|
1239
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
1240
|
+
const [error, setError] = useState(null);
|
|
1241
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
1242
|
+
const [result, setResult] = useState(null);
|
|
1243
|
+
const clear = useCallback(() => {
|
|
1244
|
+
setCurrentPassword("");
|
|
1245
|
+
setNewPassword("");
|
|
1246
|
+
setConfirmPassword("");
|
|
1247
|
+
}, []);
|
|
1248
|
+
const isSubmitDisabled = isProcessing || !recoveryMode && !currentPassword || !newPassword || !confirmPassword || getUnmetRequirement(newPassword) !== null || newPassword !== confirmPassword;
|
|
1249
|
+
const onSubmit = useCallback(() => {
|
|
1250
|
+
setError(null);
|
|
1251
|
+
if (!recoveryMode && !currentPassword || !newPassword || !confirmPassword) {
|
|
1252
|
+
return setError(m.required);
|
|
1253
|
+
}
|
|
1254
|
+
if (newPassword !== confirmPassword) return setError(m.mismatch);
|
|
1255
|
+
const unmet = getUnmetRequirement(newPassword);
|
|
1256
|
+
if (unmet !== null) return setError(unmet);
|
|
1257
|
+
if (!recoveryMode && currentPassword === newPassword) return setError(m.sameAsCurrent);
|
|
1258
|
+
setIsProcessing(true);
|
|
1259
|
+
void submit({ newPassword, currentPassword: recoveryMode ? void 0 : currentPassword }).then((outcome) => {
|
|
1260
|
+
clear();
|
|
1261
|
+
if (recoveryMode) {
|
|
1262
|
+
onClose();
|
|
1263
|
+
onRecoveryComplete?.();
|
|
1264
|
+
} else {
|
|
1265
|
+
setResult(outcome);
|
|
1266
|
+
}
|
|
1267
|
+
}).catch((e) => {
|
|
1268
|
+
const message = passwordChangeErrorMessage(e);
|
|
1269
|
+
const wrongCurrent = /invalid signature|current password|401/i.test(message);
|
|
1270
|
+
setError(wrongCurrent ? recoveryMode ? m.wrongRecoveryKey : m.wrongCurrent : message);
|
|
1271
|
+
}).finally(() => setIsProcessing(false));
|
|
1272
|
+
}, [
|
|
1273
|
+
recoveryMode,
|
|
1274
|
+
currentPassword,
|
|
1275
|
+
newPassword,
|
|
1276
|
+
confirmPassword,
|
|
1277
|
+
getUnmetRequirement,
|
|
1278
|
+
submit,
|
|
1279
|
+
clear,
|
|
1280
|
+
onClose,
|
|
1281
|
+
onRecoveryComplete,
|
|
1282
|
+
m
|
|
1283
|
+
]);
|
|
1284
|
+
return {
|
|
1285
|
+
currentPassword,
|
|
1286
|
+
onCurrentPasswordChange: setCurrentPassword,
|
|
1287
|
+
newPassword,
|
|
1288
|
+
onNewPasswordChange: setNewPassword,
|
|
1289
|
+
confirmPassword,
|
|
1290
|
+
onConfirmPasswordChange: setConfirmPassword,
|
|
1291
|
+
error,
|
|
1292
|
+
isProcessing,
|
|
1293
|
+
isSubmitDisabled,
|
|
1294
|
+
onSubmit,
|
|
1295
|
+
result,
|
|
1296
|
+
onCancel: () => {
|
|
1297
|
+
clear();
|
|
1298
|
+
setError(null);
|
|
1299
|
+
setResult(null);
|
|
1300
|
+
onClose();
|
|
1301
|
+
},
|
|
1302
|
+
onDone: () => {
|
|
1303
|
+
setResult(null);
|
|
1304
|
+
onClose();
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
function toNotificationPreferences(stored, keys) {
|
|
1309
|
+
const checked = Object.fromEntries(keys.map((key) => [key, stored?.[key] ?? true]));
|
|
1310
|
+
return {
|
|
1311
|
+
masterChecked: keys.some((key) => checked[key]),
|
|
1312
|
+
checked,
|
|
1313
|
+
masterPatch: (value) => Object.fromEntries(keys.map((key) => [key, value])),
|
|
1314
|
+
categoryPatch: (key, value) => ({ [key]: value })
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
function useUserSettings(options) {
|
|
1318
|
+
const arbi = useArbi();
|
|
1319
|
+
return useQuery({
|
|
1320
|
+
queryKey: arbiQueryKeys.userSettings(),
|
|
1321
|
+
queryFn: () => arbi.settings.get(),
|
|
1322
|
+
enabled: (options?.enabled ?? true) && arbi.isLoggedIn
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
function useNotificationPreferences(keys, options) {
|
|
1326
|
+
const arbi = useArbi();
|
|
1327
|
+
const qc = useQueryClient();
|
|
1328
|
+
const settings = useUserSettings(options);
|
|
1329
|
+
const stored = settings.data?.email_notifications;
|
|
1330
|
+
const save = useMutation({
|
|
1331
|
+
mutationFn: (patch) => arbi.settings.update({ email_notifications: patch }),
|
|
1332
|
+
onMutate: async (patch) => {
|
|
1333
|
+
await qc.cancelQueries({ queryKey: arbiQueryKeys.userSettings() });
|
|
1334
|
+
const previous = qc.getQueryData(arbiQueryKeys.userSettings());
|
|
1335
|
+
qc.setQueryData(
|
|
1336
|
+
arbiQueryKeys.userSettings(),
|
|
1337
|
+
(old) => old ? { ...old, email_notifications: { ...old.email_notifications, ...patch } } : old
|
|
1338
|
+
);
|
|
1339
|
+
return { previous };
|
|
1340
|
+
},
|
|
1341
|
+
onError: (_err, _patch, context) => {
|
|
1342
|
+
qc.setQueryData(arbiQueryKeys.userSettings(), context?.previous);
|
|
1343
|
+
},
|
|
1344
|
+
onSettled: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.userSettings() })
|
|
1345
|
+
});
|
|
1346
|
+
const model = useMemo(() => toNotificationPreferences(stored, keys), [stored, keys]);
|
|
1347
|
+
const setAll = useCallback(
|
|
1348
|
+
(value) => save.mutate(model.masterPatch(value)),
|
|
1349
|
+
[save, model]
|
|
1350
|
+
);
|
|
1351
|
+
const setCategory = useCallback(
|
|
1352
|
+
(key, value) => save.mutate(model.categoryPatch(key, value)),
|
|
1353
|
+
[save, model]
|
|
1354
|
+
);
|
|
1355
|
+
return {
|
|
1356
|
+
...model,
|
|
1357
|
+
isLoading: settings.isLoading,
|
|
1358
|
+
isSaving: save.isPending,
|
|
1359
|
+
/** The master switch handler: every category on or off. */
|
|
1360
|
+
setAll,
|
|
1361
|
+
/** One category's handler. */
|
|
1362
|
+
setCategory
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
function useTerminateSession() {
|
|
1366
|
+
const arbi = useArbi();
|
|
1367
|
+
const qc = useQueryClient();
|
|
1368
|
+
return useMutation({
|
|
1369
|
+
mutationFn: (sessionId) => arbi.sessions.terminate(sessionId),
|
|
1370
|
+
onSuccess: () => qc.invalidateQueries({ queryKey: arbiQueryKeys.sessions() })
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
function useLogoutAllSessions() {
|
|
1374
|
+
const arbi = useArbi();
|
|
1375
|
+
const qc = useQueryClient();
|
|
1376
|
+
return useMutation({
|
|
1377
|
+
mutationFn: () => arbi.sessions.logoutAll(),
|
|
1378
|
+
onSuccess: () => qc.clear()
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
function useCurrentSessionId() {
|
|
1382
|
+
return useArbi().sessions.currentId();
|
|
1383
|
+
}
|
|
1384
|
+
function parseDeleteAccountBlockers(error) {
|
|
1385
|
+
const body = error?.apiError ?? error;
|
|
1386
|
+
const detail = body?.detail;
|
|
1387
|
+
if (detail === "active_subscription") return [{ type: "active_subscription" }];
|
|
1388
|
+
if (detail && typeof detail === "object") {
|
|
1389
|
+
const d = detail;
|
|
1390
|
+
if (d.reason === "workspace_members" && Array.isArray(d.workspaces)) {
|
|
1391
|
+
return [{ type: "workspace_members", workspaces: d.workspaces.map(String) }];
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
return [];
|
|
1395
|
+
}
|
|
1396
|
+
function useDeleteAccount() {
|
|
1397
|
+
const arbi = useArbi();
|
|
1398
|
+
return useMutation({ mutationFn: () => arbi.account.requestDeletion() });
|
|
1399
|
+
}
|
|
1400
|
+
function useDeleteAccountFlow({
|
|
1401
|
+
userEmail,
|
|
1402
|
+
remove,
|
|
1403
|
+
onClose,
|
|
1404
|
+
onDeleted,
|
|
1405
|
+
onError
|
|
1406
|
+
}) {
|
|
1407
|
+
const [step, setStep] = useState("warning");
|
|
1408
|
+
const [confirmEmail, setConfirmEmail] = useState("");
|
|
1409
|
+
const [blockers, setBlockers] = useState([]);
|
|
1410
|
+
const [isDeleting, setIsDeleting] = useState(false);
|
|
1411
|
+
const close = useCallback(() => {
|
|
1412
|
+
setStep("warning");
|
|
1413
|
+
setConfirmEmail("");
|
|
1414
|
+
setBlockers([]);
|
|
1415
|
+
onClose();
|
|
1416
|
+
}, [onClose]);
|
|
1417
|
+
const onSubmit = useCallback(() => {
|
|
1418
|
+
if (confirmEmail.toLowerCase() !== userEmail.toLowerCase()) return;
|
|
1419
|
+
setIsDeleting(true);
|
|
1420
|
+
void Promise.resolve().then(remove).then(() => {
|
|
1421
|
+
close();
|
|
1422
|
+
onDeleted();
|
|
1423
|
+
}).catch((error) => {
|
|
1424
|
+
const found = parseDeleteAccountBlockers(error);
|
|
1425
|
+
if (found.length > 0) {
|
|
1426
|
+
setBlockers(found);
|
|
1427
|
+
setStep("warning");
|
|
1428
|
+
} else {
|
|
1429
|
+
onError?.(error);
|
|
1430
|
+
}
|
|
1431
|
+
}).finally(() => setIsDeleting(false));
|
|
1432
|
+
}, [confirmEmail, userEmail, remove, close, onDeleted, onError]);
|
|
1433
|
+
return {
|
|
1434
|
+
step,
|
|
1435
|
+
blockers,
|
|
1436
|
+
confirmEmail,
|
|
1437
|
+
onConfirmEmailChange: setConfirmEmail,
|
|
1438
|
+
onContinue: () => setStep("confirm"),
|
|
1439
|
+
onBack: () => setStep("warning"),
|
|
1440
|
+
isDeleting,
|
|
1441
|
+
onSubmit,
|
|
1442
|
+
onClose: close
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1110
1445
|
function useWorkspaceDocs(workspaceId) {
|
|
1111
1446
|
const { data: docs = [], isLoading, isError } = useDocuments(workspaceId);
|
|
1112
1447
|
const docIds = useMemo(
|
|
@@ -5332,6 +5667,6 @@ function hasVideoTrack(blob) {
|
|
|
5332
5667
|
});
|
|
5333
5668
|
}
|
|
5334
5669
|
|
|
5335
|
-
export { ActivityFeed, AiActionCard, AiAnswer, AppleIcon, ArbiBotIcon, ArbiIcon, ArbiWebSocketProvider, ArtifactCanvas, ChatBubble, CitationRenderer, ClaudeIcon, CommandPalette, CommandPaletteProvider, ConversationList, DEFAULT_ASPECT_OPTIONS,
|
|
5670
|
+
export { ActivityFeed, AiActionCard, AiAnswer, AppleIcon, ArbiBotIcon, ArbiIcon, ArbiWebSocketProvider, ArtifactCanvas, ChatBubble, CitationRenderer, ClaudeIcon, CommandPalette, CommandPaletteProvider, ConversationList, DEFAULT_ASPECT_OPTIONS, DEFAULT_PASSWORD_CHANGE_FORM_MESSAGES, DEFAULT_START_BY_EMAIL_LABELS, DateSeparator, DirectMessages, DmAvatar, DmComposer, DocIcon, DocQaPanel, DocSearch, DocumentCardMenu, DocumentGallery, DocumentReview, DocumentTable, DraftTitleControls, FileIcon, FireworksIcon, GeminiIcon, GitHubIcon, GoogleIcon, HtmlIcon, ImageCropModal, ImageCropper, LinkedInIcon, MAX_AVATAR_FILE_BYTES, MessageArtifactCard, MessageBubble, MessageThread, OpenAIIcon, PhotoCapture, ProviderIcon, RUN_WINDOW_MS, SemanticSearch, StartByEmail, TxtIcon, TypingIndicator, VideoCapture, VoiceNoteRecorder, XlsIcon, annotateThread, captureFrameAsBlob, cropImage, dayKey, describeActivity, getNotificationTypeMeta, getWorkspaceActionText, getWorkspaceKind, getWorkspaceSentPhrase, hasVideoTrack, isWorkspaceNotificationType, parseActivityContent, parseDeleteAccountBlockers, pickRecentWorkspaces, redlineStats, resolveActiveWorkspace, textToArtifact, titleFromQuestion, toChatCitations, toNotificationPreferences, toProfileView, toRedlineMarkdown, toShellWorkspace, useAddContacts, useAgentConfig, useAgentModels, useAgentWorkspaces, useAiTask, useArbiChat, useArbiConnected, useArbiDocumentSync, useArbiShellWorkspaces, useArbiUiStore, useArbiWebSocket, useArbiWsContext, useArbiWsMessage, useArbiWsStatus, useArbiWsStore, useArbiWsTask, useArbiWsTasks, useAvatarCrop, useCameraStream, useCommandPalette, useConfirmEmailChange, useContacts, useCreateAgent, useCreateTask, useCurrentSessionId, useDeleteAccount, useDeleteAccountFlow, useDeleteTask, useDirectMessages, useEmailChange, useGrantAgentAccess, useLogoutAllSessions, useNameEditor, useNotificationPreferences, usePasswordChange, usePasswordChangeForm, usePendingContacts, useProfile, useRemoveContacts, useRequestEmailChange, useRevokeAgentAccess, useRunTask, useSaveAgentConfig, useSemanticSearch, useShellWorkspaces, useSkills, useTaskRuns, useTerminateSession, useUpdateProfile, useUpdateTask, useUserSettings, useVideoRecorder, useWorkspaceDocs, userDisplayName, userInitials };
|
|
5336
5671
|
//# sourceMappingURL=index.js.map
|
|
5337
5672
|
//# sourceMappingURL=index.js.map
|