mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-11-24 13:37:34 +03:00
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:
parent
aaba14e819
commit
a0eeeae645
@ -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
|
||||||
|
@ -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}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user