fix: complete folder archive action handling
This commit is contained in:
@@ -363,8 +363,16 @@ export function getConversationListItemPresentation(conversation: ConversationIt
|
||||
};
|
||||
}
|
||||
|
||||
function conversationActionsPath(projectId: string) {
|
||||
return `/api/v1/conversations/${projectId}/actions`;
|
||||
export function getConversationActionAvailability(conversation: ConversationItem) {
|
||||
const canTogglePin = conversation.projectId !== "master-agent";
|
||||
return {
|
||||
canTogglePin,
|
||||
togglePinLabel: conversation.topPinnedLabel || conversation.manualPinned ? "取消置顶" : "置顶",
|
||||
};
|
||||
}
|
||||
|
||||
export function getConversationActionsPath(projectId: string) {
|
||||
return `/api/v1/conversations/${encodeURIComponent(projectId)}/actions`;
|
||||
}
|
||||
|
||||
function ConversationActionButtons({
|
||||
@@ -374,14 +382,11 @@ function ConversationActionButtons({
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = useState<"toggle_pin" | "mark_read" | null>(null);
|
||||
|
||||
if (conversation.conversationType === "folder_archive") {
|
||||
return <div className="min-h-[24px]" />;
|
||||
}
|
||||
const actionAvailability = getConversationActionAvailability(conversation);
|
||||
|
||||
async function runAction(action: "toggle_pin" | "mark_read") {
|
||||
setLoading(action);
|
||||
await fetch(conversationActionsPath(conversation.projectId), {
|
||||
await fetch(getConversationActionsPath(conversation.projectId), {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ action }),
|
||||
@@ -392,14 +397,14 @@ function ConversationActionButtons({
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
{conversation.projectId !== "master-agent" ? (
|
||||
{actionAvailability.canTogglePin ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void runAction("toggle_pin")}
|
||||
disabled={loading === "toggle_pin"}
|
||||
className="rounded-full border border-[#D9D9D9] px-3 py-1 text-[11px] text-[#57606A]"
|
||||
>
|
||||
{conversation.manualPinned ? "取消置顶" : "置顶"}
|
||||
{actionAvailability.togglePinLabel}
|
||||
</button>
|
||||
) : null}
|
||||
{conversation.unreadCount > 0 ? (
|
||||
@@ -477,7 +482,7 @@ export function ConversationList({
|
||||
<div className="min-h-[18px] text-[11px] text-[#07C160]">
|
||||
{conversation.projectId === "master-agent"
|
||||
? "置顶"
|
||||
: conversation.manualPinned
|
||||
: conversation.topPinnedLabel
|
||||
? "置顶"
|
||||
: ""}
|
||||
</div>
|
||||
|
||||
@@ -8336,26 +8336,52 @@ export async function updateConversationAction(
|
||||
action: "toggle_pin" | "mark_read",
|
||||
) {
|
||||
const project = await mutateState((state) => {
|
||||
const nextProject = state.projects.find((item) => item.id === projectId);
|
||||
if (!nextProject) throw new Error("PROJECT_NOT_FOUND");
|
||||
const directProject = state.projects.find((item) => item.id === projectId);
|
||||
const folderProjects = directProject ? [] : state.projects.filter((item) => buildProjectFolderKey(item) === projectId);
|
||||
if (!directProject && folderProjects.length === 0) throw new Error("PROJECT_NOT_FOUND");
|
||||
|
||||
if (action === "toggle_pin") {
|
||||
if (nextProject.systemPinned) {
|
||||
throw new Error("MASTER_PROJECT_PIN_LOCKED");
|
||||
if (directProject) {
|
||||
if (directProject.systemPinned) {
|
||||
throw new Error("MASTER_PROJECT_PIN_LOCKED");
|
||||
}
|
||||
directProject.pinned = !directProject.pinned;
|
||||
} else {
|
||||
const folderLocked = folderProjects.some((item) => item.systemPinned);
|
||||
if (folderLocked) {
|
||||
throw new Error("MASTER_PROJECT_PIN_LOCKED");
|
||||
}
|
||||
const folderPinned = folderProjects.some((item) => item.pinned || item.systemPinned);
|
||||
for (const item of folderProjects) {
|
||||
item.pinned = !folderPinned;
|
||||
}
|
||||
}
|
||||
nextProject.pinned = !nextProject.pinned;
|
||||
}
|
||||
|
||||
if (action === "mark_read") {
|
||||
nextProject.unreadCount = 0;
|
||||
if (directProject) {
|
||||
directProject.unreadCount = 0;
|
||||
} else {
|
||||
for (const item of folderProjects) {
|
||||
item.unreadCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nextProject;
|
||||
return directProject ?? folderProjects[0];
|
||||
});
|
||||
publishBossEvent("conversation.updated", { projectId });
|
||||
return project;
|
||||
}
|
||||
|
||||
function buildProjectFolderKey(project: Project) {
|
||||
if (project.id === "master-agent" || project.isGroup) return undefined;
|
||||
const deviceId = project.deviceIds[0];
|
||||
const folderRef = (project.threadMeta.codexFolderRef?.trim() || project.threadMeta.folderName.trim()).toLowerCase();
|
||||
if (!deviceId || !folderRef) return undefined;
|
||||
return `${deviceId}:${folderRef}`;
|
||||
}
|
||||
|
||||
export async function renameProjectThread(input: {
|
||||
projectId: string;
|
||||
threadDisplayName: string;
|
||||
|
||||
@@ -196,7 +196,7 @@ function projectType(project: Project): ConversationItem["conversationType"] {
|
||||
function buildFolderKey(project: Project) {
|
||||
if (project.id === "master-agent" || project.isGroup) return undefined;
|
||||
const deviceId = project.deviceIds[0];
|
||||
const folderRef = project.threadMeta.codexFolderRef?.trim() || project.threadMeta.folderName.trim();
|
||||
const folderRef = (project.threadMeta.codexFolderRef?.trim() || project.threadMeta.folderName.trim()).toLowerCase();
|
||||
if (!deviceId || !folderRef) return undefined;
|
||||
return `${deviceId}:${folderRef}`;
|
||||
}
|
||||
@@ -561,6 +561,8 @@ export function getConversationHomeItems(state: BossState): ConversationItem[] {
|
||||
folderLabel: recentThreadLabel ? `${items.length} 个线程 · 最近:${recentThreadLabel}` : `${items.length} 个线程`,
|
||||
folderKey,
|
||||
threadCount: items.length,
|
||||
topPinnedLabel: items.some((entry) => entry.topPinnedLabel) ? "置顶" : undefined,
|
||||
manualPinned: items.some((entry) => entry.manualPinned),
|
||||
...(searchAliases
|
||||
? {
|
||||
searchAliases: searchAliases.aliases,
|
||||
@@ -574,8 +576,6 @@ export function getConversationHomeItems(state: BossState): ConversationItem[] {
|
||||
latestItem.preview ||
|
||||
`包含 ${items.length} 个线程,最近活跃:《${latestItem.threadTitle}》`,
|
||||
activityIconCount: Math.max(0, Math.min(4, items.reduce((sum, entry) => sum + entry.activityIconCount, 0))),
|
||||
manualPinned: false,
|
||||
topPinnedLabel: undefined,
|
||||
latestReplyAt: latestItem.latestReplyAt,
|
||||
latestReplyLabel: latestItem.latestReplyLabel,
|
||||
unreadCount: items.reduce((sum, entry) => sum + entry.unreadCount, 0),
|
||||
|
||||
Reference in New Issue
Block a user