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:
parent
7ecc4ae005
commit
d767c398c7
@ -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) => {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user