AppChat: filter by open beams

This commit is contained in:
Enrico Ros
2026-05-02 17:34:28 -07:00
parent ed4edd7c0b
commit bf2d00a936
2 changed files with 23 additions and 13 deletions
@@ -16,6 +16,7 @@ import MoreVertIcon from '@mui/icons-material/MoreVert';
import StarOutlineRoundedIcon from '@mui/icons-material/StarOutlineRounded';
import type { DConversationId } from '~/common/stores/chat/chat.conversation';
import { ChatBeamIcon } from '~/common/components/icons/ChatBeamIcon';
import { CloseablePopup } from '~/common/components/CloseablePopup';
import { DFolder, useFolderStore } from '~/common/stores/folders/store-chat-folders';
import { DebouncedInputMemo } from '~/common/components/DebouncedInput';
@@ -89,6 +90,7 @@ function ChatDrawer(props: {
// external state
const {
clearFilters,
filterHasBeamOpen, toggleFilterHasBeamOpen,
filterHasDocFragments, toggleFilterHasDocFragments,
filterHasImageAssets, toggleFilterHasImageAssets,
filterHasStars, toggleFilterHasStars,
@@ -98,7 +100,7 @@ function ChatDrawer(props: {
} = useChatDrawerFilters();
const { activeFolder, allFolders, enableFolders, toggleEnableFolders } = useFolders(props.activeFolderId);
const { filteredChatsCount, filteredChatIDs, filteredChatsAreEmpty, filteredChatsBarBasis, filteredChatsIncludeActive, renderNavItems } = useChatDrawerRenderItems(
props.activeConversationId, props.chatPanesConversationIds, debouncedSearchQuery, activeFolder, allFolders, filterHasStars, filterHasImageAssets, filterHasDocFragments, filterIsArchived, navGrouping, searchSorting, showRelativeSize, searchDepth,
props.activeConversationId, props.chatPanesConversationIds, debouncedSearchQuery, activeFolder, allFolders, filterHasBeamOpen, filterHasStars, filterHasImageAssets, filterHasDocFragments, filterIsArchived, navGrouping, searchSorting, showRelativeSize, searchDepth,
);
const [uiComplexityMode, contentScaling] = useUIPreferencesStore(useShallow((state) => [state.complexityMode, state.contentScaling]));
const zenMode = uiComplexityMode === 'minimal';
@@ -240,6 +242,10 @@ function ChatDrawer(props: {
<ListItemDecorator>{filterHasDocFragments && <CheckRoundedIcon />}</ListItemDecorator>
Has Attachments <AttachFileRoundedIcon />
</MenuItem>
<MenuItem onClick={toggleFilterHasBeamOpen}>
<ListItemDecorator>{filterHasBeamOpen && <CheckRoundedIcon />}</ListItemDecorator>
Beam Open <ChatBeamIcon />
</MenuItem>
<ListDivider />
<ListItem>
@@ -288,8 +294,8 @@ function ChatDrawer(props: {
)}
</Dropdown>
), [
filterHasDocFragments, filterHasImageAssets, filterHasStars, isSearching, navGrouping, searchSorting, searchDepth, filterIsArchived, showPersonaIcons, showRelativeSize,
toggleFilterHasDocFragments, toggleFilterHasImageAssets, toggleFilterHasStars, toggleFilterIsArchived, toggleShowPersonaIcons, toggleShowRelativeSize,
filterHasBeamOpen, filterHasDocFragments, filterHasImageAssets, filterHasStars, isSearching, navGrouping, searchSorting, searchDepth, filterIsArchived, showPersonaIcons, showRelativeSize,
toggleFilterHasBeamOpen, toggleFilterHasDocFragments, toggleFilterHasImageAssets, toggleFilterHasStars, toggleFilterIsArchived, toggleShowPersonaIcons, toggleShowRelativeSize,
]);
const displayNavItems = React.useMemo(() => {
@@ -422,7 +428,7 @@ function ChatDrawer(props: {
{filterHasStars && <StarOutlineRoundedIcon sx={{ color: 'primary.softColor', fontSize: 'xl', mb: -0.5, mr: 1 }} />}
{item.message}
</Typography>
{(filterHasStars || filterHasImageAssets || filterHasDocFragments || filterIsArchived) && (
{(filterHasBeamOpen || filterHasStars || filterHasImageAssets || filterHasDocFragments || filterIsArchived) && (
<Tooltip title='Clear Filters'>
<IconButton size='sm' color='primary' onClick={clearFilters}>
<ClearIcon />
@@ -86,6 +86,7 @@ export function useChatDrawerRenderItems(
filterByQuery: string,
activeFolder: DFolder | null,
allFolders: DFolder[],
filterHasBeamOpen: boolean,
filterHasStars: boolean,
filterHasImageAssets: boolean,
filterHasDocFragments: boolean,
@@ -146,7 +147,8 @@ export function useChatDrawerRenderItems(
}
// filter for required attributes
if ((filterHasStars && !hasStars) || (filterHasImageAssets && !hasImages) || (filterHasDocFragments && !hasDocs))
const hasBeamOpen = openBeamConversationIds[_c.id];
if ((filterHasBeamOpen && !hasBeamOpen) || (filterHasStars && !hasStars) || (filterHasImageAssets && !hasImages) || (filterHasDocFragments && !hasDocs))
return null;
// rich properties
@@ -186,7 +188,7 @@ export function useChatDrawerRenderItems(
? allFolders.find(folder => folder.conversationIds.includes(_c.id)) ?? null
: null,
updatedAt: _c.updated || _c.created || 0,
hasBeamOpen: !!openBeamConversationIds?.[_c.id],
hasBeamOpen,
messageCount,
beingGenerated: !!_c._abortController, // FIXME: when the AbortController is moved at the message level, derive the state in the conv
systemPurposeId: _c.systemPurposeId,
@@ -287,19 +289,21 @@ export function useChatDrawerRenderItems(
renderNavItems.push({
type: 'nav-item-info-message',
message: (filterHasStars && (filterHasImageAssets || filterHasDocFragments)) ? 'No results'
: filterHasDocFragments ? 'No attachment results'
: filterHasImageAssets ? 'No image results'
: filterHasStars ? 'No starred results'
: filterIsArchived ? 'No archived conversations'
: isSearching ? 'Text not found'
: 'No conversations in folder',
: filterHasBeamOpen ? 'No beam conversations'
: filterHasDocFragments ? 'No attachment results'
: filterHasImageAssets ? 'No image results'
: filterHasStars ? 'No starred results'
: filterIsArchived ? 'No archived conversations'
: isSearching ? 'Text not found'
: 'No conversations in folder',
});
} else {
// filtering reminder (will be rendered with a clear button too)
if (filterHasStars || filterHasImageAssets || filterHasDocFragments || filterIsArchived) {
if (filterHasBeamOpen || filterHasStars || filterHasImageAssets || filterHasDocFragments || filterIsArchived) {
renderNavItems.unshift({
type: 'nav-item-info-message',
message: `${filterIsArchived ? 'Showing' : 'Filtering by'} ${[
filterHasBeamOpen && 'beam',
filterHasStars && 'stars',
filterHasImageAssets && 'images',
filterHasDocFragments && 'attachments',