@iota-uz/sdk 0.4.22 → 0.4.24
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 +1309 -379
- package/dist/bichat/index.cjs.map +1 -1
- package/dist/bichat/index.d.cts +1109 -827
- package/dist/bichat/index.d.ts +1109 -827
- package/dist/bichat/index.mjs +1308 -382
- 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
|
@@ -1880,7 +1880,7 @@ function pendingQuestionFromInterrupt(interrupt, fallbackTurnId) {
|
|
|
1880
1880
|
options: Array.isArray(question.options) ? question.options.filter((option) => !!option && typeof option.id === "string").map((option) => ({
|
|
1881
1881
|
id: option.id,
|
|
1882
1882
|
label: typeof option.label === "string" ? option.label : "",
|
|
1883
|
-
value:
|
|
1883
|
+
value: option.id
|
|
1884
1884
|
})) : []
|
|
1885
1885
|
})) : [];
|
|
1886
1886
|
return {
|
|
@@ -3024,14 +3024,9 @@ var ChatMachine = class {
|
|
|
3024
3024
|
if (!curSessionId || !curPendingQuestion) {
|
|
3025
3025
|
return;
|
|
3026
3026
|
}
|
|
3027
|
-
const previousTurns = this.state.messaging.turns;
|
|
3028
3027
|
this._updateMessaging({ loading: true });
|
|
3029
3028
|
this._updateSession({ error: null, errorRetryable: false });
|
|
3030
3029
|
const previousPendingQuestion = curPendingQuestion;
|
|
3031
|
-
this._updateMessaging({
|
|
3032
|
-
pendingQuestion: null,
|
|
3033
|
-
turns: applyTurnLifecycleForPendingQuestion(previousTurns, null)
|
|
3034
|
-
});
|
|
3035
3030
|
try {
|
|
3036
3031
|
const result = await this.dataSource.submitQuestionAnswers(
|
|
3037
3032
|
curSessionId,
|
|
@@ -3042,60 +3037,28 @@ var ChatMachine = class {
|
|
|
3042
3037
|
return;
|
|
3043
3038
|
}
|
|
3044
3039
|
if (result.success) {
|
|
3045
|
-
if (
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
});
|
|
3059
|
-
this._updateSession({
|
|
3060
|
-
error: "Failed to fully refresh session. Showing last known messages.",
|
|
3061
|
-
errorRetryable: true
|
|
3062
|
-
});
|
|
3063
|
-
this._updateMessaging({
|
|
3064
|
-
pendingQuestion: fetchResult.pendingQuestion || null,
|
|
3065
|
-
turns: applyTurnLifecycleForPendingQuestion(
|
|
3066
|
-
previousTurns,
|
|
3067
|
-
fetchResult.pendingQuestion || null
|
|
3068
|
-
)
|
|
3069
|
-
});
|
|
3070
|
-
} else {
|
|
3071
|
-
this._setTurnsFromFetch(fetchResult.turns, fetchResult.pendingQuestion || null);
|
|
3072
|
-
}
|
|
3073
|
-
} else {
|
|
3074
|
-
this._updateSession({ error: "Failed to load updated session", errorRetryable: true });
|
|
3075
|
-
}
|
|
3076
|
-
} catch (fetchErr) {
|
|
3077
|
-
if (this.disposed) {
|
|
3078
|
-
return;
|
|
3079
|
-
}
|
|
3080
|
-
const normalized = normalizeRPCError(fetchErr, "Failed to load updated session");
|
|
3081
|
-
this._updateSession({ error: normalized.userMessage, errorRetryable: true });
|
|
3040
|
+
if (result.data) {
|
|
3041
|
+
this._updateSession({ session: result.data.session });
|
|
3042
|
+
this._setTurnsFromFetch(result.data.turns, result.data.pendingQuestion || null);
|
|
3043
|
+
} else if (curSessionId !== "new") {
|
|
3044
|
+
const fetchResult = await this.dataSource.fetchSession(curSessionId);
|
|
3045
|
+
if (this.disposed) {
|
|
3046
|
+
return;
|
|
3047
|
+
}
|
|
3048
|
+
if (fetchResult) {
|
|
3049
|
+
this._updateSession({ session: fetchResult.session });
|
|
3050
|
+
this._setTurnsFromFetch(fetchResult.turns, fetchResult.pendingQuestion || null);
|
|
3051
|
+
} else {
|
|
3052
|
+
this._updateSession({ error: "Failed to load updated session", errorRetryable: true });
|
|
3082
3053
|
}
|
|
3083
3054
|
}
|
|
3084
3055
|
} else {
|
|
3085
|
-
this._updateMessaging({
|
|
3086
|
-
pendingQuestion: previousPendingQuestion,
|
|
3087
|
-
turns: applyTurnLifecycleForPendingQuestion(previousTurns, previousPendingQuestion)
|
|
3088
|
-
});
|
|
3089
3056
|
this._updateSession({ error: result.error || "Failed to submit answers", errorRetryable: false });
|
|
3090
3057
|
}
|
|
3091
3058
|
} catch (err) {
|
|
3092
3059
|
if (this.disposed) {
|
|
3093
3060
|
return;
|
|
3094
3061
|
}
|
|
3095
|
-
this._updateMessaging({
|
|
3096
|
-
pendingQuestion: previousPendingQuestion,
|
|
3097
|
-
turns: applyTurnLifecycleForPendingQuestion(previousTurns, previousPendingQuestion)
|
|
3098
|
-
});
|
|
3099
3062
|
const normalized = normalizeRPCError(err, "Failed to submit answers");
|
|
3100
3063
|
this._updateSession({ error: normalized.userMessage, errorRetryable: normalized.retryable });
|
|
3101
3064
|
} finally {
|
|
@@ -3340,12 +3303,151 @@ function useBranding() {
|
|
|
3340
3303
|
}, [context.extensions?.branding, t]);
|
|
3341
3304
|
return branding;
|
|
3342
3305
|
}
|
|
3343
|
-
function
|
|
3306
|
+
function hashString(str) {
|
|
3307
|
+
let hash = 0;
|
|
3308
|
+
for (let i = 0; i < str.length; i++) {
|
|
3309
|
+
const char = str.charCodeAt(i);
|
|
3310
|
+
hash = (hash << 5) - hash + char;
|
|
3311
|
+
hash = hash & hash;
|
|
3312
|
+
}
|
|
3313
|
+
return Math.abs(hash);
|
|
3314
|
+
}
|
|
3315
|
+
var colorPalette = [
|
|
3316
|
+
{ bg: "bg-blue-500", text: "text-white" },
|
|
3317
|
+
{ bg: "bg-green-500", text: "text-white" },
|
|
3318
|
+
{ bg: "bg-purple-500", text: "text-white" },
|
|
3319
|
+
{ bg: "bg-pink-500", text: "text-white" },
|
|
3320
|
+
{ bg: "bg-indigo-500", text: "text-white" },
|
|
3321
|
+
{ bg: "bg-teal-500", text: "text-white" },
|
|
3322
|
+
{ bg: "bg-orange-500", text: "text-white" },
|
|
3323
|
+
{ bg: "bg-cyan-500", text: "text-white" },
|
|
3324
|
+
{ bg: "bg-amber-500", text: "text-white" },
|
|
3325
|
+
{ bg: "bg-lime-500", text: "text-white" }
|
|
3326
|
+
];
|
|
3327
|
+
var sizeClasses = {
|
|
3328
|
+
xs: "w-6 h-6 text-[10px]",
|
|
3329
|
+
sm: "w-8 h-8 text-xs",
|
|
3330
|
+
md: "w-10 h-10 text-sm",
|
|
3331
|
+
lg: "w-12 h-12 text-base"
|
|
3332
|
+
};
|
|
3333
|
+
function UserAvatar({
|
|
3334
|
+
firstName,
|
|
3335
|
+
lastName,
|
|
3336
|
+
initials: providedInitials,
|
|
3337
|
+
size = "md",
|
|
3338
|
+
className = ""
|
|
3339
|
+
}) {
|
|
3340
|
+
const derivedInitials = (() => {
|
|
3341
|
+
const firstChar = firstName?.trim()?.charAt(0) || "";
|
|
3342
|
+
const lastChar = lastName?.trim()?.charAt(0) || "";
|
|
3343
|
+
const combined = `${firstChar}${lastChar}`.trim();
|
|
3344
|
+
return combined || "U";
|
|
3345
|
+
})();
|
|
3346
|
+
const initials = (providedInitials?.trim() || derivedInitials).toUpperCase();
|
|
3347
|
+
const fullName = `${firstName}${lastName}`;
|
|
3348
|
+
const colorIndex = hashString(fullName) % colorPalette.length;
|
|
3349
|
+
const colors = colorPalette[colorIndex];
|
|
3350
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3351
|
+
"div",
|
|
3352
|
+
{
|
|
3353
|
+
className: `
|
|
3354
|
+
${sizeClasses[size]}
|
|
3355
|
+
${colors.bg}
|
|
3356
|
+
${colors.text}
|
|
3357
|
+
${className}
|
|
3358
|
+
rounded-full
|
|
3359
|
+
flex
|
|
3360
|
+
items-center
|
|
3361
|
+
justify-center
|
|
3362
|
+
font-semibold
|
|
3363
|
+
flex-shrink-0
|
|
3364
|
+
select-none
|
|
3365
|
+
`,
|
|
3366
|
+
"aria-label": `${firstName} ${lastName}`,
|
|
3367
|
+
title: `${firstName} ${lastName}`,
|
|
3368
|
+
children: initials
|
|
3369
|
+
}
|
|
3370
|
+
);
|
|
3371
|
+
}
|
|
3372
|
+
var MemoizedUserAvatar = React.memo(UserAvatar);
|
|
3373
|
+
MemoizedUserAvatar.displayName = "UserAvatar";
|
|
3374
|
+
var overlapClasses = {
|
|
3375
|
+
xs: "-ml-1.5",
|
|
3376
|
+
sm: "-ml-2"
|
|
3377
|
+
};
|
|
3378
|
+
var badgeSizeClasses = {
|
|
3379
|
+
xs: "w-6 h-6 text-[10px]",
|
|
3380
|
+
sm: "w-8 h-8 text-xs"
|
|
3381
|
+
};
|
|
3382
|
+
function AvatarStackInner({
|
|
3383
|
+
users,
|
|
3384
|
+
max = 3,
|
|
3385
|
+
size = "sm",
|
|
3386
|
+
onClick,
|
|
3387
|
+
className = ""
|
|
3388
|
+
}) {
|
|
3389
|
+
const visible = users.slice(0, max);
|
|
3390
|
+
const overflow = users.length - max;
|
|
3391
|
+
const interactive = typeof onClick === "function";
|
|
3392
|
+
const overlap = overlapClasses[size];
|
|
3393
|
+
const badgeSize = badgeSizeClasses[size];
|
|
3394
|
+
const handleKeyDown = (e) => {
|
|
3395
|
+
if (interactive && (e.key === "Enter" || e.key === " ")) {
|
|
3396
|
+
e.preventDefault();
|
|
3397
|
+
onClick();
|
|
3398
|
+
}
|
|
3399
|
+
};
|
|
3400
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3401
|
+
"div",
|
|
3402
|
+
{
|
|
3403
|
+
className: `inline-flex items-center ${interactive ? "cursor-pointer transition-opacity hover:opacity-80" : ""} ${className}`,
|
|
3404
|
+
onClick: interactive ? onClick : void 0,
|
|
3405
|
+
onKeyDown: interactive ? handleKeyDown : void 0,
|
|
3406
|
+
role: interactive ? "button" : void 0,
|
|
3407
|
+
tabIndex: interactive ? 0 : void 0,
|
|
3408
|
+
"aria-label": interactive ? `${users.length} members` : void 0,
|
|
3409
|
+
children: [
|
|
3410
|
+
visible.map((user, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3411
|
+
"div",
|
|
3412
|
+
{
|
|
3413
|
+
className: `${i > 0 ? overlap : ""} ring-2 ring-white dark:ring-gray-900 rounded-full`,
|
|
3414
|
+
style: { zIndex: visible.length - i },
|
|
3415
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3416
|
+
MemoizedUserAvatar,
|
|
3417
|
+
{
|
|
3418
|
+
firstName: user.firstName,
|
|
3419
|
+
lastName: user.lastName,
|
|
3420
|
+
initials: user.initials,
|
|
3421
|
+
size
|
|
3422
|
+
}
|
|
3423
|
+
)
|
|
3424
|
+
},
|
|
3425
|
+
`${user.firstName}-${user.lastName}-${i}`
|
|
3426
|
+
)),
|
|
3427
|
+
overflow > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3428
|
+
"div",
|
|
3429
|
+
{
|
|
3430
|
+
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`,
|
|
3431
|
+
style: { zIndex: 0 },
|
|
3432
|
+
children: [
|
|
3433
|
+
"+",
|
|
3434
|
+
overflow
|
|
3435
|
+
]
|
|
3436
|
+
}
|
|
3437
|
+
)
|
|
3438
|
+
]
|
|
3439
|
+
}
|
|
3440
|
+
);
|
|
3441
|
+
}
|
|
3442
|
+
var AvatarStack = React.memo(AvatarStackInner);
|
|
3443
|
+
AvatarStack.displayName = "AvatarStack";
|
|
3444
|
+
function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot, members, onMembersClick }) {
|
|
3344
3445
|
const { t } = useTranslation();
|
|
3345
3446
|
const branding = useBranding();
|
|
3346
3447
|
const BackButton = onBack ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3347
3448
|
"button",
|
|
3348
3449
|
{
|
|
3450
|
+
type: "button",
|
|
3349
3451
|
onClick: onBack,
|
|
3350
3452
|
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",
|
|
3351
3453
|
"aria-label": t("BiChat.Chat.GoBack"),
|
|
@@ -3364,23 +3466,42 @@ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
|
|
|
3364
3466
|
] }) });
|
|
3365
3467
|
}
|
|
3366
3468
|
const resolvedSessionTitle = session.title?.trim() || t("BiChat.Chat.NewChat");
|
|
3469
|
+
const isGroupSession = Boolean(session.isGroup || session.memberCount && session.memberCount > 1);
|
|
3470
|
+
const memberCount = session.memberCount ?? 0;
|
|
3471
|
+
const stackUsers = members && members.length > 0 ? members : [];
|
|
3367
3472
|
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: [
|
|
3368
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
3473
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
3369
3474
|
BackButton,
|
|
3370
3475
|
Logo,
|
|
3371
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3476
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
3477
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
3478
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-[var(--bichat-text)] truncate", children: resolvedSessionTitle }),
|
|
3479
|
+
session.pinned && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3480
|
+
"svg",
|
|
3481
|
+
{
|
|
3482
|
+
className: "w-4 h-4 text-[var(--bichat-primary)] flex-shrink-0",
|
|
3483
|
+
fill: "currentColor",
|
|
3484
|
+
viewBox: "0 0 20 20",
|
|
3485
|
+
role: "img",
|
|
3486
|
+
"aria-label": t("BiChat.Chat.Pinned"),
|
|
3487
|
+
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" })
|
|
3488
|
+
}
|
|
3489
|
+
),
|
|
3490
|
+
isGroupSession && stackUsers.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3491
|
+
AvatarStack,
|
|
3492
|
+
{
|
|
3493
|
+
users: stackUsers,
|
|
3494
|
+
max: 3,
|
|
3495
|
+
size: "xs",
|
|
3496
|
+
onClick: onMembersClick,
|
|
3497
|
+
className: "flex-shrink-0"
|
|
3498
|
+
}
|
|
3499
|
+
)
|
|
3500
|
+
] }),
|
|
3501
|
+
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)) })
|
|
3502
|
+
] })
|
|
3382
3503
|
] }),
|
|
3383
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3504
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
|
|
3384
3505
|
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") }),
|
|
3385
3506
|
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") }),
|
|
3386
3507
|
actionsSlot
|
|
@@ -4255,6 +4376,7 @@ function UserMessage({
|
|
|
4255
4376
|
turn,
|
|
4256
4377
|
turnId,
|
|
4257
4378
|
initials = "U",
|
|
4379
|
+
authorName,
|
|
4258
4380
|
slots,
|
|
4259
4381
|
classNames: classNameOverrides,
|
|
4260
4382
|
onCopy,
|
|
@@ -4462,6 +4584,16 @@ function UserMessage({
|
|
|
4462
4584
|
};
|
|
4463
4585
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classes.root, children: [
|
|
4464
4586
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: classes.wrapper, children: [
|
|
4587
|
+
authorName && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4588
|
+
"span",
|
|
4589
|
+
{
|
|
4590
|
+
id: `${turn.id}-author`,
|
|
4591
|
+
role: "note",
|
|
4592
|
+
"aria-label": authorName,
|
|
4593
|
+
className: "mb-1 px-1 text-[11px] text-right text-gray-500 dark:text-gray-400",
|
|
4594
|
+
children: authorName
|
|
4595
|
+
}
|
|
4596
|
+
),
|
|
4465
4597
|
normalizedAttachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: classes.attachments, children: renderSlot(
|
|
4466
4598
|
slots?.attachments,
|
|
4467
4599
|
attachmentsSlotProps,
|
|
@@ -4473,20 +4605,28 @@ function UserMessage({
|
|
|
4473
4605
|
}
|
|
4474
4606
|
)
|
|
4475
4607
|
) }),
|
|
4476
|
-
turn.content && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4477
|
-
|
|
4608
|
+
turn.content && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4609
|
+
"div",
|
|
4478
4610
|
{
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4611
|
+
ref: bubbleRef,
|
|
4612
|
+
className: classes.bubble,
|
|
4613
|
+
"aria-describedby": authorName ? `${turn.id}-author` : void 0,
|
|
4614
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: classes.content, children: isEditing ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4615
|
+
EditForm,
|
|
4616
|
+
{
|
|
4617
|
+
draftContent,
|
|
4618
|
+
onDraftChange: handleDraftChange,
|
|
4619
|
+
onSave: handleEditSave,
|
|
4620
|
+
onCancel: handleEditCancel,
|
|
4621
|
+
onKeyDown: handleEditKeyDown,
|
|
4622
|
+
textareaRef: editTextareaRef,
|
|
4623
|
+
disabled: false,
|
|
4624
|
+
originalContent: turn.content,
|
|
4625
|
+
t
|
|
4626
|
+
}
|
|
4627
|
+
) : renderSlot(slots?.content, contentSlotProps, turn.content) })
|
|
4488
4628
|
}
|
|
4489
|
-
)
|
|
4629
|
+
),
|
|
4490
4630
|
!hideActions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${classes.actions} ${isCopied ? "opacity-100" : ""}`, children: renderSlot(
|
|
4491
4631
|
slots?.actions,
|
|
4492
4632
|
actionsSlotProps,
|
|
@@ -4535,19 +4675,25 @@ function UserTurnView({
|
|
|
4535
4675
|
turn,
|
|
4536
4676
|
slots,
|
|
4537
4677
|
classNames,
|
|
4538
|
-
initials
|
|
4678
|
+
initials,
|
|
4539
4679
|
hideAvatar,
|
|
4540
4680
|
hideActions,
|
|
4541
4681
|
hideTimestamp,
|
|
4542
|
-
allowEdit
|
|
4682
|
+
allowEdit,
|
|
4683
|
+
showAuthorName = false
|
|
4543
4684
|
}) {
|
|
4544
4685
|
const { handleEdit, handleCopy } = useChatMessaging();
|
|
4686
|
+
const author = turn.userTurn.author;
|
|
4687
|
+
const fullName = [author?.firstName || "", author?.lastName || ""].join(" ").trim();
|
|
4688
|
+
const authorName = showAuthorName && fullName.length > 0 ? fullName : void 0;
|
|
4689
|
+
const resolvedInitials = initials ?? author?.initials ?? "U";
|
|
4545
4690
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4546
4691
|
UserMessage,
|
|
4547
4692
|
{
|
|
4548
4693
|
turn: turn.userTurn,
|
|
4549
4694
|
turnId: turn.id,
|
|
4550
|
-
initials,
|
|
4695
|
+
initials: resolvedInitials,
|
|
4696
|
+
authorName,
|
|
4551
4697
|
slots,
|
|
4552
4698
|
classNames,
|
|
4553
4699
|
onCopy: handleCopy,
|
|
@@ -6529,13 +6675,13 @@ function InlineQuestionForm({ pendingQuestion }) {
|
|
|
6529
6675
|
const currentAnswer = answers[currentQuestion?.id];
|
|
6530
6676
|
const currentOtherText = otherTexts[currentQuestion?.id] || "";
|
|
6531
6677
|
const handleOptionChange = React.useCallback(
|
|
6532
|
-
(
|
|
6678
|
+
(optionID, checked) => {
|
|
6533
6679
|
if (!currentQuestion) {
|
|
6534
6680
|
return;
|
|
6535
6681
|
}
|
|
6536
6682
|
const questionId = currentQuestion.id;
|
|
6537
6683
|
const existingAnswer = answers[questionId] || { options: [] };
|
|
6538
|
-
const isOtherOption =
|
|
6684
|
+
const isOtherOption = optionID === "__other__";
|
|
6539
6685
|
const isMultiSelect2 = currentQuestion.type === "MULTIPLE_CHOICE";
|
|
6540
6686
|
if (isOtherOption) {
|
|
6541
6687
|
setAnswers({
|
|
@@ -6550,14 +6696,14 @@ function InlineQuestionForm({ pendingQuestion }) {
|
|
|
6550
6696
|
let newOptions;
|
|
6551
6697
|
if (isMultiSelect2) {
|
|
6552
6698
|
if (!checked) {
|
|
6553
|
-
newOptions = existingAnswer.options.filter((o) => o !==
|
|
6554
|
-
} else if (existingAnswer.options.includes(
|
|
6699
|
+
newOptions = existingAnswer.options.filter((o) => o !== optionID);
|
|
6700
|
+
} else if (existingAnswer.options.includes(optionID)) {
|
|
6555
6701
|
newOptions = existingAnswer.options;
|
|
6556
6702
|
} else {
|
|
6557
|
-
newOptions = [...existingAnswer.options,
|
|
6703
|
+
newOptions = [...existingAnswer.options, optionID];
|
|
6558
6704
|
}
|
|
6559
6705
|
} else {
|
|
6560
|
-
newOptions = checked ? [
|
|
6706
|
+
newOptions = checked ? [optionID] : [];
|
|
6561
6707
|
}
|
|
6562
6708
|
setAnswers({
|
|
6563
6709
|
...answers,
|
|
@@ -6648,7 +6794,7 @@ function InlineQuestionForm({ pendingQuestion }) {
|
|
|
6648
6794
|
const options = (currentQuestion.options || []).filter((option) => Boolean(option && typeof option.label === "string")).map((option, index) => ({
|
|
6649
6795
|
id: option.id || `${currentQuestion.id}-option-${index}`,
|
|
6650
6796
|
label: option.label,
|
|
6651
|
-
value: option.value || option.
|
|
6797
|
+
value: option.value || option.id || `${currentQuestion.id}-option-${index}`
|
|
6652
6798
|
}));
|
|
6653
6799
|
const isOtherSelected = currentAnswer?.customText !== void 0;
|
|
6654
6800
|
const canProceed = isCurrentAnswerValid();
|
|
@@ -6696,7 +6842,7 @@ function InlineQuestionForm({ pendingQuestion }) {
|
|
|
6696
6842
|
] }),
|
|
6697
6843
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 pb-2 space-y-1.5", children: [
|
|
6698
6844
|
options.map((option) => {
|
|
6699
|
-
const isSelected = currentAnswer?.options.includes(option.
|
|
6845
|
+
const isSelected = currentAnswer?.options.includes(option.id) || false;
|
|
6700
6846
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6701
6847
|
"label",
|
|
6702
6848
|
{
|
|
@@ -6724,7 +6870,7 @@ function InlineQuestionForm({ pendingQuestion }) {
|
|
|
6724
6870
|
name: `question-${currentQuestion.id}`,
|
|
6725
6871
|
value: option.value,
|
|
6726
6872
|
checked: isSelected,
|
|
6727
|
-
onChange: (e) => handleOptionChange(option.
|
|
6873
|
+
onChange: (e) => handleOptionChange(option.id, e.target.checked),
|
|
6728
6874
|
className: "sr-only"
|
|
6729
6875
|
}
|
|
6730
6876
|
),
|
|
@@ -8542,7 +8688,7 @@ function StreamingBubble({ content, normalizedContent }) {
|
|
|
8542
8688
|
}
|
|
8543
8689
|
function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readOnly }) {
|
|
8544
8690
|
const { t } = useTranslation();
|
|
8545
|
-
const { currentSessionId, fetching } = useChatSession();
|
|
8691
|
+
const { session, currentSessionId, fetching } = useChatSession();
|
|
8546
8692
|
const {
|
|
8547
8693
|
turns,
|
|
8548
8694
|
streamingContent,
|
|
@@ -8557,6 +8703,7 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
|
|
|
8557
8703
|
() => streamingContent ? normalizeStreamingMarkdown(streamingContent) : "",
|
|
8558
8704
|
[streamingContent]
|
|
8559
8705
|
);
|
|
8706
|
+
const showAuthorNames = Boolean(session?.isGroup);
|
|
8560
8707
|
const showEphemeral = showActivityTrace || showTypingIndicator;
|
|
8561
8708
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 min-h-0", children: [
|
|
8562
8709
|
/* @__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: [
|
|
@@ -8566,6 +8713,10 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
|
|
|
8566
8713
|
const prevDate = index > 0 ? new Date(turns[index - 1].createdAt) : null;
|
|
8567
8714
|
const showDateSeparator = !!prevDate && !dateFns.isSameDay(turnDate, prevDate);
|
|
8568
8715
|
const isLast = index === turns.length - 1;
|
|
8716
|
+
const userTurnProps = {
|
|
8717
|
+
allowEdit: readOnly ? false : isLast,
|
|
8718
|
+
showAuthorName: showAuthorNames
|
|
8719
|
+
};
|
|
8569
8720
|
return /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
|
|
8570
8721
|
showDateSeparator && /* @__PURE__ */ jsxRuntime.jsx(DateSeparator, { date: turnDate }),
|
|
8571
8722
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -8575,7 +8726,7 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
|
|
|
8575
8726
|
isLastTurn: isLast,
|
|
8576
8727
|
renderUserTurn,
|
|
8577
8728
|
renderAssistantTurn,
|
|
8578
|
-
userTurnProps
|
|
8729
|
+
userTurnProps,
|
|
8579
8730
|
assistantTurnProps: readOnly ? { allowRegenerate: false } : void 0
|
|
8580
8731
|
}
|
|
8581
8732
|
)
|
|
@@ -10781,47 +10932,665 @@ function SessionArtifactsPanel({
|
|
|
10781
10932
|
}
|
|
10782
10933
|
);
|
|
10783
10934
|
}
|
|
10935
|
+
var DialogContext = React.createContext(null);
|
|
10936
|
+
var FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
10937
|
+
function InlineDialog({ open, onClose, className, children }) {
|
|
10938
|
+
const containerRef = React.useRef(null);
|
|
10939
|
+
const previousFocusRef = React.useRef(null);
|
|
10940
|
+
React.useEffect(() => {
|
|
10941
|
+
if (!open) {
|
|
10942
|
+
return;
|
|
10943
|
+
}
|
|
10944
|
+
previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
10945
|
+
const container = containerRef.current;
|
|
10946
|
+
if (!container) {
|
|
10947
|
+
return;
|
|
10948
|
+
}
|
|
10949
|
+
const getFocusable = () => Array.from(
|
|
10950
|
+
container.querySelectorAll(FOCUSABLE_SELECTOR)
|
|
10951
|
+
);
|
|
10952
|
+
const handler = (e) => {
|
|
10953
|
+
if (e.key === "Escape") {
|
|
10954
|
+
onClose();
|
|
10955
|
+
return;
|
|
10956
|
+
}
|
|
10957
|
+
if (e.key !== "Tab") {
|
|
10958
|
+
return;
|
|
10959
|
+
}
|
|
10960
|
+
const focusable = getFocusable();
|
|
10961
|
+
if (focusable.length === 0) {
|
|
10962
|
+
e.preventDefault();
|
|
10963
|
+
container.focus();
|
|
10964
|
+
return;
|
|
10965
|
+
}
|
|
10966
|
+
const first = focusable[0];
|
|
10967
|
+
const last = focusable[focusable.length - 1];
|
|
10968
|
+
if (e.shiftKey && document.activeElement === first) {
|
|
10969
|
+
e.preventDefault();
|
|
10970
|
+
last.focus();
|
|
10971
|
+
} else if (!e.shiftKey && document.activeElement === last) {
|
|
10972
|
+
e.preventDefault();
|
|
10973
|
+
first.focus();
|
|
10974
|
+
}
|
|
10975
|
+
};
|
|
10976
|
+
(getFocusable()[0] ?? container)?.focus();
|
|
10977
|
+
container.addEventListener("keydown", handler);
|
|
10978
|
+
return () => {
|
|
10979
|
+
container.removeEventListener("keydown", handler);
|
|
10980
|
+
previousFocusRef.current?.focus();
|
|
10981
|
+
};
|
|
10982
|
+
}, [open, onClose]);
|
|
10983
|
+
if (!open) {
|
|
10984
|
+
return null;
|
|
10985
|
+
}
|
|
10986
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialogContext.Provider, { value: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10987
|
+
"div",
|
|
10988
|
+
{
|
|
10989
|
+
ref: containerRef,
|
|
10990
|
+
className,
|
|
10991
|
+
onClick: onClose,
|
|
10992
|
+
tabIndex: -1,
|
|
10993
|
+
children
|
|
10994
|
+
}
|
|
10995
|
+
) });
|
|
10996
|
+
}
|
|
10997
|
+
function InlineDialogBackdrop(props) {
|
|
10998
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", ...props });
|
|
10999
|
+
}
|
|
11000
|
+
function InlineDialogPanel({
|
|
11001
|
+
children,
|
|
11002
|
+
onClick,
|
|
11003
|
+
...rest
|
|
11004
|
+
}) {
|
|
11005
|
+
const ref = React.useRef(null);
|
|
11006
|
+
React.useEffect(() => {
|
|
11007
|
+
if (!ref.current) {
|
|
11008
|
+
return;
|
|
11009
|
+
}
|
|
11010
|
+
const target = ref.current.querySelector("[data-autofocus]") ?? ref.current.querySelector(
|
|
11011
|
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
11012
|
+
);
|
|
11013
|
+
target?.focus();
|
|
11014
|
+
}, []);
|
|
11015
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11016
|
+
"div",
|
|
11017
|
+
{
|
|
11018
|
+
ref,
|
|
11019
|
+
role: "dialog",
|
|
11020
|
+
"aria-modal": "true",
|
|
11021
|
+
onClick: (e) => {
|
|
11022
|
+
e.stopPropagation();
|
|
11023
|
+
onClick?.(e);
|
|
11024
|
+
},
|
|
11025
|
+
...rest,
|
|
11026
|
+
children
|
|
11027
|
+
}
|
|
11028
|
+
);
|
|
11029
|
+
}
|
|
11030
|
+
function InlineDialogTitle(props) {
|
|
11031
|
+
return /* @__PURE__ */ jsxRuntime.jsx("h2", { ...props });
|
|
11032
|
+
}
|
|
11033
|
+
function InlineDialogDescription(props) {
|
|
11034
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { ...props });
|
|
11035
|
+
}
|
|
10784
11036
|
|
|
10785
|
-
// ui/src/bichat/components/
|
|
11037
|
+
// ui/src/bichat/components/SessionMembersModal.tsx
|
|
10786
11038
|
init_useTranslation();
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
|
|
11039
|
+
init_useTranslation();
|
|
11040
|
+
function ConfirmModalBase({
|
|
11041
|
+
isOpen,
|
|
11042
|
+
title,
|
|
11043
|
+
message,
|
|
11044
|
+
onConfirm,
|
|
11045
|
+
onCancel,
|
|
11046
|
+
confirmText,
|
|
11047
|
+
cancelText,
|
|
11048
|
+
isDanger = false
|
|
10793
11049
|
}) {
|
|
10794
11050
|
const { t } = useTranslation();
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
11051
|
+
const resolvedConfirmText = confirmText?.trim() ? confirmText : t("BiChat.Common.Confirm");
|
|
11052
|
+
const resolvedCancelText = cancelText?.trim() ? cancelText : t("BiChat.Common.Cancel");
|
|
11053
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(InlineDialog, { open: isOpen, onClose: onCancel, className: "relative z-40", children: [
|
|
11054
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogBackdrop, { className: "fixed inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity duration-200" }),
|
|
11055
|
+
/* @__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: [
|
|
11056
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 pt-6 pb-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-4", children: [
|
|
11057
|
+
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" }) }),
|
|
11058
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
11059
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogTitle, { className: "text-base font-semibold text-gray-900 dark:text-gray-100 leading-snug", children: title }),
|
|
11060
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogDescription, { className: "mt-2 text-sm text-gray-600 dark:text-gray-400 leading-relaxed", children: message })
|
|
11061
|
+
] })
|
|
11062
|
+
] }) }),
|
|
11063
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-2.5 px-6 pb-5", children: [
|
|
11064
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11065
|
+
"button",
|
|
10806
11066
|
{
|
|
10807
|
-
|
|
10808
|
-
|
|
11067
|
+
type: "button",
|
|
11068
|
+
onClick: onCancel,
|
|
11069
|
+
...isDanger ? { "data-autofocus": true } : {},
|
|
11070
|
+
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",
|
|
11071
|
+
"data-testid": "confirm-modal-cancel",
|
|
11072
|
+
children: resolvedCancelText
|
|
10809
11073
|
}
|
|
10810
|
-
)
|
|
10811
|
-
/* @__PURE__ */ jsxRuntime.
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
11074
|
+
),
|
|
11075
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11076
|
+
"button",
|
|
11077
|
+
{
|
|
11078
|
+
type: "button",
|
|
11079
|
+
...!isDanger ? { "data-autofocus": true } : {},
|
|
11080
|
+
onClick: onConfirm,
|
|
11081
|
+
className: [
|
|
11082
|
+
"cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-white",
|
|
11083
|
+
"transition-all duration-150 shadow-sm hover:shadow",
|
|
11084
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
|
|
11085
|
+
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"
|
|
11086
|
+
].join(" "),
|
|
11087
|
+
"data-testid": "confirm-modal-confirm",
|
|
11088
|
+
children: resolvedConfirmText
|
|
11089
|
+
}
|
|
11090
|
+
)
|
|
11091
|
+
] })
|
|
11092
|
+
] }) })
|
|
11093
|
+
] });
|
|
11094
|
+
}
|
|
11095
|
+
var ConfirmModal = React.memo(ConfirmModalBase);
|
|
11096
|
+
ConfirmModal.displayName = "ConfirmModal";
|
|
11097
|
+
var ConfirmModal_default = ConfirmModal;
|
|
11098
|
+
var ROLES = ["editor", "viewer"];
|
|
11099
|
+
function RoleSegmentedControl({
|
|
11100
|
+
value,
|
|
11101
|
+
onChange,
|
|
11102
|
+
disabled,
|
|
11103
|
+
size = "md",
|
|
11104
|
+
t
|
|
11105
|
+
}) {
|
|
11106
|
+
const btnBase = size === "sm" ? "px-2 py-0.5 text-[11px]" : "px-3 py-1 text-xs";
|
|
11107
|
+
const currentIndex = ROLES.indexOf(value);
|
|
11108
|
+
const handleKeyDown = (e) => {
|
|
11109
|
+
if (disabled) {
|
|
11110
|
+
return;
|
|
11111
|
+
}
|
|
11112
|
+
let nextIndex = null;
|
|
11113
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
11114
|
+
e.preventDefault();
|
|
11115
|
+
nextIndex = currentIndex <= 0 ? ROLES.length - 1 : currentIndex - 1;
|
|
11116
|
+
} else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
11117
|
+
e.preventDefault();
|
|
11118
|
+
nextIndex = currentIndex >= ROLES.length - 1 ? 0 : currentIndex + 1;
|
|
11119
|
+
}
|
|
11120
|
+
if (nextIndex !== null) {
|
|
11121
|
+
const nextRole = ROLES[nextIndex];
|
|
11122
|
+
onChange(nextRole);
|
|
11123
|
+
const target = e.currentTarget.querySelector(`[data-role="${nextRole}"]`);
|
|
11124
|
+
target?.focus();
|
|
11125
|
+
}
|
|
11126
|
+
};
|
|
11127
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11128
|
+
"div",
|
|
11129
|
+
{
|
|
11130
|
+
role: "radiogroup",
|
|
11131
|
+
"aria-label": t("BiChat.Share.RoleLabel"),
|
|
11132
|
+
className: "inline-flex rounded-lg border border-gray-200 dark:border-gray-700 p-0.5 bg-gray-50 dark:bg-gray-800/50",
|
|
11133
|
+
onKeyDown: handleKeyDown,
|
|
11134
|
+
children: ROLES.map((role) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
11135
|
+
"button",
|
|
11136
|
+
{
|
|
11137
|
+
type: "button",
|
|
11138
|
+
role: "radio",
|
|
11139
|
+
"aria-checked": value === role,
|
|
11140
|
+
tabIndex: value === role ? 0 : -1,
|
|
11141
|
+
"data-role": role,
|
|
11142
|
+
disabled,
|
|
11143
|
+
onClick: () => onChange(role),
|
|
11144
|
+
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"}`,
|
|
11145
|
+
children: role === "editor" ? t("BiChat.Share.RoleEditor") : t("BiChat.Share.RoleViewer")
|
|
11146
|
+
},
|
|
11147
|
+
role
|
|
11148
|
+
))
|
|
11149
|
+
}
|
|
11150
|
+
);
|
|
11151
|
+
}
|
|
11152
|
+
function MemberSkeleton() {
|
|
11153
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 rounded-xl px-3 py-2.5", "aria-hidden": "true", children: [
|
|
11154
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 rounded-full bg-gray-200 dark:bg-gray-700 animate-pulse flex-shrink-0" }),
|
|
11155
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-1.5", children: [
|
|
11156
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-28 rounded bg-gray-200 dark:bg-gray-700 animate-pulse" }),
|
|
11157
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2.5 w-16 rounded bg-gray-100 dark:bg-gray-800 animate-pulse" })
|
|
11158
|
+
] }),
|
|
11159
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 w-16 rounded-lg bg-gray-200 dark:bg-gray-700 animate-pulse" })
|
|
11160
|
+
] });
|
|
11161
|
+
}
|
|
11162
|
+
function SessionMembersModal({ isOpen, sessionId, dataSource, onClose }) {
|
|
11163
|
+
const headingId = React.useId();
|
|
11164
|
+
const { t } = useTranslation();
|
|
11165
|
+
const statusTimerRef = React.useRef();
|
|
11166
|
+
const [loading, setLoading] = React.useState(false);
|
|
11167
|
+
const [saving, setSaving] = React.useState(false);
|
|
11168
|
+
const [error, setError] = React.useState(null);
|
|
11169
|
+
const [users, setUsers] = React.useState([]);
|
|
11170
|
+
const [members, setMembers] = React.useState([]);
|
|
11171
|
+
const [selectedUser, setSelectedUser] = React.useState(null);
|
|
11172
|
+
const [selectedRole, setSelectedRole] = React.useState("editor");
|
|
11173
|
+
const [query, setQuery] = React.useState("");
|
|
11174
|
+
const [confirmRemove, setConfirmRemove] = React.useState(null);
|
|
11175
|
+
const [statusMessage, setStatusMessage] = React.useState(null);
|
|
11176
|
+
const [dropdownOpen, setDropdownOpen] = React.useState(false);
|
|
11177
|
+
const [dropdownHighlightIndex, setDropdownHighlightIndex] = React.useState(0);
|
|
11178
|
+
const dropdownOptionRefs = React.useRef([]);
|
|
11179
|
+
const canManageMembers = Boolean(
|
|
11180
|
+
dataSource.listUsers && dataSource.listSessionMembers && dataSource.addSessionMember && dataSource.updateSessionMemberRole && dataSource.removeSessionMember
|
|
11181
|
+
);
|
|
11182
|
+
const refresh = React.useCallback(async () => {
|
|
11183
|
+
if (!sessionId || !canManageMembers) {
|
|
11184
|
+
return;
|
|
11185
|
+
}
|
|
11186
|
+
setLoading(true);
|
|
11187
|
+
setError(null);
|
|
11188
|
+
try {
|
|
11189
|
+
const [usersData, membersData] = await Promise.all([
|
|
11190
|
+
dataSource.listUsers(),
|
|
11191
|
+
dataSource.listSessionMembers(sessionId)
|
|
11192
|
+
]);
|
|
11193
|
+
setUsers(usersData);
|
|
11194
|
+
setMembers(membersData);
|
|
11195
|
+
} catch {
|
|
11196
|
+
setError(t("BiChat.Share.LoadFailed"));
|
|
11197
|
+
} finally {
|
|
11198
|
+
setLoading(false);
|
|
11199
|
+
}
|
|
11200
|
+
}, [canManageMembers, dataSource, sessionId, t]);
|
|
11201
|
+
React.useEffect(() => {
|
|
11202
|
+
if (!isOpen) {
|
|
11203
|
+
return;
|
|
11204
|
+
}
|
|
11205
|
+
void refresh();
|
|
11206
|
+
}, [isOpen, refresh]);
|
|
11207
|
+
React.useEffect(() => {
|
|
11208
|
+
if (!isOpen) {
|
|
11209
|
+
setQuery("");
|
|
11210
|
+
setSelectedUser(null);
|
|
11211
|
+
setSelectedRole("editor");
|
|
11212
|
+
setError(null);
|
|
11213
|
+
setConfirmRemove(null);
|
|
11214
|
+
setStatusMessage(null);
|
|
11215
|
+
setDropdownOpen(false);
|
|
11216
|
+
setDropdownHighlightIndex(0);
|
|
11217
|
+
}
|
|
11218
|
+
}, [isOpen]);
|
|
11219
|
+
const memberIDs = React.useMemo(() => new Set(members.map((m) => m.user.id)), [members]);
|
|
11220
|
+
const availableUsers = React.useMemo(
|
|
11221
|
+
() => users.filter((user) => !memberIDs.has(user.id)),
|
|
11222
|
+
[users, memberIDs]
|
|
11223
|
+
);
|
|
11224
|
+
const filteredUsers = React.useMemo(() => {
|
|
11225
|
+
if (!query.trim()) {
|
|
11226
|
+
return availableUsers;
|
|
11227
|
+
}
|
|
11228
|
+
const q = query.toLowerCase();
|
|
11229
|
+
return availableUsers.filter(
|
|
11230
|
+
(u) => u.firstName.toLowerCase().includes(q) || u.lastName.toLowerCase().includes(q) || `${u.firstName} ${u.lastName}`.toLowerCase().includes(q)
|
|
11231
|
+
);
|
|
11232
|
+
}, [availableUsers, query]);
|
|
11233
|
+
React.useEffect(() => {
|
|
11234
|
+
setDropdownHighlightIndex(
|
|
11235
|
+
(i) => Math.min(Math.max(0, i), Math.max(0, filteredUsers.length - 1))
|
|
11236
|
+
);
|
|
11237
|
+
}, [filteredUsers.length]);
|
|
11238
|
+
React.useEffect(() => () => clearTimeout(statusTimerRef.current), []);
|
|
11239
|
+
const flashStatus = React.useCallback((msg) => {
|
|
11240
|
+
clearTimeout(statusTimerRef.current);
|
|
11241
|
+
setStatusMessage(msg);
|
|
11242
|
+
statusTimerRef.current = setTimeout(() => setStatusMessage(null), 3e3);
|
|
11243
|
+
}, []);
|
|
11244
|
+
const handleAdd = React.useCallback(async () => {
|
|
11245
|
+
if (!sessionId || !selectedUser || !dataSource.addSessionMember) {
|
|
11246
|
+
return;
|
|
11247
|
+
}
|
|
11248
|
+
setSaving(true);
|
|
11249
|
+
setError(null);
|
|
11250
|
+
try {
|
|
11251
|
+
await dataSource.addSessionMember(sessionId, selectedUser.id, selectedRole);
|
|
11252
|
+
setSelectedUser(null);
|
|
11253
|
+
setQuery("");
|
|
11254
|
+
flashStatus(t("BiChat.Share.MemberAdded"));
|
|
11255
|
+
await refresh();
|
|
11256
|
+
} catch {
|
|
11257
|
+
setError(t("BiChat.Share.AddFailed"));
|
|
11258
|
+
} finally {
|
|
11259
|
+
setSaving(false);
|
|
11260
|
+
}
|
|
11261
|
+
}, [sessionId, selectedUser, selectedRole, dataSource.addSessionMember, refresh, t, flashStatus]);
|
|
11262
|
+
const handleUpdateRole = React.useCallback(async (userId, role) => {
|
|
11263
|
+
if (!sessionId || !dataSource.updateSessionMemberRole) {
|
|
11264
|
+
return;
|
|
11265
|
+
}
|
|
11266
|
+
setSaving(true);
|
|
11267
|
+
setError(null);
|
|
11268
|
+
try {
|
|
11269
|
+
await dataSource.updateSessionMemberRole(sessionId, userId, role);
|
|
11270
|
+
await refresh();
|
|
11271
|
+
} catch {
|
|
11272
|
+
setError(t("BiChat.Share.UpdateFailed"));
|
|
11273
|
+
} finally {
|
|
11274
|
+
setSaving(false);
|
|
11275
|
+
}
|
|
11276
|
+
}, [sessionId, dataSource.updateSessionMemberRole, refresh]);
|
|
11277
|
+
const handleRemove = React.useCallback(async (userId) => {
|
|
11278
|
+
if (!sessionId || !dataSource.removeSessionMember) {
|
|
11279
|
+
return;
|
|
11280
|
+
}
|
|
11281
|
+
setSaving(true);
|
|
11282
|
+
setError(null);
|
|
11283
|
+
try {
|
|
11284
|
+
await dataSource.removeSessionMember(sessionId, userId);
|
|
11285
|
+
flashStatus(t("BiChat.Share.MemberRemoved"));
|
|
11286
|
+
await refresh();
|
|
11287
|
+
} catch {
|
|
11288
|
+
setError(t("BiChat.Share.RemoveFailed"));
|
|
11289
|
+
} finally {
|
|
11290
|
+
setSaving(false);
|
|
11291
|
+
}
|
|
11292
|
+
}, [sessionId, dataSource.removeSessionMember, refresh, flashStatus]);
|
|
11293
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11294
|
+
/* @__PURE__ */ jsxRuntime.jsxs(InlineDialog, { open: isOpen, onClose, className: "relative z-40", children: [
|
|
11295
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogBackdrop, { className: "fixed inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity duration-200" }),
|
|
11296
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 flex items-center justify-center z-50 p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11297
|
+
InlineDialogPanel,
|
|
11298
|
+
{
|
|
11299
|
+
"aria-labelledby": headingId,
|
|
11300
|
+
className: "bg-white dark:bg-gray-800 rounded-2xl shadow-xl dark:shadow-2xl dark:shadow-black/30 max-w-md w-full",
|
|
11301
|
+
children: [
|
|
11302
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 pt-5 pb-4", children: [
|
|
11303
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
11304
|
+
/* @__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" }) }),
|
|
11305
|
+
/* @__PURE__ */ jsxRuntime.jsx(InlineDialogTitle, { id: headingId, className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: t("BiChat.Share.Title") })
|
|
11306
|
+
] }),
|
|
11307
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11308
|
+
"button",
|
|
11309
|
+
{
|
|
11310
|
+
type: "button",
|
|
11311
|
+
onClick: onClose,
|
|
11312
|
+
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",
|
|
11313
|
+
"aria-label": t("BiChat.Common.Close"),
|
|
11314
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { size: 18 })
|
|
11315
|
+
}
|
|
11316
|
+
)
|
|
11317
|
+
] }),
|
|
11318
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 pb-5 space-y-4", children: [
|
|
11319
|
+
!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") }),
|
|
11320
|
+
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 }),
|
|
11321
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: statusMessage }),
|
|
11322
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
11323
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400", children: [
|
|
11324
|
+
t("BiChat.Share.Members"),
|
|
11325
|
+
!loading && members.length > 0 ? ` (${members.length})` : ""
|
|
11326
|
+
] }),
|
|
11327
|
+
/* @__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: [
|
|
11328
|
+
/* @__PURE__ */ jsxRuntime.jsx(MemberSkeleton, {}),
|
|
11329
|
+
/* @__PURE__ */ jsxRuntime.jsx(MemberSkeleton, {}),
|
|
11330
|
+
/* @__PURE__ */ jsxRuntime.jsx(MemberSkeleton, {})
|
|
11331
|
+
] }) : 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: [
|
|
11332
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.UsersThree, { size: 32, weight: "thin", className: "mb-2" }),
|
|
11333
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: t("BiChat.Share.Empty") })
|
|
11334
|
+
] }) : members.map((member) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11335
|
+
"div",
|
|
11336
|
+
{
|
|
11337
|
+
className: "flex items-center gap-3 rounded-xl px-3 py-2 transition-colors hover:bg-gray-50 dark:hover:bg-gray-700/40",
|
|
11338
|
+
children: [
|
|
11339
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11340
|
+
MemoizedUserAvatar,
|
|
11341
|
+
{
|
|
11342
|
+
firstName: member.user.firstName,
|
|
11343
|
+
lastName: member.user.lastName,
|
|
11344
|
+
initials: member.user.initials,
|
|
11345
|
+
size: "sm"
|
|
11346
|
+
}
|
|
11347
|
+
),
|
|
11348
|
+
/* @__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: [
|
|
11349
|
+
member.user.firstName,
|
|
11350
|
+
" ",
|
|
11351
|
+
member.user.lastName
|
|
11352
|
+
] }) }),
|
|
11353
|
+
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: [
|
|
11354
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Crown, { size: 12, weight: "duotone" }),
|
|
11355
|
+
t("BiChat.Share.RoleOwner")
|
|
11356
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
|
|
11357
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11358
|
+
RoleSegmentedControl,
|
|
11359
|
+
{
|
|
11360
|
+
value: member.role,
|
|
11361
|
+
onChange: (role) => handleUpdateRole(member.user.id, role),
|
|
11362
|
+
disabled: saving,
|
|
11363
|
+
size: "sm",
|
|
11364
|
+
t
|
|
11365
|
+
}
|
|
11366
|
+
),
|
|
11367
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11368
|
+
"button",
|
|
11369
|
+
{
|
|
11370
|
+
type: "button",
|
|
11371
|
+
disabled: saving,
|
|
11372
|
+
onClick: () => setConfirmRemove(member),
|
|
11373
|
+
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",
|
|
11374
|
+
"aria-label": `${t("BiChat.Share.Remove")} ${member.user.firstName} ${member.user.lastName}`,
|
|
11375
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(react.Trash, { size: 14 })
|
|
11376
|
+
}
|
|
11377
|
+
)
|
|
11378
|
+
] })
|
|
11379
|
+
]
|
|
11380
|
+
},
|
|
11381
|
+
member.user.id
|
|
11382
|
+
)) })
|
|
11383
|
+
] }),
|
|
11384
|
+
canManageMembers && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-gray-200 dark:border-gray-700 p-3 space-y-3", children: [
|
|
11385
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400", children: t("BiChat.Share.AddMember") }),
|
|
11386
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11387
|
+
"div",
|
|
11388
|
+
{
|
|
11389
|
+
className: "relative",
|
|
11390
|
+
onBlur: (e) => {
|
|
11391
|
+
if (!e.currentTarget.contains(e.relatedTarget)) {
|
|
11392
|
+
setDropdownOpen(false);
|
|
11393
|
+
}
|
|
11394
|
+
},
|
|
11395
|
+
children: [
|
|
11396
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
11397
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11398
|
+
react.MagnifyingGlass,
|
|
11399
|
+
{
|
|
11400
|
+
size: 14,
|
|
11401
|
+
className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 dark:text-gray-500"
|
|
11402
|
+
}
|
|
11403
|
+
),
|
|
11404
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11405
|
+
"input",
|
|
11406
|
+
{
|
|
11407
|
+
type: "text",
|
|
11408
|
+
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",
|
|
11409
|
+
placeholder: t("BiChat.Share.SearchUsers"),
|
|
11410
|
+
value: selectedUser ? `${selectedUser.firstName} ${selectedUser.lastName}` : query,
|
|
11411
|
+
onFocus: () => {
|
|
11412
|
+
setDropdownOpen(true);
|
|
11413
|
+
setDropdownHighlightIndex(0);
|
|
11414
|
+
if (selectedUser) {
|
|
11415
|
+
setSelectedUser(null);
|
|
11416
|
+
setQuery("");
|
|
11417
|
+
}
|
|
11418
|
+
},
|
|
11419
|
+
onChange: (e) => {
|
|
11420
|
+
setQuery(e.target.value);
|
|
11421
|
+
setSelectedUser(null);
|
|
11422
|
+
setDropdownOpen(true);
|
|
11423
|
+
setDropdownHighlightIndex(0);
|
|
11424
|
+
},
|
|
11425
|
+
onKeyDown: (e) => {
|
|
11426
|
+
if (!dropdownOpen || filteredUsers.length === 0) {
|
|
11427
|
+
if (e.key === "Escape") {
|
|
11428
|
+
setDropdownOpen(false);
|
|
11429
|
+
}
|
|
11430
|
+
return;
|
|
11431
|
+
}
|
|
11432
|
+
if (e.key === "Escape") {
|
|
11433
|
+
e.preventDefault();
|
|
11434
|
+
setDropdownOpen(false);
|
|
11435
|
+
setDropdownHighlightIndex(0);
|
|
11436
|
+
return;
|
|
11437
|
+
}
|
|
11438
|
+
if (e.key === "ArrowDown") {
|
|
11439
|
+
e.preventDefault();
|
|
11440
|
+
const next = (dropdownHighlightIndex + 1) % filteredUsers.length;
|
|
11441
|
+
setDropdownHighlightIndex(next);
|
|
11442
|
+
setTimeout(() => dropdownOptionRefs.current[next]?.focus(), 0);
|
|
11443
|
+
return;
|
|
11444
|
+
}
|
|
11445
|
+
if (e.key === "ArrowUp") {
|
|
11446
|
+
e.preventDefault();
|
|
11447
|
+
const next = dropdownHighlightIndex <= 0 ? filteredUsers.length - 1 : dropdownHighlightIndex - 1;
|
|
11448
|
+
setDropdownHighlightIndex(next);
|
|
11449
|
+
setTimeout(() => dropdownOptionRefs.current[next]?.focus(), 0);
|
|
11450
|
+
return;
|
|
11451
|
+
}
|
|
11452
|
+
if (e.key === "Enter") {
|
|
11453
|
+
e.preventDefault();
|
|
11454
|
+
const user = filteredUsers[dropdownHighlightIndex];
|
|
11455
|
+
if (user) {
|
|
11456
|
+
setSelectedUser(user);
|
|
11457
|
+
setQuery("");
|
|
11458
|
+
setDropdownOpen(false);
|
|
11459
|
+
}
|
|
11460
|
+
}
|
|
11461
|
+
}
|
|
11462
|
+
}
|
|
11463
|
+
)
|
|
11464
|
+
] }),
|
|
11465
|
+
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(
|
|
11466
|
+
"button",
|
|
11467
|
+
{
|
|
11468
|
+
type: "button",
|
|
11469
|
+
ref: (el) => {
|
|
11470
|
+
dropdownOptionRefs.current[index] = el;
|
|
11471
|
+
},
|
|
11472
|
+
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" : ""}`,
|
|
11473
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
11474
|
+
onClick: () => {
|
|
11475
|
+
setSelectedUser(user);
|
|
11476
|
+
setQuery("");
|
|
11477
|
+
setDropdownOpen(false);
|
|
11478
|
+
},
|
|
11479
|
+
children: [
|
|
11480
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11481
|
+
MemoizedUserAvatar,
|
|
11482
|
+
{
|
|
11483
|
+
firstName: user.firstName,
|
|
11484
|
+
lastName: user.lastName,
|
|
11485
|
+
initials: user.initials,
|
|
11486
|
+
size: "xs"
|
|
11487
|
+
}
|
|
11488
|
+
),
|
|
11489
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-gray-900 dark:text-gray-100", children: [
|
|
11490
|
+
user.firstName,
|
|
11491
|
+
" ",
|
|
11492
|
+
user.lastName
|
|
11493
|
+
] })
|
|
11494
|
+
]
|
|
11495
|
+
},
|
|
11496
|
+
user.id
|
|
11497
|
+
)) })
|
|
11498
|
+
]
|
|
11499
|
+
}
|
|
11500
|
+
),
|
|
11501
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
11502
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11503
|
+
RoleSegmentedControl,
|
|
11504
|
+
{
|
|
11505
|
+
value: selectedRole,
|
|
11506
|
+
onChange: setSelectedRole,
|
|
11507
|
+
disabled: saving,
|
|
11508
|
+
t
|
|
11509
|
+
}
|
|
11510
|
+
),
|
|
11511
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11512
|
+
"button",
|
|
11513
|
+
{
|
|
11514
|
+
type: "button",
|
|
11515
|
+
onClick: handleAdd,
|
|
11516
|
+
disabled: saving || !selectedUser,
|
|
11517
|
+
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",
|
|
11518
|
+
children: [
|
|
11519
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.UserPlus, { size: 14 }),
|
|
11520
|
+
t("BiChat.Share.Add")
|
|
11521
|
+
]
|
|
11522
|
+
}
|
|
11523
|
+
)
|
|
11524
|
+
] })
|
|
11525
|
+
] })
|
|
11526
|
+
] })
|
|
11527
|
+
]
|
|
11528
|
+
}
|
|
11529
|
+
) })
|
|
11530
|
+
] }),
|
|
11531
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11532
|
+
ConfirmModal,
|
|
11533
|
+
{
|
|
11534
|
+
isOpen: !!confirmRemove,
|
|
11535
|
+
isDanger: true,
|
|
11536
|
+
title: t("BiChat.Share.RemoveConfirmTitle"),
|
|
11537
|
+
message: confirmRemove ? t("BiChat.Share.RemoveConfirmMessage").replace(
|
|
11538
|
+
"{{name}}",
|
|
11539
|
+
`${confirmRemove.user.firstName} ${confirmRemove.user.lastName}`
|
|
11540
|
+
) : "",
|
|
11541
|
+
confirmText: t("BiChat.Share.Remove"),
|
|
11542
|
+
onConfirm: () => {
|
|
11543
|
+
if (confirmRemove) {
|
|
11544
|
+
void handleRemove(confirmRemove.user.id);
|
|
11545
|
+
}
|
|
11546
|
+
setConfirmRemove(null);
|
|
11547
|
+
},
|
|
11548
|
+
onCancel: () => setConfirmRemove(null)
|
|
11549
|
+
}
|
|
11550
|
+
)
|
|
11551
|
+
] });
|
|
11552
|
+
}
|
|
11553
|
+
|
|
11554
|
+
// ui/src/bichat/components/StreamError.tsx
|
|
11555
|
+
init_useTranslation();
|
|
11556
|
+
function StreamError({
|
|
11557
|
+
error,
|
|
11558
|
+
onRetry,
|
|
11559
|
+
onRegenerate,
|
|
11560
|
+
onDismiss,
|
|
11561
|
+
compact = false
|
|
11562
|
+
}) {
|
|
11563
|
+
const { t } = useTranslation();
|
|
11564
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11565
|
+
framerMotion.motion.div,
|
|
11566
|
+
{
|
|
11567
|
+
initial: { opacity: 0, y: 10 },
|
|
11568
|
+
animate: { opacity: 1, y: 0 },
|
|
11569
|
+
exit: { opacity: 0, y: -10 },
|
|
11570
|
+
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`,
|
|
11571
|
+
role: "alert",
|
|
11572
|
+
children: [
|
|
11573
|
+
/* @__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(
|
|
11574
|
+
react.Warning,
|
|
11575
|
+
{
|
|
11576
|
+
className: "w-4 h-4 text-red-600 dark:text-red-400",
|
|
11577
|
+
weight: "fill"
|
|
11578
|
+
}
|
|
11579
|
+
) }),
|
|
11580
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
11581
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-200 leading-snug", children: t("BiChat.Error.Generic") }),
|
|
11582
|
+
/* @__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 }),
|
|
11583
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-2", children: [
|
|
11584
|
+
onRetry && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11585
|
+
"button",
|
|
11586
|
+
{
|
|
11587
|
+
onClick: onRetry,
|
|
11588
|
+
className: "cursor-pointer inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-white bg-red-600 hover:bg-red-700 active:bg-red-800 dark:bg-red-700 dark:hover:bg-red-600 rounded-lg transition-colors shadow-sm",
|
|
11589
|
+
type: "button",
|
|
11590
|
+
children: [
|
|
11591
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.ArrowClockwise, { className: "w-3.5 h-3.5" }),
|
|
11592
|
+
t("BiChat.StreamError.Retry")
|
|
11593
|
+
]
|
|
10825
11594
|
}
|
|
10826
11595
|
),
|
|
10827
11596
|
onRegenerate && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -10909,7 +11678,8 @@ function ChatSessionCore({
|
|
|
10909
11678
|
updateQueueItem
|
|
10910
11679
|
} = useChatInput();
|
|
10911
11680
|
const isArchived = session?.status === "archived";
|
|
10912
|
-
const
|
|
11681
|
+
const accessReadOnly = session?.access ? !session.access.canWrite : false;
|
|
11682
|
+
const effectiveReadOnly = Boolean(readOnly ?? isReadOnly) || isArchived || accessReadOnly;
|
|
10913
11683
|
const [restoring, setRestoring] = React.useState(false);
|
|
10914
11684
|
const handleRestore = React.useCallback(async () => {
|
|
10915
11685
|
if (!session?.id) {
|
|
@@ -10930,6 +11700,8 @@ function ChatSessionCore({
|
|
|
10930
11700
|
const [artifactsPanelExpanded, setArtifactsPanelExpanded] = React.useState(
|
|
10931
11701
|
artifactsPanelDefaultExpanded
|
|
10932
11702
|
);
|
|
11703
|
+
const [membersModalOpen, setMembersModalOpen] = React.useState(false);
|
|
11704
|
+
const [headerMembers, setHeaderMembers] = React.useState(null);
|
|
10933
11705
|
const [artifactsPanelWidth, setArtifactsPanelWidth] = React.useState(ARTIFACTS_PANEL_WIDTH_DEFAULT);
|
|
10934
11706
|
const [isResizingArtifactsPanel, setIsResizingArtifactsPanel] = React.useState(false);
|
|
10935
11707
|
const layoutContainerRef = React.useRef(null);
|
|
@@ -10964,6 +11736,25 @@ function ChatSessionCore({
|
|
|
10964
11736
|
} catch {
|
|
10965
11737
|
}
|
|
10966
11738
|
}, [artifactsPanelStorageKey, showArtifactsPanel]);
|
|
11739
|
+
React.useEffect(() => {
|
|
11740
|
+
if (!session?.id || !dataSource.listSessionMembers) {
|
|
11741
|
+
setHeaderMembers(null);
|
|
11742
|
+
return;
|
|
11743
|
+
}
|
|
11744
|
+
let cancelled = false;
|
|
11745
|
+
dataSource.listSessionMembers(session.id).then((members) => {
|
|
11746
|
+
if (!cancelled) {
|
|
11747
|
+
setHeaderMembers(members.map((m) => m.user));
|
|
11748
|
+
}
|
|
11749
|
+
}).catch(() => {
|
|
11750
|
+
if (!cancelled) {
|
|
11751
|
+
setHeaderMembers(null);
|
|
11752
|
+
}
|
|
11753
|
+
});
|
|
11754
|
+
return () => {
|
|
11755
|
+
cancelled = true;
|
|
11756
|
+
};
|
|
11757
|
+
}, [session?.id, dataSource.listSessionMembers]);
|
|
10967
11758
|
const handleArtifactsResizeStart = React.useCallback(() => {
|
|
10968
11759
|
setIsResizingArtifactsPanel(true);
|
|
10969
11760
|
}, []);
|
|
@@ -11052,9 +11843,27 @@ function ChatSessionCore({
|
|
|
11052
11843
|
window.dispatchEvent(new CustomEvent("bichat:artifacts-panel-expanded", { detail: { expanded: true } }));
|
|
11053
11844
|
}
|
|
11054
11845
|
}
|
|
11055
|
-
};
|
|
11056
|
-
const
|
|
11057
|
-
|
|
11846
|
+
};
|
|
11847
|
+
const canShowShareButton = Boolean(
|
|
11848
|
+
session?.access?.canManageMembers && dataSource.listUsers && dataSource.listSessionMembers && dataSource.addSessionMember && dataSource.updateSessionMemberRole && dataSource.removeSessionMember
|
|
11849
|
+
);
|
|
11850
|
+
const shareButton = canShowShareButton ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11851
|
+
"button",
|
|
11852
|
+
{
|
|
11853
|
+
type: "button",
|
|
11854
|
+
onClick: () => setMembersModalOpen(true),
|
|
11855
|
+
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",
|
|
11856
|
+
"aria-label": t("BiChat.Share.Title"),
|
|
11857
|
+
title: t("BiChat.Share.Title"),
|
|
11858
|
+
children: [
|
|
11859
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.ShareNetwork, { className: "h-4 w-4" }),
|
|
11860
|
+
t("BiChat.Share.Button")
|
|
11861
|
+
]
|
|
11862
|
+
}
|
|
11863
|
+
) : null;
|
|
11864
|
+
const headerActions = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11865
|
+
shareButton,
|
|
11866
|
+
showArtifactsControls && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11058
11867
|
"button",
|
|
11059
11868
|
{
|
|
11060
11869
|
type: "button",
|
|
@@ -11074,7 +11883,7 @@ function ChatSessionCore({
|
|
|
11074
11883
|
}
|
|
11075
11884
|
),
|
|
11076
11885
|
actionsSlot
|
|
11077
|
-
] })
|
|
11886
|
+
] });
|
|
11078
11887
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11079
11888
|
"main",
|
|
11080
11889
|
{
|
|
@@ -11087,7 +11896,9 @@ function ChatSessionCore({
|
|
|
11087
11896
|
onBack,
|
|
11088
11897
|
readOnly: effectiveReadOnly,
|
|
11089
11898
|
logoSlot,
|
|
11090
|
-
actionsSlot: headerActions
|
|
11899
|
+
actionsSlot: headerActions,
|
|
11900
|
+
members: headerMembers ?? (session?.owner ? [session.owner] : void 0),
|
|
11901
|
+
onMembersClick: canShowShareButton ? () => setMembersModalOpen(true) : void 0
|
|
11091
11902
|
}
|
|
11092
11903
|
),
|
|
11093
11904
|
error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -11284,6 +12095,15 @@ function ChatSessionCore({
|
|
|
11284
12095
|
) })
|
|
11285
12096
|
]
|
|
11286
12097
|
}
|
|
12098
|
+
),
|
|
12099
|
+
canShowShareButton && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12100
|
+
SessionMembersModal,
|
|
12101
|
+
{
|
|
12102
|
+
isOpen: membersModalOpen,
|
|
12103
|
+
sessionId: session?.id,
|
|
12104
|
+
dataSource,
|
|
12105
|
+
onClose: () => setMembersModalOpen(false)
|
|
12106
|
+
}
|
|
11287
12107
|
)
|
|
11288
12108
|
]
|
|
11289
12109
|
}
|
|
@@ -11306,7 +12126,7 @@ function ChatSession(props) {
|
|
|
11306
12126
|
// ui/src/bichat/index.ts
|
|
11307
12127
|
init_MarkdownRenderer();
|
|
11308
12128
|
init_ChartCard();
|
|
11309
|
-
var
|
|
12129
|
+
var sizeClasses2 = {
|
|
11310
12130
|
sm: {
|
|
11311
12131
|
container: "py-6 px-3",
|
|
11312
12132
|
title: "text-sm",
|
|
@@ -11331,7 +12151,7 @@ function EmptyState({
|
|
|
11331
12151
|
className = "",
|
|
11332
12152
|
size = "md"
|
|
11333
12153
|
}) {
|
|
11334
|
-
const sizes =
|
|
12154
|
+
const sizes = sizeClasses2[size];
|
|
11335
12155
|
const prefersReducedMotion2 = framerMotion.useReducedMotion();
|
|
11336
12156
|
const duration = prefersReducedMotion2 ? 0 : 0.4;
|
|
11337
12157
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -11391,7 +12211,7 @@ MemoizedEmptyState.displayName = "EmptyState";
|
|
|
11391
12211
|
|
|
11392
12212
|
// ui/src/bichat/components/EditableText.tsx
|
|
11393
12213
|
init_useTranslation();
|
|
11394
|
-
var
|
|
12214
|
+
var sizeClasses3 = {
|
|
11395
12215
|
sm: "text-sm",
|
|
11396
12216
|
md: "text-base",
|
|
11397
12217
|
lg: "text-lg"
|
|
@@ -11462,7 +12282,7 @@ var EditableText = React.forwardRef(
|
|
|
11462
12282
|
const handleBlur = () => {
|
|
11463
12283
|
handleSave();
|
|
11464
12284
|
};
|
|
11465
|
-
const sizeClass =
|
|
12285
|
+
const sizeClass = sizeClasses3[size];
|
|
11466
12286
|
if (isEditing) {
|
|
11467
12287
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11468
12288
|
"div",
|
|
@@ -11522,7 +12342,7 @@ var MemoizedEditableText = React.memo(EditableText);
|
|
|
11522
12342
|
|
|
11523
12343
|
// ui/src/bichat/components/SearchInput.tsx
|
|
11524
12344
|
init_useTranslation();
|
|
11525
|
-
var
|
|
12345
|
+
var sizeClasses4 = {
|
|
11526
12346
|
sm: {
|
|
11527
12347
|
container: "py-1.5 pl-8 pr-8 text-xs",
|
|
11528
12348
|
icon: 14,
|
|
@@ -11555,7 +12375,7 @@ function SearchInput({
|
|
|
11555
12375
|
const resolvedPlaceholder = placeholder ?? t("BiChat.Common.Search");
|
|
11556
12376
|
const resolvedAriaLabel = ariaLabel ?? t("BiChat.Common.Search");
|
|
11557
12377
|
const inputRef = React.useRef(null);
|
|
11558
|
-
const sizes =
|
|
12378
|
+
const sizes = sizeClasses4[size];
|
|
11559
12379
|
React.useEffect(() => {
|
|
11560
12380
|
if (autoFocus && inputRef.current) {
|
|
11561
12381
|
inputRef.current.focus();
|
|
@@ -11982,134 +12802,6 @@ function ToastContainer({ toasts, onDismiss, dismissLabel }) {
|
|
|
11982
12802
|
}
|
|
11983
12803
|
);
|
|
11984
12804
|
}
|
|
11985
|
-
|
|
11986
|
-
// ui/src/bichat/components/ConfirmModal.tsx
|
|
11987
|
-
init_useTranslation();
|
|
11988
|
-
function ConfirmModalBase({
|
|
11989
|
-
isOpen,
|
|
11990
|
-
title,
|
|
11991
|
-
message,
|
|
11992
|
-
onConfirm,
|
|
11993
|
-
onCancel,
|
|
11994
|
-
confirmText,
|
|
11995
|
-
cancelText,
|
|
11996
|
-
isDanger = false
|
|
11997
|
-
}) {
|
|
11998
|
-
const { t } = useTranslation();
|
|
11999
|
-
const resolvedConfirmText = confirmText?.trim() ? confirmText : t("BiChat.Common.Confirm");
|
|
12000
|
-
const resolvedCancelText = cancelText?.trim() ? cancelText : t("BiChat.Common.Cancel");
|
|
12001
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(react$1.Dialog, { open: isOpen, onClose: onCancel, className: "relative z-40", children: [
|
|
12002
|
-
/* @__PURE__ */ jsxRuntime.jsx(react$1.DialogBackdrop, { className: "fixed inset-0 bg-black/40 dark:bg-black/60 backdrop-blur-sm transition-opacity duration-200" }),
|
|
12003
|
-
/* @__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: [
|
|
12004
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 pt-6 pb-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3.5", children: [
|
|
12005
|
-
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" }) }),
|
|
12006
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
12007
|
-
/* @__PURE__ */ jsxRuntime.jsx(react$1.DialogTitle, { className: "text-base font-semibold text-gray-900 dark:text-gray-100 leading-snug", children: title }),
|
|
12008
|
-
/* @__PURE__ */ jsxRuntime.jsx(react$1.Description, { className: "mt-2 text-sm text-gray-600 dark:text-gray-400 leading-relaxed", children: message })
|
|
12009
|
-
] })
|
|
12010
|
-
] }) }),
|
|
12011
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-2.5 px-6 pb-5", children: [
|
|
12012
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12013
|
-
"button",
|
|
12014
|
-
{
|
|
12015
|
-
type: "button",
|
|
12016
|
-
onClick: onCancel,
|
|
12017
|
-
...isDanger ? { "data-autofocus": true } : {},
|
|
12018
|
-
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",
|
|
12019
|
-
"data-testid": "confirm-modal-cancel",
|
|
12020
|
-
children: resolvedCancelText
|
|
12021
|
-
}
|
|
12022
|
-
),
|
|
12023
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12024
|
-
"button",
|
|
12025
|
-
{
|
|
12026
|
-
type: "button",
|
|
12027
|
-
...!isDanger ? { "data-autofocus": true } : {},
|
|
12028
|
-
onClick: onConfirm,
|
|
12029
|
-
className: [
|
|
12030
|
-
"cursor-pointer px-4 py-2 text-sm font-medium rounded-xl text-white",
|
|
12031
|
-
"transition-all duration-150 shadow-sm hover:shadow",
|
|
12032
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
|
|
12033
|
-
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"
|
|
12034
|
-
].join(" "),
|
|
12035
|
-
"data-testid": "confirm-modal-confirm",
|
|
12036
|
-
children: resolvedConfirmText
|
|
12037
|
-
}
|
|
12038
|
-
)
|
|
12039
|
-
] })
|
|
12040
|
-
] }) })
|
|
12041
|
-
] });
|
|
12042
|
-
}
|
|
12043
|
-
var ConfirmModal = React.memo(ConfirmModalBase);
|
|
12044
|
-
ConfirmModal.displayName = "ConfirmModal";
|
|
12045
|
-
var ConfirmModal_default = ConfirmModal;
|
|
12046
|
-
function hashString(str) {
|
|
12047
|
-
let hash = 0;
|
|
12048
|
-
for (let i = 0; i < str.length; i++) {
|
|
12049
|
-
const char = str.charCodeAt(i);
|
|
12050
|
-
hash = (hash << 5) - hash + char;
|
|
12051
|
-
hash = hash & hash;
|
|
12052
|
-
}
|
|
12053
|
-
return Math.abs(hash);
|
|
12054
|
-
}
|
|
12055
|
-
var colorPalette = [
|
|
12056
|
-
{ bg: "bg-blue-500", text: "text-white" },
|
|
12057
|
-
{ bg: "bg-green-500", text: "text-white" },
|
|
12058
|
-
{ bg: "bg-purple-500", text: "text-white" },
|
|
12059
|
-
{ bg: "bg-pink-500", text: "text-white" },
|
|
12060
|
-
{ bg: "bg-indigo-500", text: "text-white" },
|
|
12061
|
-
{ bg: "bg-teal-500", text: "text-white" },
|
|
12062
|
-
{ bg: "bg-orange-500", text: "text-white" },
|
|
12063
|
-
{ bg: "bg-cyan-500", text: "text-white" },
|
|
12064
|
-
{ bg: "bg-amber-500", text: "text-white" },
|
|
12065
|
-
{ bg: "bg-lime-500", text: "text-white" }
|
|
12066
|
-
];
|
|
12067
|
-
var sizeClasses4 = {
|
|
12068
|
-
sm: "w-8 h-8 text-xs",
|
|
12069
|
-
md: "w-10 h-10 text-sm",
|
|
12070
|
-
lg: "w-12 h-12 text-base"
|
|
12071
|
-
};
|
|
12072
|
-
function UserAvatar({
|
|
12073
|
-
firstName,
|
|
12074
|
-
lastName,
|
|
12075
|
-
initials: providedInitials,
|
|
12076
|
-
size = "md",
|
|
12077
|
-
className = ""
|
|
12078
|
-
}) {
|
|
12079
|
-
const derivedInitials = (() => {
|
|
12080
|
-
const firstChar = firstName?.trim()?.charAt(0) || "";
|
|
12081
|
-
const lastChar = lastName?.trim()?.charAt(0) || "";
|
|
12082
|
-
const combined = `${firstChar}${lastChar}`.trim();
|
|
12083
|
-
return combined || "U";
|
|
12084
|
-
})();
|
|
12085
|
-
const initials = (providedInitials?.trim() || derivedInitials).toUpperCase();
|
|
12086
|
-
const fullName = `${firstName}${lastName}`;
|
|
12087
|
-
const colorIndex = hashString(fullName) % colorPalette.length;
|
|
12088
|
-
const colors = colorPalette[colorIndex];
|
|
12089
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12090
|
-
"div",
|
|
12091
|
-
{
|
|
12092
|
-
className: `
|
|
12093
|
-
${sizeClasses4[size]}
|
|
12094
|
-
${colors.bg}
|
|
12095
|
-
${colors.text}
|
|
12096
|
-
${className}
|
|
12097
|
-
rounded-full
|
|
12098
|
-
flex
|
|
12099
|
-
items-center
|
|
12100
|
-
justify-center
|
|
12101
|
-
font-semibold
|
|
12102
|
-
flex-shrink-0
|
|
12103
|
-
select-none
|
|
12104
|
-
`,
|
|
12105
|
-
"aria-label": `${firstName} ${lastName}`,
|
|
12106
|
-
title: `${firstName} ${lastName}`,
|
|
12107
|
-
children: initials
|
|
12108
|
-
}
|
|
12109
|
-
);
|
|
12110
|
-
}
|
|
12111
|
-
var MemoizedUserAvatar = React.memo(UserAvatar);
|
|
12112
|
-
MemoizedUserAvatar.displayName = "UserAvatar";
|
|
12113
12805
|
function PermissionGuard({
|
|
12114
12806
|
permissions,
|
|
12115
12807
|
mode = "all",
|
|
@@ -12551,6 +13243,11 @@ var SessionItem = React.memo(
|
|
|
12551
13243
|
const isTitleGenerating = !session.title?.trim();
|
|
12552
13244
|
const displayTitle = isTitleGenerating ? t("BiChat.Common.Generating") : session.title ?? t("BiChat.Common.Untitled");
|
|
12553
13245
|
const lastActivity = formatRelativeTime(session.updatedAt, t);
|
|
13246
|
+
const accessRole = session.access?.role ?? "owner";
|
|
13247
|
+
const roleLabel = accessRole === "editor" ? t("BiChat.Share.RoleEditor") : accessRole === "viewer" ? t("BiChat.Share.RoleViewer") : accessRole === "read_all" ? t("BiChat.Share.RoleReadOnly") : "";
|
|
13248
|
+
const visibilityLabel = session.isGroup ? t("BiChat.Sidebar.GroupChat") : accessRole === "editor" || accessRole === "viewer" ? t("BiChat.Sidebar.SharedWithYou") : "";
|
|
13249
|
+
const isGroupOrShared = Boolean(session.isGroup || session.memberCount && session.memberCount > 1);
|
|
13250
|
+
const metaParts = [lastActivity, visibilityLabel, roleLabel].filter(Boolean);
|
|
12554
13251
|
const { handlers: longPressHandlers } = useLongPress({
|
|
12555
13252
|
delay: 500,
|
|
12556
13253
|
onLongPress: (e) => {
|
|
@@ -12692,17 +13389,23 @@ var SessionItem = React.memo(
|
|
|
12692
13389
|
"data-testid": `${testIdPrefix}-session-${session.id}`,
|
|
12693
13390
|
...longPressHandlers,
|
|
12694
13391
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
12695
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex
|
|
12696
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12697
|
-
|
|
12698
|
-
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12703
|
-
|
|
12704
|
-
|
|
12705
|
-
|
|
13392
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2 min-w-0 flex-1", children: [
|
|
13393
|
+
isGroupOrShared && /* @__PURE__ */ jsxRuntime.jsx(react.UsersThree, { size: 14, weight: "duotone", className: "text-primary-500 dark:text-primary-400 mt-1 flex-shrink-0" }),
|
|
13394
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
|
|
13395
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13396
|
+
MemoizedEditableText,
|
|
13397
|
+
{
|
|
13398
|
+
ref: editableTitleRef,
|
|
13399
|
+
value: displayTitle,
|
|
13400
|
+
onSave: (newTitle) => onRename?.(newTitle),
|
|
13401
|
+
isLoading: isTitleGenerating
|
|
13402
|
+
}
|
|
13403
|
+
),
|
|
13404
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] text-gray-400 dark:text-gray-500 truncate mt-0.5", children: [
|
|
13405
|
+
metaParts.join(" \u2022 "),
|
|
13406
|
+
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 })
|
|
13407
|
+
] })
|
|
13408
|
+
] })
|
|
12706
13409
|
] }),
|
|
12707
13410
|
!isTouch && hasContextMenu && /* @__PURE__ */ jsxRuntime.jsxs(react$1.Menu, { children: [
|
|
12708
13411
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -13056,24 +13759,23 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
|
|
|
13056
13759
|
setOffset((prev) => prev + limit);
|
|
13057
13760
|
}
|
|
13058
13761
|
}, [fetching, hasMore]);
|
|
13059
|
-
const
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13762
|
+
const loadMoreNodeRef = React.useRef(null);
|
|
13763
|
+
const loadMoreRef = React.useCallback((node) => {
|
|
13764
|
+
loadMoreNodeRef.current = node;
|
|
13765
|
+
}, []);
|
|
13766
|
+
React.useEffect(() => {
|
|
13767
|
+
const node = loadMoreNodeRef.current;
|
|
13768
|
+
if (!node || fetching || !hasMore) {
|
|
13769
|
+
return;
|
|
13770
|
+
}
|
|
13771
|
+
const observer = new IntersectionObserver((entries) => {
|
|
13772
|
+
if (entries[0].isIntersecting) {
|
|
13773
|
+
handleLoadMore();
|
|
13063
13774
|
}
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
}
|
|
13069
|
-
},
|
|
13070
|
-
{ threshold: 0.1 }
|
|
13071
|
-
);
|
|
13072
|
-
observer.observe(node);
|
|
13073
|
-
return () => observer.disconnect();
|
|
13074
|
-
},
|
|
13075
|
-
[fetching, hasMore, handleLoadMore]
|
|
13076
|
-
);
|
|
13775
|
+
}, { threshold: 0.1 });
|
|
13776
|
+
observer.observe(node);
|
|
13777
|
+
return () => observer.disconnect();
|
|
13778
|
+
}, [fetching, hasMore, handleLoadMore]);
|
|
13077
13779
|
const derivedUsers = React.useMemo(() => {
|
|
13078
13780
|
if (dataSource.listUsers) {
|
|
13079
13781
|
return users;
|
|
@@ -13131,57 +13833,61 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
|
|
|
13131
13833
|
role: "list",
|
|
13132
13834
|
"aria-label": t("BiChat.AllChats.OrganizationChatSessions"),
|
|
13133
13835
|
children: [
|
|
13134
|
-
chats.map((chat) =>
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
|
|
13139
|
-
|
|
13140
|
-
|
|
13141
|
-
|
|
13142
|
-
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
|
|
13148
|
-
|
|
13149
|
-
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
|
|
13836
|
+
chats.map((chat) => {
|
|
13837
|
+
const owner = chat.owner ?? {
|
|
13838
|
+
firstName: "",
|
|
13839
|
+
lastName: "",
|
|
13840
|
+
initials: "U"
|
|
13841
|
+
};
|
|
13842
|
+
const ownerName = [owner.firstName, owner.lastName].filter(Boolean).join(" ");
|
|
13843
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13844
|
+
framerMotion.motion.div,
|
|
13845
|
+
{
|
|
13846
|
+
initial: { opacity: 0, y: -10 },
|
|
13847
|
+
animate: { opacity: 1, y: 0 },
|
|
13848
|
+
exit: { opacity: 0, y: -10 },
|
|
13849
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13850
|
+
"div",
|
|
13851
|
+
{
|
|
13852
|
+
role: "link",
|
|
13853
|
+
tabIndex: 0,
|
|
13854
|
+
onClick: () => onSessionSelect(chat.id),
|
|
13855
|
+
onKeyDown: (e) => {
|
|
13856
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
13857
|
+
e.preventDefault();
|
|
13858
|
+
onSessionSelect(chat.id);
|
|
13859
|
+
}
|
|
13860
|
+
},
|
|
13861
|
+
className: `
|
|
13153
13862
|
block px-3 py-2 rounded-lg transition-smooth group cursor-pointer
|
|
13154
13863
|
${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"}
|
|
13155
13864
|
`,
|
|
13156
|
-
|
|
13157
|
-
|
|
13158
|
-
|
|
13159
|
-
|
|
13160
|
-
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
chat.
|
|
13171
|
-
|
|
13172
|
-
|
|
13173
|
-
|
|
13174
|
-
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: [
|
|
13175
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 12, className: "w-3 h-3" }),
|
|
13176
|
-
t("BiChat.Chat.Archived")
|
|
13865
|
+
"aria-current": chat.id === activeSessionId ? "page" : void 0,
|
|
13866
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
|
|
13867
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13868
|
+
MemoizedUserAvatar,
|
|
13869
|
+
{
|
|
13870
|
+
firstName: owner.firstName,
|
|
13871
|
+
lastName: owner.lastName,
|
|
13872
|
+
initials: owner.initials,
|
|
13873
|
+
size: "sm"
|
|
13874
|
+
}
|
|
13875
|
+
),
|
|
13876
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
13877
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: chat.title || t("BiChat.Common.Untitled") }),
|
|
13878
|
+
ownerName && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: ownerName }),
|
|
13879
|
+
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: [
|
|
13880
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 12, className: "w-3 h-3" }),
|
|
13881
|
+
t("BiChat.Chat.Archived")
|
|
13882
|
+
] })
|
|
13177
13883
|
] })
|
|
13178
13884
|
] })
|
|
13179
|
-
|
|
13180
|
-
|
|
13181
|
-
|
|
13182
|
-
|
|
13183
|
-
|
|
13184
|
-
)
|
|
13885
|
+
}
|
|
13886
|
+
)
|
|
13887
|
+
},
|
|
13888
|
+
chat.id
|
|
13889
|
+
);
|
|
13890
|
+
}),
|
|
13185
13891
|
hasMore && /* @__PURE__ */ jsxRuntime.jsx("div", { ref: loadMoreRef, className: "py-4 text-center", children: fetching ? /* @__PURE__ */ jsxRuntime.jsx(SessionSkeleton, { count: 2 }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
13186
13892
|
"button",
|
|
13187
13893
|
{
|
|
@@ -13951,19 +14657,22 @@ function Sidebar2({
|
|
|
13951
14657
|
animate: "visible",
|
|
13952
14658
|
role: "list",
|
|
13953
14659
|
"aria-label": t("BiChat.Sidebar.PinnedChats"),
|
|
13954
|
-
children: pinnedSessions.map((session) =>
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13966
|
-
|
|
14660
|
+
children: pinnedSessions.map((session) => {
|
|
14661
|
+
const canWrite = session.access?.canWrite ?? true;
|
|
14662
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14663
|
+
SessionItem_default,
|
|
14664
|
+
{
|
|
14665
|
+
session,
|
|
14666
|
+
isActive: session.id === activeSessionId,
|
|
14667
|
+
onSelect: () => handleSessionSelect(session.id),
|
|
14668
|
+
onArchive: canWrite ? () => handleSessionArchive(session.id) : void 0,
|
|
14669
|
+
onPin: canWrite ? () => handleSessionPin(session.id, session.pinned) : void 0,
|
|
14670
|
+
onRename: canWrite ? (newTitle) => handleSessionRename(session.id, newTitle) : void 0,
|
|
14671
|
+
onRegenerateTitle: canWrite ? () => handleSessionRegenerateTitle(session.id) : void 0
|
|
14672
|
+
},
|
|
14673
|
+
session.id
|
|
14674
|
+
);
|
|
14675
|
+
})
|
|
13967
14676
|
}
|
|
13968
14677
|
),
|
|
13969
14678
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-gray-200 dark:border-gray-700 my-3" })
|
|
@@ -13985,19 +14694,22 @@ function Sidebar2({
|
|
|
13985
14694
|
animate: "visible",
|
|
13986
14695
|
role: "list",
|
|
13987
14696
|
"aria-label": `${group.name} chats`,
|
|
13988
|
-
children: group.sessions.map((session) =>
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
|
|
14697
|
+
children: group.sessions.map((session) => {
|
|
14698
|
+
const canWrite = session.access?.canWrite ?? true;
|
|
14699
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14700
|
+
SessionItem_default,
|
|
14701
|
+
{
|
|
14702
|
+
session,
|
|
14703
|
+
isActive: session.id === activeSessionId,
|
|
14704
|
+
onSelect: () => handleSessionSelect(session.id),
|
|
14705
|
+
onArchive: canWrite ? () => handleSessionArchive(session.id) : void 0,
|
|
14706
|
+
onPin: canWrite ? () => handleSessionPin(session.id, session.pinned) : void 0,
|
|
14707
|
+
onRename: canWrite ? (newTitle) => handleSessionRename(session.id, newTitle) : void 0,
|
|
14708
|
+
onRegenerateTitle: canWrite ? () => handleSessionRegenerateTitle(session.id) : void 0
|
|
14709
|
+
},
|
|
14710
|
+
session.id
|
|
14711
|
+
);
|
|
14712
|
+
})
|
|
14001
14713
|
}
|
|
14002
14714
|
)
|
|
14003
14715
|
] }, group.name)),
|
|
@@ -14873,12 +15585,12 @@ function QuestionStep({
|
|
|
14873
15585
|
const data = selectedAnswers[question.id] || { };
|
|
14874
15586
|
setOtherText(data.customText || "");
|
|
14875
15587
|
}, [question.id]);
|
|
14876
|
-
const handleOptionClick = (
|
|
15588
|
+
const handleOptionClick = (optionID) => {
|
|
14877
15589
|
if (isMultiSelect) {
|
|
14878
|
-
const newOptions = selectedOptions.includes(
|
|
15590
|
+
const newOptions = selectedOptions.includes(optionID) ? selectedOptions.filter((a) => a !== optionID) : [...selectedOptions, optionID];
|
|
14879
15591
|
onAnswer({ options: newOptions, customText: otherText || void 0 });
|
|
14880
15592
|
} else {
|
|
14881
|
-
onAnswer({ options: [
|
|
15593
|
+
onAnswer({ options: [optionID], customText: otherText || void 0 });
|
|
14882
15594
|
}
|
|
14883
15595
|
};
|
|
14884
15596
|
const handleOtherTextChange = (text) => {
|
|
@@ -14892,11 +15604,11 @@ function QuestionStep({
|
|
|
14892
15604
|
/* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white mb-2", children: question.text }) }),
|
|
14893
15605
|
isMultiSelect && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 dark:text-gray-500 italic", children: t("BiChat.Question.SelectMulti") }),
|
|
14894
15606
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2", children: (question.options || []).map((option) => {
|
|
14895
|
-
const isSelected = selectedOptions.includes(option.
|
|
15607
|
+
const isSelected = selectedOptions.includes(option.id);
|
|
14896
15608
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
14897
15609
|
"button",
|
|
14898
15610
|
{
|
|
14899
|
-
onClick: () => handleOptionClick(option.
|
|
15611
|
+
onClick: () => handleOptionClick(option.id),
|
|
14900
15612
|
className: `
|
|
14901
15613
|
cursor-pointer relative p-4 text-left border-2 rounded-lg transition-all
|
|
14902
15614
|
${isSelected ? "border-primary-500 bg-white dark:bg-gray-800" : "border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 hover:border-gray-300 dark:hover:border-gray-600"}
|
|
@@ -14964,6 +15676,7 @@ function ConfirmationStep({
|
|
|
14964
15676
|
const answerData = answers[question.id] || { options: [] };
|
|
14965
15677
|
const selectedOptions = answerData.options || [];
|
|
14966
15678
|
const customText = answerData.customText;
|
|
15679
|
+
const optionLabelByID = new Map((question.options || []).map((option) => [option.id, option.label]));
|
|
14967
15680
|
const hasAnswer = selectedOptions.length > 0 || !!customText;
|
|
14968
15681
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14969
15682
|
"div",
|
|
@@ -14976,7 +15689,7 @@ function ConfirmationStep({
|
|
|
14976
15689
|
"span",
|
|
14977
15690
|
{
|
|
14978
15691
|
className: "inline-flex items-center px-3 py-1 rounded-lg text-sm font-medium border border-primary-500 bg-primary-500/10 text-primary-600 dark:border-primary-400 dark:bg-primary-400/10 dark:text-primary-400",
|
|
14979
|
-
children: option
|
|
15692
|
+
children: optionLabelByID.get(option) || option
|
|
14980
15693
|
},
|
|
14981
15694
|
option
|
|
14982
15695
|
)),
|
|
@@ -16157,6 +16870,76 @@ function useScrollToBottom(items) {
|
|
|
16157
16870
|
scrollToBottom
|
|
16158
16871
|
};
|
|
16159
16872
|
}
|
|
16873
|
+
function useHttpDataSourceConfigFromApplet(options) {
|
|
16874
|
+
return React.useMemo(() => {
|
|
16875
|
+
const ctx = typeof window !== "undefined" ? window.__APPLET_CONTEXT__ : void 0;
|
|
16876
|
+
if (!ctx) {
|
|
16877
|
+
throw new Error(
|
|
16878
|
+
"Applet context not found. Ensure window.__APPLET_CONTEXT__ is injected by the backend."
|
|
16879
|
+
);
|
|
16880
|
+
}
|
|
16881
|
+
const rpcEndpoint = ctx.config?.rpcUIEndpoint ?? "/rpc";
|
|
16882
|
+
const streamEndpoint = ctx.config?.streamEndpoint ?? "/stream";
|
|
16883
|
+
const csrfToken = ctx.session?.csrfToken ?? (typeof window !== "undefined" ? window.__CSRF_TOKEN__ : void 0) ?? "";
|
|
16884
|
+
const isDev = typeof undefined?.DEV === "boolean" && undefined?.DEV;
|
|
16885
|
+
if (!csrfToken && isDev) {
|
|
16886
|
+
console.warn(
|
|
16887
|
+
"[useHttpDataSourceConfigFromApplet] CSRF token is empty \u2014 requests may be rejected by the server."
|
|
16888
|
+
);
|
|
16889
|
+
}
|
|
16890
|
+
return {
|
|
16891
|
+
baseUrl: "",
|
|
16892
|
+
rpcEndpoint,
|
|
16893
|
+
streamEndpoint,
|
|
16894
|
+
csrfToken,
|
|
16895
|
+
timeout: options?.timeout ?? 12e4
|
|
16896
|
+
};
|
|
16897
|
+
}, [options?.timeout]);
|
|
16898
|
+
}
|
|
16899
|
+
var SESSION_PATH_REGEX = /\/session\/([^/]+)/;
|
|
16900
|
+
function useBichatRouter({
|
|
16901
|
+
navigate,
|
|
16902
|
+
pathname,
|
|
16903
|
+
onNavigate
|
|
16904
|
+
}) {
|
|
16905
|
+
const activeSessionId = React.useMemo(
|
|
16906
|
+
() => pathname.match(SESSION_PATH_REGEX)?.[1],
|
|
16907
|
+
[pathname]
|
|
16908
|
+
);
|
|
16909
|
+
const maybeClose = React.useCallback(() => {
|
|
16910
|
+
onNavigate?.();
|
|
16911
|
+
}, [onNavigate]);
|
|
16912
|
+
const onSessionSelect = React.useCallback(
|
|
16913
|
+
(sessionId) => {
|
|
16914
|
+
if (sessionId) {
|
|
16915
|
+
navigate(`/session/${sessionId}`);
|
|
16916
|
+
} else {
|
|
16917
|
+
navigate("/");
|
|
16918
|
+
}
|
|
16919
|
+
maybeClose();
|
|
16920
|
+
},
|
|
16921
|
+
[navigate, maybeClose]
|
|
16922
|
+
);
|
|
16923
|
+
const onNewChat = React.useCallback(() => {
|
|
16924
|
+
navigate("/");
|
|
16925
|
+
maybeClose();
|
|
16926
|
+
}, [navigate, maybeClose]);
|
|
16927
|
+
const onArchivedView = React.useCallback(() => {
|
|
16928
|
+
navigate("/archived");
|
|
16929
|
+
maybeClose();
|
|
16930
|
+
}, [navigate, maybeClose]);
|
|
16931
|
+
const onBack = React.useCallback(() => {
|
|
16932
|
+
navigate("/");
|
|
16933
|
+
maybeClose();
|
|
16934
|
+
}, [navigate, maybeClose]);
|
|
16935
|
+
return {
|
|
16936
|
+
activeSessionId,
|
|
16937
|
+
onSessionSelect,
|
|
16938
|
+
onNewChat,
|
|
16939
|
+
onArchivedView,
|
|
16940
|
+
onBack
|
|
16941
|
+
};
|
|
16942
|
+
}
|
|
16160
16943
|
|
|
16161
16944
|
// ui/src/bichat/index.ts
|
|
16162
16945
|
init_IotaContext();
|
|
@@ -16460,10 +17243,59 @@ function resolveArtifactName(artifact) {
|
|
|
16460
17243
|
}
|
|
16461
17244
|
return `${label} artifact`;
|
|
16462
17245
|
}
|
|
17246
|
+
function mapSessionUser(rawUser) {
|
|
17247
|
+
if (!isRecord2(rawUser)) {
|
|
17248
|
+
return void 0;
|
|
17249
|
+
}
|
|
17250
|
+
const rawId = rawUser.id;
|
|
17251
|
+
const id = readNonEmptyString(rawId) ?? (typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : null);
|
|
17252
|
+
if (!id) {
|
|
17253
|
+
return void 0;
|
|
17254
|
+
}
|
|
17255
|
+
const firstName = readString2(rawUser.firstName);
|
|
17256
|
+
const lastName = readString2(rawUser.lastName);
|
|
17257
|
+
const initials = readNonEmptyString(rawUser.initials) || `${firstName.charAt(0)}${lastName.charAt(0)}`.trim().toUpperCase() || "U";
|
|
17258
|
+
return {
|
|
17259
|
+
id,
|
|
17260
|
+
firstName,
|
|
17261
|
+
lastName,
|
|
17262
|
+
initials
|
|
17263
|
+
};
|
|
17264
|
+
}
|
|
17265
|
+
function mapSessionAccess(rawAccess) {
|
|
17266
|
+
if (!isRecord2(rawAccess)) {
|
|
17267
|
+
return void 0;
|
|
17268
|
+
}
|
|
17269
|
+
const role = readString2(rawAccess.role).toLowerCase();
|
|
17270
|
+
const source = readString2(rawAccess.source).toLowerCase();
|
|
17271
|
+
const normalizedRole = role === "owner" || role === "editor" || role === "viewer" || role === "read_all" ? role : "none";
|
|
17272
|
+
const normalizedSource = source === "owner" || source === "member" || source === "permission" ? source : "none";
|
|
17273
|
+
const canRead = rawAccess.canRead === true || rawAccess.canRead === "true";
|
|
17274
|
+
const canWrite = rawAccess.canWrite === true || rawAccess.canWrite === "true";
|
|
17275
|
+
const canManageMembers = rawAccess.canManageMembers === true || rawAccess.canManageMembers === "true";
|
|
17276
|
+
if (normalizedRole === "none" && normalizedSource === "none" && !canRead && !canWrite && !canManageMembers) {
|
|
17277
|
+
return void 0;
|
|
17278
|
+
}
|
|
17279
|
+
return {
|
|
17280
|
+
role: normalizedRole,
|
|
17281
|
+
source: normalizedSource,
|
|
17282
|
+
canRead,
|
|
17283
|
+
canWrite,
|
|
17284
|
+
canManageMembers
|
|
17285
|
+
};
|
|
17286
|
+
}
|
|
16463
17287
|
function toSession(session) {
|
|
16464
17288
|
return {
|
|
16465
|
-
|
|
16466
|
-
|
|
17289
|
+
id: readString2(session.id),
|
|
17290
|
+
title: readString2(session.title),
|
|
17291
|
+
status: session.status === "archived" ? "archived" : "active",
|
|
17292
|
+
pinned: Boolean(session.pinned),
|
|
17293
|
+
createdAt: readString2(session.createdAt),
|
|
17294
|
+
updatedAt: readString2(session.updatedAt),
|
|
17295
|
+
owner: mapSessionUser(session.owner),
|
|
17296
|
+
isGroup: Boolean(session.isGroup),
|
|
17297
|
+
memberCount: typeof session.memberCount === "number" ? session.memberCount : void 0,
|
|
17298
|
+
access: mapSessionAccess(session.access)
|
|
16467
17299
|
};
|
|
16468
17300
|
}
|
|
16469
17301
|
function toSessionArtifact(artifact) {
|
|
@@ -16737,6 +17569,7 @@ function sanitizeConversationTurn(rawTurn, index, fallbackSessionID) {
|
|
|
16737
17569
|
id: userTurnID,
|
|
16738
17570
|
content: readString2(rawTurn.userTurn.content),
|
|
16739
17571
|
attachments: sanitizeUserAttachments(rawTurn.userTurn.attachments, turnID),
|
|
17572
|
+
author: mapSessionUser(rawTurn.userTurn.author),
|
|
16740
17573
|
createdAt: readString2(rawTurn.userTurn.createdAt, createdAt)
|
|
16741
17574
|
},
|
|
16742
17575
|
assistantTurn: sanitizeAssistantTurn(rawTurn.assistantTurn, createdAt, turnID),
|
|
@@ -16805,10 +17638,11 @@ function sanitizePendingQuestion(rawPendingQuestion, sessionID) {
|
|
|
16805
17638
|
return true;
|
|
16806
17639
|
}).map((option, optionIndex) => {
|
|
16807
17640
|
const label = readString2(option.label);
|
|
17641
|
+
const id = readString2(option.id, `${questionID}-opt-${optionIndex}`);
|
|
16808
17642
|
return {
|
|
16809
|
-
id
|
|
17643
|
+
id,
|
|
16810
17644
|
label,
|
|
16811
|
-
value:
|
|
17645
|
+
value: id
|
|
16812
17646
|
};
|
|
16813
17647
|
}) : [];
|
|
16814
17648
|
return {
|
|
@@ -17228,6 +18062,68 @@ async function clearSessionHistory(callRPC, sessionId) {
|
|
|
17228
18062
|
async function compactSessionHistory(callRPC, sessionId) {
|
|
17229
18063
|
return callRPC("bichat.session.compact", { id: sessionId });
|
|
17230
18064
|
}
|
|
18065
|
+
async function listUsers(callRPC) {
|
|
18066
|
+
const data = await callRPC("bichat.user.list", {});
|
|
18067
|
+
return data.users.map((user) => ({
|
|
18068
|
+
id: String(user.id),
|
|
18069
|
+
firstName: user.firstName || "",
|
|
18070
|
+
lastName: user.lastName || "",
|
|
18071
|
+
initials: user.initials || ""
|
|
18072
|
+
}));
|
|
18073
|
+
}
|
|
18074
|
+
async function listAllSessions(callRPC, options) {
|
|
18075
|
+
const data = await callRPC("bichat.session.listAll", {
|
|
18076
|
+
limit: options?.limit ?? 50,
|
|
18077
|
+
offset: options?.offset ?? 0,
|
|
18078
|
+
includeArchived: options?.includeArchived ?? false,
|
|
18079
|
+
userId: options?.userId ?? null
|
|
18080
|
+
});
|
|
18081
|
+
return {
|
|
18082
|
+
sessions: data.sessions.map(toSession),
|
|
18083
|
+
total: typeof data.total === "number" ? data.total : data.sessions.length,
|
|
18084
|
+
hasMore: Boolean(data.hasMore)
|
|
18085
|
+
};
|
|
18086
|
+
}
|
|
18087
|
+
async function listSessionMembers(callRPC, sessionId) {
|
|
18088
|
+
const data = await callRPC("bichat.session.members.list", { sessionId });
|
|
18089
|
+
return data.members.map((member) => ({
|
|
18090
|
+
user: {
|
|
18091
|
+
id: String(member.user.id),
|
|
18092
|
+
firstName: member.user.firstName,
|
|
18093
|
+
lastName: member.user.lastName,
|
|
18094
|
+
initials: member.user.initials
|
|
18095
|
+
},
|
|
18096
|
+
role: (() => {
|
|
18097
|
+
const normalizedRole = (member.role || "").toLowerCase();
|
|
18098
|
+
if (normalizedRole === "owner") {
|
|
18099
|
+
return "owner";
|
|
18100
|
+
}
|
|
18101
|
+
if (normalizedRole === "editor") {
|
|
18102
|
+
return "editor";
|
|
18103
|
+
}
|
|
18104
|
+
return "viewer";
|
|
18105
|
+
})(),
|
|
18106
|
+
createdAt: member.createdAt,
|
|
18107
|
+
updatedAt: member.updatedAt
|
|
18108
|
+
}));
|
|
18109
|
+
}
|
|
18110
|
+
async function addSessionMember(callRPC, sessionId, userId, role) {
|
|
18111
|
+
await callRPC("bichat.session.members.add", {
|
|
18112
|
+
sessionId,
|
|
18113
|
+
userId,
|
|
18114
|
+
role: role.toUpperCase()
|
|
18115
|
+
});
|
|
18116
|
+
}
|
|
18117
|
+
async function updateSessionMemberRole(callRPC, sessionId, userId, role) {
|
|
18118
|
+
await callRPC("bichat.session.members.updateRole", {
|
|
18119
|
+
sessionId,
|
|
18120
|
+
userId,
|
|
18121
|
+
role: role.toUpperCase()
|
|
18122
|
+
});
|
|
18123
|
+
}
|
|
18124
|
+
async function removeSessionMember(callRPC, sessionId, userId) {
|
|
18125
|
+
await callRPC("bichat.session.members.remove", { sessionId, userId });
|
|
18126
|
+
}
|
|
17231
18127
|
|
|
17232
18128
|
// ui/src/bichat/utils/sseParser.ts
|
|
17233
18129
|
function* processDataLines(lines) {
|
|
@@ -17786,12 +18682,19 @@ async function submitQuestionAnswers(callRPC, sessionId, questionId, answers) {
|
|
|
17786
18682
|
flatAnswers[qId] = answerData.options.join(", ");
|
|
17787
18683
|
}
|
|
17788
18684
|
}
|
|
17789
|
-
await callRPC("bichat.question.submit", {
|
|
18685
|
+
const result = await callRPC("bichat.question.submit", {
|
|
17790
18686
|
sessionId,
|
|
17791
18687
|
checkpointId: questionId,
|
|
17792
18688
|
answers: flatAnswers
|
|
17793
18689
|
});
|
|
17794
|
-
return {
|
|
18690
|
+
return {
|
|
18691
|
+
success: true,
|
|
18692
|
+
data: {
|
|
18693
|
+
session: toSession(result.session),
|
|
18694
|
+
turns: normalizeTurns(sanitizeConversationTurns(result.turns, sessionId)),
|
|
18695
|
+
pendingQuestion: sanitizePendingQuestion(result.pendingQuestion, sessionId)
|
|
18696
|
+
}
|
|
18697
|
+
};
|
|
17795
18698
|
} catch (err) {
|
|
17796
18699
|
return { success: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
17797
18700
|
}
|
|
@@ -17833,7 +18736,12 @@ async function uploadSessionArtifacts(callRPC, sessionId, files, uploadFileFn) {
|
|
|
17833
18736
|
const data = await callRPC("bichat.session.uploadArtifacts", {
|
|
17834
18737
|
sessionId,
|
|
17835
18738
|
attachments: uploads.map((upload) => ({
|
|
17836
|
-
|
|
18739
|
+
id: String(upload.id),
|
|
18740
|
+
filename: upload.name,
|
|
18741
|
+
uploadId: upload.id,
|
|
18742
|
+
mimeType: upload.mimetype || "application/octet-stream",
|
|
18743
|
+
sizeBytes: upload.size,
|
|
18744
|
+
url: upload.url
|
|
17837
18745
|
}))
|
|
17838
18746
|
});
|
|
17839
18747
|
return {
|
|
@@ -17960,6 +18868,24 @@ var HttpDataSource = class {
|
|
|
17960
18868
|
async compactSessionHistory(sessionId) {
|
|
17961
18869
|
return compactSessionHistory(this.boundCallRPC, sessionId);
|
|
17962
18870
|
}
|
|
18871
|
+
async listUsers() {
|
|
18872
|
+
return listUsers(this.boundCallRPC);
|
|
18873
|
+
}
|
|
18874
|
+
async listAllSessions(options) {
|
|
18875
|
+
return listAllSessions(this.boundCallRPC, options);
|
|
18876
|
+
}
|
|
18877
|
+
async listSessionMembers(sessionId) {
|
|
18878
|
+
return listSessionMembers(this.boundCallRPC, sessionId);
|
|
18879
|
+
}
|
|
18880
|
+
async addSessionMember(sessionId, userId, role) {
|
|
18881
|
+
return addSessionMember(this.boundCallRPC, sessionId, userId, role);
|
|
18882
|
+
}
|
|
18883
|
+
async updateSessionMemberRole(sessionId, userId, role) {
|
|
18884
|
+
return updateSessionMemberRole(this.boundCallRPC, sessionId, userId, role);
|
|
18885
|
+
}
|
|
18886
|
+
async removeSessionMember(sessionId, userId) {
|
|
18887
|
+
return removeSessionMember(this.boundCallRPC, sessionId, userId);
|
|
18888
|
+
}
|
|
17963
18889
|
// -------------------------------------------------------------------------
|
|
17964
18890
|
// Message transport (delegates to MessageTransport)
|
|
17965
18891
|
// -------------------------------------------------------------------------
|
|
@@ -18095,6 +19021,7 @@ exports.AttachmentGrid = MemoizedAttachmentGrid;
|
|
|
18095
19021
|
exports.AttachmentPreview = AttachmentPreview_default;
|
|
18096
19022
|
exports.AttachmentUpload = AttachmentUpload_default;
|
|
18097
19023
|
exports.Avatar = Avatar;
|
|
19024
|
+
exports.AvatarStack = AvatarStack;
|
|
18098
19025
|
exports.BiChatLayout = BiChatLayout;
|
|
18099
19026
|
exports.Bubble = Bubble;
|
|
18100
19027
|
exports.CHART_VISUAL = CHART_VISUAL;
|
|
@@ -18138,6 +19065,7 @@ exports.SessionArtifactList = SessionArtifactList;
|
|
|
18138
19065
|
exports.SessionArtifactPreview = SessionArtifactPreview;
|
|
18139
19066
|
exports.SessionArtifactsPanel = SessionArtifactsPanel;
|
|
18140
19067
|
exports.SessionItem = SessionItem_default;
|
|
19068
|
+
exports.SessionMembersModal = SessionMembersModal;
|
|
18141
19069
|
exports.SessionSkeleton = SessionSkeleton;
|
|
18142
19070
|
exports.Sidebar = Sidebar2;
|
|
18143
19071
|
exports.Skeleton = MemoizedSkeleton;
|
|
@@ -18204,6 +19132,7 @@ exports.useActionButtonContext = useActionButtonContext;
|
|
|
18204
19132
|
exports.useAttachments = useAttachments;
|
|
18205
19133
|
exports.useAutoScroll = useAutoScroll;
|
|
18206
19134
|
exports.useAvatarContext = useAvatarContext;
|
|
19135
|
+
exports.useBichatRouter = useBichatRouter;
|
|
18207
19136
|
exports.useBubbleContext = useBubbleContext;
|
|
18208
19137
|
exports.useChatInput = useChatInput;
|
|
18209
19138
|
exports.useChatMessaging = useChatMessaging;
|
|
@@ -18211,6 +19140,7 @@ exports.useChatSession = useChatSession;
|
|
|
18211
19140
|
exports.useConfig = useConfig;
|
|
18212
19141
|
exports.useDataTable = useDataTable;
|
|
18213
19142
|
exports.useFocusTrap = useFocusTrap;
|
|
19143
|
+
exports.useHttpDataSourceConfigFromApplet = useHttpDataSourceConfigFromApplet;
|
|
18214
19144
|
exports.useImageGallery = useImageGallery;
|
|
18215
19145
|
exports.useIotaContext = useIotaContext;
|
|
18216
19146
|
exports.useKeyboardShortcuts = useKeyboardShortcuts;
|