Skip to content

✨ feat(resource): add select all hint and improve resource explorer selection#13134

Merged
Innei merged 21 commits intocanaryfrom
resource-select-all-hint
Mar 28, 2026
Merged

✨ feat(resource): add select all hint and improve resource explorer selection#13134
Innei merged 21 commits intocanaryfrom
resource-select-all-hint

Conversation

@Innei
Copy link
Copy Markdown
Member

@Innei Innei commented Mar 19, 2026

💻 Change Type

  • ✨ feat
  • 🐛 fix
  • ♻️ refactor
  • 💄 style
  • 👷 build
  • ⚡️ perf
  • ✅ test
  • 📝 docs
  • 🔨 chore

🔗 Related Issue

Fixes LOBE-6180
Fixes LOBE-6181
Fixes LOBE-5081
Fixes LOBE-5082

🔀 Description of Change

  • Add select all hint in resource explorer when viewing paginated results
  • Improve resource selection UX in list and masonry views
  • Support select all across pages in resource explorer
  • Refactor selection logic into store actions and selectors

🧪 How to Test

  • Tested locally
  • Added/updated tests
  • No tests needed

📸 Screenshots / Videos

Before After
... ...

📝 Additional Information

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Mar 19, 2026

Reviewer's Guide

Adds cross-page select-all support and UI hints to the Resource Manager explorer (list and masonry views), centralizes selection logic in the resource store (including resolve-all-IDs and delete-by-query flows), enhances bulk knowledge-base operations to respect select-all, and introduces safer immutable updates and new backend endpoints for resolving and deleting resources by query.

Sequence diagram for resolving select-all IDs and performing bulk delete

sequenceDiagram
  actor User
  participant UI_Explorer as UI_Explorer
  participant RM_Store as ResourceManagerStore
  participant ResourceService as ResourceService
  participant FileService as FileService
  participant Lambda_FileRouter as LambdaFileRouter
  participant KnowledgeRepo as KnowledgeRepo
  participant DocumentService as DocumentService
  participant FileModel as FileModel
  participant FileStorageService as FileStorageService

  User->>UI_Explorer: Click toolbar checkbox then Select all
  UI_Explorer->>RM_Store: setSelectAllState(all)
  RM_Store-->>UI_Explorer: selectAllState = all

  User->>UI_Explorer: Trigger Delete action
  UI_Explorer->>RM_Store: onActionClick(delete)
  RM_Store->>FileService: get queryParams from useFileStore
  alt selectAllState is all
    RM_Store->>ResourceService: deleteResourcesByQuery(queryParams)
    ResourceService->>FileService: deleteKnowledgeItemsByQuery(backendParams)
    FileService->>Lambda_FileRouter: deleteKnowledgeItemsByQuery(input)
    loop batched query
      Lambda_FileRouter->>KnowledgeRepo: query(input with limit and offset)
      KnowledgeRepo-->>Lambda_FileRouter: knowledgeItems
      Lambda_FileRouter->>Lambda_FileRouter: filterKnowledgeItems
      Lambda_FileRouter->>Lambda_FileRouter: split fileIds and documentIds
    end
    Lambda_FileRouter->>DocumentService: deleteDocuments(documentIds)
    DocumentService-->>Lambda_FileRouter: documents deleted
    Lambda_FileRouter->>FileModel: deleteMany(fileIds, REMOVE_GLOBAL_FILE)
    FileModel-->>Lambda_FileRouter: needToRemoveFileList
    Lambda_FileRouter->>FileStorageService: deleteFiles(fileUrls)
    FileStorageService-->>Lambda_FileRouter: files deleted
    Lambda_FileRouter-->>FileService: { count }
    FileService-->>ResourceService: { count }
    ResourceService-->>RM_Store: { count }
    RM_Store->>RM_Store: clearSelectAllState and selectedFileIds
  else normal selection
    RM_Store->>FileService: deleteResources(selectedFileIds)
    FileService-->>RM_Store: deletion complete
    RM_Store->>RM_Store: set selectedFileIds []
  end
  RM_Store-->>UI_Explorer: updated state
  UI_Explorer-->>User: List refreshed with items removed
Loading

Sequence diagram for select-all add to knowledge base with ID resolution

