Skip to content

Specifications for Uploading folders#4417

Open
ildyria wants to merge 7 commits into
masterfrom
upload-folders
Open

Specifications for Uploading folders#4417
ildyria wants to merge 7 commits into
masterfrom
upload-folders

Conversation

@ildyria

@ildyria ildyria commented Jun 13, 2026

Copy link
Copy Markdown
Member

Fixes #1694

Summary by CodeRabbit

Summary

  • New Features

    • Added folder drag-and-drop album creation that converts dropped folder trees into albums, including recursive sub-albums up to a configurable maximum depth.
    • Added settings to enable/disable folder uploads and control recursion depth, with automatic fallback to the existing flat-file drop flow when unsupported.
  • Bug Fixes

    • Improved post-upload refresh so albums created from dropped folders appear reliably, including correct per-file album targeting.
  • Documentation

    • Added/updated feature specs, plans, task checklists, and open questions for folder-drop behavior and edge cases.

@ildyria ildyria requested a review from a team as a code owner June 13, 2026 11:47
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces comprehensive specification, planning, and implementation foundation for Feature 044: "Folder Drag-and-Drop Album Creation." The changes add detailed documentation defining the feature vision and requirements, backend configuration infrastructure with multi-language support across 21 locales, frontend state management and TypeScript type definitions, a new composable for folder detection and processing, integration into the upload event handler, and wiring across UploadPanel, Album, Albums, Timeline, and CameraCapture components to support recursive album creation from dropped folders.

Changes

Feature 044: Complete Implementation Foundation

