Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

const handleDeleteAnnotation = async () => {
try {
await deleteAnnotation(annotation.sample_id);
await deleteAnnotation(annotation.sample_id, annotation.annotation_type);

toast.success('Annotation deleted successfully');

Expand Down
43 changes: 31 additions & 12 deletions lightly_studio_view/src/lib/components/Header/Header.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import UserAvatar from '$lib/components/UserAvatar/UserAvatar.svelte';
import useAuth from '$lib/hooks/useAuth/useAuth';
import { hasMinimumRole } from '$lib/hooks/useAuth/hasMinimumRole';
import { usePostHog } from '$lib/hooks';

let { collection }: { collection: CollectionView } = $props();

Expand All @@ -33,6 +34,31 @@
const { setIsEditingMode, isEditingMode, reversibleActions, executeReversibleAction } =
page.data.globalStorage;

const { trackEvent } = usePostHog();

type TriggeredBy = 'click' | 'keyboard_shortcut';

const setEditMode = (active: boolean, triggeredBy: TriggeredBy) => {
if (active) {
trackEvent('edit_mode_started', {
collection_id: collection.collection_id,
triggered_by: triggeredBy
});
}
setIsEditingMode(active);
};

const executeUndoAction = async (triggeredBy: TriggeredBy) => {
const latestAction = $reversibleActions[0];
if (latestAction) {
trackEvent('edit_undo', {
collection_id: collection.collection_id,
triggered_by: triggeredBy
});
await executeReversibleAction(latestAction.id);
}
};

const handleKeyDown = (event: KeyboardEvent) => {
if (isInputElement(event.target)) {
return;
Expand All @@ -42,16 +68,9 @@
return;
}
if (event.key === get(settingsStore).key_toggle_edit_mode) {
setIsEditingMode(!$isEditingMode);
setEditMode(!$isEditingMode, 'keyboard_shortcut');
} else if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'z') {
executeUndoAction();
}
};

const executeUndoAction = async () => {
const latestAction = $reversibleActions[0];
if (latestAction) {
await executeReversibleAction(latestAction.id);
void executeUndoAction('keyboard_shortcut');
}
};

Expand Down Expand Up @@ -86,7 +105,7 @@
<Button
icon={Undo2}
buttonProps={{
onclick: executeUndoAction,
onclick: () => executeUndoAction('click'),
disabled: $reversibleActions.length === 0,
title: $reversibleActions[0]
? $reversibleActions[0].description
Expand All @@ -100,7 +119,7 @@
<Button
icon={Check}
buttonProps={{
onclick: () => setIsEditingMode(false),
onclick: () => setEditMode(false, 'click'),
title: 'Finish Editing',
'data-testid': 'header-editing-mode-button',
class: 'nav-button'
Expand All @@ -112,7 +131,7 @@
<Button
icon={Pencil}
buttonProps={{
onclick: () => setIsEditingMode(true),
onclick: () => setEditMode(true, 'click'),
title: 'Edit annotations',
'data-testid': 'header-editing-mode-button',
class: 'nav-button'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
} = useSampleDetailsToolbarContext();
const { settingsStore } = useSettings();

const activateBrushMode = (mode: 'brush' | 'eraser') => {
setBrushMode(mode);
};

const {
context: annotationLabelContext,
setAnnotationId,
Expand Down Expand Up @@ -42,10 +46,10 @@

if (key === brushShortcut) {
event.preventDefault();
setBrushMode('brush');
activateBrushMode('brush');
} else if (key === eraserShortcut) {
event.preventDefault();
setBrushMode('eraser');
activateBrushMode('eraser');
}
};

Expand Down Expand Up @@ -121,7 +125,7 @@
? 'bg-primary/20 text-primary'
: 'text-muted-foreground hover:bg-muted'}
"
onclick={() => setBrushMode('brush')}
onclick={() => activateBrushMode('brush')}
>
<Brush class="h-4 w-4" />
</button>
Expand All @@ -135,7 +139,7 @@
? 'bg-primary/20 text-primary'
: 'text-muted-foreground hover:bg-muted'}
"
onclick={() => setBrushMode('eraser')}
onclick={() => activateBrushMode('eraser')}
>
<Eraser class="h-4 w-4" />
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@
refetch
});

await deleteAnnotation(annotationId);
await deleteAnnotation(annotationId, annotation.annotation_type);
toast.success('Annotation deleted successfully');
refetch();
if (annotationLabelContext.annotationId === annotationId) {
Expand Down Expand Up @@ -230,7 +230,11 @@
}}
canHighlight={annotationLabelContext.lastCreatedAnnotationId === annotation.sample_id}
onClickSelectList={() => {
setAnnotationId(annotation.sample_id);
selectAnnotation({
annotationId: annotation.sample_id,
annotations,
collectionId
});
}}
/>
{/snippet}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
refetch
});