sequenceDiagram
  actor User
  participant UI_Explorer as UI_Explorer
  participant RM_Store as ResourceManagerStore
  participant AddKBModal as AddFilesToKnowledgeBaseModal
  participant SelectForm as SelectForm
  participant ResourceService as ResourceService
  participant FileService as FileService
  participant Lambda_FileRouter as LambdaFileRouter
  participant KnowledgeRepo as KnowledgeRepo
  participant KB_Store as KnowledgeBaseStore

  User->>UI_Explorer: Click Select all
  UI_Explorer->>RM_Store: setSelectAllState(all)
  RM_Store-->>UI_Explorer: selectAllState = all

  User->>UI_Explorer: Choose Add to knowledge base
  UI_Explorer->>RM_Store: onActionClick(addToKnowledgeBase)
  RM_Store->>UI_Explorer: delegate to modal handler
  UI_Explorer->>AddKBModal: openAddFilesToKnowledgeBaseModal({ fileIds, resolveFileIds, selectedCount })
  AddKBModal->>SelectForm: render with resolveFileIds and selectedCount

  User->>SelectForm: Submit target knowledge base
  SelectForm->>SelectForm: await resolveFileIds()
  SelectForm->>RM_Store: resolveSelectedResourceIds
  alt selectAllState is all
    RM_Store->>ResourceService: resolveSelectionIds(queryParams)
    ResourceService->>FileService: resolveKnowledgeItemIds(backendParams)
    FileService->>Lambda_FileRouter: resolveKnowledgeItemIds(input)
    loop batched query
      Lambda_FileRouter->>KnowledgeRepo: query(input with limit and offset)
      KnowledgeRepo-->>Lambda_FileRouter: knowledgeItems
      Lambda_FileRouter->>Lambda_FileRouter: filterKnowledgeItems
      Lambda_FileRouter->>Lambda_FileRouter: collect item ids
    end
    Lambda_FileRouter-->>FileService: { ids, total }
    FileService-->>ResourceService: { ids, total }
    ResourceService-->>RM_Store: { ids, total }
    RM_Store-->>SelectForm: ids
  else partial selection
    RM_Store-->>SelectForm: selectedFileIds
  end

  SelectForm->>KB_Store: addFilesToKnowledgeBase(targetKbId, resolvedIds)
  KB_Store-->>SelectForm: success
  SelectForm-->>AddKBModal: close
  AddKBModal-->>UI_Explorer: onClose
  UI_Explorer->>RM_Store: setSelectedFileIds([])
  UI_Explorer-->>User: Success message and updated selection
Loading

Class diagram for ResourceManager store, select-all state, and services