Layer / File(s) Summary
Feature Specification, Planning, and Documentation
docs/specs/4-architecture/features/044-folder-drop-album-creation/spec.md, plan.md, tasks.md; docs/specs/4-architecture/roadmap.md; docs/specs/4-architecture/open-questions.md
Comprehensive feature documentation defining vision, success criteria, scope, and implementation roadmap. Specification covers 15 functional requirements (directory detection via webkitGetAsEntry(), album resolution/creation, batched readEntries(), per-file album_id overrides, permission gating, refresh emission), admin configuration via UploadConfig (folder_upload_enabled, folder_upload_max_depth), UI mocks, scenario matrix, and browser compatibility. Plan establishes scope alignment, success criteria, assumptions, risks, and implementation increments (I-1 through I-5) with scenario tracking. Tasks provide concrete checklist covering backend config migration, Uploadable.album_id extension, folderDrop.ts composable creation, uploadEvents.ts integration, view wiring, testing, and quality gates. Roadmap registers Feature 044 (Draft, Medium priority) in active features. Open questions document and resolve seven architectural decisions (Q-044-01 through Q-044-07) including composable signatures, config ownership, cache invalidation, album matching scope, and feature boundaries.
Backend Configuration and Migration
database/migrations/2026_06_13_000002_add_folder_upload_config.php; app/Http/Resources/GalleryConfigs/UploadConfig.php
Backend infrastructure establishing folder upload feature configuration. Migration defines two config entries under Image Processing category: folder_upload_enabled (boolean, default enabled) and folder_upload_max_depth (integer with 0 = unlimited). UploadConfig.php extends the gallery configuration resource to expose both settings as public properties, reading from ConfigManager with type conversions, making feature controls available to frontend via API response.
Language Strings and Localization
lang/*/all_settings.php (21 locales)
Multi-language support for folder upload configuration across 21 locales (Arabic, Bulgarian, Czech, German, Greek, English, Spanish, Farsi, French, Hungarian, Italian, Japanese, Dutch, Norwegian, Polish, Portuguese, Russian, Slovak, Swedish, Turkish, Vietnamese, Simplified Chinese, Traditional Chinese). Each language file adds two configuration setting entries: folder_upload_enabled and folder_upload_max_depth. Each setting appears in both documentation (short user-facing description) and details (expanded help text shown in settings UI), enabling admin settings presentation in diverse languages and regions.
Frontend Types and State Management
resources/js/lychee.d.ts; resources/js/stores/ModalsState.ts
Frontend infrastructure for upload configuration state and TypeScript definitions. lychee.d.ts extends UploadConfig TypeScript interface with folder_upload_enabled: boolean and folder_upload_max_depth: number fields. ModalsState.ts extends Pinia togglable store with upload_config state property and new loadUploadConfig() action fetching and caching setup data via UploadService.getSetUp(), centralizing configuration availability.
Folder Drop Composable Core Logic
resources/js/composables/album/folderDrop.ts
New composable implementing browser-safe folder drag-and-drop detection and recursive album-creation processing. Exports getEntry() helper normalizing DataTransferItem entry access with cross-browser fallback, and hasDirectoryEntry() detecting directory drops. Internal utilities include readDirectoryEntries() for batched directory enumeration, fileEntryToFile() converting FileSystemFileEntry to File, resolveOrCreateAlbum() performing case-insensitive album matching and creation, and fetchChildAlbums() paginating AlbumService.getAlbums() for child-album lists. Recursive processDirectory() traversal enforces maxDepth limit, resolves/reuses album IDs, enqueues files with album_id and albumTitle, and aggregates errors. Main handleFolderDrop() orchestrator partitions dropped items, processes directories concurrently, and reports whether uploads were enqueued.
Upload Events Handler Integration
resources/js/composables/album/uploadEvents.ts
Integrates folder drag-and-drop detection and processing into the main upload event handler. Extends Uploadable type with required uid field and optional album_id and albumTitle overrides. Expands useMouseEvents() signature with parent_id, existingAlbums, and upload_config ref parameters. Adds folder-drop path in dropUpload(): when folder_upload_enabled and directory entries detected, routes through handleFolderDrop() with context, sets visibility, and exits early. Preserves flat-file fallback behavior. Updates onPaste() to assign unique uid to pasted files.
Upload Display and Camera Capture Updates
resources/js/components/forms/upload/UploadingLine.vue; resources/js/components/modals/CameraCapture.vue
Updates to display uploaded files with optional album context and support unique file tracking. UploadingLine.vue: refactors props into named UploadingLineProps type, updates template to optionally display albumTitle as muted prefix before file name, enabling visual indication of album placement for folder-dropped files. CameraCapture.vue: assigns unique uid to each queued upload item via crypto.randomUUID().
Upload Panel Configuration and Cache Management
resources/js/components/modals/UploadPanel.vue
Migrates setup from local ref with loader to Pinia store value, removing explicit loading. Passes :album-id per item via uploadable override or route-level fallback. Updates cache invalidation to target route-level album plus all per-file overrides for proper nested album invalidation. Switches :key from file.name to uid. Includes generated uid in queued upload items.
Album and Albums View Integration
resources/js/views/gallery-panels/Album.vue; resources/js/views/gallery-panels/Albums.vue
Wires folder-drop context into upload event handlers. Album.vue: computes album_parent_id (current album for nested drops) and album_existing_albums (sibling albums for matching), passes into useMouseEvents() alongside upload config, loads config on mount. Albums.vue: defines root_parent_id (null) and root_existing_albums computed from albumsStore.albums, passes into useMouseEvents(), clears albums on refresh, loads config before registering global paste/drag-drop listeners.
Timeline View Folder Drop Integration
resources/js/views/gallery-panels/Timeline.vue
Enables folder drag-and-drop handling on Timeline. Introduces timeline_parent_id and timeline_existing_albums refs, passes into updated useMouseEvents() invocation with upload config, loads upload configuration during setup to enable folder-drop detection when global event handlers initialize.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A folder drops from desktop to deep,
Nested albums in recursive heap,
No backend toil, the config's exposed,
Frontend composables compose and compose!
Feature 044 hops complete. 🥕

🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a950372f-0ecf-4690-ab18-5ba038bb4ed4

📥 Commits

Reviewing files that changed from the base of the PR and between 9edf3f6 and 0a6063b.

📒 Files selected for processing (4)
  • docs/specs/4-architecture/features/044-folder-drop-album-creation/plan.md
  • docs/specs/4-architecture/features/044-folder-drop-album-creation/spec.md
  • docs/specs/4-architecture/features/044-folder-drop-album-creation/tasks.md
  • docs/specs/4-architecture/roadmap.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/specs/4-architecture/open-questions.md (1)

3600-3602: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update and relocate the documentation timestamp footer.

The *Last updated: 2026-03-15* footer is stale for this June 2026 update and is not at the true bottom of the file (additional sections continue after it). Move the footer to the actual end and set the current update date.

Source: Coding guidelines

resources/js/components/modals/UploadPanel.vue (1)

33-37: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use a collision-safe key for UploadingLine entries.

Folder drops frequently contain repeated filenames across subfolders; :key="uploadable.file.name" can collide and cause row/component reuse bugs during upload processing.

Suggested fix
-						:key="uploadable.file.name"
+						:key="`${uploadable.album_id ?? albumId ?? 'unsorted'}:${uploadable.file.name}:${index}`"

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e70564f2-217b-4b5f-91cf-abb17c344da2

📥 Commits

Reviewing files that changed from the base of the PR and between 0a6063b and 55fc1d2.

📒 Files selected for processing (35)
  • app/Http/Resources/GalleryConfigs/UploadConfig.php
  • database/migrations/2026_06_13_000002_add_folder_upload_config.php
  • docs/specs/4-architecture/features/044-folder-drop-album-creation/plan.md
  • docs/specs/4-architecture/open-questions.md
  • lang/ar/all_settings.php
  • lang/bg/all_settings.php
  • lang/cz/all_settings.php
  • lang/de/all_settings.php
  • lang/el/all_settings.php
  • lang/en/all_settings.php
  • lang/es/all_settings.php
  • lang/fa/all_settings.php
  • lang/fr/all_settings.php
  • lang/hu/all_settings.php
  • lang/it/all_settings.php
  • lang/ja/all_settings.php
  • lang/nl/all_settings.php
  • lang/no/all_settings.php
  • lang/pl/all_settings.php
  • lang/pt/all_settings.php
  • lang/ru/all_settings.php
  • lang/sk/all_settings.php
  • lang/sv/all_settings.php
  • lang/tr/all_settings.php
  • lang/vi/all_settings.php
  • lang/zh_CN/all_settings.php
  • lang/zh_TW/all_settings.php
  • resources/js/components/modals/UploadPanel.vue
  • resources/js/composables/album/folderDrop.ts
  • resources/js/composables/album/uploadEvents.ts
  • resources/js/lychee.d.ts
  • resources/js/stores/ModalsState.ts
  • resources/js/views/gallery-panels/Album.vue
  • resources/js/views/gallery-panels/Albums.vue
  • resources/js/views/gallery-panels/Timeline.vue
✅ Files skipped from review due to trivial changes (5)
  • lang/pt/all_settings.php
  • lang/it/all_settings.php
  • docs/specs/4-architecture/features/044-folder-drop-album-creation/plan.md
  • lang/ja/all_settings.php
  • lang/ar/all_settings.php

Comment thread docs/specs/4-architecture/open-questions.md
Comment thread resources/js/composables/album/folderDrop.ts Outdated
Comment thread resources/js/composables/album/uploadEvents.ts
Comment thread resources/js/composables/album/uploadEvents.ts
Comment thread resources/js/stores/ModalsState.ts
Comment thread resources/js/views/gallery-panels/Album.vue
Comment thread resources/js/views/gallery-panels/Timeline.vue
@codecov

codecov Bot commented Jun 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.44%. Comparing base (7d541c9) to head (4e25e91).

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 64bb6a3e-4b51-4472-b425-31608206b0d7

📥 Commits

Reviewing files that changed from the base of the PR and between 55fc1d2 and b38783b.

📒 Files selected for processing (1)
  • app/Http/Resources/GalleryConfigs/UploadConfig.php

Comment thread app/Http/Resources/GalleryConfigs/UploadConfig.php

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
resources/js/composables/album/uploadEvents.ts (1)

48-49: ⚡ Quick win

Clarify comment to match implementation behavior.

The comment states "enabled by default; disabled only when explicitly set to false," but the code on lines 50-51 requires upload_config.value !== undefined AND folder_upload_enabled === true. This means the feature is disabled until the config loads and explicitly enables it, contradicting "enabled by default." Consider revising to: "Folder drop path: requires loaded config with folder_upload_enabled === true."


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ce0207a7-c82a-4c51-a19d-6eef466c859a

📥 Commits

Reviewing files that changed from the base of the PR and between cd0212b and 4e25e91.

📒 Files selected for processing (31)
  • database/migrations/2026_06_13_000002_add_folder_upload_config.php
  • lang/ar/all_settings.php
  • lang/bg/all_settings.php
  • lang/cz/all_settings.php
  • lang/de/all_settings.php
  • lang/el/all_settings.php
  • lang/en/all_settings.php
  • lang/es/all_settings.php
  • lang/fa/all_settings.php
  • lang/fr/all_settings.php
  • lang/hu/all_settings.php
  • lang/it/all_settings.php
  • lang/ja/all_settings.php
  • lang/nl/all_settings.php
  • lang/no/all_settings.php
  • lang/pl/all_settings.php
  • lang/pt/all_settings.php
  • lang/ru/all_settings.php
  • lang/sk/all_settings.php
  • lang/sv/all_settings.php
  • lang/tr/all_settings.php
  • lang/vi/all_settings.php
  • lang/zh_CN/all_settings.php
  • lang/zh_TW/all_settings.php
  • resources/js/components/forms/upload/UploadingLine.vue
  • resources/js/components/modals/UploadPanel.vue
  • resources/js/composables/album/folderDrop.ts
  • resources/js/composables/album/uploadEvents.ts
  • resources/js/lychee.d.ts
  • resources/js/stores/ModalsState.ts
  • resources/js/views/gallery-panels/Albums.vue
✅ Files skipped from review due to trivial changes (7)
  • lang/pt/all_settings.php
  • lang/hu/all_settings.php
  • lang/no/all_settings.php
  • lang/tr/all_settings.php
  • lang/fr/all_settings.php
  • lang/it/all_settings.php
  • lang/pl/all_settings.php
🚧 Files skipped from review as they are similar to previous changes (15)
  • lang/ru/all_settings.php
  • lang/nl/all_settings.php
  • resources/js/lychee.d.ts
  • lang/el/all_settings.php
  • lang/vi/all_settings.php
  • database/migrations/2026_06_13_000002_add_folder_upload_config.php
  • lang/ar/all_settings.php
  • lang/ja/all_settings.php
  • lang/sv/all_settings.php
  • lang/zh_CN/all_settings.php
  • lang/sk/all_settings.php
  • lang/en/all_settings.php
  • lang/de/all_settings.php
  • lang/zh_TW/all_settings.php
  • resources/js/composables/album/folderDrop.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement] Drag folder with images to upload

1 participant