Refactor search functionality in project layout

This commit refactors the search functionality present in the project layout. Instead of using a debounced input event handler to update the search query, a form is now used to handle search submission. The search functionality in the search page has also been updated to use the query param instead of a writable store, and the fetchResultData function has been extracted for better readability.

Changes:
- Replace debounced input event handler with form submission in project layout
- Update search functionality in search page to use query param
- Extract fetchResultData function for better readability
- Remove unnecessary context and store usage
This commit is contained in:
Nikita Galaiko 2023-03-23 15:20:27 +01:00
parent aaba14e819
commit a0eeeae645
2 changed files with 39 additions and 44 deletions

View File

@ -6,28 +6,15 @@
import { onDestroy } from 'svelte'; import { onDestroy } from 'svelte';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { currentProject } from '$lib/current_project'; import { currentProject } from '$lib/current_project';
import { setContext } from 'svelte'; import { goto } from '$app/navigation';
import { writable } from 'svelte/store';
export let data: LayoutData; export let data: LayoutData;
let query: string; let query: string;
const searchTerm = writable('');
setContext('searchTerm', searchTerm);
$: project = data.project; $: project = data.project;
$: currentProject.set($project); $: currentProject.set($project);
const debounce = <T extends (...args: any[]) => any>(fn: T, delay: number) => { const onSearchSubmit = () => goto(`/projects/${$project?.id}/search?q=${query}`);
let timeout: ReturnType<typeof setTimeout>;
return (...args: any[]) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), delay);
};
};
const updateQuery = debounce(async () => {
searchTerm.set(query);
}, 500);
function projectUrl(project: Project) { function projectUrl(project: Project) {
const gitUrl = project.api?.git_url; const gitUrl = project.api?.git_url;
@ -68,20 +55,23 @@
/></svg /></svg
> >
</div> </div>
<div class="flex w-48 max-w-lg rounded-md shadow-sm"> <form
on:submit|preventDefault={onSearchSubmit}
class="flex w-48 max-w-lg rounded-md shadow-sm"
>
<input type="submit" class="hidden" />
<input <input
type="text" type="text"
name="search" name="search"
id="search" id="search"
placeholder="search history" placeholder="search history"
bind:value={query} bind:value={query}
on:input={updateQuery}
autocomplete="off" autocomplete="off"
aria-label="Search input" aria-label="Search input"
class="block w-full min-w-0 flex-1 rounded border border-zinc-700 bg-zinc-800 p-[3px] px-2 pl-10 text-zinc-200 placeholder:text-zinc-500 sm:text-sm sm:leading-6" class="block w-full min-w-0 flex-1 rounded border border-zinc-700 bg-zinc-800 p-[3px] px-2 pl-10 text-zinc-200 placeholder:text-zinc-500 sm:text-sm sm:leading-6"
style="" style=""
/> />
</div> </form>
</div> </div>
</form> </form>
<div <div

View File

@ -1,12 +1,11 @@
<script lang="ts"> <script lang="ts">
import type { PageData } from './$types'; import type { PageData } from './$types';
import { search } from '$lib'; import { search, type SearchResult } from '$lib';
import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import { listFiles } from '$lib/sessions'; import { listFiles } from '$lib/sessions';
import { formatDistanceToNow } from 'date-fns'; import { formatDistanceToNow } from 'date-fns';
import { list as listDeltas, type Delta } from '$lib/deltas'; import { list as listDeltas, type Delta } from '$lib/deltas';
import { CodeViewer } from '$lib/components'; import { CodeViewer } from '$lib/components';
import { page } from '$app/stores';
export let data: PageData; export let data: PageData;
const { project } = data; const { project } = data;
@ -17,17 +16,38 @@
filepath: string; filepath: string;
highlight: string[]; highlight: string[];
}[]; }[];
let searchTerm: Writable<string> = getContext('searchTerm');
let stopProcessing = false; let stopProcessing = false;
$: query = $page.url.searchParams.get('q');
$: { $: {
stopProcessing = true; if (query && $project?.id) {
processedResults = []; stopProcessing = true;
if ($searchTerm) { processedResults = [];
fetchResults($project?.id ?? '', $searchTerm); fetchResults($project.id, query);
} }
} }
const fetchResultData = async ({
sessionId,
projectId,
filePath,
index,
highlighted
}: SearchResult) => {
const [doc, deltas] = await Promise.all([
listFiles({ projectId, sessionId, paths: [filePath] }).then((r) => r[filePath] ?? ''),
listDeltas({ projectId, sessionId, paths: [filePath] })
.then((r) => r[filePath] ?? [])
.then((d) => d.slice(0, index + 1))
]);
return {
doc,
deltas,
filepath: filePath,
highlight: highlighted
};
};
const fetchResults = async (projectId: string, query: string) => { const fetchResults = async (projectId: string, query: string) => {
const results = await search({ projectId, query }); const results = await search({ projectId, query });
stopProcessing = false; stopProcessing = false;
@ -37,22 +57,7 @@
stopProcessing = false; stopProcessing = false;
return; return;
} }
const { sessionId, projectId, filePath } = result; processedResults = [...processedResults, await fetchResultData(result)];
const [doc, deltas] = await Promise.all([
listFiles({ projectId, sessionId, paths: [filePath] }).then((r) => r[filePath] ?? ''),
listDeltas({ projectId, sessionId, paths: [filePath] })
.then((r) => r[filePath] ?? [])
.then((d) => d.slice(0, result.index + 1))
]);
processedResults = [
...processedResults,
{
doc,
deltas,
filepath: filePath,
highlight: result.highlighted
}
];
} }
}; };
</script> </script>
@ -60,12 +65,12 @@
<figure class="mx-14 flex h-full flex-col gap-2"> <figure class="mx-14 flex h-full flex-col gap-2">
{#if processedResults.length > 0} {#if processedResults.length > 0}
<div class="mb-10 mt-14"> <div class="mb-10 mt-14">
<p class="mb-2 text-xl text-[#D4D4D8]">Results for "{$searchTerm}"</p> <p class="mb-2 text-xl text-[#D4D4D8]">Results for "{query}"</p>
<p class="text-lg text-[#717179]">{processedResults.length} change instances</p> <p class="text-lg text-[#717179]">{processedResults.length} change instances</p>
</div> </div>
{:else} {:else}
<div class="mb-10 mt-14"> <div class="mb-10 mt-14">
<p class="mb-2 text-xl text-[#D4D4D8]">No results for "{$searchTerm}"</p> <p class="mb-2 text-xl text-[#D4D4D8]">No results for "{query}"</p>
</div> </div>
{/if} {/if}