classDiagram
  class State {
    ViewMode viewMode
    ResourceManagerMode mode
    string~[]~ selectedFileIds
    SelectAllState selectAllState
    boolean isSelectingAllItems
    boolean isMasonryReady
    boolean isTransitioning
    string~undefined~ libraryId
    string~undefined~ category
    number fileListOffset
    boolean fileListHasMore
    string~null~ searchQuery
    string sorter
    SortType sortType
    string~null~ pendingRenameItemId
  }

  class SelectAllStateEnum {
    <<enumeration>>
    all
    loaded
    none
  }

  class Action {
    +clearSelectAllState() void
    +handleBackToList() void
    +handleOpenFile(id string) void
    +onActionClick(type MultiSelectActionType) Promise~void~
    +resolveSelectedResourceIds() Promise~string~[]~~
    +selectAllLoadedResources(ids string~[]~) void
    +selectAllResources() void
    +setCategory(category string~undefined~) void
    +setFileListHasMore(hasMore boolean) void
    +setFileListOffset(offset number) void
    +setIsSelectingAllItems(value boolean) void
    +setIsMasonryReady(value boolean) void
    +setIsTransitioning(value boolean) void
    +setLibraryId(id string~undefined~) void
    +setMode(mode ResourceManagerMode) void
    +setPendingRenameItemId(id string~null~) void
    +setSearchQuery(query string~null~) void
    +setSelectAllState(state SelectAllState) void
    +setSelectedFileIds(ids string~[]~) void
    +setSortType(sortType SortType) void
    +setSorter(sorter string) void
    +setViewMode(viewMode ViewMode) void
  }

  class ResourceService {
    +resolveSelectionIds(params ResourceQueryParams) Promise~ResolveIdsResult~
    +deleteResourcesByQuery(params ResourceQueryParams) Promise~DeleteByQueryResult~
  }

  class FileServiceFrontend {
    +getKnowledgeItems(params QueryFileListParams) Promise~KnowledgeItemList~
    +resolveKnowledgeItemIds(params QueryFileListParams) Promise~ResolveIdsResult~
    +deleteKnowledgeItemsByQuery(params QueryFileListParams) Promise~DeleteByQueryResult~
  }

  class LambdaFileRouter {
    +getKnowledgeItems(input QueryFileListSchema) FileListResponse
    +resolveKnowledgeItemIds(input QueryFileListSchema) ResolveIdsResult
    +deleteKnowledgeItemsByQuery(input QueryFileListSchema) DeleteByQueryResult
  }

  class KnowledgeRepo {
    +query(input QueryFileListSchema) KnowledgeItem~[]~
  }

  class DocumentService {
    +deleteDocuments(ids string~[]~) Promise~void~
  }

  class FileModel {
    +deleteMany(ids string~[]~, removeGlobal boolean) Promise~FileRecord~[]~
    +query() Promise~FileRecord~[]~
  }

  class FileServiceBackend {
    +deleteFiles(urls string~[]~) Promise~void~
  }

  class getExplorerSelectAllUiStateFn {
    +getExplorerSelectAllUiState(params SelectAllUiParams) SelectAllUiState
  }

  class SelectAllUiParams {
    data Array~FileListItem~
    boolean hasMore
    SelectAllState selectAllState
    string~[]~ selectedIds
  }

  class SelectAllUiState {
    boolean allSelected
    boolean indeterminate
    boolean showSelectAllHint
  }

  State --> SelectAllStateEnum : uses
  State ..> Action : implemented by store
  Action --> State : mutates

  ResourceService --> FileServiceFrontend : delegates
  FileServiceFrontend --> LambdaFileRouter : calls
  LambdaFileRouter --> KnowledgeRepo : queries
  LambdaFileRouter --> DocumentService : deletes documents
  LambdaFileRouter --> FileModel : deletes records
  FileModel --> FileServiceBackend : provides urls
  FileServiceBackend <.. LambdaFileRouter : used for file deletion

  getExplorerSelectAllUiStateFn --> SelectAllUiParams : input
  getExplorerSelectAllUiStateFn --> SelectAllUiState : output
  State --> getExplorerSelectAllUiStateFn : selection UI state computation
  Action --> ResourceService : resolveSelectedResourceIds and deleteResourcesByQuery
Loading

File-Level Changes

Change Details Files
Add select-all toolbar, hint banner, and cross-page selection behavior to list and masonry resource explorer views.
  • Introduce sticky toolbar and select-all hint styles for masonry and list views.
  • Compute select-all checkbox state and hint visibility via shared getExplorerSelectAllUiState selector.
  • Wire checkbox and per-item selection callbacks to new store actions for selecting loaded items vs all results across pages.
  • Show dynamic selection counts and total file counts, including special messaging when all results are selected.
src/features/ResourceManager/components/Explorer/MasonryView/index.tsx
src/features/ResourceManager/components/Explorer/ListView/index.tsx
src/routes/(main)/resource/features/store/selectors.ts
src/features/ResourceManager/components/Explorer/MasonryView/MasonryItem/MasonryItemWrapper.tsx
src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx
src/locales/default/components.ts
locales/en-US/components.json
locales/zh-CN/components.json
Refactor selection state into the ResourceManager store with explicit select-all modes and resolution helpers used across explorer, header, and batch actions.
  • Extend store state with selectAllState and isSelectingAllItems plus setters and a clearSelectAllState helper.
  • Add actions to select all loaded resources vs all results, and a resolveSelectedResourceIds helper that calls the resource service when select-all is active.
  • Ensure setSelectedFileIds keeps select-all flags consistent when selections are cleared or updated.
  • Update explorer hook and header to consume store-managed selection instead of local hooks, and to adjust confirmation messaging for delete-all.
