Skip to content

feat(upload): add bulk folder upload preserving subfolder structure - #6166

Open
shadoskill wants to merge 2 commits into
secondlife:developfrom
shadoskill:upload-options
Open

feat(upload): add bulk folder upload preserving subfolder structure#6166
shadoskill wants to merge 2 commits into
secondlife:developfrom
shadoskill:upload-options

Conversation

@shadoskill

@shadoskill shadoskill commented Aug 20, 2026

Copy link
Copy Markdown

Description

This adds a new option to bulk upload a folder structure and allows a user to upload to a specific inventory folder without needing to change the default upload location every time.

Bulk folder upload from the Build > Upload menu will place the folder into the root "Inventory" folder.

Bulk folder uploading a GLTF material will instead of placing the Textures and Material into the system folders create new Material and Texture folders in the same folder as the GLTF/GLB file its self.


Checklist

Please ensure the following before requesting review:

  • I have provided a clear title and detailed description for this pull request.
  • If useful, I have included media such as screenshots and video to show off my changes.
  • The PR is linked to a relevant issue with sufficient context.
  • I have tested the changes locally and verified they work as intended.
  • All new and existing tests pass.
  • Code follows the project's style guidelines.
  • Documentation has been updated if needed.
  • Any dependent changes have been merged and published in downstream modules
  • I have reviewed the contributing guidelines.

secondlife-bin_sewmrkqwU5_10mb.mp4

Recurse a local folder into inventory, mirroring the directory hierarchy.
Regular files and GLTF assets upload per subfolder.
New inventory folder options in viewer and inventory menus.

Copilot AI 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.

Pull request overview

Adds a new “Bulk > Folder…” upload flow that preserves local subfolder structure when uploading into inventory, including special handling for GLTF/GLB material uploads so generated Materials/Textures folders are created alongside the model rather than using system folders.

Changes:

  • Replaces the single “Bulk…” upload menu item with a “Bulk” submenu containing “Files…” and new “Folder…” actions.
  • Implements recursive folder scanning + inventory folder creation, and routes folder uploads through the existing bulk upload confirmation floater.
  • Extends material upload plumbing to support a separate texture destination folder for GLTF material uploads.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
indra/newview/skins/default/xui/en/menu_viewer.xml Adds “Bulk” submenu and new “Folder…” entry in the main Upload menu.
indra/newview/skins/default/xui/en/menu_inventory.xml Adds “Bulk” submenu and new “Folder…” entry for inventory-context upload location.
indra/newview/llviewermenufile.h Extends bulk upload API and declares new folder-upload entry points.
indra/newview/llviewermenufile.cpp Implements folder scan + recursive upload, and GLTF upload-to-subfolders behavior.
indra/newview/llmaterialeditor.h Extends upload API and adds a texture-destination member.
indra/newview/llmaterialeditor.cpp Wires texture destination through material uploads so textures can land outside system folders.
indra/newview/llinventoryfunctions.cpp Adds inventory action handler for “upload_bulk_folder”.
indra/newview/llfloaterbulkupload.h Stores local folder path for folder-upload confirmation flow.
indra/newview/llfloaterbulkupload.cpp Starts recursive folder upload when the bulk floater represents a folder upload.
indra/newview/lldirpicker.cpp Implements modeless directory picking on Darwin and enables modeless picker thread path.
Suppressed comments (1)

indra/newview/llviewermenufile.cpp:1554

  • upload_folder_recursive_impl() also calls is_regular_file(it->status()) / is_directory(it->status()) without using an error_code overload. This can throw on filesystem errors (permissions, broken links), crashing during the actual upload traversal. Use error_code-based status/symlink_status and handle failures by skipping entries.
    for (bfs::directory_iterator it(local_dir, ec), end; !ec && it != end; ++it)
    {
        if (bfs::is_regular_file(it->status()))
        {
            std::string path_str = it->path().string();
            std::string ext = gDirUtilp->getExtension(path_str);
            if (ext == "gltf" || ext == "glb")
                gltf_files.push_back(path_str);
            else
                regular_files.push_back(path_str);
        }
        else if (bfs::is_directory(it->status()))
            subdirs.emplace_back(it->path().string(), it->path().filename().string());
    }

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread indra/newview/lldirpicker.cpp Outdated
Comment on lines +316 to +327
struct Bridge {
void (*cb)(bool, std::string&, void*);
void* ud;
};
Bridge* bridge = new Bridge{callback, userdata};
auto vectorCb = [](bool success, std::vector<std::string>& files, void* data) {
Bridge* b = static_cast<Bridge*>(data);
std::string path = (!files.empty()) ? files[0] : std::string();
b->cb(success && !path.empty(), path, b->ud);
delete b;
};
return mFilePicker->getOpenFileModeless(LLFilePicker::FFLOAD_DIRECTORY, vectorCb, bridge);
Comment on lines +1499 to +1505
for (bfs::directory_iterator it(local_dir, ec), end; !ec && it != end; ++it)
{
if (bfs::is_regular_file(it->status()))
files.push_back(it->path().string());
else if (bfs::is_directory(it->status()))
collect_files_recursive(it->path().string(), files);
}
On macOS, if the directory picker fails to open, the Bridge adapter
object was allocated but never freed. Now deleted on failure.

In folder scanning, calling status() on a directory entry without an
error code can throw if a file is unreadable.
Both recursive scan functions now use the error_code overload
and skip problem entries instead of crashing.

Copilot AI 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.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Suppressed comments (2)

indra/newview/skins/default/xui/en/menu_viewer.xml:1801

  • The Upload.CalculateCosts parameter still targets menu name "Bulk Upload" (used by LLUploadCostCalculator -> gMenuHolder->childSetLabelArg), but this menu item is now named "Bulk Upload Files". Update the parameter (and/or the item's name) so the cost calculator isn't looking up a non-existent child control.
                <menu_item_call.on_visible
                 function="Upload.CalculateCosts"
                 parameter="Bulk Upload,texture" />
                <menu_item_call.on_click
                 function="File.UploadBulk"

indra/newview/skins/default/xui/en/menu_inventory.xml:1065

  • The Upload.CalculateCosts parameter is still "Bulk Upload,texture", but the relevant menu item is now named "Bulk Upload Files". LLUploadCostCalculator uses this string for gMenuHolder->childSetLabelArg lookup, so the name/parameter mismatch should be resolved.
        <menu_item_call.on_visible
         function="Upload.CalculateCosts"
         parameter="Bulk Upload,texture" />
      </menu_item_call>

Comment on lines +1789 to +1792
<menu
label="Bulk"
layout="topleft"
name="Bulk Upload">
name="Bulk Upload &gt;">
Comment on lines +1051 to +1054
<menu
label="Bulk"
layout="topleft"
name="Bulk Upload">
<menu_item_call.on_click
function="Inventory.FileUploadLocation"
parameter="upload_bulk" />
<menu_item_call.on_visible
function="Upload.CalculateCosts"
parameter="Bulk Upload,texture" />
</menu_item_call>
name="Bulk Upload &gt;">
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants