gitbutler/apps/desktop/src/lib/file/BranchFilesList.svelte
2024-07-31 13:08:48 +02:00

140 lines
3.8 KiB
Svelte

<script lang="ts">
import BranchFilesHeader from './BranchFilesHeader.svelte';
import FileListItem from './FileListItem.svelte';
import LazyloadContainer from '$lib/shared/LazyloadContainer.svelte';
import TextBox from '$lib/shared/TextBox.svelte';
import { copyToClipboard } from '$lib/utils/clipboard';
import { getContext } from '$lib/utils/context';
import { selectFilesInList } from '$lib/utils/selectFilesInList';
import { maybeMoveSelection } from '$lib/utils/selection';
import { getCommitStore } from '$lib/vbranches/contexts';
import { FileIdSelection, stringifyFileKey } from '$lib/vbranches/fileIdSelection';
import { sortLikeFileTree } from '$lib/vbranches/filetree';
import Button from '@gitbutler/ui/inputs/Button.svelte';
import type { AnyFile } from '$lib/vbranches/types';
export let files: AnyFile[];
export let isUnapplied = false;
export let showCheckboxes = false;
export let allowMultiple = false;
export let readonly = false;
const fileIdSelection = getContext(FileIdSelection);
const commit = getCommitStore();
function chunk<T>(arr: T[], size: number) {
return Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
arr.slice(i * size, i * size + size)
);
}
let chunkedFiles: AnyFile[][] = [];
let displayedFiles: AnyFile[] = [];
let currentDisplayIndex = 0;
function setFiles(files: AnyFile[]) {
chunkedFiles = chunk(sortLikeFileTree(files), 100);
displayedFiles = chunkedFiles[0] || [];
currentDisplayIndex = 0;
}
// Make sure we display when the file list is reset
$: setFiles(files);
export function loadMore() {
if (currentDisplayIndex + 1 >= chunkedFiles.length) return;
currentDisplayIndex += 1;
displayedFiles = [...displayedFiles, ...chunkedFiles[currentDisplayIndex]];
}
let mergeDiffCommand = 'git diff-tree --cc ';
</script>
{#if !$commit?.isMergeCommit()}
<BranchFilesHeader title="Changed files" {files} {showCheckboxes} />
{:else}
<div class="merge-commit-error">
<p class="info">
Displaying diffs for merge commits is currently not supported. Please view the merge commit in
GitHub, or run the following command in your project directory:
</p>
<div class="command">
<TextBox value={mergeDiffCommand + $commit.id.slice(0, 7)} wide readonly />
<Button
icon="copy"
style="ghost"
outline
on:mousedown={() => copyToClipboard(mergeDiffCommand + $commit.id.slice(0, 7))}
/>
</div>
</div>
{/if}
{#if displayedFiles.length > 0}
<!-- Maximum amount for initial render is 100 files
`minTriggerCount` set to 80 in order to start the loading a bit earlier. -->
<LazyloadContainer
minTriggerCount={80}
ontrigger={() => {
console.log('loading more files...');
loadMore();
}}
role="listbox"
>
{#each displayedFiles as file (file.id)}
<FileListItem
{file}
{readonly}
{isUnapplied}
showCheckbox={showCheckboxes}
selected={$fileIdSelection.includes(stringifyFileKey(file.id, $commit?.id))}
on:click={(e) => {
selectFilesInList(e, file, fileIdSelection, displayedFiles, allowMultiple, $commit);
}}
on:keydown={(e) => {
e.preventDefault();
maybeMoveSelection(
{
allowMultiple,
shiftKey: e.shiftKey,
key: e.key,
targetElement: e.currentTarget as HTMLElement,
file,
files: displayedFiles,
selectedFileIds: $fileIdSelection,
fileIdSelection
}
);
if (e.key === 'Escape') {
fileIdSelection.clear();
const targetEl = e.target as HTMLElement;
targetEl.blur();
}
}}
/>
{/each}
</LazyloadContainer>
{/if}
<style lang="postcss">
.merge-commit-error {
display: flex;
flex-direction: column;
gap: 14px;
padding: 14px;
& .info {
color: var(--clr-text-2);
}
& .command {
display: flex;
gap: 8px;
align-items: center;
width: 100%;
}
}
</style>