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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { useAnnotationLabels } from '$lib/hooks/useAnnotationLabels/useAnnotationLabels';
import LabelNotFound from '$lib/components/LabelNotFound/LabelNotFound.svelte';
import { getSelectionItems } from '$lib/components/SelectList/getSelectionItems';
import { usePostHog } from '$lib/hooks/usePostHog';
Comment thread
LeonardoRosaa marked this conversation as resolved.
Outdated

type Props = {
selectedAnnotations: Array<AnnotationView>;
Expand All @@ -17,6 +18,16 @@

const { selectedAnnotations, onSelect, disabled, isLoading, collectionId }: Props = $props();

const { trackEvent } = usePostHog();

const handleSelect = (item: { value: string; label: string }) => {
Comment thread
LeonardoRosaa marked this conversation as resolved.
Outdated
trackEvent('annotations_bulk_labeled', {
collection_id: collectionId,
annotation_count: selectedAnnotations.length
});
Comment thread
LeonardoRosaa marked this conversation as resolved.
Outdated
onSelect(item);
};

const result = useAnnotationLabels(() => ({ collectionId }));

const items = $derived(getSelectionItems(result.data || []));
Expand All @@ -37,7 +48,7 @@
name="annotation-label"
placeholder="Select or create a class"
label="Select a class"
{onSelect}
onSelect={handleSelect}
{isLoading}
{disabled}
>
Expand Down
43 changes: 40 additions & 3 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/usePostHog';

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

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

const { trackEvent } = usePostHog();

const handleKeyDown = (event: KeyboardEvent) => {
if (isInputElement(event.target)) {
return;
Expand All @@ -42,15 +45,37 @@
return;
}
if (event.key === get(settingsStore).key_toggle_edit_mode) {
if (!$isEditingMode) {
trackEvent('edit_mode_started', {
collection_id: collection.collection_id,
triggered_by: 'keyboard_shortcut'
});
Comment thread
LeonardoRosaa marked this conversation as resolved.
Outdated
} else {
trackEvent('edit_mode_finished', {
collection_id: collection.collection_id,
triggered_by: 'keyboard_shortcut'
});
}
setIsEditingMode(!$isEditingMode);
} else if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'z') {
executeUndoAction();
const action = $reversibleActions[0];
if (action) {
trackEvent('edit_undo', {
collection_id: collection.collection_id,
triggered_by: 'keyboard_shortcut'
});
void executeReversibleAction(action.id);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}
};

const executeUndoAction = async () => {
const latestAction = $reversibleActions[0];
if (latestAction) {
trackEvent('edit_undo', {
collection_id: collection.collection_id,
triggered_by: 'click'
});
await executeReversibleAction(latestAction.id);
}
};
Expand Down Expand Up @@ -100,7 +125,13 @@
<Button
icon={Check}
buttonProps={{
onclick: () => setIsEditingMode(false),
onclick: () => {
trackEvent('edit_mode_finished', {
collection_id: collection.collection_id,
triggered_by: 'click'
});
setIsEditingMode(false);
},
title: 'Finish Editing',
'data-testid': 'header-editing-mode-button',
class: 'nav-button'
Expand All @@ -112,7 +143,13 @@
<Button
icon={Pencil}
buttonProps={{
onclick: () => setIsEditingMode(true),
onclick: () => {
trackEvent('edit_mode_started', {
collection_id: collection.collection_id,
triggered_by: 'click'
});
setIsEditingMode(true);
},
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 @@ -5,13 +5,28 @@
import { isInputElement } from '$lib/utils/isInputElement';
import { Brush, Eraser } from '@lucide/svelte';
import { onDestroy, onMount } from 'svelte';
import { usePostHog } from '$lib/hooks/usePostHog';
import { page } from '$app/state';

const {
context: sampleDetailsToolbarContext,
setBrushMode,
setBrushSize
} = useSampleDetailsToolbarContext();
const { settingsStore } = useSettings();
const { trackEvent } = usePostHog();

const activateBrushMode = (
mode: 'brush' | 'eraser',
triggeredBy: 'click' | 'keyboard_shortcut'
) => {
trackEvent('annotation_tool_selected', {
collection_id: page.params.collection_id,
tool: mode,
triggered_by: triggeredBy
});
setBrushMode(mode);
};

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

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

Expand Down Expand Up @@ -121,7 +136,7 @@
? 'bg-primary/20 text-primary'
: 'text-muted-foreground hover:bg-muted'}
"
onclick={() => setBrushMode('brush')}
onclick={() => activateBrushMode('brush', 'click')}
>
<Brush class="h-4 w-4" />
</button>
Expand All @@ -135,7 +150,7 @@
? 'bg-primary/20 text-primary'
: 'text-muted-foreground hover:bg-muted'}
"
onclick={() => setBrushMode('eraser')}
onclick={() => activateBrushMode('eraser', 'click')}
>
<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
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
import CursorToolbarButton from '../CursorToolbarButton/CursorToolbarButton.svelte';
import DragToolbarButton from '../DragToolbarButton/DragToolbarButton.svelte';
import { useSettings } from '$lib/hooks/useSettings';
import { usePostHog } from '$lib/hooks/usePostHog';
import { page } from '$app/state';

const { showSegmentationTool = true }: { showSegmentationTool?: boolean } = $props();

const { settingsStore } = useSettings();
const { trackEvent } = usePostHog();
let isSpacePressed = false;

const onKeyDown = (e: KeyboardEvent) => {
Expand All @@ -32,11 +35,11 @@
onClickCursor();
} else if (key === $settingsStore.key_toolbar_bounding_box) {
e.preventDefault();
onClickBoundingBox();
activateBoundingBox('keyboard_shortcut');
} else if (key === $settingsStore.key_toolbar_segmentation_mask) {
if (!showSegmentationTool) return;
e.preventDefault();
onClickBrush();
activateBrush('keyboard_shortcut');
} else if (key === $settingsStore.key_toolbar_drag) {
e.preventDefault();
onClickDrag();
Expand Down Expand Up @@ -109,15 +112,22 @@
}
});

const onClickBoundingBox = () => {
const activateBoundingBox = (triggeredBy: 'click' | 'keyboard_shortcut') => {
if (annotationLabelContext.isOnAnnotationDetailsView) return;

trackEvent('annotation_tool_selected', {
collection_id: page.params.collection_id,
tool: 'bounding-box',
triggered_by: triggeredBy
});
setStatus('bounding-box');
setAnnotationType(AnnotationType.OBJECT_DETECTION);
setAnnotationId(null);
setLastCreatedAnnotationId(null);
};

const onClickBoundingBox = () => activateBoundingBox('click');

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

const onClickBrush = () => {
const activateBrush = (triggeredBy: 'click' | 'keyboard_shortcut') => {
if (!showSegmentationTool) return;

trackEvent('annotation_tool_selected', {
collection_id: page.params.collection_id,
tool: 'brush',
triggered_by: triggeredBy
});
setStatus('brush');
setAnnotationType(AnnotationType.SEGMENTATION_MASK);
if (!annotationLabelContext.isOnAnnotationDetailsView) setAnnotationId(null);
setLastCreatedAnnotationId(null);
};

const onClickBrush = () => activateBrush('click');
</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 @@ -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/usePostHog';

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/usePostHog';
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 = $state(false);
Comment thread
LeonardoRosaa marked this conversation as resolved.
Outdated

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
Loading
Loading