Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ const closeLabelEditModal = () => {
const confirmLabelChange = async () => {
if (!editingAnnotation.value || !selectedNewLabelId.value) return;

// FIX: Not working
await handleLabelChange(editingAnnotation.value, selectedNewLabelId.value.toString());
closeLabelEditModal();
};
Expand Down
33 changes: 30 additions & 3 deletions frontend/src/components/project/UploadImagesModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
type="file"
:multiple="uploadType === 'files'"
:webkitdirectory="uploadType === 'folder'"
accept="image/*"
:directory="uploadType === 'folder'"
:accept="uploadType === 'files' ? 'image/*' : undefined"
@change="handleFileSelection"
class="hidden-input"
>
Expand All @@ -55,7 +56,7 @@
Drag and drop images here, or click to select files
</span>
<span v-else>
Click to select a folder containing images
Drag and drop a folder here, or click to select folder
</span>
</p>
<p class="dropzone-subtext">
Expand Down Expand Up @@ -117,7 +118,11 @@
></div>
</div>
<p class="progress-text">
Uploading {{ currentFileIndex }} of {{ selectedFiles.length }} files...
Uploading {{ selectedFiles.length }} files...
<br>
<small v-if="selectedFiles.length > 15 || getTotalFileSize() > 25000000">
Large upload detected - processing in batches
</small>
</p>
</div>

Expand Down Expand Up @@ -259,6 +264,8 @@ const handleFileSelection = (event: Event) => {
const files = Array.from(target.files);
const imageFiles = files.filter(file => file.type.startsWith('image/'));

logger.info(`File selection detected: ${files.length} total files, ${imageFiles.length} image files, upload type: ${uploadType.value}`);

// Use helper function to add files with duplicate checking
addFilesToSelection(imageFiles);

Expand All @@ -273,6 +280,15 @@ const handleFileSelection = (event: Event) => {
showWarning(title, message);
logger.warn(`Filtered out ${nonImageCount} non-image files`);
}

// Show success message for folder uploads
if (uploadType.value === 'folder' && imageFiles.length > 0) {
showSuccess('Folder Selected', `Selected ${imageFiles.length} images from the folder.`);
}
} else if (uploadType.value === 'folder') {
// User likely cancelled the folder selection or didn't confirm it properly
logger.warn('Folder selection cancelled or no files detected');
showWarning('Folder Selection', 'No folder selected. Make sure to select a folder and confirm the selection in the file dialog.');
}
// Clear the input value so the same file can be selected again
// and to prevent cancelled selections from affecting future selections
Expand All @@ -294,6 +310,8 @@ const handleDrop = (event: DragEvent) => {
const files = Array.from(event.dataTransfer.files);
const imageFiles = files.filter(file => file.type.startsWith('image/'));

logger.info(`Drop detected: ${files.length} total files, ${imageFiles.length} image files, upload type: ${uploadType.value}`);

// Use helper function to add files with duplicate checking
addFilesToSelection(imageFiles);

Expand All @@ -308,6 +326,11 @@ const handleDrop = (event: DragEvent) => {
showWarning(title, message);
logger.warn(`Filtered out ${nonImageCount} non-image files`);
}

// Show success message for folder uploads
if (uploadType.value === 'folder' && imageFiles.length > 0) {
showSuccess('Files Dropped', `Added ${imageFiles.length} images from the dropped folder/files.`);
}
}
};

Expand Down Expand Up @@ -336,6 +359,10 @@ const formatFileSize = (bytes: number): string => {
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};

const getTotalFileSize = (): number => {
return selectedFiles.value.reduce((total, file) => total + file.size, 0);
};

const handleUploadError = (error: unknown) => {
logger.error('Upload process failed', error);

Expand Down
24 changes: 24 additions & 0 deletions frontend/src/composables/useAssetPreview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,28 @@ export function useAssetPreview() {
});
};

// Cache invalidation functions
const clearAnnotationsCache = (assetId?: number) => {
if (assetId) {
// Clear specific asset annotations
assetAnnotations.value.delete(assetId);
loadingAnnotations.value.delete(assetId);
logger.debug(`Cleared annotations cache for asset ${assetId}`);
} else {
// Clear all annotations cache
assetAnnotations.value.clear();
loadingAnnotations.value.clear();
logger.debug('Cleared all annotations cache');
}
};

const refreshAnnotations = async (projectId: number, assetId: number) => {
// Force refresh annotations for specific asset
clearAnnotationsCache(assetId);
await loadAnnotations(projectId, assetId);
logger.debug(`Force refreshed annotations for asset ${assetId}`);
};

// Utility functions
const formatFileSize = (bytes?: number): string => {
if (!bytes) return 'Unknown size';
Expand Down Expand Up @@ -340,6 +362,8 @@ export function useAssetPreview() {
handlePreviewImageLoad,
handlePreviewImageError,
preloadVisibleAssets,
clearAnnotationsCache,
refreshAnnotations,
formatFileSize
};
}
2 changes: 2 additions & 0 deletions frontend/src/core/timeTracking/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { TimeTracker } from './timeTracker';
export type { TimerService } from './types';
Loading
Loading