@iota-uz/sdk 0.4.23 → 0.4.25
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/applet/host.cjs +97 -10
- package/dist/applet/host.cjs.map +1 -1
- package/dist/applet/host.d.cts +9 -1
- package/dist/applet/host.d.ts +9 -1
- package/dist/applet/host.mjs +97 -10
- package/dist/applet/host.mjs.map +1 -1
- package/dist/bichat/index.cjs +1388 -351
- package/dist/bichat/index.cjs.map +1 -1
- package/dist/bichat/index.d.cts +1082 -837
- package/dist/bichat/index.d.ts +1082 -837
- package/dist/bichat/index.mjs +1387 -354
- package/dist/bichat/index.mjs.map +1 -1
- package/dist/index.cjs +97 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +97 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/tailwind/compiled.css +1 -1
package/dist/bichat/index.cjs
CHANGED
|
@@ -2454,6 +2454,33 @@ var ChatMachine = class {
|
|
|
2454
2454
|
});
|
|
2455
2455
|
}
|
|
2456
2456
|
}
|
|
2457
|
+
async _resumeAcceptedRunOrPoll(sessionId, runId) {
|
|
2458
|
+
setRunMarker(sessionId, runId);
|
|
2459
|
+
try {
|
|
2460
|
+
await this._runResumeStream(sessionId, runId);
|
|
2461
|
+
} catch (err) {
|
|
2462
|
+
if (this.disposed) {
|
|
2463
|
+
return;
|
|
2464
|
+
}
|
|
2465
|
+
console.warn("[ChatMachine] resumeStream failed, switching to status polling fallback:", err);
|
|
2466
|
+
const getStreamStatus2 = this.dataSource.getStreamStatus;
|
|
2467
|
+
const status = getStreamStatus2 ? await getStreamStatus2(sessionId).catch(() => null) : null;
|
|
2468
|
+
if (!status?.active) {
|
|
2469
|
+
clearRunMarker(sessionId);
|
|
2470
|
+
await this._syncSessionFromServer(sessionId, true).catch(() => {
|
|
2471
|
+
});
|
|
2472
|
+
this._updateMessaging({ generationInProgress: false });
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
setRunMarker(sessionId, status.runId ?? runId);
|
|
2476
|
+
this._updateMessaging({
|
|
2477
|
+
isStreaming: false,
|
|
2478
|
+
loading: false,
|
|
2479
|
+
generationInProgress: true
|
|
2480
|
+
});
|
|
2481
|
+
this._startPassivePolling(sessionId);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2457
2484
|
// =====================================================================
|
|
2458
2485
|
// Private — actions
|
|
2459
2486
|
// =====================================================================
|
|
@@ -2572,20 +2599,28 @@ var ChatMachine = class {
|
|
|
2572
2599
|
streamingContent: ""
|
|
2573
2600
|
});
|
|
2574
2601
|
try {
|
|
2575
|
-
const
|
|
2576
|
-
|
|
2602
|
+
const accepted = await this.dataSource.compactSessionHistory(curSessionId);
|
|
2603
|
+
if (!accepted.runId) {
|
|
2604
|
+
throw new Error("Async compaction run metadata is missing");
|
|
2605
|
+
}
|
|
2577
2606
|
this._updateMessaging({
|
|
2578
|
-
turns: applyTurnLifecycleForPendingQuestion(
|
|
2607
|
+
turns: applyTurnLifecycleForPendingQuestion(
|
|
2608
|
+
[createCompactedSystemTurn(curSessionId, "Compacting conversation history...")],
|
|
2609
|
+
null
|
|
2610
|
+
),
|
|
2579
2611
|
pendingQuestion: null
|
|
2580
2612
|
});
|
|
2581
|
-
|
|
2582
|
-
if (
|
|
2583
|
-
this.
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2613
|
+
await this._resumeAcceptedRunOrPoll(curSessionId, accepted.runId);
|
|
2614
|
+
if (!this.state.messaging.generationInProgress) {
|
|
2615
|
+
const result = await this.dataSource.fetchSession(curSessionId);
|
|
2616
|
+
if (result) {
|
|
2617
|
+
this._updateSession({ session: result.session });
|
|
2618
|
+
this._setTurnsFromFetch(result.turns, result.pendingQuestion || null);
|
|
2619
|
+
} else {
|
|
2620
|
+
this._setTurnsFromFetch([], null);
|
|
2621
|
+
}
|
|
2622
|
+
this._updateMessaging({ codeOutputs: [] });
|
|
2587
2623
|
}
|
|
2588
|
-
this._updateMessaging({ codeOutputs: [] });
|
|
2589
2624
|
} catch (err) {
|
|
2590
2625
|
const normalized = normalizeRPCError(err, "Failed to compact session history");
|
|
2591
2626
|
this._updateInput({ inputError: normalized.userMessage });
|
|
@@ -2750,8 +2785,6 @@ var ChatMachine = class {
|
|
|
2750
2785
|
this._notifySessionsUpdated("session_created", targetSessionId);
|
|
2751
2786
|
if (this.onSessionCreated) {
|
|
2752
2787
|
this.onSessionCreated(targetSessionId);
|
|
2753
|
-
} else {
|
|
2754
|
-
this.dataSource.navigateToSession?.(targetSessionId);
|
|
2755
2788
|
}
|
|
2756
2789
|
}
|
|
2757
2790
|
this._clearStreamError();
|
|
@@ -3037,9 +3070,24 @@ var ChatMachine = class {
|
|
|
3037
3070
|
return;
|
|
3038
3071
|
}
|
|
3039
3072
|
if (result.success) {
|
|
3073
|
+
this._updateMessaging({
|
|
3074
|
+
pendingQuestion: null,
|
|
3075
|
+
turns: applyTurnLifecycleForPendingQuestion(this.state.messaging.turns, null)
|
|
3076
|
+
});
|
|
3040
3077
|
if (result.data) {
|
|
3041
|
-
this.
|
|
3042
|
-
this.
|
|
3078
|
+
await this._resumeAcceptedRunOrPoll(curSessionId, result.data.runId);
|
|
3079
|
+
if (!this.state.messaging.generationInProgress) {
|
|
3080
|
+
const fetchResult = await this.dataSource.fetchSession(curSessionId);
|
|
3081
|
+
if (this.disposed) {
|
|
3082
|
+
return;
|
|
3083
|
+
}
|
|
3084
|
+
if (fetchResult) {
|
|
3085
|
+
this._updateSession({ session: fetchResult.session });
|
|
3086
|
+
this._setTurnsFromFetch(fetchResult.turns, fetchResult.pendingQuestion || null);
|
|
3087
|
+
} else {
|
|
3088
|
+
this._updateSession({ error: "Failed to load updated session", errorRetryable: true });
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3043
3091
|
} else if (curSessionId !== "new") {
|
|
3044
3092
|
const fetchResult = await this.dataSource.fetchSession(curSessionId);
|
|
3045
3093
|
if (this.disposed) {
|
|
@@ -3083,7 +3131,9 @@ var ChatMachine = class {
|
|
|
3083
3131
|
pendingQuestion: null,
|
|
3084
3132
|
turns: applyTurnLifecycleForPendingQuestion(this.state.messaging.turns, null)
|
|
3085
3133
|
});
|
|
3086
|
-
if (
|
|
3134
|
+
if (result.data) {
|
|
3135
|
+
await this._resumeAcceptedRunOrPoll(curSessionId, result.data.runId);
|
|
3136
|
+
} else if (curSessionId !== "new") {
|
|
3087
3137
|
const fetchResult = await this.dataSource.fetchSession(curSessionId);
|
|
3088
3138
|
if (this.disposed) {
|
|
3089
3139
|
return;
|
|
@@ -3303,12 +3353,151 @@ function useBranding() {
|
|
|
3303
3353
|
}, [context.extensions?.branding, t]);
|
|
3304
3354
|
return branding;
|
|
3305
3355
|
}
|
|
3306
|
-
function
|
|
3356
|
+
function hashString(str) {
|
|
3357
|
+
let hash = 0;
|
|
3358
|
+
for (let i = 0; i < str.length; i++) {
|
|
3359
|
+
const char = str.charCodeAt(i);
|
|
3360
|
+
hash = (hash << 5) - hash + char;
|
|
3361
|
+
hash = hash & hash;
|
|
3362
|
+
}
|
|
3363
|
+
return Math.abs(hash);
|
|
3364
|
+
}
|
|
3365
|
+
var colorPalette = [
|
|
3366
|
+
{ bg: "bg-blue-500", text: "text-white" },
|
|
3367
|
+
{ bg: "bg-green-500", text: "text-white" },
|
|
3368
|
+
{ bg: "bg-purple-500", text: "text-white" },
|
|
3369
|
+
{ bg: "bg-pink-500", text: "text-white" },
|
|
3370
|
+
{ bg: "bg-indigo-500", text: "text-white" },
|
|
3371
|
+
{ bg: "bg-teal-500", text: "text-white" },
|
|
3372
|
+
{ bg: "bg-orange-500", text: "text-white" },
|
|
3373
|
+
{ bg: "bg-cyan-500", text: "text-white" },
|
|
3374
|
+
{ bg: "bg-amber-500", text: "text-white" },
|
|
3375
|
+
{ bg: "bg-lime-500", text: "text-white" }
|
|
3376
|
+
];
|
|
3377
|
+
var sizeClasses = {
|
|
3378
|
+
xs: "w-6 h-6 text-[10px]",
|
|
3379
|
+
sm: "w-8 h-8 text-xs",
|
|
3380
|
+
md: "w-10 h-10 text-sm",
|
|
3381
|
+
lg: "w-12 h-12 text-base"
|
|
3382
|
+
};
|
|
3383
|
+
function UserAvatar({
|
|
3384
|
+
firstName,
|
|
3385
|
+
lastName,
|
|
3386
|
+
initials: providedInitials,
|
|
3387
|
+
size = "md",
|
|
3388
|
+
className = ""
|
|
3389
|
+
}) {
|
|
3390
|
+
const derivedInitials = (() => {
|
|
3391
|
+
const firstChar = firstName?.trim()?.charAt(0) || "";
|
|
3392
|
+
const lastChar = lastName?.trim()?.charAt(0) || "";
|
|
3393
|
+
const combined = `${firstChar}${lastChar}`.trim();
|
|
3394
|
+
return combined || "U";
|
|
3395
|
+
})();
|
|
3396
|
+
const initials = (providedInitials?.trim() || derivedInitials).toUpperCase();
|
|
3397
|
+
const fullName = `${firstName}${lastName}`;
|
|
3398
|
+
const colorIndex = hashString(fullName) % colorPalette.length;
|
|
3399
|
+
const colors = colorPalette[colorIndex];
|
|
3400
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3401
|
+
"div",
|
|
3402
|
+
{
|
|
3403
|
+
className: `
|
|
3404
|
+
${sizeClasses[size]}
|
|
3405
|
+
${colors.bg}
|
|
3406
|
+
${colors.text}
|
|
3407
|
+
${className}
|
|
3408
|
+
rounded-full
|
|
3409
|
+
flex
|
|
3410
|
+
items-center
|
|
3411
|
+
justify-center
|
|
3412
|
+
font-semibold
|
|
3413
|
+
flex-shrink-0
|
|
3414
|
+
select-none
|
|
3415
|
+
`,
|
|
3416
|
+
"aria-label": `${firstName} ${lastName}`,
|
|
3417
|
+
title: `${firstName} ${lastName}`,
|
|
3418
|
+
children: initials
|
|
3419
|
+
}
|
|
3420
|
+
);
|
|
3421
|
+
}
|
|
3422
|
+
var MemoizedUserAvatar = React.memo(UserAvatar);
|
|
3423
|
+
MemoizedUserAvatar.displayName = "UserAvatar";
|
|
3424
|
+
var overlapClasses = {
|
|
3425
|
+
xs: "-ml-1.5",
|
|
3426
|
+
sm: "-ml-2"
|
|
3427
|
+
};
|
|
3428
|
+
var badgeSizeClasses = {
|
|
3429
|
+
xs: "w-6 h-6 text-[10px]",
|
|
3430
|
+
sm: "w-8 h-8 text-xs"
|
|
3431
|
+
};
|
|
3432
|
+
function AvatarStackInner({
|
|
3433
|
+
users,
|
|
3434
|
+
max = 3,
|
|
3435
|
+
size = "sm",
|
|
3436
|
+
onClick,
|
|
3437
|
+
className = ""
|
|
3438
|
+
}) {
|
|
3439
|
+
const visible = users.slice(0, max);
|
|
3440
|
+
const overflow = users.length - max;
|
|
3441
|
+
const interactive = typeof onClick === "function";
|
|
3442
|
+
const overlap = overlapClasses[size];
|
|
3443
|
+
const badgeSize = badgeSizeClasses[size];
|
|
3444
|
+
const handleKeyDown = (e) => {
|
|
3445
|
+
if (interactive && (e.key === "Enter" || e.key === " ")) {
|
|
3446
|
+
e.preventDefault();
|
|
3447
|
+
onClick();
|
|
3448
|
+
}
|
|
3449
|
+
};
|
|
3450
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3451
|
+
"div",
|
|
3452
|
+
{
|
|
3453
|
+
className: `inline-flex items-center ${interactive ? "cursor-pointer transition-opacity hover:opacity-80" : ""} ${className}`,
|
|
3454
|
+
onClick: interactive ? onClick : void 0,
|
|
3455
|
+
onKeyDown: interactive ? handleKeyDown : void 0,
|
|
3456
|
+
role: interactive ? "button" : void 0,
|
|
3457
|
+
tabIndex: interactive ? 0 : void 0,
|
|
3458
|
+
"aria-label": interactive ? `${users.length} members` : void 0,
|
|
3459
|
+
children: [
|
|
3460
|
+
visible.map((user, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3461
|
+
"div",
|
|
3462
|
+
{
|
|
3463
|
+
className: `${i > 0 ? overlap : ""} ring-2 ring-white dark:ring-gray-900 rounded-full`,
|
|
3464
|
+
style: { zIndex: visible.length - i },
|
|
3465
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3466
|
+
MemoizedUserAvatar,
|
|
3467
|
+
{
|
|
3468
|
+
firstName: user.firstName,
|
|
3469
|
+
lastName: user.lastName,
|
|
3470
|
+
initials: user.initials,
|
|
3471
|
+
size
|
|
3472
|
+
}
|
|
3473
|
+
)
|
|
3474
|
+
},
|
|
3475
|
+
`${user.firstName}-${user.lastName}-${i}`
|
|
3476
|
+
)),
|
|
3477
|
+
overflow > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3478
|
+
"div",
|
|
3479
|
+
{
|
|
3480
|
+
className: `${overlap} ${badgeSize} rounded-full bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300 font-medium flex items-center justify-center flex-shrink-0 ring-2 ring-white dark:ring-gray-900`,
|
|
3481
|
+
style: { zIndex: 0 },
|
|
3482
|
+
children: [
|
|
3483
|
+
"+",
|
|
3484
|
+
overflow
|
|
3485
|
+
]
|
|
3486
|
+
}
|
|
3487
|
+
)
|
|
3488
|
+
]
|
|
3489
|
+
}
|
|
3490
|
+
);
|
|
3491
|
+
}
|
|
3492
|
+
var AvatarStack = React.memo(AvatarStackInner);
|
|
3493
|
+
AvatarStack.displayName = "AvatarStack";
|
|
3494
|
+
function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot, members, onMembersClick }) {
|
|
3307
3495
|
const { t } = useTranslation();
|
|
3308
3496
|
const branding = useBranding();
|
|
3309
3497
|
const BackButton = onBack ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3310
3498
|
"button",
|
|
3311
3499
|
{
|
|
3500
|
+
type: "button",
|
|
3312
3501
|
onClick: onBack,
|
|
3313
3502
|
className: "cursor-pointer p-2 hover:bg-gray-100 dark:hover:bg-gray-700 active:bg-gray-200 dark:active:bg-gray-600 rounded-lg transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
|
|
3314
3503
|
"aria-label": t("BiChat.Chat.GoBack"),
|
|
@@ -3327,23 +3516,42 @@ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
|
|
|
3327
3516
|
] }) });
|
|
3328
3517
|
}
|
|
3329
3518
|
const resolvedSessionTitle = session.title?.trim() || t("BiChat.Chat.NewChat");
|
|
3519
|
+
const isGroupSession = Boolean(session.isGroup || session.memberCount && session.memberCount > 1);
|
|
3520
|
+
const memberCount = session.memberCount ?? 0;
|
|
3521
|
+
const stackUsers = members && members.length > 0 ? members : [];
|
|
3330
3522
|
return /* @__PURE__ */ jsxRuntime.jsx("header", { className: "bichat-header border-b border-gray-200 dark:border-gray-700 px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
3331
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
3523
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
3332
3524
|
BackButton,
|
|
3333
3525
|
Logo,
|
|
3334
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3526
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
3527
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
3528
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-[var(--bichat-text)] truncate", children: resolvedSessionTitle }),
|
|
3529
|
+
session.pinned && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3530
|
+
"svg",
|
|
3531
|
+
{
|
|
3532
|
+
className: "w-4 h-4 text-[var(--bichat-primary)] flex-shrink-0",
|
|
3533
|
+
fill: "currentColor",
|
|
3534
|
+
viewBox: "0 0 20 20",
|
|
3535
|
+
role: "img",
|
|
3536
|
+
"aria-label": t("BiChat.Chat.Pinned"),
|
|
3537
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 2a1 1 0 011 1v1.323l3.954 1.582 1.599-.8a1 1 0 01.894 1.79l-1.233.616 1.738 5.42a1 1 0 01-.285 1.05A3.989 3.989 0 0115 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.715-5.349L11 6.477V16h2a1 1 0 110 2H7a1 1 0 110-2h2V6.477L6.237 7.582l1.715 5.349a1 1 0 01-.285 1.05A3.989 3.989 0 015 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.738-5.42-1.233-.617a1 1 0 01.894-1.788l1.599.799L9 4.323V3a1 1 0 011-1z" })
|
|
3538
|
+
}
|
|
3539
|
+
),
|
|
3540
|
+
isGroupSession && stackUsers.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3541
|
+
AvatarStack,
|
|
3542
|
+
{
|
|
3543
|
+
users: stackUsers,
|
|
3544
|
+
max: 3,
|
|
3545
|
+
size: "xs",
|
|
3546
|
+
onClick: onMembersClick,
|
|
3547
|
+
className: "flex-shrink-0"
|
|
3548
|
+
}
|
|
3549
|
+
)
|
|
3550
|
+
] }),
|
|
3551
|
+
isGroupSession && memberCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-600 dark:text-gray-400 mt-0.5", children: memberCount === 1 ? t("BiChat.Chat.OneMember") : t("BiChat.Chat.MemberCount").replace("{{count}}", String(memberCount)) })
|
|
3552
|
+
] })
|
|
3345
3553
|
] }),
|
|
3346
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3554
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
|
|
3347
3555
|
readOnly && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-200 rounded", children: t("BiChat.Chat.ReadOnly") }),
|
|
3348
3556
|
session.status === "archived" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded", children: t("BiChat.Chat.Archived") }),
|
|
3349
3557
|
actionsSlot
|
|
@@ -4218,6 +4426,7 @@ function UserMessage({
|
|
|
4218
4426
|
turn,
|
|
4219
4427
|
turnId,
|
|
4220
4428
|
initials = "U",
|
|
4429
|
+
authorName,
|
|
4221
4430
|
slots,
|
|
4222
4431
|
classNames: classNameOverrides,
|
|
4223
4432
|
onCopy,
|
|
@@ -4425,6 +4634,16 @@ function UserMessage({
|
|
|
4425
4634
|
};
|
|
4426
4635
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classes.root, children: [
|
|
4427
4636
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: classes.wrapper, children: [
|
|
4637
|
+
authorName && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4638
|
+
"span",
|
|
4639
|
+
{
|
|
4640
|
+
id: `${turn.id}-author`,
|
|
4641
|
+
role: "note",
|
|
4642
|
+
"aria-label": authorName,
|
|
4643
|
+
className: "mb-1 px-1 text-[11px] text-right text-gray-500 dark:text-gray-400",
|
|
4644
|
+
children: authorName
|
|
4645
|
+
}
|
|
4646
|
+
),
|
|
4428
4647
|
normalizedAttachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: classes.attachments, children: renderSlot(
|
|
4429
4648
|
slots?.attachments,
|
|
4430
4649
|
attachmentsSlotProps,
|
|
@@ -4436,20 +4655,28 @@ function UserMessage({
|
|
|
4436
4655
|
}
|
|
4437
4656
|
)
|
|
4438
4657
|
) }),
|
|
4439
|
-
turn.content && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4440
|
-
|
|
4658
|
+
turn.content && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4659
|
+
"div",
|
|
4441
4660
|
{
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4661
|
+
ref: bubbleRef,
|
|
4662
|
+
className: classes.bubble,
|
|
4663
|
+
"aria-describedby": authorName ? `${turn.id}-author` : void 0,
|
|
4664
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: classes.content, children: isEditing ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4665
|
+
EditForm,
|
|
4666
|
+
{
|
|
4667
|
+
draftContent,
|
|
4668
|
+
onDraftChange: handleDraftChange,
|
|
4669
|
+
onSave: handleEditSave,
|
|
4670
|
+
onCancel: handleEditCancel,
|
|
4671
|
+
onKeyDown: handleEditKeyDown,
|
|
4672
|
+
textareaRef: editTextareaRef,
|
|
4673
|
+
disabled: false,
|
|
4674
|
+
originalContent: turn.content,
|
|
4675
|
+
t
|
|
4676
|
+
}
|
|
4677
|
+
) : renderSlot(slots?.content, contentSlotProps, turn.content) })
|
|
4451
4678
|
}
|
|
4452
|
-
)
|
|
4679
|
+
),
|
|
4453
4680
|
!hideActions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${classes.actions} ${isCopied ? "opacity-100" : ""}`, children: renderSlot(
|
|
4454
4681
|
slots?.actions,
|
|
4455
4682
|
actionsSlotProps,
|
|
@@ -4498,19 +4725,25 @@ function UserTurnView({
|
|
|
4498
4725
|
turn,
|
|
4499
4726
|
slots,
|
|
4500
4727
|
classNames,
|
|
4501
|
-
initials
|
|
4728
|
+
initials,
|
|
4502
4729
|
hideAvatar,
|
|
4503
4730
|
hideActions,
|
|
4504
4731
|
hideTimestamp,
|
|
4505
|
-
allowEdit
|
|
4732
|
+
allowEdit,
|
|
4733
|
+
showAuthorName = false
|
|
4506
4734
|
}) {
|
|
4507
4735
|
const { handleEdit, handleCopy } = useChatMessaging();
|
|
4736
|
+
const author = turn.userTurn.author;
|
|
4737
|
+
const fullName = [author?.firstName || "", author?.lastName || ""].join(" ").trim();
|
|
4738
|
+
const authorName = showAuthorName && fullName.length > 0 ? fullName : void 0;
|
|
4739
|
+
const resolvedInitials = initials ?? author?.initials ?? "U";
|
|
4508
4740
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4509
4741
|
UserMessage,
|
|
4510
4742
|
{
|
|
4511
4743
|
turn: turn.userTurn,
|
|
4512
4744
|
turnId: turn.id,
|
|
4513
|
-
initials,
|
|
4745
|
+
initials: resolvedInitials,
|
|
4746
|
+
authorName,
|
|
4514
4747
|
slots,
|
|
4515
4748
|
classNames,
|
|
4516
4749
|
onCopy: handleCopy,
|
|
@@ -8505,7 +8738,7 @@ function StreamingBubble({ content, normalizedContent }) {
|
|
|
8505
8738
|
}
|
|
8506
8739
|
function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readOnly }) {
|
|
8507
8740
|
const { t } = useTranslation();
|
|
8508
|
-
const { currentSessionId, fetching } = useChatSession();
|
|
8741
|
+
const { session, currentSessionId, fetching } = useChatSession();
|
|
8509
8742
|
const {
|
|
8510
8743
|
turns,
|
|
8511
8744
|
streamingContent,
|
|
@@ -8520,6 +8753,7 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
|
|
|
8520
8753
|
() => streamingContent ? normalizeStreamingMarkdown(streamingContent) : "",
|
|
8521
8754
|
[streamingContent]
|
|
8522
8755
|
);
|
|
8756
|
+
const showAuthorNames = Boolean(session?.isGroup);
|
|
8523
8757
|
const showEphemeral = showActivityTrace || showTypingIndicator;
|
|
8524
8758
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 min-h-0", children: [
|
|
8525
8759
|
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "h-full overflow-y-auto overflow-x-hidden px-4 py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto space-y-6", children: [
|
|
@@ -8529,6 +8763,10 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
|
|
|
8529
8763
|
const prevDate = index > 0 ? new Date(turns[index - 1].createdAt) : null;
|
|
8530
8764
|
const showDateSeparator = !!prevDate && !dateFns.isSameDay(turnDate, prevDate);
|
|
8531
8765
|
const isLast = index === turns.length - 1;
|
|
8766
|
+
const userTurnProps = {
|
|
8767
|
+
allowEdit: readOnly ? false : isLast,
|
|
8768
|
+
showAuthorName: showAuthorNames
|
|
8769
|
+
};
|
|
8532
8770
|
return /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
|
|
8533
8771
|
showDateSeparator && /* @__PURE__ */ jsxRuntime.jsx(DateSeparator, { date: turnDate }),
|
|
8534
8772
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -8538,7 +8776,7 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
|
|
|
8538
8776
|
isLastTurn: isLast,
|
|
8539
8777
|
renderUserTurn,
|
|
8540
8778
|
renderAssistantTurn,
|
|
8541
|
-
userTurnProps
|
|
8779
|
+
userTurnProps,
|
|
8542
8780
|
assistantTurnProps: readOnly ? { allowRegenerate: false } : void 0
|
|
8543
8781
|
}
|
|
8544
8782
|
)
|
|
@@ -10744,37 +10982,655 @@ function SessionArtifactsPanel({
|
|
|
10744
10982
|
}
|
|
10745
10983
|
);
|
|
10746
10984
|
}
|
|
10985
|
+
var DialogContext = React.createContext(null);
|
|
10986
|
+
var FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
10987
|
+
function InlineDialog({ open, onClose, className, children }) {
|
|
10988
|
+
const containerRef = React.useRef(null);
|
|
10989
|
+
const previousFocusRef = React.useRef(null);
|
|
10990
|
+
React.useEffect(() => {
|
|
10991
|
+
if (!open) {
|
|
10992
|
+
return;
|
|
10993
|
+
}
|
|
10994
|
+
previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
10995
|
+
const container = containerRef.current;
|
|
10996
|
+
if (!container) {
|
|
10997
|
+
return;
|
|
10998
|
+
}
|
|
10999
|
+
const getFocusable = () => Array.from(
|
|
11000
|
+
container.querySelectorAll(FOCUSABLE_SELECTOR)
|
|
11001
|
+
);
|
|
11002
|
+
const handler = (e) => {
|
|
11003
|
+
if (e.key === "Escape") {
|
|
11004
|
+
onClose();
|
|
11005
|
+
return;
|
|
11006
|
+
}
|
|
11007
|
+
if (e.key !== "Tab") {
|
|
11008
|
+
return;
|
|
11009
|
+
}
|
|
11010
|
+
const focusable = getFocusable();
|
|
11011
|
+
if (focusable.length === 0) {
|
|
11012
|
+
e.preventDefault();
|
|
11013
|
+
container.focus();
|
|
11014
|
+
return;
|
|
11015
|
+
}
|
|
11016
|
+
const first = focusable[0];
|
|
11017
|
+
const last = focusable[focusable.length - 1];
|
|
11018
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
11019
|
+
e.preventDefault();
|
|
11020
|
+
last.focus();
|
|
11021
|
+
} else if (!e.shiftKey && document.activeElement === last) {
|
|
11022
|
+
e.preventDefault();
|
|
11023
|
+
first.focus();
|
|
11024
|
+
}
|
|
11025
|
+
};
|
|
11026
|
+
(getFocusable()[0] ?? container)?.focus();
|
|
11027
|
+
container.addEventListener("keydown", handler);
|
|
11028
|
+
return () => {
|
|
11029
|
+
container.removeEventListener("keydown", handler);
|
|
11030
|
+
previousFocusRef.current?.focus();
|
|
11031
|
+
};
|
|
11032
|
+
}, [open, onClose]);
|
|
11033
|
+
if (!open) {
|
|
11034
|
+
return null;
|
|
11035
|
+
}
|
|
11036
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialogContext.Provider, { value: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11037
|
+
"div",
|
|
11038
|
+
{
|
|
11039
|
+
ref: containerRef,
|
|
11040
|
+
className,
|
|
11041
|
+
onClick: onClose,
|
|
11042
|
+
tabIndex: -1,
|
|
11043
|
+
children
|
|
11044
|
+
}
|
|
11045
|
+
) });
|
|
11046
|
+
}
|
|
11047
|
+
function InlineDialogBackdrop(props) {
|
|
11048
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", ...props });
|
|
11049
|
+
}
|
|
11050
|
+
function InlineDialogPanel({
|
|
11051
|
+
children,
|
|
11052
|
+
onClick,
|
|
11053
|
+
...rest
|
|
11054
|
+
}) {
|
|
11055
|
+
const ref = React.useRef(null);
|
|
11056
|
+
React.useEffect(() => {
|
|
11057
|
+
if (!ref.current) {
|
|
11058
|
+
return;
|
|
11059
|
+
}
|
|
11060
|
+
const target = ref.current.querySelector("[data-autofocus]") ?? ref.current.querySelector(
|
|
11061
|
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
11062
|
+
);
|
|
11063
|
+
target?.focus();
|
|
11064
|
+
}, []);
|
|
11065
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11066
|
+
"div",
|
|
11067
|
+
{
|
|
11068
|
+
ref,
|
|
11069
|
+
role: "dialog",
|
|
11070
|
+
"aria-modal": "true",
|
|
11071
|
+
onClick: (e) => {
|
|
11072
|
+
e.stopPropagation();
|
|
11073
|
+
onClick?.(e);
|
|
11074
|
+
},
|
|
11075
|
+
...rest,
|
|
11076
|
+
children
|
|
11077
|
+
}
|
|
11078
|
+
);
|
|
11079
|
+
}
|
|
11080
|
+
function InlineDialogTitle(props) {
|
|
11081
|
+
return /* @__PURE__ */ jsxRuntime.jsx("h2", { ...props });
|
|
11082
|
+
}
|
|
11083
|
+
function InlineDialogDescription(props) {
|
|
11084
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { ...props });
|
|
11085
|
+
}
|
|
10747
11086
|
|
|
10748
|
-
// ui/src/bichat/components/
|
|
11087
|
+
// ui/src/bichat/components/SessionMembersModal.tsx
|
|
10749
11088
|
init_useTranslation();
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
11089
|
+
init_useTranslation();
|
|
11090
|
+
function ConfirmModalBase({
|
|
11091
|
+
isOpen,
|
|
11092
|
+
title,
|
|
11093
|
+
message,
|
|
11094
|
+
onConfirm,
|
|
11095
|
+
onCancel,
|
|
11096
|
+
confirmText,
|
|
11097
|
+
cancelText,
|
|
11098
|
+
isDanger = false
|
|
10756
11099
|
}) {
|
|
10757
11100
|
const { t } = useTranslation();
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
role: "alert",
|
|
10766
|
-
children: [
|
|
10767
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 mt-0.5 flex items-center justify-center w-7 h-7 rounded-full bg-red-100 dark:bg-red-900/40", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10768
|
-
react.Warning,
|
|
10769
|
-
{
|
|
10770
|
-
className: "w-4 h-4 text-red-600 dark:text-red-400",
|
|
10771
|
-
weight: "fill"
|
|
10772
|
-
}
|
|
10773
|
-
) }),
|
|
11101
|
+
const resolvedConfirmText = confirmText?.trim() ? confirmText : t("BiChat.Common.Confirm");
|
|
11102
|
+
const resolvedCancelText = cancelText?.trim() ? cancelText : t("BiChat.Common.Cancel");
|
|
11103
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(InlineDialog, { open: isOpen, onClose: onCancel, className: "relative z-40", children: [
|
|
11104
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogBackdrop, { className: "fixed inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity duration-200" }),
|
|
11105
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50 p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(InlineDialogPanel, { className: "bg-white dark:bg-gray-800 rounded-2xl shadow-xl dark:shadow-2xl dark:shadow-black/30 max-w-sm w-full overflow-hidden", children: [
|
|
11106
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 pt-6 pb-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-4", children: [
|
|
11107
|
+
isDanger && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 flex items-center justify-center w-10 h-10 rounded-xl bg-red-50 dark:bg-red-950/40 border border-red-200/60 dark:border-red-800/40", children: /* @__PURE__ */ jsxRuntime.jsx(react.WarningCircle, { size: 22, weight: "duotone", className: "text-red-600 dark:text-red-400" }) }),
|
|
10774
11108
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
10775
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10776
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10777
|
-
|
|
11109
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogTitle, { className: "text-base font-semibold text-gray-900 dark:text-gray-100 leading-snug", children: title }),
|
|
11110
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogDescription, { className: "mt-2 text-sm text-gray-600 dark:text-gray-400 leading-relaxed", children: message })
|
|
11111
|
+
] })
|
|
11112
|
+
] }) }),
|
|
11113
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-2.5 px-6 pb-5", children: [
|
|
11114
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11115
|
+
"button",
|
|
11116
|
+
{
|
|
11117
|
+
type: "button",
|
|
11118
|
+
onClick: onCancel,
|
|
11119
|
+
...isDanger ? { "data-autofocus": true } : {},
|
|
11120
|
+
className: "cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700/60 hover:bg-gray-200 dark:hover:bg-gray-700 active:bg-gray-250 dark:active:bg-gray-600 transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
|
|
11121
|
+
"data-testid": "confirm-modal-cancel",
|
|
11122
|
+
children: resolvedCancelText
|
|
11123
|
+
}
|
|
11124
|
+
),
|
|
11125
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11126
|
+
"button",
|
|
11127
|
+
{
|
|
11128
|
+
type: "button",
|
|
11129
|
+
...!isDanger ? { "data-autofocus": true } : {},
|
|
11130
|
+
onClick: onConfirm,
|
|
11131
|
+
className: [
|
|
11132
|
+
"cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-white",
|
|
11133
|
+
"transition-all duration-150 shadow-sm hover:shadow",
|
|
11134
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
|
|
11135
|
+
isDanger ? "bg-red-600 hover:bg-red-700 active:bg-red-800 focus-visible:ring-red-500/50" : "bg-primary-600 hover:bg-primary-700 active:bg-primary-800 focus-visible:ring-primary-500/50"
|
|
11136
|
+
].join(" "),
|
|
11137
|
+
"data-testid": "confirm-modal-confirm",
|
|
11138
|
+
children: resolvedConfirmText
|
|
11139
|
+
}
|
|
11140
|
+
)
|
|
11141
|
+
] })
|
|
11142
|
+
] }) })
|
|
11143
|
+
] });
|
|
11144
|
+
}
|
|
11145
|
+
var ConfirmModal = React.memo(ConfirmModalBase);
|
|
11146
|
+
ConfirmModal.displayName = "ConfirmModal";
|
|
11147
|
+
var ConfirmModal_default = ConfirmModal;
|
|
11148
|
+
var ROLES = ["editor", "viewer"];
|
|
11149
|
+
function RoleSegmentedControl({
|
|
11150
|
+
value,
|
|
11151
|
+
onChange,
|
|
11152
|
+
disabled,
|
|
11153
|
+
size = "md",
|
|
11154
|
+
t
|
|
11155
|
+
}) {
|
|
11156
|
+
const btnBase = size === "sm" ? "px-2 py-0.5 text-[11px]" : "px-3 py-1 text-xs";
|
|
11157
|
+
const currentIndex = ROLES.indexOf(value);
|
|
11158
|
+
const handleKeyDown = (e) => {
|
|
11159
|
+
if (disabled) {
|
|
11160
|
+
return;
|
|
11161
|
+
}
|
|
11162
|
+
let nextIndex = null;
|
|
11163
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
11164
|
+
e.preventDefault();
|
|
11165
|
+
nextIndex = currentIndex <= 0 ? ROLES.length - 1 : currentIndex - 1;
|
|
11166
|
+
} else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
11167
|
+
e.preventDefault();
|
|
11168
|
+
nextIndex = currentIndex >= ROLES.length - 1 ? 0 : currentIndex + 1;
|
|
11169
|
+
}
|
|
11170
|
+
if (nextIndex !== null) {
|
|
11171
|
+
const nextRole = ROLES[nextIndex];
|
|
11172
|
+
onChange(nextRole);
|
|
11173
|
+
const target = e.currentTarget.querySelector(`[data-role="${nextRole}"]`);
|
|
11174
|
+
target?.focus();
|
|
11175
|
+
}
|
|
11176
|
+
};
|
|
11177
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11178
|
+
"div",
|
|
11179
|
+
{
|
|
11180
|
+
role: "radiogroup",
|
|
11181
|
+
"aria-label": t("BiChat.Share.RoleLabel"),
|
|
11182
|
+
className: "inline-flex rounded-lg border border-gray-200 dark:border-gray-700 p-0.5 bg-gray-50 dark:bg-gray-800/50",
|
|
11183
|
+
onKeyDown: handleKeyDown,
|
|
11184
|
+
children: ROLES.map((role) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
11185
|
+
"button",
|
|
11186
|
+
{
|
|
11187
|
+
type: "button",
|
|
11188
|
+
role: "radio",
|
|
11189
|
+
"aria-checked": value === role,
|
|
11190
|
+
tabIndex: value === role ? 0 : -1,
|
|
11191
|
+
"data-role": role,
|
|
11192
|
+
disabled,
|
|
11193
|
+
onClick: () => onChange(role),
|
|
11194
|
+
className: `${btnBase} cursor-pointer rounded-md font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 disabled:opacity-50 disabled:cursor-not-allowed ${value === role ? "bg-primary-600 text-white shadow-sm" : "text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100"}`,
|
|
11195
|
+
children: role === "editor" ? t("BiChat.Share.RoleEditor") : t("BiChat.Share.RoleViewer")
|
|
11196
|
+
},
|
|
11197
|
+
role
|
|
11198
|
+
))
|
|
11199
|
+
}
|
|
11200
|
+
);
|
|
11201
|
+
}
|
|
11202
|
+
function MemberSkeleton() {
|
|
11203
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 rounded-xl px-3 py-2.5", "aria-hidden": "true", children: [
|
|
11204
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-full bg-gray-200 dark:bg-gray-700 animate-pulse flex-shrink-0" }),
|
|
11205
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-1.5", children: [
|
|
11206
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-28 rounded bg-gray-200 dark:bg-gray-700 animate-pulse" }),
|
|
11207
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2.5 w-16 rounded bg-gray-100 dark:bg-gray-800 animate-pulse" })
|
|
11208
|
+
] }),
|
|
11209
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 w-16 rounded-lg bg-gray-200 dark:bg-gray-700 animate-pulse" })
|
|
11210
|
+
] });
|
|
11211
|
+
}
|
|
11212
|
+
function SessionMembersModal({ isOpen, sessionId, dataSource, onClose }) {
|
|
11213
|
+
const headingId = React.useId();
|
|
11214
|
+
const { t } = useTranslation();
|
|
11215
|
+
const statusTimerRef = React.useRef();
|
|
11216
|
+
const [loading, setLoading] = React.useState(false);
|
|
11217
|
+
const [saving, setSaving] = React.useState(false);
|
|
11218
|
+
const [error, setError] = React.useState(null);
|
|
11219
|
+
const [users, setUsers] = React.useState([]);
|
|
11220
|
+
const [members, setMembers] = React.useState([]);
|
|
11221
|
+
const [selectedUser, setSelectedUser] = React.useState(null);
|
|
11222
|
+
const [selectedRole, setSelectedRole] = React.useState("editor");
|
|
11223
|
+
const [query, setQuery] = React.useState("");
|
|
11224
|
+
const [confirmRemove, setConfirmRemove] = React.useState(null);
|
|
11225
|
+
const [statusMessage, setStatusMessage] = React.useState(null);
|
|
11226
|
+
const [dropdownOpen, setDropdownOpen] = React.useState(false);
|
|
11227
|
+
const [dropdownHighlightIndex, setDropdownHighlightIndex] = React.useState(0);
|
|
11228
|
+
const dropdownOptionRefs = React.useRef([]);
|
|
11229
|
+
const canManageMembers = Boolean(
|
|
11230
|
+
dataSource.listUsers && dataSource.listSessionMembers && dataSource.addSessionMember && dataSource.updateSessionMemberRole && dataSource.removeSessionMember
|
|
11231
|
+
);
|
|
11232
|
+
const refresh = React.useCallback(async () => {
|
|
11233
|
+
if (!sessionId || !canManageMembers) {
|
|
11234
|
+
return;
|
|
11235
|
+
}
|
|
11236
|
+
setLoading(true);
|
|
11237
|
+
setError(null);
|
|
11238
|
+
try {
|
|
11239
|
+
const [usersData, membersData] = await Promise.all([
|
|
11240
|
+
dataSource.listUsers(),
|
|
11241
|
+
dataSource.listSessionMembers(sessionId)
|
|
11242
|
+
]);
|
|
11243
|
+
setUsers(usersData);
|
|
11244
|
+
setMembers(membersData);
|
|
11245
|
+
} catch {
|
|
11246
|
+
setError(t("BiChat.Share.LoadFailed"));
|
|
11247
|
+
} finally {
|
|
11248
|
+
setLoading(false);
|
|
11249
|
+
}
|
|
11250
|
+
}, [canManageMembers, dataSource, sessionId, t]);
|
|
11251
|
+
React.useEffect(() => {
|
|
11252
|
+
if (!isOpen) {
|
|
11253
|
+
return;
|
|
11254
|
+
}
|
|
11255
|
+
void refresh();
|
|
11256
|
+
}, [isOpen, refresh]);
|
|
11257
|
+
React.useEffect(() => {
|
|
11258
|
+
if (!isOpen) {
|
|
11259
|
+
setQuery("");
|
|
11260
|
+
setSelectedUser(null);
|
|
11261
|
+
setSelectedRole("editor");
|
|
11262
|
+
setError(null);
|
|
11263
|
+
setConfirmRemove(null);
|
|
11264
|
+
setStatusMessage(null);
|
|
11265
|
+
setDropdownOpen(false);
|
|
11266
|
+
setDropdownHighlightIndex(0);
|
|
11267
|
+
}
|
|
11268
|
+
}, [isOpen]);
|
|
11269
|
+
const memberIDs = React.useMemo(() => new Set(members.map((m) => m.user.id)), [members]);
|
|
11270
|
+
const availableUsers = React.useMemo(
|
|
11271
|
+
() => users.filter((user) => !memberIDs.has(user.id)),
|
|
11272
|
+
[users, memberIDs]
|
|
11273
|
+
);
|
|
11274
|
+
const filteredUsers = React.useMemo(() => {
|
|
11275
|
+
if (!query.trim()) {
|
|
11276
|
+
return availableUsers;
|
|
11277
|
+
}
|
|
11278
|
+
const q = query.toLowerCase();
|
|
11279
|
+
return availableUsers.filter(
|
|
11280
|
+
(u) => u.firstName.toLowerCase().includes(q) || u.lastName.toLowerCase().includes(q) || `${u.firstName} ${u.lastName}`.toLowerCase().includes(q)
|
|
11281
|
+
);
|
|
11282
|
+
}, [availableUsers, query]);
|
|
11283
|
+
React.useEffect(() => {
|
|
11284
|
+
setDropdownHighlightIndex(
|
|
11285
|
+
(i) => Math.min(Math.max(0, i), Math.max(0, filteredUsers.length - 1))
|
|
11286
|
+
);
|
|
11287
|
+
}, [filteredUsers.length]);
|
|
11288
|
+
React.useEffect(() => () => clearTimeout(statusTimerRef.current), []);
|
|
11289
|
+
const flashStatus = React.useCallback((msg) => {
|
|
11290
|
+
clearTimeout(statusTimerRef.current);
|
|
11291
|
+
setStatusMessage(msg);
|
|
11292
|
+
statusTimerRef.current = setTimeout(() => setStatusMessage(null), 3e3);
|
|
11293
|
+
}, []);
|
|
11294
|
+
const handleAdd = React.useCallback(async () => {
|
|
11295
|
+
if (!sessionId || !selectedUser || !dataSource.addSessionMember) {
|
|
11296
|
+
return;
|
|
11297
|
+
}
|
|
11298
|
+
setSaving(true);
|
|
11299
|
+
setError(null);
|
|
11300
|
+
try {
|
|
11301
|
+
await dataSource.addSessionMember(sessionId, selectedUser.id, selectedRole);
|
|
11302
|
+
setSelectedUser(null);
|
|
11303
|
+
setQuery("");
|
|
11304
|
+
flashStatus(t("BiChat.Share.MemberAdded"));
|
|
11305
|
+
await refresh();
|
|
11306
|
+
} catch {
|
|
11307
|
+
setError(t("BiChat.Share.AddFailed"));
|
|
11308
|
+
} finally {
|
|
11309
|
+
setSaving(false);
|
|
11310
|
+
}
|
|
11311
|
+
}, [sessionId, selectedUser, selectedRole, dataSource.addSessionMember, refresh, t, flashStatus]);
|
|
11312
|
+
const handleUpdateRole = React.useCallback(async (userId, role) => {
|
|
11313
|
+
if (!sessionId || !dataSource.updateSessionMemberRole) {
|
|
11314
|
+
return;
|
|
11315
|
+
}
|
|
11316
|
+
setSaving(true);
|
|
11317
|
+
setError(null);
|
|
11318
|
+
try {
|
|
11319
|
+
await dataSource.updateSessionMemberRole(sessionId, userId, role);
|
|
11320
|
+
await refresh();
|
|
11321
|
+
} catch {
|
|
11322
|
+
setError(t("BiChat.Share.UpdateFailed"));
|
|
11323
|
+
} finally {
|
|
11324
|
+
setSaving(false);
|
|
11325
|
+
}
|
|
11326
|
+
}, [sessionId, dataSource.updateSessionMemberRole, refresh]);
|
|
11327
|
+
const handleRemove = React.useCallback(async (userId) => {
|
|
11328
|
+
if (!sessionId || !dataSource.removeSessionMember) {
|
|
11329
|
+
return;
|
|
11330
|
+
}
|
|
11331
|
+
setSaving(true);
|
|
11332
|
+
setError(null);
|
|
11333
|
+
try {
|
|
11334
|
+
await dataSource.removeSessionMember(sessionId, userId);
|
|
11335
|
+
flashStatus(t("BiChat.Share.MemberRemoved"));
|
|
11336
|
+
await refresh();
|
|
11337
|
+
} catch {
|
|
11338
|
+
setError(t("BiChat.Share.RemoveFailed"));
|
|
11339
|
+
} finally {
|
|
11340
|
+
setSaving(false);
|
|
11341
|
+
}
|
|
11342
|
+
}, [sessionId, dataSource.removeSessionMember, refresh, flashStatus]);
|
|
11343
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11344
|
+
/* @__PURE__ */ jsxRuntime.jsxs(InlineDialog, { open: isOpen, onClose, className: "relative z-40", children: [
|
|
11345
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogBackdrop, { className: "fixed inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity duration-200" }),
|
|
11346
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50 p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11347
|
+
InlineDialogPanel,
|
|
11348
|
+
{
|
|
11349
|
+
"aria-labelledby": headingId,
|
|
11350
|
+
className: "bg-white dark:bg-gray-800 rounded-2xl shadow-xl dark:shadow-2xl dark:shadow-black/30 max-w-md w-full",
|
|
11351
|
+
children: [
|
|
11352
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 pt-5 pb-4", children: [
|
|
11353
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
11354
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center w-9 h-9 rounded-xl bg-primary-50 dark:bg-primary-950/40 border border-primary-200/60 dark:border-primary-800/40", children: /* @__PURE__ */ jsxRuntime.jsx(react.UsersThree, { size: 18, weight: "duotone", className: "text-primary-600 dark:text-primary-400" }) }),
|
|
11355
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogTitle, { id: headingId, className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: t("BiChat.Share.Title") })
|
|
11356
|
+
] }),
|
|
11357
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11358
|
+
"button",
|
|
11359
|
+
{
|
|
11360
|
+
type: "button",
|
|
11361
|
+
onClick: onClose,
|
|
11362
|
+
className: "rounded-lg p-1.5 text-gray-400 hover:text-gray-600 hover:bg-gray-100 dark:hover:text-gray-300 dark:hover:bg-gray-700 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
|
|
11363
|
+
"aria-label": t("BiChat.Common.Close"),
|
|
11364
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { size: 18 })
|
|
11365
|
+
}
|
|
11366
|
+
)
|
|
11367
|
+
] }),
|
|
11368
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 pb-5 space-y-4", children: [
|
|
11369
|
+
!canManageMembers && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border border-amber-200 bg-amber-50 px-3 py-2.5 text-xs text-amber-700 dark:border-amber-800/60 dark:bg-amber-900/20 dark:text-amber-300", children: t("BiChat.Share.Unsupported") }),
|
|
11370
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border border-red-200 bg-red-50 px-3 py-2.5 text-xs text-red-700 dark:border-red-800/60 dark:bg-red-900/20 dark:text-red-300", children: error }),
|
|
11371
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: statusMessage }),
|
|
11372
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
11373
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400", children: [
|
|
11374
|
+
t("BiChat.Share.Members"),
|
|
11375
|
+
!loading && members.length > 0 ? ` (${members.length})` : ""
|
|
11376
|
+
] }),
|
|
11377
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-64 overflow-y-auto -mx-1 px-1 space-y-1", children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11378
|
+
/* @__PURE__ */ jsxRuntime.jsx(MemberSkeleton, {}),
|
|
11379
|
+
/* @__PURE__ */ jsxRuntime.jsx(MemberSkeleton, {}),
|
|
11380
|
+
/* @__PURE__ */ jsxRuntime.jsx(MemberSkeleton, {})
|
|
11381
|
+
] }) : members.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-8 text-gray-400 dark:text-gray-500", children: [
|
|
11382
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.UsersThree, { size: 32, weight: "thin", className: "mb-2" }),
|
|
11383
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: t("BiChat.Share.Empty") })
|
|
11384
|
+
] }) : members.map((member) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11385
|
+
"div",
|
|
11386
|
+
{
|
|
11387
|
+
className: "flex items-center gap-3 rounded-xl px-3 py-2 transition-colors hover:bg-gray-50 dark:hover:bg-gray-700/40",
|
|
11388
|
+
children: [
|
|
11389
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11390
|
+
MemoizedUserAvatar,
|
|
11391
|
+
{
|
|
11392
|
+
firstName: member.user.firstName,
|
|
11393
|
+
lastName: member.user.lastName,
|
|
11394
|
+
initials: member.user.initials,
|
|
11395
|
+
size: "sm"
|
|
11396
|
+
}
|
|
11397
|
+
),
|
|
11398
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "truncate text-sm font-medium text-gray-900 dark:text-gray-100", children: [
|
|
11399
|
+
member.user.firstName,
|
|
11400
|
+
" ",
|
|
11401
|
+
member.user.lastName
|
|
11402
|
+
] }) }),
|
|
11403
|
+
member.role === "owner" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-amber-50 dark:bg-amber-900/20 border border-amber-200/60 dark:border-amber-800/40 px-2.5 py-0.5 text-[11px] font-medium text-amber-700 dark:text-amber-300", children: [
|
|
11404
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Crown, { size: 12, weight: "duotone" }),
|
|
11405
|
+
t("BiChat.Share.RoleOwner")
|
|
11406
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
|
|
11407
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11408
|
+
RoleSegmentedControl,
|
|
11409
|
+
{
|
|
11410
|
+
value: member.role,
|
|
11411
|
+
onChange: (role) => handleUpdateRole(member.user.id, role),
|
|
11412
|
+
disabled: saving,
|
|
11413
|
+
size: "sm",
|
|
11414
|
+
t
|
|
11415
|
+
}
|
|
11416
|
+
),
|
|
11417
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11418
|
+
"button",
|
|
11419
|
+
{
|
|
11420
|
+
type: "button",
|
|
11421
|
+
disabled: saving,
|
|
11422
|
+
onClick: () => setConfirmRemove(member),
|
|
11423
|
+
className: "cursor-pointer rounded-lg p-1.5 text-gray-400 transition-colors hover:bg-red-50 hover:text-red-600 dark:hover:bg-red-900/20 dark:hover:text-red-400 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500/50",
|
|
11424
|
+
"aria-label": `${t("BiChat.Share.Remove")} ${member.user.firstName} ${member.user.lastName}`,
|
|
11425
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.Trash, { size: 14 })
|
|
11426
|
+
}
|
|
11427
|
+
)
|
|
11428
|
+
] })
|
|
11429
|
+
]
|
|
11430
|
+
},
|
|
11431
|
+
member.user.id
|
|
11432
|
+
)) })
|
|
11433
|
+
] }),
|
|
11434
|
+
canManageMembers && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-gray-200 dark:border-gray-700 p-3 space-y-3", children: [
|
|
11435
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("BiChat.Share.AddMember") }),
|
|
11436
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11437
|
+
"div",
|
|
11438
|
+
{
|
|
11439
|
+
className: "relative",
|
|
11440
|
+
onBlur: (e) => {
|
|
11441
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
11442
|
+
setDropdownOpen(false);
|
|
11443
|
+
}
|
|
11444
|
+
},
|
|
11445
|
+
children: [
|
|
11446
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
11447
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11448
|
+
react.MagnifyingGlass,
|
|
11449
|
+
{
|
|
11450
|
+
size: 14,
|
|
11451
|
+
className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 dark:text-gray-500"
|
|
11452
|
+
}
|
|
11453
|
+
),
|
|
11454
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11455
|
+
"input",
|
|
11456
|
+
{
|
|
11457
|
+
type: "text",
|
|
11458
|
+
className: "w-full rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800/60 pl-8 pr-3 py-2 text-sm text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 transition-colors focus:border-primary-400 dark:focus:border-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500/20",
|
|
11459
|
+
placeholder: t("BiChat.Share.SearchUsers"),
|
|
11460
|
+
value: selectedUser ? `${selectedUser.firstName} ${selectedUser.lastName}` : query,
|
|
11461
|
+
onFocus: () => {
|
|
11462
|
+
setDropdownOpen(true);
|
|
11463
|
+
setDropdownHighlightIndex(0);
|
|
11464
|
+
if (selectedUser) {
|
|
11465
|
+
setSelectedUser(null);
|
|
11466
|
+
setQuery("");
|
|
11467
|
+
}
|
|
11468
|
+
},
|
|
11469
|
+
onChange: (e) => {
|
|
11470
|
+
setQuery(e.target.value);
|
|
11471
|
+
setSelectedUser(null);
|
|
11472
|
+
setDropdownOpen(true);
|
|
11473
|
+
setDropdownHighlightIndex(0);
|
|
11474
|
+
},
|
|
11475
|
+
onKeyDown: (e) => {
|
|
11476
|
+
if (!dropdownOpen || filteredUsers.length === 0) {
|
|
11477
|
+
if (e.key === "Escape") {
|
|
11478
|
+
setDropdownOpen(false);
|
|
11479
|
+
}
|
|
11480
|
+
return;
|
|
11481
|
+
}
|
|
11482
|
+
if (e.key === "Escape") {
|
|
11483
|
+
e.preventDefault();
|
|
11484
|
+
setDropdownOpen(false);
|
|
11485
|
+
setDropdownHighlightIndex(0);
|
|
11486
|
+
return;
|
|
11487
|
+
}
|
|
11488
|
+
if (e.key === "ArrowDown") {
|
|
11489
|
+
e.preventDefault();
|
|
11490
|
+
const next = (dropdownHighlightIndex + 1) % filteredUsers.length;
|
|
11491
|
+
setDropdownHighlightIndex(next);
|
|
11492
|
+
setTimeout(() => dropdownOptionRefs.current[next]?.focus(), 0);
|
|
11493
|
+
return;
|
|
11494
|
+
}
|
|
11495
|
+
if (e.key === "ArrowUp") {
|
|
11496
|
+
e.preventDefault();
|
|
11497
|
+
const next = dropdownHighlightIndex <= 0 ? filteredUsers.length - 1 : dropdownHighlightIndex - 1;
|
|
11498
|
+
setDropdownHighlightIndex(next);
|
|
11499
|
+
setTimeout(() => dropdownOptionRefs.current[next]?.focus(), 0);
|
|
11500
|
+
return;
|
|
11501
|
+
}
|
|
11502
|
+
if (e.key === "Enter") {
|
|
11503
|
+
e.preventDefault();
|
|
11504
|
+
const user = filteredUsers[dropdownHighlightIndex];
|
|
11505
|
+
if (user) {
|
|
11506
|
+
setSelectedUser(user);
|
|
11507
|
+
setQuery("");
|
|
11508
|
+
setDropdownOpen(false);
|
|
11509
|
+
}
|
|
11510
|
+
}
|
|
11511
|
+
}
|
|
11512
|
+
}
|
|
11513
|
+
)
|
|
11514
|
+
] }),
|
|
11515
|
+
dropdownOpen && !selectedUser && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute z-10 mt-1 max-h-48 w-full overflow-auto rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 shadow-lg py-1", children: filteredUsers.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-gray-500 dark:text-gray-400", children: availableUsers.length === 0 ? t("BiChat.Share.NoUsersAvailable") : t("BiChat.Share.NoSearchResults") }) : filteredUsers.map((user, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11516
|
+
"button",
|
|
11517
|
+
{
|
|
11518
|
+
type: "button",
|
|
11519
|
+
ref: (el) => {
|
|
11520
|
+
dropdownOptionRefs.current[index] = el;
|
|
11521
|
+
},
|
|
11522
|
+
className: `flex w-full items-center gap-2.5 px-3 py-2 cursor-pointer transition-colors hover:bg-primary-50 dark:hover:bg-primary-900/20 ${index === dropdownHighlightIndex ? "bg-primary-50 dark:bg-primary-900/20" : ""}`,
|
|
11523
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
11524
|
+
onClick: () => {
|
|
11525
|
+
setSelectedUser(user);
|
|
11526
|
+
setQuery("");
|
|
11527
|
+
setDropdownOpen(false);
|
|
11528
|
+
},
|
|
11529
|
+
children: [
|
|
11530
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11531
|
+
MemoizedUserAvatar,
|
|
11532
|
+
{
|
|
11533
|
+
firstName: user.firstName,
|
|
11534
|
+
lastName: user.lastName,
|
|
11535
|
+
initials: user.initials,
|
|
11536
|
+
size: "xs"
|
|
11537
|
+
}
|
|
11538
|
+
),
|
|
11539
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-900 dark:text-gray-100", children: [
|
|
11540
|
+
user.firstName,
|
|
11541
|
+
" ",
|
|
11542
|
+
user.lastName
|
|
11543
|
+
] })
|
|
11544
|
+
]
|
|
11545
|
+
},
|
|
11546
|
+
user.id
|
|
11547
|
+
)) })
|
|
11548
|
+
]
|
|
11549
|
+
}
|
|
11550
|
+
),
|
|
11551
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
11552
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11553
|
+
RoleSegmentedControl,
|
|
11554
|
+
{
|
|
11555
|
+
value: selectedRole,
|
|
11556
|
+
onChange: setSelectedRole,
|
|
11557
|
+
disabled: saving,
|
|
11558
|
+
t
|
|
11559
|
+
}
|
|
11560
|
+
),
|
|
11561
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11562
|
+
"button",
|
|
11563
|
+
{
|
|
11564
|
+
type: "button",
|
|
11565
|
+
onClick: handleAdd,
|
|
11566
|
+
disabled: saving || !selectedUser,
|
|
11567
|
+
className: "inline-flex cursor-pointer items-center gap-1.5 rounded-xl bg-primary-600 px-3.5 py-2 text-sm font-medium text-white shadow-sm transition-all duration-150 hover:bg-primary-700 hover:shadow active:bg-primary-800 disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
|
|
11568
|
+
children: [
|
|
11569
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.UserPlus, { size: 14 }),
|
|
11570
|
+
t("BiChat.Share.Add")
|
|
11571
|
+
]
|
|
11572
|
+
}
|
|
11573
|
+
)
|
|
11574
|
+
] })
|
|
11575
|
+
] })
|
|
11576
|
+
] })
|
|
11577
|
+
]
|
|
11578
|
+
}
|
|
11579
|
+
) })
|
|
11580
|
+
] }),
|
|
11581
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11582
|
+
ConfirmModal,
|
|
11583
|
+
{
|
|
11584
|
+
isOpen: !!confirmRemove,
|
|
11585
|
+
isDanger: true,
|
|
11586
|
+
title: t("BiChat.Share.RemoveConfirmTitle"),
|
|
11587
|
+
message: confirmRemove ? t("BiChat.Share.RemoveConfirmMessage").replace(
|
|
11588
|
+
"{{name}}",
|
|
11589
|
+
`${confirmRemove.user.firstName} ${confirmRemove.user.lastName}`
|
|
11590
|
+
) : "",
|
|
11591
|
+
confirmText: t("BiChat.Share.Remove"),
|
|
11592
|
+
onConfirm: () => {
|
|
11593
|
+
if (confirmRemove) {
|
|
11594
|
+
void handleRemove(confirmRemove.user.id);
|
|
11595
|
+
}
|
|
11596
|
+
setConfirmRemove(null);
|
|
11597
|
+
},
|
|
11598
|
+
onCancel: () => setConfirmRemove(null)
|
|
11599
|
+
}
|
|
11600
|
+
)
|
|
11601
|
+
] });
|
|
11602
|
+
}
|
|
11603
|
+
|
|
11604
|
+
// ui/src/bichat/components/StreamError.tsx
|
|
11605
|
+
init_useTranslation();
|
|
11606
|
+
function StreamError({
|
|
11607
|
+
error,
|
|
11608
|
+
onRetry,
|
|
11609
|
+
onRegenerate,
|
|
11610
|
+
onDismiss,
|
|
11611
|
+
compact = false
|
|
11612
|
+
}) {
|
|
11613
|
+
const { t } = useTranslation();
|
|
11614
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11615
|
+
framerMotion.motion.div,
|
|
11616
|
+
{
|
|
11617
|
+
initial: { opacity: 0, y: 10 },
|
|
11618
|
+
animate: { opacity: 1, y: 0 },
|
|
11619
|
+
exit: { opacity: 0, y: -10 },
|
|
11620
|
+
className: `flex items-start gap-3 ${compact ? "px-3 py-2.5" : "px-4 py-3"} bg-red-50 dark:bg-red-950/40 border border-red-200/80 dark:border-red-900/60 rounded-xl shadow-sm`,
|
|
11621
|
+
role: "alert",
|
|
11622
|
+
children: [
|
|
11623
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 mt-0.5 flex items-center justify-center w-7 h-7 rounded-full bg-red-100 dark:bg-red-900/40", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11624
|
+
react.Warning,
|
|
11625
|
+
{
|
|
11626
|
+
className: "w-4 h-4 text-red-600 dark:text-red-400",
|
|
11627
|
+
weight: "fill"
|
|
11628
|
+
}
|
|
11629
|
+
) }),
|
|
11630
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
11631
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-200 leading-snug", children: t("BiChat.Error.Generic") }),
|
|
11632
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-red-600/80 dark:text-red-400/70 break-words leading-relaxed", children: error }),
|
|
11633
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-2", children: [
|
|
10778
11634
|
onRetry && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10779
11635
|
"button",
|
|
10780
11636
|
{
|
|
@@ -10872,7 +11728,8 @@ function ChatSessionCore({
|
|
|
10872
11728
|
updateQueueItem
|
|
10873
11729
|
} = useChatInput();
|
|
10874
11730
|
const isArchived = session?.status === "archived";
|
|
10875
|
-
const
|
|
11731
|
+
const accessReadOnly = session?.access ? !session.access.canWrite : false;
|
|
11732
|
+
const effectiveReadOnly = Boolean(readOnly ?? isReadOnly) || isArchived || accessReadOnly;
|
|
10876
11733
|
const [restoring, setRestoring] = React.useState(false);
|
|
10877
11734
|
const handleRestore = React.useCallback(async () => {
|
|
10878
11735
|
if (!session?.id) {
|
|
@@ -10893,6 +11750,8 @@ function ChatSessionCore({
|
|
|
10893
11750
|
const [artifactsPanelExpanded, setArtifactsPanelExpanded] = React.useState(
|
|
10894
11751
|
artifactsPanelDefaultExpanded
|
|
10895
11752
|
);
|
|
11753
|
+
const [membersModalOpen, setMembersModalOpen] = React.useState(false);
|
|
11754
|
+
const [headerMembers, setHeaderMembers] = React.useState(null);
|
|
10896
11755
|
const [artifactsPanelWidth, setArtifactsPanelWidth] = React.useState(ARTIFACTS_PANEL_WIDTH_DEFAULT);
|
|
10897
11756
|
const [isResizingArtifactsPanel, setIsResizingArtifactsPanel] = React.useState(false);
|
|
10898
11757
|
const layoutContainerRef = React.useRef(null);
|
|
@@ -10927,6 +11786,25 @@ function ChatSessionCore({
|
|
|
10927
11786
|
} catch {
|
|
10928
11787
|
}
|
|
10929
11788
|
}, [artifactsPanelStorageKey, showArtifactsPanel]);
|
|
11789
|
+
React.useEffect(() => {
|
|
11790
|
+
if (!session?.id || !dataSource.listSessionMembers) {
|
|
11791
|
+
setHeaderMembers(null);
|
|
11792
|
+
return;
|
|
11793
|
+
}
|
|
11794
|
+
let cancelled = false;
|
|
11795
|
+
dataSource.listSessionMembers(session.id).then((members) => {
|
|
11796
|
+
if (!cancelled) {
|
|
11797
|
+
setHeaderMembers(members.map((m) => m.user));
|
|
11798
|
+
}
|
|
11799
|
+
}).catch(() => {
|
|
11800
|
+
if (!cancelled) {
|
|
11801
|
+
setHeaderMembers(null);
|
|
11802
|
+
}
|
|
11803
|
+
});
|
|
11804
|
+
return () => {
|
|
11805
|
+
cancelled = true;
|
|
11806
|
+
};
|
|
11807
|
+
}, [session?.id, dataSource.listSessionMembers]);
|
|
10930
11808
|
const handleArtifactsResizeStart = React.useCallback(() => {
|
|
10931
11809
|
setIsResizingArtifactsPanel(true);
|
|
10932
11810
|
}, []);
|
|
@@ -11016,8 +11894,26 @@ function ChatSessionCore({
|
|
|
11016
11894
|
}
|
|
11017
11895
|
}
|
|
11018
11896
|
};
|
|
11019
|
-
const
|
|
11020
|
-
|
|
11897
|
+
const canShowShareButton = Boolean(
|
|
11898
|
+
session?.access?.canManageMembers && dataSource.listUsers && dataSource.listSessionMembers && dataSource.addSessionMember && dataSource.updateSessionMemberRole && dataSource.removeSessionMember
|
|
11899
|
+
);
|
|
11900
|
+
const shareButton = canShowShareButton ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11901
|
+
"button",
|
|
11902
|
+
{
|
|
11903
|
+
type: "button",
|
|
11904
|
+
onClick: () => setMembersModalOpen(true),
|
|
11905
|
+
className: "inline-flex cursor-pointer items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium text-gray-500 transition-all duration-150 hover:bg-gray-100 hover:text-gray-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200",
|
|
11906
|
+
"aria-label": t("BiChat.Share.Title"),
|
|
11907
|
+
title: t("BiChat.Share.Title"),
|
|
11908
|
+
children: [
|
|
11909
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.ShareNetwork, { className: "h-4 w-4" }),
|
|
11910
|
+
t("BiChat.Share.Button")
|
|
11911
|
+
]
|
|
11912
|
+
}
|
|
11913
|
+
) : null;
|
|
11914
|
+
const headerActions = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11915
|
+
shareButton,
|
|
11916
|
+
showArtifactsControls && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11021
11917
|
"button",
|
|
11022
11918
|
{
|
|
11023
11919
|
type: "button",
|
|
@@ -11037,7 +11933,7 @@ function ChatSessionCore({
|
|
|
11037
11933
|
}
|
|
11038
11934
|
),
|
|
11039
11935
|
actionsSlot
|
|
11040
|
-
] })
|
|
11936
|
+
] });
|
|
11041
11937
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11042
11938
|
"main",
|
|
11043
11939
|
{
|
|
@@ -11050,7 +11946,9 @@ function ChatSessionCore({
|
|
|
11050
11946
|
onBack,
|
|
11051
11947
|
readOnly: effectiveReadOnly,
|
|
11052
11948
|
logoSlot,
|
|
11053
|
-
actionsSlot: headerActions
|
|
11949
|
+
actionsSlot: headerActions,
|
|
11950
|
+
members: headerMembers ?? (session?.owner ? [session.owner] : void 0),
|
|
11951
|
+
onMembersClick: canShowShareButton ? () => setMembersModalOpen(true) : void 0
|
|
11054
11952
|
}
|
|
11055
11953
|
),
|
|
11056
11954
|
error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -11247,6 +12145,15 @@ function ChatSessionCore({
|
|
|
11247
12145
|
) })
|
|
11248
12146
|
]
|
|
11249
12147
|
}
|
|
12148
|
+
),
|
|
12149
|
+
canShowShareButton && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12150
|
+
SessionMembersModal,
|
|
12151
|
+
{
|
|
12152
|
+
isOpen: membersModalOpen,
|
|
12153
|
+
sessionId: session?.id,
|
|
12154
|
+
dataSource,
|
|
12155
|
+
onClose: () => setMembersModalOpen(false)
|
|
12156
|
+
}
|
|
11250
12157
|
)
|
|
11251
12158
|
]
|
|
11252
12159
|
}
|
|
@@ -11269,7 +12176,7 @@ function ChatSession(props) {
|
|
|
11269
12176
|
// ui/src/bichat/index.ts
|
|
11270
12177
|
init_MarkdownRenderer();
|
|
11271
12178
|
init_ChartCard();
|
|
11272
|
-
var
|
|
12179
|
+
var sizeClasses2 = {
|
|
11273
12180
|
sm: {
|
|
11274
12181
|
container: "py-6 px-3",
|
|
11275
12182
|
title: "text-sm",
|
|
@@ -11294,7 +12201,7 @@ function EmptyState({
|
|
|
11294
12201
|
className = "",
|
|
11295
12202
|
size = "md"
|
|
11296
12203
|
}) {
|
|
11297
|
-
const sizes =
|
|
12204
|
+
const sizes = sizeClasses2[size];
|
|
11298
12205
|
const prefersReducedMotion2 = framerMotion.useReducedMotion();
|
|
11299
12206
|
const duration = prefersReducedMotion2 ? 0 : 0.4;
|
|
11300
12207
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -11354,7 +12261,7 @@ MemoizedEmptyState.displayName = "EmptyState";
|
|
|
11354
12261
|
|
|
11355
12262
|
// ui/src/bichat/components/EditableText.tsx
|
|
11356
12263
|
init_useTranslation();
|
|
11357
|
-
var
|
|
12264
|
+
var sizeClasses3 = {
|
|
11358
12265
|
sm: "text-sm",
|
|
11359
12266
|
md: "text-base",
|
|
11360
12267
|
lg: "text-lg"
|
|
@@ -11425,7 +12332,7 @@ var EditableText = React.forwardRef(
|
|
|
11425
12332
|
const handleBlur = () => {
|
|
11426
12333
|
handleSave();
|
|
11427
12334
|
};
|
|
11428
|
-
const sizeClass =
|
|
12335
|
+
const sizeClass = sizeClasses3[size];
|
|
11429
12336
|
if (isEditing) {
|
|
11430
12337
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11431
12338
|
"div",
|
|
@@ -11485,7 +12392,7 @@ var MemoizedEditableText = React.memo(EditableText);
|
|
|
11485
12392
|
|
|
11486
12393
|
// ui/src/bichat/components/SearchInput.tsx
|
|
11487
12394
|
init_useTranslation();
|
|
11488
|
-
var
|
|
12395
|
+
var sizeClasses4 = {
|
|
11489
12396
|
sm: {
|
|
11490
12397
|
container: "py-1.5 pl-8 pr-8 text-xs",
|
|
11491
12398
|
icon: 14,
|
|
@@ -11518,7 +12425,7 @@ function SearchInput({
|
|
|
11518
12425
|
const resolvedPlaceholder = placeholder ?? t("BiChat.Common.Search");
|
|
11519
12426
|
const resolvedAriaLabel = ariaLabel ?? t("BiChat.Common.Search");
|
|
11520
12427
|
const inputRef = React.useRef(null);
|
|
11521
|
-
const sizes =
|
|
12428
|
+
const sizes = sizeClasses4[size];
|
|
11522
12429
|
React.useEffect(() => {
|
|
11523
12430
|
if (autoFocus && inputRef.current) {
|
|
11524
12431
|
inputRef.current.focus();
|
|
@@ -11931,148 +12838,20 @@ function Toast({
|
|
|
11931
12838
|
|
|
11932
12839
|
// ui/src/bichat/components/ToastContainer.tsx
|
|
11933
12840
|
init_useTranslation();
|
|
11934
|
-
function ToastContainer({ toasts, onDismiss, dismissLabel }) {
|
|
11935
|
-
const { t } = useTranslation();
|
|
11936
|
-
if (toasts.length === 0) {
|
|
11937
|
-
return null;
|
|
11938
|
-
}
|
|
11939
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11940
|
-
"div",
|
|
11941
|
-
{
|
|
11942
|
-
"aria-label": t("BiChat.Common.Notifications"),
|
|
11943
|
-
className: "fixed top-6 right-6 z-[var(--bichat-z-toast,60)] flex flex-col gap-2 pointer-events-none",
|
|
11944
|
-
children: toasts.map((toast) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsxRuntime.jsx(Toast, { ...toast, onDismiss, dismissLabel }) }, toast.id))
|
|
11945
|
-
}
|
|
11946
|
-
);
|
|
11947
|
-
}
|
|
11948
|
-
|
|
11949
|
-
// ui/src/bichat/components/ConfirmModal.tsx
|
|
11950
|
-
init_useTranslation();
|
|
11951
|
-
function ConfirmModalBase({
|
|
11952
|
-
isOpen,
|
|
11953
|
-
title,
|
|
11954
|
-
message,
|
|
11955
|
-
onConfirm,
|
|
11956
|
-
onCancel,
|
|
11957
|
-
confirmText,
|
|
11958
|
-
cancelText,
|
|
11959
|
-
isDanger = false
|
|
11960
|
-
}) {
|
|
12841
|
+
function ToastContainer({ toasts, onDismiss, dismissLabel }) {
|
|
11961
12842
|
const { t } = useTranslation();
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(react$1.Dialog, { open: isOpen, onClose: onCancel, className: "relative z-40", children: [
|
|
11965
|
-
/* @__PURE__ */ jsxRuntime.jsx(react$1.DialogBackdrop, { className: "fixed inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity duration-200" }),
|
|
11966
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50 p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(react$1.DialogPanel, { className: "bg-white dark:bg-gray-800 rounded-2xl shadow-xl dark:shadow-2xl dark:shadow-black/30 max-w-sm w-full overflow-hidden", children: [
|
|
11967
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 pt-6 pb-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3.5", children: [
|
|
11968
|
-
isDanger && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 flex items-center justify-center w-10 h-10 rounded-xl bg-red-50 dark:bg-red-950/40 border border-red-200/60 dark:border-red-800/40", children: /* @__PURE__ */ jsxRuntime.jsx(react.WarningCircle, { size: 22, weight: "duotone", className: "text-red-600 dark:text-red-400" }) }),
|
|
11969
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
11970
|
-
/* @__PURE__ */ jsxRuntime.jsx(react$1.DialogTitle, { className: "text-base font-semibold text-gray-900 dark:text-gray-100 leading-snug", children: title }),
|
|
11971
|
-
/* @__PURE__ */ jsxRuntime.jsx(react$1.Description, { className: "mt-2 text-sm text-gray-600 dark:text-gray-400 leading-relaxed", children: message })
|
|
11972
|
-
] })
|
|
11973
|
-
] }) }),
|
|
11974
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-2.5 px-6 pb-5", children: [
|
|
11975
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11976
|
-
"button",
|
|
11977
|
-
{
|
|
11978
|
-
type: "button",
|
|
11979
|
-
onClick: onCancel,
|
|
11980
|
-
...isDanger ? { "data-autofocus": true } : {},
|
|
11981
|
-
className: "cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700/60 hover:bg-gray-200 dark:hover:bg-gray-700 active:bg-gray-250 dark:active:bg-gray-600 transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
|
|
11982
|
-
"data-testid": "confirm-modal-cancel",
|
|
11983
|
-
children: resolvedCancelText
|
|
11984
|
-
}
|
|
11985
|
-
),
|
|
11986
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11987
|
-
"button",
|
|
11988
|
-
{
|
|
11989
|
-
type: "button",
|
|
11990
|
-
...!isDanger ? { "data-autofocus": true } : {},
|
|
11991
|
-
onClick: onConfirm,
|
|
11992
|
-
className: [
|
|
11993
|
-
"cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-white",
|
|
11994
|
-
"transition-all duration-150 shadow-sm hover:shadow",
|
|
11995
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
|
|
11996
|
-
isDanger ? "bg-red-600 hover:bg-red-700 active:bg-red-800 focus-visible:ring-red-500/50" : "bg-primary-600 hover:bg-primary-700 active:bg-primary-800 focus-visible:ring-primary-500/50"
|
|
11997
|
-
].join(" "),
|
|
11998
|
-
"data-testid": "confirm-modal-confirm",
|
|
11999
|
-
children: resolvedConfirmText
|
|
12000
|
-
}
|
|
12001
|
-
)
|
|
12002
|
-
] })
|
|
12003
|
-
] }) })
|
|
12004
|
-
] });
|
|
12005
|
-
}
|
|
12006
|
-
var ConfirmModal = React.memo(ConfirmModalBase);
|
|
12007
|
-
ConfirmModal.displayName = "ConfirmModal";
|
|
12008
|
-
var ConfirmModal_default = ConfirmModal;
|
|
12009
|
-
function hashString(str) {
|
|
12010
|
-
let hash = 0;
|
|
12011
|
-
for (let i = 0; i < str.length; i++) {
|
|
12012
|
-
const char = str.charCodeAt(i);
|
|
12013
|
-
hash = (hash << 5) - hash + char;
|
|
12014
|
-
hash = hash & hash;
|
|
12843
|
+
if (toasts.length === 0) {
|
|
12844
|
+
return null;
|
|
12015
12845
|
}
|
|
12016
|
-
return Math.abs(hash);
|
|
12017
|
-
}
|
|
12018
|
-
var colorPalette = [
|
|
12019
|
-
{ bg: "bg-blue-500", text: "text-white" },
|
|
12020
|
-
{ bg: "bg-green-500", text: "text-white" },
|
|
12021
|
-
{ bg: "bg-purple-500", text: "text-white" },
|
|
12022
|
-
{ bg: "bg-pink-500", text: "text-white" },
|
|
12023
|
-
{ bg: "bg-indigo-500", text: "text-white" },
|
|
12024
|
-
{ bg: "bg-teal-500", text: "text-white" },
|
|
12025
|
-
{ bg: "bg-orange-500", text: "text-white" },
|
|
12026
|
-
{ bg: "bg-cyan-500", text: "text-white" },
|
|
12027
|
-
{ bg: "bg-amber-500", text: "text-white" },
|
|
12028
|
-
{ bg: "bg-lime-500", text: "text-white" }
|
|
12029
|
-
];
|
|
12030
|
-
var sizeClasses4 = {
|
|
12031
|
-
sm: "w-8 h-8 text-xs",
|
|
12032
|
-
md: "w-10 h-10 text-sm",
|
|
12033
|
-
lg: "w-12 h-12 text-base"
|
|
12034
|
-
};
|
|
12035
|
-
function UserAvatar({
|
|
12036
|
-
firstName,
|
|
12037
|
-
lastName,
|
|
12038
|
-
initials: providedInitials,
|
|
12039
|
-
size = "md",
|
|
12040
|
-
className = ""
|
|
12041
|
-
}) {
|
|
12042
|
-
const derivedInitials = (() => {
|
|
12043
|
-
const firstChar = firstName?.trim()?.charAt(0) || "";
|
|
12044
|
-
const lastChar = lastName?.trim()?.charAt(0) || "";
|
|
12045
|
-
const combined = `${firstChar}${lastChar}`.trim();
|
|
12046
|
-
return combined || "U";
|
|
12047
|
-
})();
|
|
12048
|
-
const initials = (providedInitials?.trim() || derivedInitials).toUpperCase();
|
|
12049
|
-
const fullName = `${firstName}${lastName}`;
|
|
12050
|
-
const colorIndex = hashString(fullName) % colorPalette.length;
|
|
12051
|
-
const colors = colorPalette[colorIndex];
|
|
12052
12846
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12053
12847
|
"div",
|
|
12054
12848
|
{
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
12058
|
-
${colors.text}
|
|
12059
|
-
${className}
|
|
12060
|
-
rounded-full
|
|
12061
|
-
flex
|
|
12062
|
-
items-center
|
|
12063
|
-
justify-center
|
|
12064
|
-
font-semibold
|
|
12065
|
-
flex-shrink-0
|
|
12066
|
-
select-none
|
|
12067
|
-
`,
|
|
12068
|
-
"aria-label": `${firstName} ${lastName}`,
|
|
12069
|
-
title: `${firstName} ${lastName}`,
|
|
12070
|
-
children: initials
|
|
12849
|
+
"aria-label": t("BiChat.Common.Notifications"),
|
|
12850
|
+
className: "fixed top-6 right-6 z-[var(--bichat-z-toast,60)] flex flex-col gap-2 pointer-events-none",
|
|
12851
|
+
children: toasts.map((toast) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsxRuntime.jsx(Toast, { ...toast, onDismiss, dismissLabel }) }, toast.id))
|
|
12071
12852
|
}
|
|
12072
12853
|
);
|
|
12073
12854
|
}
|
|
12074
|
-
var MemoizedUserAvatar = React.memo(UserAvatar);
|
|
12075
|
-
MemoizedUserAvatar.displayName = "UserAvatar";
|
|
12076
12855
|
function PermissionGuard({
|
|
12077
12856
|
permissions,
|
|
12078
12857
|
mode = "all",
|
|
@@ -12514,6 +13293,11 @@ var SessionItem = React.memo(
|
|
|
12514
13293
|
const isTitleGenerating = !session.title?.trim();
|
|
12515
13294
|
const displayTitle = isTitleGenerating ? t("BiChat.Common.Generating") : session.title ?? t("BiChat.Common.Untitled");
|
|
12516
13295
|
const lastActivity = formatRelativeTime(session.updatedAt, t);
|
|
13296
|
+
const accessRole = session.access?.role ?? "owner";
|
|
13297
|
+
const roleLabel = accessRole === "editor" ? t("BiChat.Share.RoleEditor") : accessRole === "viewer" ? t("BiChat.Share.RoleViewer") : accessRole === "read_all" ? t("BiChat.Share.RoleReadOnly") : "";
|
|
13298
|
+
const visibilityLabel = session.isGroup ? t("BiChat.Sidebar.GroupChat") : accessRole === "editor" || accessRole === "viewer" ? t("BiChat.Sidebar.SharedWithYou") : "";
|
|
13299
|
+
const isGroupOrShared = Boolean(session.isGroup || session.memberCount && session.memberCount > 1);
|
|
13300
|
+
const metaParts = [lastActivity, visibilityLabel, roleLabel].filter(Boolean);
|
|
12517
13301
|
const { handlers: longPressHandlers } = useLongPress({
|
|
12518
13302
|
delay: 500,
|
|
12519
13303
|
onLongPress: (e) => {
|
|
@@ -12655,17 +13439,23 @@ var SessionItem = React.memo(
|
|
|
12655
13439
|
"data-testid": `${testIdPrefix}-session-${session.id}`,
|
|
12656
13440
|
...longPressHandlers,
|
|
12657
13441
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
12658
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex
|
|
12659
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
13442
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 min-w-0 flex-1", children: [
|
|
13443
|
+
isGroupOrShared && /* @__PURE__ */ jsxRuntime.jsx(react.UsersThree, { size: 14, weight: "duotone", className: "text-primary-500 dark:text-primary-400 mt-1 flex-shrink-0" }),
|
|
13444
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
|
|
13445
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13446
|
+
MemoizedEditableText,
|
|
13447
|
+
{
|
|
13448
|
+
ref: editableTitleRef,
|
|
13449
|
+
value: displayTitle,
|
|
13450
|
+
onSave: (newTitle) => onRename?.(newTitle),
|
|
13451
|
+
isLoading: isTitleGenerating
|
|
13452
|
+
}
|
|
13453
|
+
),
|
|
13454
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] text-gray-400 dark:text-gray-500 truncate mt-0.5", children: [
|
|
13455
|
+
metaParts.join(" \u2022 "),
|
|
13456
|
+
isGroupOrShared && session.memberCount && session.memberCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center ml-1 rounded-full bg-primary-50 dark:bg-primary-900/30 px-1.5 text-[10px] font-medium text-primary-600 dark:text-primary-400", children: session.memberCount })
|
|
13457
|
+
] })
|
|
13458
|
+
] })
|
|
12669
13459
|
] }),
|
|
12670
13460
|
!isTouch && hasContextMenu && /* @__PURE__ */ jsxRuntime.jsxs(react$1.Menu, { children: [
|
|
12671
13461
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -13019,24 +13809,23 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
|
|
|
13019
13809
|
setOffset((prev) => prev + limit);
|
|
13020
13810
|
}
|
|
13021
13811
|
}, [fetching, hasMore]);
|
|
13022
|
-
const
|
|
13023
|
-
|
|
13024
|
-
|
|
13025
|
-
|
|
13812
|
+
const loadMoreNodeRef = React.useRef(null);
|
|
13813
|
+
const loadMoreRef = React.useCallback((node) => {
|
|
13814
|
+
loadMoreNodeRef.current = node;
|
|
13815
|
+
}, []);
|
|
13816
|
+
React.useEffect(() => {
|
|
13817
|
+
const node = loadMoreNodeRef.current;
|
|
13818
|
+
if (!node || fetching || !hasMore) {
|
|
13819
|
+
return;
|
|
13820
|
+
}
|
|
13821
|
+
const observer = new IntersectionObserver((entries) => {
|
|
13822
|
+
if (entries[0].isIntersecting) {
|
|
13823
|
+
handleLoadMore();
|
|
13026
13824
|
}
|
|
13027
|
-
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
}
|
|
13032
|
-
},
|
|
13033
|
-
{ threshold: 0.1 }
|
|
13034
|
-
);
|
|
13035
|
-
observer.observe(node);
|
|
13036
|
-
return () => observer.disconnect();
|
|
13037
|
-
},
|
|
13038
|
-
[fetching, hasMore, handleLoadMore]
|
|
13039
|
-
);
|
|
13825
|
+
}, { threshold: 0.1 });
|
|
13826
|
+
observer.observe(node);
|
|
13827
|
+
return () => observer.disconnect();
|
|
13828
|
+
}, [fetching, hasMore, handleLoadMore]);
|
|
13040
13829
|
const derivedUsers = React.useMemo(() => {
|
|
13041
13830
|
if (dataSource.listUsers) {
|
|
13042
13831
|
return users;
|
|
@@ -13094,57 +13883,61 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
|
|
|
13094
13883
|
role: "list",
|
|
13095
13884
|
"aria-label": t("BiChat.AllChats.OrganizationChatSessions"),
|
|
13096
13885
|
children: [
|
|
13097
|
-
chats.map((chat) =>
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
|
|
13105
|
-
|
|
13106
|
-
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
|
|
13110
|
-
|
|
13111
|
-
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13886
|
+
chats.map((chat) => {
|
|
13887
|
+
const owner = chat.owner ?? {
|
|
13888
|
+
firstName: "",
|
|
13889
|
+
lastName: "",
|
|
13890
|
+
initials: "U"
|
|
13891
|
+
};
|
|
13892
|
+
const ownerName = [owner.firstName, owner.lastName].filter(Boolean).join(" ");
|
|
13893
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13894
|
+
framerMotion.motion.div,
|
|
13895
|
+
{
|
|
13896
|
+
initial: { opacity: 0, y: -10 },
|
|
13897
|
+
animate: { opacity: 1, y: 0 },
|
|
13898
|
+
exit: { opacity: 0, y: -10 },
|
|
13899
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13900
|
+
"div",
|
|
13901
|
+
{
|
|
13902
|
+
role: "link",
|
|
13903
|
+
tabIndex: 0,
|
|
13904
|
+
onClick: () => onSessionSelect(chat.id),
|
|
13905
|
+
onKeyDown: (e) => {
|
|
13906
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
13907
|
+
e.preventDefault();
|
|
13908
|
+
onSessionSelect(chat.id);
|
|
13909
|
+
}
|
|
13910
|
+
},
|
|
13911
|
+
className: `
|
|
13116
13912
|
block px-3 py-2 rounded-lg transition-smooth group cursor-pointer
|
|
13117
13913
|
${chat.id === activeSessionId ? "bg-primary-50/50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-400 border-l-4 border-primary-400 dark:border-primary-600" : "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 border-l-4 border-transparent"}
|
|
13118
13914
|
`,
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
|
|
13125
|
-
|
|
13126
|
-
|
|
13127
|
-
|
|
13128
|
-
|
|
13129
|
-
|
|
13130
|
-
|
|
13131
|
-
|
|
13132
|
-
|
|
13133
|
-
chat.
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
chat.status === "archived" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 mt-1 px-2 py-0.5 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded-full text-xs", children: [
|
|
13138
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 12, className: "w-3 h-3" }),
|
|
13139
|
-
t("BiChat.Chat.Archived")
|
|
13915
|
+
"aria-current": chat.id === activeSessionId ? "page" : void 0,
|
|
13916
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
|
|
13917
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13918
|
+
MemoizedUserAvatar,
|
|
13919
|
+
{
|
|
13920
|
+
firstName: owner.firstName,
|
|
13921
|
+
lastName: owner.lastName,
|
|
13922
|
+
initials: owner.initials,
|
|
13923
|
+
size: "sm"
|
|
13924
|
+
}
|
|
13925
|
+
),
|
|
13926
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
13927
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: chat.title || t("BiChat.Common.Untitled") }),
|
|
13928
|
+
ownerName && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: ownerName }),
|
|
13929
|
+
chat.status === "archived" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 mt-1 px-2 py-0.5 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded-full text-xs", children: [
|
|
13930
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 12, className: "w-3 h-3" }),
|
|
13931
|
+
t("BiChat.Chat.Archived")
|
|
13932
|
+
] })
|
|
13140
13933
|
] })
|
|
13141
13934
|
] })
|
|
13142
|
-
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
)
|
|
13935
|
+
}
|
|
13936
|
+
)
|
|
13937
|
+
},
|
|
13938
|
+
chat.id
|
|
13939
|
+
);
|
|
13940
|
+
}),
|
|
13148
13941
|
hasMore && /* @__PURE__ */ jsxRuntime.jsx("div", { ref: loadMoreRef, className: "py-4 text-center", children: fetching ? /* @__PURE__ */ jsxRuntime.jsx(SessionSkeleton, { count: 2 }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
13149
13942
|
"button",
|
|
13150
13943
|
{
|
|
@@ -13914,19 +14707,22 @@ function Sidebar2({
|
|
|
13914
14707
|
animate: "visible",
|
|
13915
14708
|
role: "list",
|
|
13916
14709
|
"aria-label": t("BiChat.Sidebar.PinnedChats"),
|
|
13917
|
-
children: pinnedSessions.map((session) =>
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
14710
|
+
children: pinnedSessions.map((session) => {
|
|
14711
|
+
const canWrite = session.access?.canWrite ?? true;
|
|
14712
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14713
|
+
SessionItem_default,
|
|
14714
|
+
{
|
|
14715
|
+
session,
|
|
14716
|
+
isActive: session.id === activeSessionId,
|
|
14717
|
+
onSelect: () => handleSessionSelect(session.id),
|
|
14718
|
+
onArchive: canWrite ? () => handleSessionArchive(session.id) : void 0,
|
|
14719
|
+
onPin: canWrite ? () => handleSessionPin(session.id, session.pinned) : void 0,
|
|
14720
|
+
onRename: canWrite ? (newTitle) => handleSessionRename(session.id, newTitle) : void 0,
|
|
14721
|
+
onRegenerateTitle: canWrite ? () => handleSessionRegenerateTitle(session.id) : void 0
|
|
14722
|
+
},
|
|
14723
|
+
session.id
|
|
14724
|
+
);
|
|
14725
|
+
})
|
|
13930
14726
|
}
|
|
13931
14727
|
),
|
|
13932
14728
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-gray-200 dark:border-gray-700 my-3" })
|
|
@@ -13948,19 +14744,22 @@ function Sidebar2({
|
|
|
13948
14744
|
animate: "visible",
|
|
13949
14745
|
role: "list",
|
|
13950
14746
|
"aria-label": `${group.name} chats`,
|
|
13951
|
-
children: group.sessions.map((session) =>
|
|
13952
|
-
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
13963
|
-
|
|
14747
|
+
children: group.sessions.map((session) => {
|
|
14748
|
+
const canWrite = session.access?.canWrite ?? true;
|
|
14749
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14750
|
+
SessionItem_default,
|
|
14751
|
+
{
|
|
14752
|
+
session,
|
|
14753
|
+
isActive: session.id === activeSessionId,
|
|
14754
|
+
onSelect: () => handleSessionSelect(session.id),
|
|
14755
|
+
onArchive: canWrite ? () => handleSessionArchive(session.id) : void 0,
|
|
14756
|
+
onPin: canWrite ? () => handleSessionPin(session.id, session.pinned) : void 0,
|
|
14757
|
+
onRename: canWrite ? (newTitle) => handleSessionRename(session.id, newTitle) : void 0,
|
|
14758
|
+
onRegenerateTitle: canWrite ? () => handleSessionRegenerateTitle(session.id) : void 0
|
|
14759
|
+
},
|
|
14760
|
+
session.id
|
|
14761
|
+
);
|
|
14762
|
+
})
|
|
13964
14763
|
}
|
|
13965
14764
|
)
|
|
13966
14765
|
] }, group.name)),
|
|
@@ -16121,6 +16920,77 @@ function useScrollToBottom(items) {
|
|
|
16121
16920
|
scrollToBottom
|
|
16122
16921
|
};
|
|
16123
16922
|
}
|
|
16923
|
+
function useHttpDataSourceConfigFromApplet(options) {
|
|
16924
|
+
return React.useMemo(() => {
|
|
16925
|
+
const ctx = typeof window !== "undefined" ? window.__APPLET_CONTEXT__ : void 0;
|
|
16926
|
+
if (!ctx) {
|
|
16927
|
+
throw new Error(
|
|
16928
|
+
"Applet context not found. Ensure window.__APPLET_CONTEXT__ is injected by the backend."
|
|
16929
|
+
);
|
|
16930
|
+
}
|
|
16931
|
+
const rpcEndpoint = ctx.config?.rpcUIEndpoint ?? "/rpc";
|
|
16932
|
+
const streamEndpoint = ctx.config?.streamEndpoint ?? "/stream";
|
|
16933
|
+
const csrfToken = ctx.session?.csrfToken ?? (typeof window !== "undefined" ? window.__CSRF_TOKEN__ : void 0) ?? "";
|
|
16934
|
+
const isDev = typeof undefined?.DEV === "boolean" && undefined?.DEV;
|
|
16935
|
+
if (!csrfToken && isDev) {
|
|
16936
|
+
console.warn(
|
|
16937
|
+
"[useHttpDataSourceConfigFromApplet] CSRF token is empty \u2014 requests may be rejected by the server."
|
|
16938
|
+
);
|
|
16939
|
+
}
|
|
16940
|
+
return {
|
|
16941
|
+
baseUrl: "",
|
|
16942
|
+
rpcEndpoint,
|
|
16943
|
+
streamEndpoint,
|
|
16944
|
+
csrfToken,
|
|
16945
|
+
rpcTimeoutMs: options?.rpcTimeoutMs ?? 12e4,
|
|
16946
|
+
streamConnectTimeoutMs: options?.streamConnectTimeoutMs ?? 3e4
|
|
16947
|
+
};
|
|
16948
|
+
}, [options?.rpcTimeoutMs, options?.streamConnectTimeoutMs]);
|
|
16949
|
+
}
|
|
16950
|
+
var SESSION_PATH_REGEX = /\/session\/([^/]+)/;
|
|
16951
|
+
function useBichatRouter({
|
|
16952
|
+
navigate,
|
|
16953
|
+
pathname,
|
|
16954
|
+
onNavigate
|
|
16955
|
+
}) {
|
|
16956
|
+
const activeSessionId = React.useMemo(
|
|
16957
|
+
() => pathname.match(SESSION_PATH_REGEX)?.[1],
|
|
16958
|
+
[pathname]
|
|
16959
|
+
);
|
|
16960
|
+
const maybeClose = React.useCallback(() => {
|
|
16961
|
+
onNavigate?.();
|
|
16962
|
+
}, [onNavigate]);
|
|
16963
|
+
const onSessionSelect = React.useCallback(
|
|
16964
|
+
(sessionId) => {
|
|
16965
|
+
if (sessionId) {
|
|
16966
|
+
navigate(`/session/${sessionId}`);
|
|
16967
|
+
} else {
|
|
16968
|
+
navigate("/");
|
|
16969
|
+
}
|
|
16970
|
+
maybeClose();
|
|
16971
|
+
},
|
|
16972
|
+
[navigate, maybeClose]
|
|
16973
|
+
);
|
|
16974
|
+
const onNewChat = React.useCallback(() => {
|
|
16975
|
+
navigate("/");
|
|
16976
|
+
maybeClose();
|
|
16977
|
+
}, [navigate, maybeClose]);
|
|
16978
|
+
const onArchivedView = React.useCallback(() => {
|
|
16979
|
+
navigate("/archived");
|
|
16980
|
+
maybeClose();
|
|
16981
|
+
}, [navigate, maybeClose]);
|
|
16982
|
+
const onBack = React.useCallback(() => {
|
|
16983
|
+
navigate("/");
|
|
16984
|
+
maybeClose();
|
|
16985
|
+
}, [navigate, maybeClose]);
|
|
16986
|
+
return {
|
|
16987
|
+
activeSessionId,
|
|
16988
|
+
onSessionSelect,
|
|
16989
|
+
onNewChat,
|
|
16990
|
+
onArchivedView,
|
|
16991
|
+
onBack
|
|
16992
|
+
};
|
|
16993
|
+
}
|
|
16124
16994
|
|
|
16125
16995
|
// ui/src/bichat/index.ts
|
|
16126
16996
|
init_IotaContext();
|
|
@@ -16424,10 +17294,59 @@ function resolveArtifactName(artifact) {
|
|
|
16424
17294
|
}
|
|
16425
17295
|
return `${label} artifact`;
|
|
16426
17296
|
}
|
|
17297
|
+
function mapSessionUser(rawUser) {
|
|
17298
|
+
if (!isRecord2(rawUser)) {
|
|
17299
|
+
return void 0;
|
|
17300
|
+
}
|
|
17301
|
+
const rawId = rawUser.id;
|
|
17302
|
+
const id = readNonEmptyString(rawId) ?? (typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : null);
|
|
17303
|
+
if (!id) {
|
|
17304
|
+
return void 0;
|
|
17305
|
+
}
|
|
17306
|
+
const firstName = readString2(rawUser.firstName);
|
|
17307
|
+
const lastName = readString2(rawUser.lastName);
|
|
17308
|
+
const initials = readNonEmptyString(rawUser.initials) || `${firstName.charAt(0)}${lastName.charAt(0)}`.trim().toUpperCase() || "U";
|
|
17309
|
+
return {
|
|
17310
|
+
id,
|
|
17311
|
+
firstName,
|
|
17312
|
+
lastName,
|
|
17313
|
+
initials
|
|
17314
|
+
};
|
|
17315
|
+
}
|
|
17316
|
+
function mapSessionAccess(rawAccess) {
|
|
17317
|
+
if (!isRecord2(rawAccess)) {
|
|
17318
|
+
return void 0;
|
|
17319
|
+
}
|
|
17320
|
+
const role = readString2(rawAccess.role).toLowerCase();
|
|
17321
|
+
const source = readString2(rawAccess.source).toLowerCase();
|
|
17322
|
+
const normalizedRole = role === "owner" || role === "editor" || role === "viewer" || role === "read_all" ? role : "none";
|
|
17323
|
+
const normalizedSource = source === "owner" || source === "member" || source === "permission" ? source : "none";
|
|
17324
|
+
const canRead = rawAccess.canRead === true || rawAccess.canRead === "true";
|
|
17325
|
+
const canWrite = rawAccess.canWrite === true || rawAccess.canWrite === "true";
|
|
17326
|
+
const canManageMembers = rawAccess.canManageMembers === true || rawAccess.canManageMembers === "true";
|
|
17327
|
+
if (normalizedRole === "none" && normalizedSource === "none" && !canRead && !canWrite && !canManageMembers) {
|
|
17328
|
+
return void 0;
|
|
17329
|
+
}
|
|
17330
|
+
return {
|
|
17331
|
+
role: normalizedRole,
|
|
17332
|
+
source: normalizedSource,
|
|
17333
|
+
canRead,
|
|
17334
|
+
canWrite,
|
|
17335
|
+
canManageMembers
|
|
17336
|
+
};
|
|
17337
|
+
}
|
|
16427
17338
|
function toSession(session) {
|
|
16428
17339
|
return {
|
|
16429
|
-
|
|
16430
|
-
|
|
17340
|
+
id: readString2(session.id),
|
|
17341
|
+
title: readString2(session.title),
|
|
17342
|
+
status: session.status === "archived" ? "archived" : "active",
|
|
17343
|
+
pinned: Boolean(session.pinned),
|
|
17344
|
+
createdAt: readString2(session.createdAt),
|
|
17345
|
+
updatedAt: readString2(session.updatedAt),
|
|
17346
|
+
owner: mapSessionUser(session.owner),
|
|
17347
|
+
isGroup: Boolean(session.isGroup),
|
|
17348
|
+
memberCount: typeof session.memberCount === "number" ? session.memberCount : void 0,
|
|
17349
|
+
access: mapSessionAccess(session.access)
|
|
16431
17350
|
};
|
|
16432
17351
|
}
|
|
16433
17352
|
function toSessionArtifact(artifact) {
|
|
@@ -16701,6 +17620,7 @@ function sanitizeConversationTurn(rawTurn, index, fallbackSessionID) {
|
|
|
16701
17620
|
id: userTurnID,
|
|
16702
17621
|
content: readString2(rawTurn.userTurn.content),
|
|
16703
17622
|
attachments: sanitizeUserAttachments(rawTurn.userTurn.attachments, turnID),
|
|
17623
|
+
author: mapSessionUser(rawTurn.userTurn.author),
|
|
16704
17624
|
createdAt: readString2(rawTurn.userTurn.createdAt, createdAt)
|
|
16705
17625
|
},
|
|
16706
17626
|
assistantTurn: sanitizeAssistantTurn(rawTurn.assistantTurn, createdAt, turnID),
|
|
@@ -17191,7 +18111,85 @@ async function clearSessionHistory(callRPC, sessionId) {
|
|
|
17191
18111
|
return callRPC("bichat.session.clear", { id: sessionId });
|
|
17192
18112
|
}
|
|
17193
18113
|
async function compactSessionHistory(callRPC, sessionId) {
|
|
17194
|
-
|
|
18114
|
+
const result = await callRPC("bichat.session.compact", { id: sessionId });
|
|
18115
|
+
if (!result.accepted) {
|
|
18116
|
+
throw new Error("Session compact request was not accepted");
|
|
18117
|
+
}
|
|
18118
|
+
if (result.operation !== "session_compact") {
|
|
18119
|
+
throw new Error(`Unexpected async operation: ${result.operation}`);
|
|
18120
|
+
}
|
|
18121
|
+
if (!result.sessionId || !result.runId) {
|
|
18122
|
+
throw new Error("Missing async run metadata");
|
|
18123
|
+
}
|
|
18124
|
+
return {
|
|
18125
|
+
accepted: true,
|
|
18126
|
+
operation: result.operation,
|
|
18127
|
+
sessionId: result.sessionId,
|
|
18128
|
+
runId: result.runId,
|
|
18129
|
+
startedAt: result.startedAt
|
|
18130
|
+
};
|
|
18131
|
+
}
|
|
18132
|
+
async function listUsers(callRPC) {
|
|
18133
|
+
const data = await callRPC("bichat.user.list", {});
|
|
18134
|
+
return data.users.map((user) => ({
|
|
18135
|
+
id: String(user.id),
|
|
18136
|
+
firstName: user.firstName || "",
|
|
18137
|
+
lastName: user.lastName || "",
|
|
18138
|
+
initials: user.initials || ""
|
|
18139
|
+
}));
|
|
18140
|
+
}
|
|
18141
|
+
async function listAllSessions(callRPC, options) {
|
|
18142
|
+
const data = await callRPC("bichat.session.listAll", {
|
|
18143
|
+
limit: options?.limit ?? 50,
|
|
18144
|
+
offset: options?.offset ?? 0,
|
|
18145
|
+
includeArchived: options?.includeArchived ?? false,
|
|
18146
|
+
userId: options?.userId ?? null
|
|
18147
|
+
});
|
|
18148
|
+
return {
|
|
18149
|
+
sessions: data.sessions.map(toSession),
|
|
18150
|
+
total: typeof data.total === "number" ? data.total : data.sessions.length,
|
|
18151
|
+
hasMore: Boolean(data.hasMore)
|
|
18152
|
+
};
|
|
18153
|
+
}
|
|
18154
|
+
async function listSessionMembers(callRPC, sessionId) {
|
|
18155
|
+
const data = await callRPC("bichat.session.members.list", { sessionId });
|
|
18156
|
+
return data.members.map((member) => ({
|
|
18157
|
+
user: {
|
|
18158
|
+
id: String(member.user.id),
|
|
18159
|
+
firstName: member.user.firstName,
|
|
18160
|
+
lastName: member.user.lastName,
|
|
18161
|
+
initials: member.user.initials
|
|
18162
|
+
},
|
|
18163
|
+
role: (() => {
|
|
18164
|
+
const normalizedRole = (member.role || "").toLowerCase();
|
|
18165
|
+
if (normalizedRole === "owner") {
|
|
18166
|
+
return "owner";
|
|
18167
|
+
}
|
|
18168
|
+
if (normalizedRole === "editor") {
|
|
18169
|
+
return "editor";
|
|
18170
|
+
}
|
|
18171
|
+
return "viewer";
|
|
18172
|
+
})(),
|
|
18173
|
+
createdAt: member.createdAt,
|
|
18174
|
+
updatedAt: member.updatedAt
|
|
18175
|
+
}));
|
|
18176
|
+
}
|
|
18177
|
+
async function addSessionMember(callRPC, sessionId, userId, role) {
|
|
18178
|
+
await callRPC("bichat.session.members.add", {
|
|
18179
|
+
sessionId,
|
|
18180
|
+
userId,
|
|
18181
|
+
role: role.toUpperCase()
|
|
18182
|
+
});
|
|
18183
|
+
}
|
|
18184
|
+
async function updateSessionMemberRole(callRPC, sessionId, userId, role) {
|
|
18185
|
+
await callRPC("bichat.session.members.updateRole", {
|
|
18186
|
+
sessionId,
|
|
18187
|
+
userId,
|
|
18188
|
+
role: role.toUpperCase()
|
|
18189
|
+
});
|
|
18190
|
+
}
|
|
18191
|
+
async function removeSessionMember(callRPC, sessionId, userId) {
|
|
18192
|
+
await callRPC("bichat.session.members.remove", { sessionId, userId });
|
|
17195
18193
|
}
|
|
17196
18194
|
|
|
17197
18195
|
// ui/src/bichat/utils/sseParser.ts
|
|
@@ -17248,6 +18246,9 @@ var TERMINAL_TYPES = /* @__PURE__ */ new Set(["done", "error"]);
|
|
|
17248
18246
|
async function* parseBichatStream(reader) {
|
|
17249
18247
|
let yieldedTerminal = false;
|
|
17250
18248
|
for await (const event of parseSSEStream(reader)) {
|
|
18249
|
+
if (event.type === "ping") {
|
|
18250
|
+
continue;
|
|
18251
|
+
}
|
|
17251
18252
|
const parsed = event;
|
|
17252
18253
|
const inferredType = parsed.type || (parsed.content ? "content" : "error");
|
|
17253
18254
|
const normalized = {
|
|
@@ -17585,7 +18586,7 @@ async function* sendMessage(deps, sessionId, content, attachments = [], signal,
|
|
|
17585
18586
|
replaceFromMessageId: options?.replaceFromMessageID,
|
|
17586
18587
|
attachments: streamAttachments
|
|
17587
18588
|
};
|
|
17588
|
-
const timeoutMs = deps.
|
|
18589
|
+
const timeoutMs = deps.streamConnectTimeoutMs ?? 0;
|
|
17589
18590
|
if (timeoutMs > 0) {
|
|
17590
18591
|
connectionTimeoutID = setTimeout(() => {
|
|
17591
18592
|
connectionTimedOut = true;
|
|
@@ -17620,7 +18621,7 @@ async function* sendMessage(deps, sessionId, content, attachments = [], signal,
|
|
|
17620
18621
|
if (err.name === "AbortError") {
|
|
17621
18622
|
yield {
|
|
17622
18623
|
type: "error",
|
|
17623
|
-
error: connectionTimedOut ? `Stream request timed out after ${deps.
|
|
18624
|
+
error: connectionTimedOut ? `Stream request timed out after ${deps.streamConnectTimeoutMs}ms` : "Stream cancelled"
|
|
17624
18625
|
};
|
|
17625
18626
|
} else {
|
|
17626
18627
|
yield {
|
|
@@ -17708,7 +18709,7 @@ async function resumeStream(deps, sessionId, runId, onChunk, signal) {
|
|
|
17708
18709
|
const url = buildStreamUrl(deps, "/resume");
|
|
17709
18710
|
const controller = new AbortController();
|
|
17710
18711
|
let timeoutId;
|
|
17711
|
-
const timeoutMs = deps.
|
|
18712
|
+
const timeoutMs = deps.connectTimeoutMs;
|
|
17712
18713
|
if (timeoutMs != null && timeoutMs > 0) {
|
|
17713
18714
|
timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
17714
18715
|
}
|
|
@@ -17725,6 +18726,10 @@ async function resumeStream(deps, sessionId, runId, onChunk, signal) {
|
|
|
17725
18726
|
if (!response.ok) {
|
|
17726
18727
|
throw new Error(`Resume stream failed: HTTP ${response.status}`);
|
|
17727
18728
|
}
|
|
18729
|
+
if (timeoutId !== void 0) {
|
|
18730
|
+
clearTimeout(timeoutId);
|
|
18731
|
+
timeoutId = void 0;
|
|
18732
|
+
}
|
|
17728
18733
|
if (!response.body) {
|
|
17729
18734
|
throw new Error("Resume response body is null");
|
|
17730
18735
|
}
|
|
@@ -17758,11 +18763,7 @@ async function submitQuestionAnswers(callRPC, sessionId, questionId, answers) {
|
|
|
17758
18763
|
});
|
|
17759
18764
|
return {
|
|
17760
18765
|
success: true,
|
|
17761
|
-
data:
|
|
17762
|
-
session: toSession(result.session),
|
|
17763
|
-
turns: normalizeTurns(sanitizeConversationTurns(result.turns, sessionId)),
|
|
17764
|
-
pendingQuestion: sanitizePendingQuestion(result.pendingQuestion, sessionId)
|
|
17765
|
-
}
|
|
18766
|
+
data: normalizeAsyncRunAccepted(result)
|
|
17766
18767
|
};
|
|
17767
18768
|
} catch (err) {
|
|
17768
18769
|
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
@@ -17770,12 +18771,33 @@ async function submitQuestionAnswers(callRPC, sessionId, questionId, answers) {
|
|
|
17770
18771
|
}
|
|
17771
18772
|
async function rejectPendingQuestion(callRPC, sessionId) {
|
|
17772
18773
|
try {
|
|
17773
|
-
await callRPC("bichat.question.reject", { sessionId });
|
|
17774
|
-
return { success: true };
|
|
18774
|
+
const result = await callRPC("bichat.question.reject", { sessionId });
|
|
18775
|
+
return { success: true, data: normalizeAsyncRunAccepted(result) };
|
|
17775
18776
|
} catch (err) {
|
|
17776
18777
|
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
17777
18778
|
}
|
|
17778
18779
|
}
|
|
18780
|
+
function isAsyncRunOperation(value) {
|
|
18781
|
+
return value === "question_submit" || value === "question_reject" || value === "session_compact";
|
|
18782
|
+
}
|
|
18783
|
+
function normalizeAsyncRunAccepted(input) {
|
|
18784
|
+
if (!input.accepted) {
|
|
18785
|
+
throw new Error("Async run request was not accepted");
|
|
18786
|
+
}
|
|
18787
|
+
if (!isAsyncRunOperation(input.operation)) {
|
|
18788
|
+
throw new Error(`Unexpected async operation: ${input.operation}`);
|
|
18789
|
+
}
|
|
18790
|
+
if (!input.sessionId || !input.runId) {
|
|
18791
|
+
throw new Error("Missing async run metadata");
|
|
18792
|
+
}
|
|
18793
|
+
return {
|
|
18794
|
+
accepted: true,
|
|
18795
|
+
operation: input.operation,
|
|
18796
|
+
sessionId: input.sessionId,
|
|
18797
|
+
runId: input.runId,
|
|
18798
|
+
startedAt: input.startedAt
|
|
18799
|
+
};
|
|
18800
|
+
}
|
|
17779
18801
|
|
|
17780
18802
|
// ui/src/bichat/data/ArtifactManager.ts
|
|
17781
18803
|
async function fetchSessionArtifacts(callRPC, sessionId, options) {
|
|
@@ -17805,7 +18827,12 @@ async function uploadSessionArtifacts(callRPC, sessionId, files, uploadFileFn) {
|
|
|
17805
18827
|
const data = await callRPC("bichat.session.uploadArtifacts", {
|
|
17806
18828
|
sessionId,
|
|
17807
18829
|
attachments: uploads.map((upload) => ({
|
|
17808
|
-
|
|
18830
|
+
id: String(upload.id),
|
|
18831
|
+
filename: upload.name,
|
|
18832
|
+
uploadId: upload.id,
|
|
18833
|
+
mimeType: upload.mimetype || "application/octet-stream",
|
|
18834
|
+
sizeBytes: upload.size,
|
|
18835
|
+
url: upload.url
|
|
17809
18836
|
}))
|
|
17810
18837
|
});
|
|
17811
18838
|
return {
|
|
@@ -17842,15 +18869,13 @@ var HttpDataSource = class {
|
|
|
17842
18869
|
this.config = {
|
|
17843
18870
|
streamEndpoint: "/stream",
|
|
17844
18871
|
uploadEndpoint: "/api/uploads",
|
|
17845
|
-
|
|
17846
|
-
|
|
18872
|
+
...config,
|
|
18873
|
+
rpcTimeoutMs: typeof config.rpcTimeoutMs === "number" ? config.rpcTimeoutMs : 12e4,
|
|
18874
|
+
streamConnectTimeoutMs: typeof config.streamConnectTimeoutMs === "number" ? config.streamConnectTimeoutMs : 3e4
|
|
17847
18875
|
};
|
|
17848
|
-
if (config.navigateToSession) {
|
|
17849
|
-
this.navigateToSession = config.navigateToSession;
|
|
17850
|
-
}
|
|
17851
18876
|
this.rpc = createAppletRPCClient({
|
|
17852
18877
|
endpoint: `${this.config.baseUrl}${this.config.rpcEndpoint}`,
|
|
17853
|
-
timeoutMs: this.config.
|
|
18878
|
+
timeoutMs: this.config.rpcTimeoutMs
|
|
17854
18879
|
});
|
|
17855
18880
|
}
|
|
17856
18881
|
// -------------------------------------------------------------------------
|
|
@@ -17932,6 +18957,24 @@ var HttpDataSource = class {
|
|
|
17932
18957
|
async compactSessionHistory(sessionId) {
|
|
17933
18958
|
return compactSessionHistory(this.boundCallRPC, sessionId);
|
|
17934
18959
|
}
|
|
18960
|
+
async listUsers() {
|
|
18961
|
+
return listUsers(this.boundCallRPC);
|
|
18962
|
+
}
|
|
18963
|
+
async listAllSessions(options) {
|
|
18964
|
+
return listAllSessions(this.boundCallRPC, options);
|
|
18965
|
+
}
|
|
18966
|
+
async listSessionMembers(sessionId) {
|
|
18967
|
+
return listSessionMembers(this.boundCallRPC, sessionId);
|
|
18968
|
+
}
|
|
18969
|
+
async addSessionMember(sessionId, userId, role) {
|
|
18970
|
+
return addSessionMember(this.boundCallRPC, sessionId, userId, role);
|
|
18971
|
+
}
|
|
18972
|
+
async updateSessionMemberRole(sessionId, userId, role) {
|
|
18973
|
+
return updateSessionMemberRole(this.boundCallRPC, sessionId, userId, role);
|
|
18974
|
+
}
|
|
18975
|
+
async removeSessionMember(sessionId, userId) {
|
|
18976
|
+
return removeSessionMember(this.boundCallRPC, sessionId, userId);
|
|
18977
|
+
}
|
|
17935
18978
|
// -------------------------------------------------------------------------
|
|
17936
18979
|
// Message transport (delegates to MessageTransport)
|
|
17937
18980
|
// -------------------------------------------------------------------------
|
|
@@ -17952,7 +18995,7 @@ var HttpDataSource = class {
|
|
|
17952
18995
|
baseUrl: this.config.baseUrl,
|
|
17953
18996
|
streamEndpoint: this.config.streamEndpoint,
|
|
17954
18997
|
createHeaders: (h) => this.createHeaders(h),
|
|
17955
|
-
timeoutMs: this.config.
|
|
18998
|
+
timeoutMs: this.config.rpcTimeoutMs
|
|
17956
18999
|
},
|
|
17957
19000
|
sessionId
|
|
17958
19001
|
);
|
|
@@ -17963,7 +19006,7 @@ var HttpDataSource = class {
|
|
|
17963
19006
|
baseUrl: this.config.baseUrl,
|
|
17964
19007
|
streamEndpoint: this.config.streamEndpoint,
|
|
17965
19008
|
createHeaders: (h) => this.createHeaders(h),
|
|
17966
|
-
|
|
19009
|
+
connectTimeoutMs: this.config.streamConnectTimeoutMs
|
|
17967
19010
|
},
|
|
17968
19011
|
sessionId,
|
|
17969
19012
|
runId,
|
|
@@ -17987,7 +19030,8 @@ var HttpDataSource = class {
|
|
|
17987
19030
|
callRPC: this.boundCallRPC,
|
|
17988
19031
|
baseUrl: this.config.baseUrl,
|
|
17989
19032
|
streamEndpoint: this.config.streamEndpoint,
|
|
17990
|
-
|
|
19033
|
+
rpcTimeoutMs: this.config.rpcTimeoutMs,
|
|
19034
|
+
streamConnectTimeoutMs: this.config.streamConnectTimeoutMs,
|
|
17991
19035
|
createHeaders: (additional) => this.createHeaders(additional),
|
|
17992
19036
|
uploadFileFn: this.boundUploadFile,
|
|
17993
19037
|
logAttachmentLifecycle: () => {
|
|
@@ -18038,17 +19082,6 @@ var HttpDataSource = class {
|
|
|
18038
19082
|
async deleteSessionArtifact(artifactId) {
|
|
18039
19083
|
return deleteSessionArtifact(this.boundCallRPC, artifactId);
|
|
18040
19084
|
}
|
|
18041
|
-
// -------------------------------------------------------------------------
|
|
18042
|
-
// Navigation (optional, deprecated)
|
|
18043
|
-
// -------------------------------------------------------------------------
|
|
18044
|
-
/**
|
|
18045
|
-
* @deprecated Pass `onSessionCreated` to `ChatSessionProvider` instead.
|
|
18046
|
-
*/
|
|
18047
|
-
navigateToSession(sessionId) {
|
|
18048
|
-
if (typeof window !== "undefined") {
|
|
18049
|
-
window.location.href = `/chat/${sessionId}`;
|
|
18050
|
-
}
|
|
18051
|
-
}
|
|
18052
19085
|
};
|
|
18053
19086
|
function createHttpDataSource(config) {
|
|
18054
19087
|
return new HttpDataSource(config);
|
|
@@ -18067,6 +19100,7 @@ exports.AttachmentGrid = MemoizedAttachmentGrid;
|
|
|
18067
19100
|
exports.AttachmentPreview = AttachmentPreview_default;
|
|
18068
19101
|
exports.AttachmentUpload = AttachmentUpload_default;
|
|
18069
19102
|
exports.Avatar = Avatar;
|
|
19103
|
+
exports.AvatarStack = AvatarStack;
|
|
18070
19104
|
exports.BiChatLayout = BiChatLayout;
|
|
18071
19105
|
exports.Bubble = Bubble;
|
|
18072
19106
|
exports.CHART_VISUAL = CHART_VISUAL;
|
|
@@ -18110,6 +19144,7 @@ exports.SessionArtifactList = SessionArtifactList;
|
|
|
18110
19144
|
exports.SessionArtifactPreview = SessionArtifactPreview;
|
|
18111
19145
|
exports.SessionArtifactsPanel = SessionArtifactsPanel;
|
|
18112
19146
|
exports.SessionItem = SessionItem_default;
|
|
19147
|
+
exports.SessionMembersModal = SessionMembersModal;
|
|
18113
19148
|
exports.SessionSkeleton = SessionSkeleton;
|
|
18114
19149
|
exports.Sidebar = Sidebar2;
|
|
18115
19150
|
exports.Skeleton = MemoizedSkeleton;
|
|
@@ -18176,6 +19211,7 @@ exports.useActionButtonContext = useActionButtonContext;
|
|
|
18176
19211
|
exports.useAttachments = useAttachments;
|
|
18177
19212
|
exports.useAutoScroll = useAutoScroll;
|
|
18178
19213
|
exports.useAvatarContext = useAvatarContext;
|
|
19214
|
+
exports.useBichatRouter = useBichatRouter;
|
|
18179
19215
|
exports.useBubbleContext = useBubbleContext;
|
|
18180
19216
|
exports.useChatInput = useChatInput;
|
|
18181
19217
|
exports.useChatMessaging = useChatMessaging;
|
|
@@ -18183,6 +19219,7 @@ exports.useChatSession = useChatSession;
|
|
|
18183
19219
|
exports.useConfig = useConfig;
|
|
18184
19220
|
exports.useDataTable = useDataTable;
|
|
18185
19221
|
exports.useFocusTrap = useFocusTrap;
|
|
19222
|
+
exports.useHttpDataSourceConfigFromApplet = useHttpDataSourceConfigFromApplet;
|
|
18186
19223
|
exports.useImageGallery = useImageGallery;
|
|
18187
19224
|
exports.useIotaContext = useIotaContext;
|
|
18188
19225
|
exports.useKeyboardShortcuts = useKeyboardShortcuts;
|