await deleteAnnotation(annotationId);
await deleteAnnotation(annotationId, annotation.annotation_type);
toast.success('Classification deleted successfully');
refetch();
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,11 @@
isOnAnnotationDetailsView
)
return;
selectAnnotation({ annotationId, annotations: sample.annotations ?? [], collectionId });
selectAnnotation({
annotationId,
annotations: sample.annotations ?? [],
collectionId
});
};

let annotationsToShow = $derived(sample?.annotations ? getAnnotations(sample.annotations) : []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
onClickCursor();
} else if (key === $settingsStore.key_toolbar_bounding_box) {
e.preventDefault();
onClickBoundingBox();
activateBoundingBox();
} else if (key === $settingsStore.key_toolbar_segmentation_mask) {
if (!showSegmentationTool) return;
e.preventDefault();
onClickBrush();
activateBrush();
} else if (key === $settingsStore.key_toolbar_drag) {
e.preventDefault();
onClickDrag();
Expand Down Expand Up @@ -109,7 +109,7 @@
}
});

const onClickBoundingBox = () => {
const activateBoundingBox = () => {
if (annotationLabelContext.isOnAnnotationDetailsView) return;

setStatus('bounding-box');
Expand All @@ -118,6 +118,8 @@
setLastCreatedAnnotationId(null);
};

const onClickBoundingBox = () => activateBoundingBox();

const onClickCursor = () => {
setStatus('cursor');
};
Expand All @@ -126,14 +128,16 @@
setStatus('drag');
};

const onClickBrush = () => {
const activateBrush = () => {
if (!showSegmentationTool) return;

setStatus('brush');
setAnnotationType(AnnotationType.SEGMENTATION_MASK);
if (!annotationLabelContext.isOnAnnotationDetailsView) setAnnotationId(null);
setLastCreatedAnnotationId(null);
};

const onClickBrush = () => activateBrush();
</script>

<div class="pointer-events-none absolute left-1 top-1 z-20">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@
refetch
});

await deleteAnnotation(annotation!.sample_id);
await deleteAnnotation(annotation!.sample_id, annotation!.annotation_type);
toast.success('Annotation deleted successfully');

if (annotationLabelContext.isOnAnnotationDetailsView) return gotoNextAnnotation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import SelectClassDialog from '$lib/components/SelectClassDialog/SelectClassDialog.svelte';
import { getBoundingBox } from '$lib/components/SampleAnnotation/utils';
import type { PendingChange } from '../pendingChange';
import { usePostHog } from '$lib/hooks';

type D3Event = D3DragEvent<SVGRectElement, unknown, unknown>;

Expand Down Expand Up @@ -52,6 +53,8 @@

let temporaryBbox = $state<BoundingBox | null>(null);
let shouldDisableInteraction = $state(false);
let drawStartFired = false;
const { trackEvent } = usePostHog();
const labels = useAnnotationLabels(() => ({ collectionId }));

