mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-02 21:19:12 +00:00
Overview - Khoj references files it used in its response as markdown links. For example [1](file://path/to/file.txt#line=121) - Previously these file links were just shown as raw text - This change renders khoj's inline file references as a proper links and shows file content preview (around specified line if deeplink) on hover or click in the web app Details - Render inline file references as links in chat message on web app. Previously references like [1](file://path/to/file.txt#line=120) would be shown as plain text. Now they are rendered as links - Preview file content of referenced files on click or hover. If reference uses a deeplink with line number, the file content around that line is shown on hover, click. Click allows viewing file preview on mobile, unlike hover. Hover is easier with mouse.
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
|
|
export interface UseFileContentResult {
|
|
content: string;
|
|
loading: boolean;
|
|
error: string | null;
|
|
}
|
|
|
|
// Fetch file content for a given path when `enabled` is true.
|
|
export function useFileContent(path: string | undefined, enabled: boolean): UseFileContentResult {
|
|
const [content, setContent] = useState<string>("");
|
|
const [loading, setLoading] = useState<boolean>(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
async function run() {
|
|
if (!enabled || !path) return;
|
|
setLoading(true);
|
|
setError(null);
|
|
setContent("");
|
|
try {
|
|
const resp = await fetch(`/api/content/file?file_name=${encodeURIComponent(path)}`);
|
|
if (!resp.ok) {
|
|
throw new Error(`Failed to fetch file content (${resp.status})`);
|
|
}
|
|
const data = await resp.json();
|
|
if (!cancelled) setContent(data.raw_text || "");
|
|
} catch (err) {
|
|
if (!cancelled)
|
|
setError(err instanceof Error ? err.message : "Failed to load file content");
|
|
} finally {
|
|
if (!cancelled) setLoading(false);
|
|
}
|
|
}
|
|
run();
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [path, enabled]);
|
|
|
|
return { content, loading, error };
|
|
}
|