src/routes/(main)/resource/features/store/initialState.ts
src/routes/(main)/resource/features/store/action.ts
src/features/ResourceManager/components/Explorer/useResourceExplorer.ts
src/features/ResourceManager/components/Explorer/Header/index.tsx
src/features/ResourceManager/components/Explorer/ToolBar/BatchActionsDropdown.tsx
src/features/ResourceManager/components/Explorer/hooks/useFileSelection.ts
Enhance bulk knowledge-base operations (add/move/remove, batch chunking) to work with select-all and to resolve full ID sets on demand.
  • Extend AddFilesToKnowledgeBase modal and SelectForm to optionally resolve file IDs lazily and display a separate selected count.
  • Use resolveSelectedResourceIds for store-level actions like removeFromKnowledgeBase and batchChunking.
  • Update batch action dropdown to resolve effective IDs before adding to a knowledge base and to compute success messages based on actual counts.
src/features/LibraryModal/AddFilesToKnowledgeBase/index.tsx
src/features/LibraryModal/AddFilesToKnowledgeBase/SelectForm.tsx
src/features/ResourceManager/components/Explorer/useResourceExplorer.ts
src/features/ResourceManager/components/Explorer/ToolBar/BatchActionsDropdown.tsx
Add backend and service-layer support for resolving IDs and deleting resources by query while respecting inbox folder filtering, plus improve removeAllFiles behavior.
  • Extract filterKnowledgeItems helper and reuse it in existing list endpoint and new query-based endpoints.
  • Add resolveKnowledgeItemIds and deleteKnowledgeItemsByQuery handlers on the file lambda router, including batched iteration over all query results and proper document/file deletion.
  • Expose corresponding methods on FileService and ResourceService to drive select-all resolution and delete-by-query from the frontend.
  • Update removeAllFiles to use deleteMany and S3 cleanup instead of a simple clear call.
src/server/routers/lambda/file.ts
src/services/file/index.ts
src/services/resource/index.ts
Make resource sync engine mutations immutable and compatible with immer-style state updates.
  • Wrap syncingIds, resourceMap, resourceList, and optimistic state updates in produce calls instead of mutating state directly.
  • Ensure temp resource replacement, resource updates, optimistic flag clearing, and error marking all use cloned state before setState.
src/store/file/slices/resource/syncEngine.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lobehub Ready Ready Preview, Comment Mar 27, 2026 2:27pm

Request Review

@lobehubbot
Copy link
Copy Markdown
Member

@rivertwilight @nekomeowww - This PR adds select-all support and improves resource explorer selection UX, with changes to knowledge base file operations and backend file APIs. Please coordinate on the review.

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The new isSelectingAllItems flag is wired into the UI (e.g., Masonry/List view toolbar and hint) but never actually set to true anywhere, so the loading/disabled states for cross-page select-all never activate; consider toggling it in selectAllResources and clearing it when actions complete or selections are reset.
  • The select-all toolbar and hint logic (translation keys, count resolution, button behavior) is largely duplicated between ListView and MasonryView; factoring this into a shared component or helper would reduce repetition and keep the behaviors in sync more easily.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `isSelectingAllItems` flag is wired into the UI (e.g., Masonry/List view toolbar and hint) but never actually set to `true` anywhere, so the loading/disabled states for cross-page select-all never activate; consider toggling it in `selectAllResources` and clearing it when actions complete or selections are reset.
- The select-all toolbar and hint logic (translation keys, count resolution, button behavior) is largely duplicated between `ListView` and `MasonryView`; factoring this into a shared component or helper would reduce repetition and keep the behaviors in sync more easily.

## Individual Comments

### Comment 1
<location path="src/server/routers/lambda/file.ts" line_range="312-321" />
<code_context>
     };
   }),

+  resolveKnowledgeItemIds: fileProcedure
+    .input(QueryFileListSchema)
+    .query(async ({ ctx, input }): Promise<{ ids: string[]; total: number }> => {
+      const ids: string[] = [];
+      const batchSize = 500;
+      let offset = 0;
+      let hasMore = true;
+
+      while (hasMore) {
+        const knowledgeItems = await ctx.knowledgeRepo.query({
+          ...input,
+          limit: batchSize + 1,
+          offset,
+        });
+
+        const currentHasMore = knowledgeItems.length > batchSize;
+        const itemsToProcess = currentHasMore ? knowledgeItems.slice(0, batchSize) : knowledgeItems;
+        const filteredItems = filterKnowledgeItems(itemsToProcess, input.knowledgeBaseId);
+
+        ids.push(...filteredItems.map((item) => item.id));
+
+        offset += itemsToProcess.length;
+        hasMore = currentHasMore;
+      }
+
+      return { ids, total: ids.length };
+    }),
+
</code_context>
<issue_to_address>
**suggestion (performance):** Consider protecting `resolveKnowledgeItemIds` against very large result sets

