✨ feat(resource): add select all hint and improve resource explorer selection#13134
✨ feat(resource): add select all hint and improve resource explorer selection#13134
Conversation
…election Made-with: Cursor
Reviewer's GuideAdds 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 deletesequenceDiagram
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
Sequence diagram for select-all add to knowledge base with ID resolutionsequenceDiagram
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
Class diagram for ResourceManager store, select-all state, and servicesclassDiagram
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
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@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. |
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The new
isSelectingAllItemsflag is wired into the UI (e.g., Masonry/List view toolbar and hint) but never actually set totrueanywhere, so the loading/disabled states for cross-page select-all never activate; consider toggling it inselectAllResourcesand 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
ListViewandMasonryView; 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>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| 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({ |
There was a problem hiding this comment.
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 };
}),- Ensure
TRPCErroris imported at the top ofsrc/server/routers/lambda/file.ts:- Add (or extend) an import from
@trpc/server:
import { TRPCError } from '@trpc/server';
- Add (or extend) an import from
- 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.
- For example:
- 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 Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## canary #13134 +/- ##
=========================================
Coverage ? 66.95%
=========================================
Files ? 1896
Lines ? 152781
Branches ? 17569
=========================================
Hits ? 102295
Misses ? 50374
Partials ? 112
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
💡 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".
| // Sort data using current sort settings | ||
| const data = sortFileList(rawData, sorter, sortType); | ||
|
|
||
| const { handleSelectionChange, selectFileIds, setSelectedFileIds } = useFileSelection(data); | ||
|
|
||
| useCheckTaskStatus(data); |
There was a problem hiding this comment.
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 👍 / 👎.
| 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); |
There was a problem hiding this comment.
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 👍 / 👎.
src/server/routers/lambda/file.ts
Outdated
| for (const item of filteredItems) { | ||
| if (item.sourceType === 'file') { | ||
| fileIds.push(item.id); | ||
| } else { | ||
| documentIds.push(item.id); |
There was a problem hiding this comment.
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 👍 / 👎.
Made-with: Cursor
Signed-off-by: Innei <tukon479@gmail.com>
|
@codex review |
There was a problem hiding this comment.
💡 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".
| (id: string, checked: boolean) => { | ||
| clearSelectAllState(); | ||
|
|
||
| const currentSelected = useResourceManagerStore.getState().selectedFileIds; | ||
| if (checked) { |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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 👍 / 👎.
| const optimisticItems = Array.from(localResourceMap.values()).filter( | ||
| (item) => item._optimistic?.queryKey === queryKey, | ||
| ); |
There was a problem hiding this comment.
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 👍 / 👎.
|
@codex review it |
There was a problem hiding this comment.
💡 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".
| const chunkableFileIds = resourceIds.filter((id) => { | ||
| const resource = fileStore.resourceMap?.get(id); | ||
| return resource && !isChunkingUnsupported(resource.fileType); |
There was a problem hiding this comment.
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 👍 / 👎.
| // Clear selections when category/library/search changes | ||
| useEffect(() => { | ||
| setSelectedFileIds([]); |
There was a problem hiding this comment.
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 👍 / 👎.
|
@codex review it |
There was a problem hiding this comment.
💡 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
Made-with: Cursor
Made-with: Cursor
Made-with: Cursor
|
❤️ 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. |
💻 Change Type
🔗 Related Issue
Fixes LOBE-6180
Fixes LOBE-6181
Fixes LOBE-5081
Fixes LOBE-5082
🔀 Description of Change
🧪 How to Test
📸 Screenshots / Videos
📝 Additional Information