const {
Expand Down Expand Up @@ -84,6 +87,7 @@
const cancelDrag = () => {
setIsDrawing(false);
temporaryBbox = null;
drawStartFired = false;
};

const datasetId = $derived(page.params.dataset_id!);
Expand All @@ -105,6 +109,14 @@
// Remove focus from any selected annotation.
setAnnotationId(null);
setIsDrawing(true);
if (!drawStartFired) {
trackEvent('annotation_draw_started', {
collection_id: collectionId,
tool: 'bounding-box',
parent_sample_type: page.params.collection_type
});
drawStartFired = true;
}
// Get mouse position relative to the SVG element
const svgRect = interactionRect!.getBoundingClientRect();
const clientX = event.sourceEvent.clientX;
Expand Down Expand Up @@ -156,6 +168,7 @@

cancelDrag();
startPoint = null;
drawStartFired = false;
});

rectSelection.call(dragBehavior);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
useDeleteAnnotation
} from '$lib/hooks';
import { page } from '$app/state';
import { usePostHog } from '$lib/hooks';
import type { PendingChange } from '../pendingChange';
import SampleAnnotationRect from '../SampleAnnotationRect/SampleAnnotationRect.svelte';
import SelectClassDialog from '$lib/components/SelectClassDialog/SelectClassDialog.svelte';
Expand Down Expand Up @@ -59,6 +60,9 @@
setAnnotationId
} = useAnnotationLabelContext();

const { trackEvent } = usePostHog();
let drawStartFired = false;

const { deleteAnnotation } = useDeleteAnnotation({ collectionId });

const labels = useAnnotationLabels(() => ({ collectionId }));
Expand Down Expand Up @@ -213,6 +217,7 @@

const handleStrokeComplete = (e: PointerEvent) => {
releasePointerCapture(e);
drawStartFired = false;
resetPreviewState({ clearDrawing: false });

const targetAnnotation = resolveSelectedAnnotation();
Expand Down Expand Up @@ -252,6 +257,7 @@

const handleStrokeCancel = (e: PointerEvent) => {
releasePointerCapture(e);
drawStartFired = false;
resetPreviewState();
};
</script>
Expand Down Expand Up @@ -347,6 +353,14 @@
return;
}

if (!drawStartFired) {
trackEvent('annotation_draw_started', {
collection_id: collectionId,
tool: 'brush',
parent_sample_type: page.params.collection_type
});
drawStartFired = true;
}
setIsDrawing(true);
lastBrushPoint = point;
isPreviewVisible = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@

async function handleEventDelete(event: VideoEvent) {
try {
await deleteAnnotation(event.id);
await deleteAnnotation(event.id, AnnotationType.CLASSIFICATION);
onVideoUpdate();
toast.success('Event deleted');
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion lightly_studio_view/src/lib/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ export { useColorPicker } from '$lib/hooks/useColorPicker/useColorPicker.svelte'
export { useSubmitCombinationSelection } from '$lib/hooks/useSubmitCombinationSelection/useSubmitCombinationSelection';
export { useOperatorsDialog } from '$lib/hooks/useOperatorsDialog/useOperatorsDialog';
export { useDeleteAnnotation } from '$lib/hooks/useDeleteAnnotation/useDeleteAnnotation';
export { useSettings } from '$lib/hooks/useSettings';
export { usePostHog } from '$lib/hooks/usePostHog';
export { useSettings } from '$lib/hooks/useSettings';
export { useTrackSampleInspected } from '$lib/hooks/useTrackSampleInspected';
export { useAnnotationClassVisibility } from '$lib/hooks/useAnnotationClassVisibility/useAnnotationClassVisibility';
export {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export function useAnnotationSelection() {
);

setLastCreatedAnnotationId(null);

setAnnotationId(context.annotationId === annotationId ? null : annotationId);
}

Expand Down
Loading
Loading