mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 00:36:31 +02:00
fix(hooks): add AbortController to properly cancel fetch requests on unmount
This commit is contained in:
parent
0cd2b8164d
commit
8a8e5fcd76
4 changed files with 34 additions and 24 deletions
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "SurfSense",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
||||||
|
|
@ -34,9 +34,12 @@ export const CirclebackConfig: FC<CirclebackConfigProps> = ({ connector, onNameC
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
|
// Fetch webhook info
|
||||||
// Fetch webhook info
|
// Fetch webhook info
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchWebhookInfo = async () => {
|
const controller = new AbortController();
|
||||||
|
|
||||||
|
const doFetch = async () => {
|
||||||
if (!connector.search_space_id) return;
|
if (!connector.search_space_id) return;
|
||||||
|
|
||||||
const baseUrl = process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL;
|
const baseUrl = process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL;
|
||||||
|
|
@ -49,8 +52,11 @@ export const CirclebackConfig: FC<CirclebackConfigProps> = ({ connector, onNameC
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await authenticatedFetch(
|
const response = await authenticatedFetch(
|
||||||
`${baseUrl}/api/v1/webhooks/circleback/${connector.search_space_id}/info`
|
`${baseUrl}/api/v1/webhooks/circleback/${connector.search_space_id}/info`,
|
||||||
|
{ signal: controller.signal }
|
||||||
);
|
);
|
||||||
|
if (controller.signal.aborted) return;
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: unknown = await response.json();
|
const data: unknown = await response.json();
|
||||||
// Runtime validation with zod schema
|
// Runtime validation with zod schema
|
||||||
|
|
@ -59,16 +65,18 @@ export const CirclebackConfig: FC<CirclebackConfigProps> = ({ connector, onNameC
|
||||||
setWebhookUrl(validatedData.webhook_url);
|
setWebhookUrl(validatedData.webhook_url);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (controller.signal.aborted) return;
|
||||||
console.error("Failed to fetch webhook info:", error);
|
console.error("Failed to fetch webhook info:", error);
|
||||||
// Reset state on error
|
// Reset state on error
|
||||||
setWebhookInfo(null);
|
setWebhookInfo(null);
|
||||||
setWebhookUrl("");
|
setWebhookUrl("");
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
if (!controller.signal.aborted) setIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchWebhookInfo();
|
doFetch().catch(() => {});
|
||||||
|
return () => controller.abort();
|
||||||
}, [connector.search_space_id]);
|
}, [connector.search_space_id]);
|
||||||
|
|
||||||
const handleNameChange = (value: string) => {
|
const handleNameChange = (value: string) => {
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ export function EditorPanelContent({
|
||||||
const [displayTitle, setDisplayTitle] = useState(title || "Untitled");
|
const [displayTitle, setDisplayTitle] = useState(title || "Untitled");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false;
|
const controller = new AbortController();
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
setEditorDoc(null);
|
setEditorDoc(null);
|
||||||
|
|
@ -78,7 +78,7 @@ export function EditorPanelContent({
|
||||||
initialLoadDone.current = false;
|
initialLoadDone.current = false;
|
||||||
changeCountRef.current = 0;
|
changeCountRef.current = 0;
|
||||||
|
|
||||||
const fetchContent = async () => {
|
const doFetch = async () => {
|
||||||
const token = getBearerToken();
|
const token = getBearerToken();
|
||||||
if (!token) {
|
if (!token) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
|
|
@ -88,10 +88,10 @@ export function EditorPanelContent({
|
||||||
try {
|
try {
|
||||||
const response = await authenticatedFetch(
|
const response = await authenticatedFetch(
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-spaces/${searchSpaceId}/documents/${documentId}/editor-content`,
|
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-spaces/${searchSpaceId}/documents/${documentId}/editor-content`,
|
||||||
{ method: "GET" }
|
{ method: "GET", signal: controller.signal }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (cancelled) return;
|
if (controller.signal.aborted) return;
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response
|
const errorData = await response
|
||||||
|
|
@ -115,18 +115,16 @@ export function EditorPanelContent({
|
||||||
setEditorDoc(data);
|
setEditorDoc(data);
|
||||||
initialLoadDone.current = true;
|
initialLoadDone.current = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (cancelled) return;
|
if (controller.signal.aborted) return;
|
||||||
console.error("Error fetching document:", err);
|
console.error("Error fetching document:", err);
|
||||||
setError(err instanceof Error ? err.message : "Failed to fetch document");
|
setError(err instanceof Error ? err.message : "Failed to fetch document");
|
||||||
} finally {
|
} finally {
|
||||||
if (!cancelled) setIsLoading(false);
|
if (!controller.signal.aborted) setIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchContent();
|
doFetch().catch(() => {});
|
||||||
return () => {
|
return () => controller.abort();
|
||||||
cancelled = true;
|
|
||||||
};
|
|
||||||
}, [documentId, searchSpaceId, title]);
|
}, [documentId, searchSpaceId, title]);
|
||||||
|
|
||||||
const handleMarkdownChange = useCallback((md: string) => {
|
const handleMarkdownChange = useCallback((md: string) => {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ export function DocumentTabContent({ documentId, searchSpaceId, title }: Documen
|
||||||
const changeCountRef = useRef(0);
|
const changeCountRef = useRef(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false;
|
const controller = new AbortController();
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
setDoc(null);
|
setDoc(null);
|
||||||
|
|
@ -64,7 +64,7 @@ export function DocumentTabContent({ documentId, searchSpaceId, title }: Documen
|
||||||
initialLoadDone.current = false;
|
initialLoadDone.current = false;
|
||||||
changeCountRef.current = 0;
|
changeCountRef.current = 0;
|
||||||
|
|
||||||
const fetchContent = async () => {
|
const doFetch = async () => {
|
||||||
const token = getBearerToken();
|
const token = getBearerToken();
|
||||||
if (!token) {
|
if (!token) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
|
|
@ -74,10 +74,10 @@ export function DocumentTabContent({ documentId, searchSpaceId, title }: Documen
|
||||||
try {
|
try {
|
||||||
const response = await authenticatedFetch(
|
const response = await authenticatedFetch(
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-spaces/${searchSpaceId}/documents/${documentId}/editor-content`,
|
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/search-spaces/${searchSpaceId}/documents/${documentId}/editor-content`,
|
||||||
{ method: "GET" }
|
{ method: "GET", signal: controller.signal }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (cancelled) return;
|
if (controller.signal.aborted) return;
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errorData = await response
|
const errorData = await response
|
||||||
|
|
@ -98,18 +98,16 @@ export function DocumentTabContent({ documentId, searchSpaceId, title }: Documen
|
||||||
setDoc(data);
|
setDoc(data);
|
||||||
initialLoadDone.current = true;
|
initialLoadDone.current = true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (cancelled) return;
|
if (controller.signal.aborted) return;
|
||||||
console.error("Error fetching document:", err);
|
console.error("Error fetching document:", err);
|
||||||
setError(err instanceof Error ? err.message : "Failed to fetch document");
|
setError(err instanceof Error ? err.message : "Failed to fetch document");
|
||||||
} finally {
|
} finally {
|
||||||
if (!cancelled) setIsLoading(false);
|
if (!controller.signal.aborted) setIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchContent();
|
doFetch().catch(() => {});
|
||||||
return () => {
|
return () => controller.abort();
|
||||||
cancelled = true;
|
|
||||||
};
|
|
||||||
}, [documentId, searchSpaceId]);
|
}, [documentId, searchSpaceId]);
|
||||||
|
|
||||||
const handleMarkdownChange = useCallback((md: string) => {
|
const handleMarkdownChange = useCallback((md: string) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue