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