This endpoint walks the full result set in 500-item batches and accumulates all IDs in memory. For very large libraries or broad queries, this can lead to long-running requests and high memory usage on the lambda. Consider adding a server-side cap or pagination (e.g., max total, max pages, or returning an error once a safe threshold is exceeded) to avoid pathological cases.

Suggested implementation:

```typescript
  resolveKnowledgeItemIds: fileProcedure
    .input(QueryFileListSchema)
    .query(async ({ ctx, input }): Promise<{ ids: string[]; total: number }> => {
      const ids: string[] = [];
      const batchSize = 500;
      let offset = 0;
      let hasMore = true;

      while (hasMore) {
        const knowledgeItems = await ctx.knowledgeRepo.query({
          ...input,
          limit: batchSize + 1,
          offset,
        });

        const currentHasMore = knowledgeItems.length > batchSize;
        const itemsToProcess = currentHasMore ? knowledgeItems.slice(0, batchSize) : knowledgeItems;
        const filteredItems = filterKnowledgeItems(itemsToProcess, input.knowledgeBaseId);

        ids.push(...filteredItems.map((item) => item.id));

        if (ids.length > MAX_KNOWLEDGE_ITEM_IDS) {
          throw new TRPCError({
            code: 'PAYLOAD_TOO_LARGE',
            message:
              'Query matches too many knowledge items. Please narrow your filters or paginate the request.',
          });
        }

        offset += itemsToProcess.length;
        hasMore = currentHasMore;
      }

      return { ids, total: ids.length };
    }),

```

1. Ensure `TRPCError` is imported at the top of `src/server/routers/lambda/file.ts`:
   - Add (or extend) an import from `@trpc/server`:
     `import { TRPCError } from '@trpc/server';`
2. Define a safe upper bound for IDs in the same file, near other constants/config:
   - For example:
     `const MAX_KNOWLEDGE_ITEM_IDS = 10_000;`
   - Adjust the numeric value to match your system’s operational limits or config.
