From 31a2ae9482d64d7354ef53e6fa5b8ecb784a1989 Mon Sep 17 00:00:00 2001 From: Innei Date: Sat, 18 Oct 2025 01:11:49 +0800 Subject: [PATCH] feat(ai): add block disable functionality - Introduced a `disabled` state for context blocks, allowing users to toggle blocks on and off without removing them. - Updated `ContextBlock` and `CombinedContextBlock` components to handle the new `disabled` prop and associated click behavior. - Filtered out disabled blocks in the `ChatInterface` to improve user experience. Signed-off-by: Innei --- .../context-bar/blocks/ContextBlock.tsx | 63 ++++++++++++++----- .../components/layouts/ChatInterface.tsx | 2 +- .../ai-chat/store/slices/block.slice.ts | 16 +++++ .../src/modules/ai-chat/store/types.ts | 1 + 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/apps/desktop/layer/renderer/src/modules/ai-chat/components/context-bar/blocks/ContextBlock.tsx b/apps/desktop/layer/renderer/src/modules/ai-chat/components/context-bar/blocks/ContextBlock.tsx index 6acea82c7..3790126a4 100644 --- a/apps/desktop/layer/renderer/src/modules/ai-chat/components/context-bar/blocks/ContextBlock.tsx +++ b/apps/desktop/layer/renderer/src/modules/ai-chat/components/context-bar/blocks/ContextBlock.tsx @@ -14,21 +14,30 @@ const BlockContainer: FC<{ icon: string | null | undefined label?: string onRemove?: () => void + disabled?: boolean + onDisableClick?: () => void content: ReactNode -}> = memo(({ icon, label, onRemove, content }) => { +}> = memo(({ icon, label, onRemove, content, disabled, onDisableClick }) => { const isStringContent = typeof content === "string" return (
{ + if (disabled) { + onDisableClick?.() + } + }} >
@@ -45,13 +54,15 @@ const BlockContainer: FC<{
- + {onRemove && !disabled && ( + + )}
) }) @@ -70,10 +81,11 @@ export const CombinedContextBlock: FC<{ const blockActions = useChatBlockActions() const viewIcon = viewBlock && getView(Number(viewBlock.value))?.icon.props.className + const feedIcon = feedBlock && "i-mgc-rss-cute-fi" const handleRemove = () => { - viewBlock && blockActions.removeBlock(viewBlock.id) - feedBlock && blockActions.removeBlock(feedBlock.id) + viewBlock && blockActions.toggleBlockDisabled(viewBlock.id, true) + feedBlock && blockActions.toggleBlockDisabled(feedBlock.id, true) unreadOnlyBlock && blockActions.removeBlock(unreadOnlyBlock.id) } @@ -94,7 +106,18 @@ export const CombinedContextBlock: FC<{ ) - return + return ( + { + viewBlock && blockActions.toggleBlockDisabled(viewBlock.id, false) + feedBlock && blockActions.toggleBlockDisabled(feedBlock.id, false) + }} + content={displayContent} + /> + ) }) CombinedContextBlock.displayName = "CombinedContextBlock" @@ -107,7 +130,19 @@ export const ContextBlock: FC<{ block: AIChatContextBlock }> = memo(({ block }) blockActions.removeBlock(block.id)} + disabled={block.disabled} + onRemove={() => { + if (block.type === "mainEntry") { + blockActions.toggleBlockDisabled(block.id, true) + } else { + blockActions.removeBlock(block.id) + } + }} + onDisableClick={() => { + if (block.type === "mainEntry") { + blockActions.toggleBlockDisabled(block.id, false) + } + }} content={displayContent} /> ) diff --git a/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx b/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx index 0a31575af..59c294300 100644 --- a/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx +++ b/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx @@ -221,7 +221,7 @@ const ChatInterfaceContent = ({ centerInputOnEmpty }: ChatInterfaceProps) => { const parts: BizUIMessage["parts"] = [ { type: "data-block", - data: blocks, + data: blocks.filter((block) => !block.disabled), }, ] diff --git a/apps/desktop/layer/renderer/src/modules/ai-chat/store/slices/block.slice.ts b/apps/desktop/layer/renderer/src/modules/ai-chat/store/slices/block.slice.ts index a5d38bf52..28a708368 100644 --- a/apps/desktop/layer/renderer/src/modules/ai-chat/store/slices/block.slice.ts +++ b/apps/desktop/layer/renderer/src/modules/ai-chat/store/slices/block.slice.ts @@ -73,6 +73,22 @@ export class BlockSliceAction { ) } + toggleBlockDisabled(id: string, disabled?: boolean) { + this.set( + produce((state: BlockSlice) => { + const block = state.blocks.find((block) => block.id === id) + if (block) { + const nextDisabled = disabled ?? !block.disabled + + if (!nextDisabled) { + delete block.disabled + } else { + block.disabled = true + } + } + }), + ) + } updateBlock(id: string, updates: Partial) { this.set( produce((state: BlockSlice) => { diff --git a/apps/desktop/layer/renderer/src/modules/ai-chat/store/types.ts b/apps/desktop/layer/renderer/src/modules/ai-chat/store/types.ts index 8f1413ce2..0bf1fdc97 100644 --- a/apps/desktop/layer/renderer/src/modules/ai-chat/store/types.ts +++ b/apps/desktop/layer/renderer/src/modules/ai-chat/store/types.ts @@ -17,6 +17,7 @@ export interface FileAttachment { interface BaseContextBlock { id: string + disabled?: boolean } export type ValueContextBlockType =