feat : auto-select newly uploaded docs/URLs in my documents list (#5222)

* auto-select newly uploaded docs/URLs in My Documents list

* fix: improve auto-select reliability and fix debounce/selection bugs

- Add missing `await` on fetchKeys in handleSendLink so loading state
  and auto-select timing work correctly
- Use functional update for setSelectedItems to merge with existing
  selections instead of replacing them
- Stabilize debounced fetchKeys with useRef so rapid uploads actually
  debounce instead of creating independent timers per render
- Rename shadowed local variables (availableDocs -> filteredAvailableDocs)
  for clarity

---------

Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
This commit is contained in:
Neha Prasad 2026-03-27 03:29:25 +05:30 committed by GitHub
parent 7ecc4ae005
commit d767c398c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 13 deletions

View File

@ -1,5 +1,5 @@
import { CloudArrowUp } from "@phosphor-icons/react";
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import showToast from "../../../../../utils/toast";
import System from "../../../../../models/system";
@ -34,7 +34,7 @@ export default function UploadFile({
if (!response.ok) {
showToast(`Error uploading link: ${data.error}`, "error");
} else {
fetchKeys(true);
await fetchKeys(true, { autoSelectNew: true });
showToast("Link uploaded successfully", "success");
formEl.reset();
}
@ -42,11 +42,12 @@ export default function UploadFile({
setFetchingUrl(false);
};
// Queue all fetchKeys calls through the same debouncer to prevent spamming the server.
// either a success or error will trigger a fetchKeys call so the UI is not stuck loading.
const debouncedFetchKeys = debounce(() => fetchKeys(true), 1000);
const handleUploadSuccess = () => debouncedFetchKeys();
const handleUploadError = () => debouncedFetchKeys();
const debouncedFetchKeysRef = useRef(
debounce((fn, opts) => fn(true, opts), 1000)
);
const handleUploadSuccess = () =>
debouncedFetchKeysRef.current(fetchKeys, { autoSelectNew: true });
const handleUploadError = () => debouncedFetchKeysRef.current(fetchKeys, {});
const onDrop = async (acceptedFiles, rejections) => {
const newAccepted = acceptedFiles.map((file) => {

View File

@ -1,5 +1,5 @@
import { ArrowsDownUp } from "@phosphor-icons/react";
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import Workspace from "../../../../models/workspace";
import System from "../../../../models/system";
import showToast from "../../../../utils/toast";
@ -25,8 +25,23 @@ export default function DocumentSettings({ workspace, systemSettings }) {
const [movedItems, setMovedItems] = useState([]);
const [embeddingsCost, setEmbeddingsCost] = useState(0);
const [loadingMessage, setLoadingMessage] = useState("");
const availableDocsRef = useRef([]);
useEffect(() => {
availableDocsRef.current = availableDocs;
}, [availableDocs]);
async function fetchKeys(refetchWorkspace = false, options = {}) {
const { autoSelectNew = false } = options;
const previousIds = new Set();
if (autoSelectNew && availableDocsRef.current?.items) {
for (const folder of availableDocsRef.current.items) {
for (const file of folder.items ?? []) {
if (file?.id) previousIds.add(file.id);
}
}
}
async function fetchKeys(refetchWorkspace = false) {
setLoading(true);
const localFiles = await System.localFiles();
const currentWorkspace = refetchWorkspace
@ -37,7 +52,7 @@ export default function DocumentSettings({ workspace, systemSettings }) {
currentWorkspace.documents.map((doc) => doc.docpath) || [];
// Documents that are not in the workspace
const availableDocs = {
const filteredAvailableDocs = {
...localFiles,
items: localFiles.items.map((folder) => {
if (folder.items && folder.type === "folder") {
@ -56,7 +71,7 @@ export default function DocumentSettings({ workspace, systemSettings }) {
};
// Documents that are already in the workspace
const workspaceDocs = {
const filteredWorkspaceDocs = {
...localFiles,
items: localFiles.items.map((folder) => {
if (folder.items && folder.type === "folder") {
@ -74,8 +89,23 @@ export default function DocumentSettings({ workspace, systemSettings }) {
}),
};
setAvailableDocs(availableDocs);
setWorkspaceDocs(workspaceDocs);
setAvailableDocs(filteredAvailableDocs);
setWorkspaceDocs(filteredWorkspaceDocs);
if (autoSelectNew) {
const newSelected = {};
for (const folder of filteredAvailableDocs.items ?? []) {
for (const file of folder.items ?? []) {
if (file?.id && !previousIds.has(file.id)) {
newSelected[file.id] = true;
}
}
}
if (Object.keys(newSelected).length > 0) {
setSelectedItems((prev) => ({ ...prev, ...newSelected }));
}
}
setLoading(false);
}