fix(chat): 优化权限请求折叠状态
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
||||
alpha,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import type { Theme } from "@mui/material/styles";
|
||||
import ContentCopyRounded from "@mui/icons-material/ContentCopyRounded";
|
||||
import RefreshRounded from "@mui/icons-material/RefreshRounded";
|
||||
import EditRounded from "@mui/icons-material/EditRounded";
|
||||
@@ -149,6 +150,27 @@ const getPermissionStatusLabel = (status: NonNullable<Message["permissions"]>[nu
|
||||
};
|
||||
|
||||
const pendingPermissionColor = "#f9a825";
|
||||
const approvedOncePermissionColor = "#00838f";
|
||||
|
||||
const getPermissionStatusColor = (
|
||||
status: NonNullable<Message["permissions"]>[number]["status"],
|
||||
theme: Theme,
|
||||
) => {
|
||||
if (status === "approved_once") return approvedOncePermissionColor;
|
||||
if (status === "approved_always") return theme.palette.success.main;
|
||||
if (status === "rejected" || status === "error") return theme.palette.error.main;
|
||||
return pendingPermissionColor;
|
||||
};
|
||||
|
||||
const getPermissionStatusTextColor = (
|
||||
status: NonNullable<Message["permissions"]>[number]["status"],
|
||||
theme: Theme,
|
||||
) => {
|
||||
if (status === "approved_once") return "#006c78";
|
||||
if (status === "approved_always") return theme.palette.success.dark;
|
||||
if (status === "rejected" || status === "error") return theme.palette.error.main;
|
||||
return "#8a5a00";
|
||||
};
|
||||
|
||||
const PermissionRequestCard = ({
|
||||
permission,
|
||||
@@ -162,19 +184,9 @@ const PermissionRequestCard = ({
|
||||
const isSubmitting = permission.status === "submitting";
|
||||
const primaryValue = getPermissionPrimaryValue(permission);
|
||||
const metadataText = formatMetadata(permission.metadata);
|
||||
const accentColor =
|
||||
permission.status === "rejected" || permission.status === "error"
|
||||
? theme.palette.error.main
|
||||
: permission.status === "pending" || permission.status === "submitting"
|
||||
? pendingPermissionColor
|
||||
: theme.palette.success.main;
|
||||
const accentColor = getPermissionStatusColor(permission.status, theme);
|
||||
const statusTextColor = getPermissionStatusTextColor(permission.status, theme);
|
||||
const statusLabel = getPermissionStatusLabel(permission.status);
|
||||
const statusColor =
|
||||
permission.status === "rejected" || permission.status === "error"
|
||||
? "error"
|
||||
: permission.status === "pending" || permission.status === "submitting"
|
||||
? "warning"
|
||||
: "success";
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -229,25 +241,14 @@ const PermissionRequestCard = ({
|
||||
</Box>
|
||||
<Chip
|
||||
size="small"
|
||||
color={statusColor}
|
||||
label={statusLabel}
|
||||
sx={{
|
||||
height: 24,
|
||||
fontSize: "0.7rem",
|
||||
fontWeight: 800,
|
||||
borderRadius: "12px",
|
||||
bgcolor:
|
||||
statusColor === "success"
|
||||
? alpha(theme.palette.success.main, 0.12)
|
||||
: statusColor === "error"
|
||||
? alpha(theme.palette.error.main, 0.1)
|
||||
: alpha(pendingPermissionColor, 0.14),
|
||||
color:
|
||||
statusColor === "success"
|
||||
? theme.palette.success.dark
|
||||
: statusColor === "error"
|
||||
? theme.palette.error.main
|
||||
: "#8a5a00",
|
||||
bgcolor: alpha(accentColor, 0.12),
|
||||
color: statusTextColor,
|
||||
"& .MuiChip-label": { px: 1 },
|
||||
}}
|
||||
/>
|
||||
@@ -401,9 +402,11 @@ const PermissionRequestCard = ({
|
||||
|
||||
const PermissionRequestGroup = ({
|
||||
permissions,
|
||||
isRunning,
|
||||
onReply,
|
||||
}: {
|
||||
permissions: NonNullable<Message["permissions"]>;
|
||||
isRunning: boolean;
|
||||
onReply: (requestId: string, reply: PermissionReply) => void;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
@@ -422,11 +425,12 @@ const PermissionRequestGroup = ({
|
||||
);
|
||||
const summaryItems = [
|
||||
{ label: "共", value: permissions.length, color: theme.palette.text.secondary },
|
||||
{ label: "允许一次", value: onceCount, color: "#00838f" },
|
||||
{ label: "始终允许", value: alwaysCount, color: theme.palette.success.main },
|
||||
{ label: "拒绝", value: rejectedCount, color: theme.palette.error.main },
|
||||
{ label: "允许一次", value: onceCount, color: getPermissionStatusColor("approved_once", theme), textColor: getPermissionStatusTextColor("approved_once", theme) },
|
||||
{ label: "始终允许", value: alwaysCount, color: getPermissionStatusColor("approved_always", theme), textColor: getPermissionStatusTextColor("approved_always", theme) },
|
||||
{ label: "拒绝", value: rejectedCount, color: getPermissionStatusColor("rejected", theme), textColor: getPermissionStatusTextColor("rejected", theme) },
|
||||
];
|
||||
const chipColor = pendingCount > 0 ? pendingPermissionColor : rejectedCount > 0 ? theme.palette.error.main : theme.palette.success.main;
|
||||
const chipColor = pendingCount > 0 ? getPermissionStatusColor("pending", theme) : rejectedCount > 0 ? getPermissionStatusColor("rejected", theme) : getPermissionStatusColor("approved_always", theme);
|
||||
const chipTextColor = pendingCount > 0 ? getPermissionStatusTextColor("pending", theme) : rejectedCount > 0 ? getPermissionStatusTextColor("rejected", theme) : getPermissionStatusTextColor("approved_always", theme);
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -498,14 +502,20 @@ const PermissionRequestGroup = ({
|
||||
borderRadius: "11px",
|
||||
bgcolor: alpha(item.color, 0.08),
|
||||
border: `1px solid ${alpha(item.color, 0.12)}`,
|
||||
color: item.color,
|
||||
color: "textColor" in item ? item.textColor : item.color,
|
||||
fontSize: "0.7rem",
|
||||
fontWeight: 800,
|
||||
lineHeight: 1,
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
<Box component="span" sx={{ color: alpha(item.color, 0.82), fontWeight: 700 }}>
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
color: "textColor" in item ? item.textColor : item.color,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</Box>
|
||||
<Box component="span">{item.value} 项</Box>
|
||||
@@ -513,19 +523,21 @@ const PermissionRequestGroup = ({
|
||||
))}
|
||||
</Stack>
|
||||
</Box>
|
||||
<Chip
|
||||
size="small"
|
||||
label={`待确认 ${pendingCount} 项`}
|
||||
sx={{
|
||||
height: 24,
|
||||
borderRadius: "12px",
|
||||
fontSize: "0.7rem",
|
||||
fontWeight: 800,
|
||||
color: chipColor,
|
||||
bgcolor: alpha(chipColor, 0.1),
|
||||
"& .MuiChip-label": { px: 1 },
|
||||
}}
|
||||
/>
|
||||
{isRunning && pendingCount > 0 ? (
|
||||
<Chip
|
||||
size="small"
|
||||
label={`待确认 ${pendingCount} 项`}
|
||||
sx={{
|
||||
height: 24,
|
||||
borderRadius: "12px",
|
||||
fontSize: "0.7rem",
|
||||
fontWeight: 800,
|
||||
color: chipTextColor,
|
||||
bgcolor: alpha(chipColor, 0.1),
|
||||
"& .MuiChip-label": { px: 1 },
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<IconButton
|
||||
size="small"
|
||||
aria-label={expanded ? "收起权限请求" : "展开权限请求"}
|
||||
@@ -545,17 +557,13 @@ const PermissionRequestGroup = ({
|
||||
</IconButton>
|
||||
</Stack>
|
||||
|
||||
{!expanded && !hasPendingPermissions && latestPermissions.length > 0 ? (
|
||||
{!expanded && isRunning && !hasPendingPermissions && latestPermissions.length > 0 ? (
|
||||
<Stack spacing={0} sx={{ px: 1.5, pb: 1.25 }}>
|
||||
{latestPermissions.map((permission, index) => {
|
||||
const primaryValue = getPermissionPrimaryValue(permission);
|
||||
const isLast = index === latestPermissions.length - 1;
|
||||
const itemColor =
|
||||
permission.status === "rejected" || permission.status === "error"
|
||||
? theme.palette.error.main
|
||||
: permission.status === "approved_once" || permission.status === "approved_always"
|
||||
? theme.palette.success.main
|
||||
: pendingPermissionColor;
|
||||
const itemColor = getPermissionStatusColor(permission.status, theme);
|
||||
const itemTextColor = getPermissionStatusTextColor(permission.status, theme);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
@@ -607,7 +615,7 @@ const PermissionRequestGroup = ({
|
||||
borderRadius: "11px",
|
||||
fontSize: "0.68rem",
|
||||
fontWeight: 800,
|
||||
color: itemColor,
|
||||
color: itemTextColor,
|
||||
bgcolor: alpha(itemColor, 0.08),
|
||||
"& .MuiChip-label": { px: 0.85 },
|
||||
}}
|
||||
@@ -619,7 +627,7 @@ const PermissionRequestGroup = ({
|
||||
) : null}
|
||||
|
||||
<AnimatePresence initial={false}>
|
||||
{!expanded && hasPendingPermissions ? (
|
||||
{!expanded && isRunning && hasPendingPermissions ? (
|
||||
<motion.div
|
||||
key="pending-permissions"
|
||||
initial={{ opacity: 0, y: -10, height: 0 }}
|
||||
@@ -678,6 +686,12 @@ export const AgentTurn = React.memo(
|
||||
const [isEditing, setIsEditing] = React.useState(false);
|
||||
const [editDraft, setEditDraft] = React.useState(message.content);
|
||||
const rootMessageId = message.branchRootId ?? message.id;
|
||||
const isProgressComplete = message.progress?.some(
|
||||
(item) => item.phase === "complete" && item.status === "completed",
|
||||
) ?? false;
|
||||
const isProgressRunning = !isErrorMessage && !isProgressComplete && (
|
||||
message.progress?.some((item) => item.status === "running") ?? false
|
||||
);
|
||||
|
||||
const parsedAssistantSections = useMemo(
|
||||
() =>
|
||||
@@ -956,6 +970,7 @@ export const AgentTurn = React.memo(
|
||||
{message.permissions?.length ? (
|
||||
<PermissionRequestGroup
|
||||
permissions={message.permissions}
|
||||
isRunning={isProgressRunning}
|
||||
onReply={onReplyPermission}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user