3. If your project centralizes error codes/messages, you may want to replace the inline message and/or `'PAYLOAD_TOO_LARGE'` with your existing conventions.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +312 to +321
resolveKnowledgeItemIds: fileProcedure
.input(QueryFileListSchema)
.query(async ({ ctx, input }): Promise<{ ids: string[]; total: number }> => {
const ids: string[] = [];
const batchSize = 500;
let offset = 0;
let hasMore = true;

while (hasMore) {
const knowledgeItems = await ctx.knowledgeRepo.query({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Consider protecting resolveKnowledgeItemIds against very large result sets

This endpoint walks the full result set in 500-item batches and accumulates all IDs in memory. For very large libraries or broad queries, this can lead to long-running requests and high memory usage on the lambda. Consider adding a server-side cap or pagination (e.g., max total, max pages, or returning an error once a safe threshold is exceeded) to avoid pathological cases.

Suggested implementation:

  resolveKnowledgeItemIds: fileProcedure
    .input(QueryFileListSchema)
    .query(async ({ ctx, input }): Promise<{ ids: string[]; total: number }> => {
      const ids: string[] = [];
      const batchSize = 500;
      let offset = 0;
      let hasMore = true;

      while (hasMore) {
        const knowledgeItems = await ctx.knowledgeRepo.query({
          ...input,
          limit: batchSize + 1,
          offset,
        });

        const currentHasMore = knowledgeItems.length > batchSize;
        const itemsToProcess = currentHasMore ? knowledgeItems.slice(0, batchSize) : knowledgeItems;
        const filteredItems = filterKnowledgeItems(itemsToProcess, input.knowledgeBaseId);

        ids.push(...filteredItems.map((item) => item.id));

        if (ids.length > MAX_KNOWLEDGE_ITEM_IDS) {
          throw new TRPCError({
            code: 'PAYLOAD_TOO_LARGE',
            message:
              'Query matches too many knowledge items. Please narrow your filters or paginate the request.',
          });
        }

        offset += itemsToProcess.length;
        hasMore = currentHasMore;
      }

      return { ids, total: ids.length };
    }),
  1. Ensure TRPCError is imported at the top of src/server/routers/lambda/file.ts:
    • Add (or extend) an import from @trpc/server:
      import { TRPCError } from '@trpc/server';
  2. Define a safe upper bound for IDs in the same file, near other constants/config:
    • For example:
      const MAX_KNOWLEDGE_ITEM_IDS = 10_000;
    • Adjust the numeric value to match your system’s operational limits or config.
  3. If your project centralizes error codes/messages, you may want to replace the inline message and/or 'PAYLOAD_TOO_LARGE' with your existing conventions.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 19, 2026

Codecov Report

❌ Patch coverage is 61.99377% with 732 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (canary@46602be). Learn more about missing BASE report.

Additional details and impacted files
@@            Coverage Diff            @@
##             canary   #13134   +/-   ##
=========================================
  Coverage          ?   66.95%           
=========================================
  Files             ?     1896           
  Lines             ?   152781           
  Branches          ?    17569           
=========================================
  Hits              ?   102295           
  Misses            ?    50374           
  Partials          ?      112           
Flag Coverage Δ
app 58.58% <61.99%> (?)
database 96.64% <ø> (?)
packages/agent-runtime 89.61% <ø> (?)
packages/context-engine 83.22% <ø> (?)
packages/conversation-flow 92.36% <ø> (?)
packages/file-loaders 87.02% <ø> (?)
packages/memory-user-memory 66.68% <ø> (?)
packages/model-bank 99.85% <ø> (?)
packages/model-runtime 84.48% <ø> (?)
packages/prompts 67.76% <ø> (?)
packages/python-interpreter 92.90% <ø> (?)
packages/ssrf-safe-fetch 0.00% <ø> (?)
packages/utils 90.41% <ø> (?)
packages/web-crawler 88.82% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Store 67.27% <0.00%> (?)
Services 49.29% <0.00%> (?)
Server 67.40% <0.00%> (?)
Libs 51.06% <0.00%> (?)
Utils 91.01% <0.00%> (?)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4a95c584b0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 96 to 99
// Sort data using current sort settings
const data = sortFileList(rawData, sorter, sortType);

const { handleSelectionChange, selectFileIds, setSelectedFileIds } = useFileSelection(data);

useCheckTaskStatus(data);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve selection cleanup when the visible folder changes

Removing the selection hook here also removed the effect that pruned selectedFileIds against the currently displayed data. ResourceExplorer now only clears selection on category, libraryId, or searchQuery changes (src/features/ResourceManager/components/Explorer/index.tsx:93-96), so navigating into another folder leaves the previous folder's ids in the shared store. Batch delete/chunking/remove actions can then target hidden items from the old folder, and selectAllState === 'all' even makes the new folder appear fully selected without any new user action.

Useful? React with 👍 / 👎.

Comment on lines 461 to +464
removeAllFiles: fileProcedure.mutation(async ({ ctx }) => {
return ctx.fileModel.clear();
// Get all file IDs for this user
const allFiles = await ctx.fileModel.query();
const fileIds = allFiles.map((f) => f.id);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Query all files before removeAllFiles deletes user data

fileModel.query() defaults to excluding anything linked through knowledge_base_files when showFilesInKnowledgeBase is omitted (see packages/database/src/models/file.ts:278-289). After this change, removeAllFiles uses that filtered query result as the source for deleteMany, so the Settings “clear all data” flow only removes inbox files and silently leaves every file stored in a knowledge base behind.

Useful? React with 👍 / 👎.

Comment on lines +360 to +364
for (const item of filteredItems) {
if (item.sourceType === 'file') {
fileIds.push(item.id);
} else {
documentIds.push(item.id);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Delete knowledge-base pages with their document ids

In knowledge-base queries, KnowledgeRepo.buildFileQuery() returns page-backed entries with source_type = 'file' but id = COALESCE(d.id, f.id), so many of these rows carry a docs_* document id instead of the underlying file id (packages/database/src/repositories/knowledge/index.ts:369-390). This branch puts those ids into fileIds and hands them to fileModel.deleteMany, so “delete all results” skips knowledge-base pages while still counting them as deleted.

Useful? React with 👍 / 👎.

@Innei
Copy link
Copy Markdown
Member Author

Innei commented Mar 20, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a447847106

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +75 to +79
(id: string, checked: boolean) => {
clearSelectAllState();

const currentSelected = useResourceManagerStore.getState().selectedFileIds;
if (checked) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve cross-page selection when toggling one row

If the user clicked “select all N resources”, selectAllState becomes 'all' but selectedFileIds still only contains the currently loaded page. Clearing that mode before applying the checkbox change turns “all results except this item” into just loadedIds - id, so the next batch delete/move/chunking runs on a few visible rows instead of the full result set. This is easy to hit in any paginated folder or search result.

Useful? React with 👍 / 👎.


const syncEngine = this.#getSyncEngine();
const tx = syncEngine.createTransaction(`moveResource(${id})`);
const shouldKeepVisible = queryParams?.parentId == null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove moved items from the root query when parent changes

In the root explorer view (parentId === null), dropping an item into a folder changes its parentId, so it no longer matches the current list (packages/database/src/repositories/knowledge/index.ts filters root queries to parent_id IS NULL). Because shouldKeepVisible is derived only from the old query being root, the optimistic move keeps the row rendered and onSuccess preserves it, leaving a stale item in the root list until a full refresh.

Useful? React with 👍 / 👎.

Comment on lines +27 to +29
const optimisticItems = Array.from(localResourceMap.values()).filter(
(item) => item._optimistic?.queryKey === queryKey,
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep off-screen optimistic resources in the global map

This merge keeps only optimistic entries whose queryKey matches the current query. After the new optimistic upload/create flow inserts a temp row and the user navigates elsewhere before it finishes, that temp id is dropped from resourceMap; when src/store/file/slices/fileManager/action.ts later calls replaceLocalResource, the missing target makes the completed file get prepended into the new folder/list even though it belongs to the old query. Background uploads can therefore leak into the wrong explorer view.

Useful? React with 👍 / 👎.

@Innei
Copy link
Copy Markdown
Member Author

Innei commented Mar 20, 2026

@codex review it

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80107fea42

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 93 to 95
const chunkableFileIds = resourceIds.filter((id) => {
const resource = fileStore.resourceMap?.get(id);
return resource && !isChunkingUnsupported(resource.fileType);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Chunk all resolved resources in batchChunking

When the new “select all results” flow is used on a query with more items than the first page, resolveSelectedResourceIds() returns every matching id, but this filter only keeps ids already present in fileStore.resourceMap. That map is populated from the currently loaded page, so off-screen matches are silently dropped and parseFilesToChunks only runs for the visible subset, which makes the new select-all UX incomplete for large libraries/searches.

Useful? React with 👍 / 👎.

Comment on lines 90 to 92
// Clear selections when category/library/search changes
useEffect(() => {
setSelectedFileIds([]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Clear select-all state when the explorer query changes

This effect only clears selectedFileIds, and only for category/library/search changes. After the refactor, folder changes are no longer covered, and setSelectedFileIds([]) deliberately preserves selectAllState === 'all'. As a result, selecting files (or “all results”) in one folder/query and then navigating can leave hidden items, or even the entire new query, still selected, so batch delete/remove/chunking acts on resources the user is no longer looking at.

Useful? React with 👍 / 👎.

@Innei
Copy link
Copy Markdown
Member Author

Innei commented Mar 26, 2026

@codex review it

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: af2f4b1ef4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…visibility

- batchChunking: pass through server-resolved IDs not in local resourceMap
  when selectAllState is 'all', letting server filter unsupported types
- replaceLocalResource: keep replacement visible if the optimistic item was
  already in the list, avoiding slug-vs-UUID mismatch in visibility check
…erve off-screen optimistic items

- Reset selectAllState to 'none' after delete, removeFromKnowledgeBase,
  and batchChunking to prevent stale 'all' state causing unintended
  re-selection of remaining items
- Preserve off-screen optimistic resources in clearCurrentQueryResources
  so background uploads from other folders survive delete-all-by-query
@Innei Innei merged commit 26449e5 into canary Mar 28, 2026
34 checks passed
@Innei Innei deleted the resource-select-all-hint branch March 28, 2026 03:51
@lobehubbot
Copy link
Copy Markdown
Member

❤️ Great PR @Innei ❤️

The growth of project is inseparable from user feedback and contribution, thanks for your contribution! If you are interesting with the lobehub developer community, please join our discord and then dm @arvinxx or @canisminor1990. They will invite you to our private developer channel. We are talking about the lobe-chat development or sharing ai newsletter around the world.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants