FileListItem fix (#4799)

* show lock icons and lock tooltip

* replace state with derived

* allow to drag files
This commit is contained in:
Pavel Laptev 2024-08-30 13:11:23 +02:00 committed by GitHub
parent 2c7773a6cd
commit fe3c73ccfd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 43 additions and 11 deletions

View File

@ -4,11 +4,14 @@
import { DraggableFile } from '$lib/dragging/draggables'; import { DraggableFile } from '$lib/dragging/draggables';
import { getContext, maybeGetContextStore } from '$lib/utils/context'; import { getContext, maybeGetContextStore } from '$lib/utils/context';
import { computeFileStatus } from '$lib/utils/fileStatus'; import { computeFileStatus } from '$lib/utils/fileStatus';
import { getLocalCommits, getLocalAndRemoteCommits } from '$lib/vbranches/contexts';
import { getCommitStore } from '$lib/vbranches/contexts'; import { getCommitStore } from '$lib/vbranches/contexts';
import { FileIdSelection } from '$lib/vbranches/fileIdSelection'; import { FileIdSelection } from '$lib/vbranches/fileIdSelection';
import { Ownership } from '$lib/vbranches/ownership'; import { Ownership } from '$lib/vbranches/ownership';
import { VirtualBranch, type AnyFile } from '$lib/vbranches/types'; import { getLockText } from '$lib/vbranches/tooltip';
import { VirtualBranch, type AnyFile, LocalFile } from '$lib/vbranches/types';
import FileListItem from '@gitbutler/ui/file/FileListItem.svelte'; import FileListItem from '@gitbutler/ui/file/FileListItem.svelte';
import { onDestroy } from 'svelte';
import type { Writable } from 'svelte/store'; import type { Writable } from 'svelte/store';
interface Props { interface Props {
@ -29,6 +32,16 @@
const fileIdSelection = getContext(FileIdSelection); const fileIdSelection = getContext(FileIdSelection);
const commit = getCommitStore(); const commit = getCommitStore();
// TODO: Refactor this into something more meaningful.
const localCommits = file instanceof LocalFile ? getLocalCommits() : undefined;
const remoteCommits = file instanceof LocalFile ? getLocalAndRemoteCommits() : undefined;
let lockedIds = file.lockedIds;
let lockText = $derived(
lockedIds.length > 0 && $localCommits
? getLockText(lockedIds, ($localCommits || []).concat($remoteCommits || []))
: ''
);
const selectedFiles = fileIdSelection.files; const selectedFiles = fileIdSelection.files;
let contextMenu: FileContextMenu; let contextMenu: FileContextMenu;
@ -75,6 +88,7 @@
<FileContextMenu bind:this={contextMenu} target={draggableEl} {isUnapplied} /> <FileContextMenu bind:this={contextMenu} target={draggableEl} {isUnapplied} />
<FileListItem <FileListItem
id={`file-${file.id}`}
bind:ref={draggableEl} bind:ref={draggableEl}
fileName={file.filename} fileName={file.filename}
filePath={file.path} filePath={file.path}
@ -85,6 +99,8 @@
{draggable} {draggable}
{onclick} {onclick}
{onkeydown} {onkeydown}
locked={file.locked}
{lockText}
oncheck={(e) => { oncheck={(e) => {
const isChecked = e.currentTarget.checked; const isChecked = e.currentTarget.checked;
lastCheckboxDetail = isChecked; lastCheckboxDetail = isChecked;
@ -125,21 +141,43 @@
} }
const files = await $selectedFiles; const files = await $selectedFiles;
let animationEndHandler: () => void;
function addAnimationEndListener(element: HTMLElement) {
animationEndHandler = () => {
element.classList.remove('locked-file-animation');
element.removeEventListener('animationend', animationEndHandler);
};
element.addEventListener('animationend', animationEndHandler);
};
if (files.length > 0) { if (files.length > 0) {
files.forEach((f) => { files.forEach((f) => {
if (f.locked) { if (f.locked) {
const lockedElement = document.getElementById(`file-${f.id}`); const lockedElement = document.getElementById(`file-${f.id}`);
if (lockedElement) { if (lockedElement) {
// add a class to the locked file
lockedElement.classList.add('locked-file-animation'); lockedElement.classList.add('locked-file-animation');
addAnimationEndListener(lockedElement);
} }
} }
}); });
} else if (file.locked) { } else if (file.locked) {
draggableEl?.classList.add('locked-file-animation'); draggableEl?.classList.add('locked-file-animation');
draggableEl && addAnimationEndListener(draggableEl);
} }
onDestroy(() => {
// Ensure any listeners are removed if the component is destroyed before animation ends
if (draggableEl && animationEndHandler) {
draggableEl.removeEventListener('animationend', animationEndHandler);
}
files.forEach((f) => {
const lockedElement = document.getElementById(`file-${f.id}`);
if (lockedElement && animationEndHandler) {
lockedElement.removeEventListener('animationend', animationEndHandler);
}
});
});
}} }}
oncontextmenu={async (e) => { oncontextmenu={async (e) => {
if (fileIdSelection.has(file.id, $commit?.id)) { if (fileIdSelection.has(file.id, $commit?.id)) {

View File

@ -76,12 +76,6 @@
}} }}
ondragstart={(e) => { ondragstart={(e) => {
if (draggable) { if (draggable) {
if (locked) {
e.preventDefault();
console.log('Cannot drag locked file');
return;
}
ondragstart?.(e); ondragstart?.(e);
} }
}} }}
@ -100,8 +94,8 @@
</div> </div>
<div class="details"> <div class="details">
{#if lockText} {#if locked}
<div class="locked" use:tooltip={{ text: lockText, delay: 500 }}> <div class="locked" use:tooltip={{ text: lockText ?? '', delay: 500 }}>
<Icon name="locked-small" color="warning" /> <Icon name="locked-small" color="warning" />
</div> </div>
{/if} {/if}