Skip to content

feat: Add Yes/No to all for batch asset import#3052

Open
Acissathar wants to merge 3 commits intostride3d:masterfrom
Acissathar:feat-Add-Yes-and-No-to-All-For-Import
Open

feat: Add Yes/No to all for batch asset import#3052
Acissathar wants to merge 3 commits intostride3d:masterfrom
Acissathar:feat-Add-Yes-and-No-to-All-For-Import

Conversation

@Acissathar
Copy link
Contributor

PR Details

This change modifies the asset import to help with the flow of importing more than one item at a time. Importing multiple assets into Stride can be a bit of a pain, especially coming from Unity where drag and drop handles asset source copying for you.

While Stride does support multiple asset imports, it can very quickly add up as you're prompted with a dialogue box to copy the object to resources for every single asset, an additional one for the location (if choosing yes), and lastly, one more potential box if it already exists in that location.

Depending on the number of assets, this can quickly become a hassle to have to click 3+ times per asset just to get them imported.

The intent of this is to allow a user to pick once and handle it for all assets, or individually if still desired.

When picking a different location to copy the resources to, this makes the assumption (if you hit yes to all) that you want everything copied to that location. Otherwise, hitting Yes will prompt per asset as it currently does.

Related Issue

#2916

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My change requires a change to the documentation.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have built and run the editor to try this change out.

There is currently a failure around BuildResult and an assembly reference in SampleTestFixture, but since this is mentioned in another PR, I don't believe its related to these changes.

@Acissathar
Copy link
Contributor Author

Acissathar commented Feb 4, 2026

Marked as a draft as I have a fair bit of test cases I want to run through locally before saying its ready, but I likely won't get to them until later this week/weekend so wanted to throw it up incase anyone had thoughts / nitpicks.

Test cases I plan to run through (think this covers all scenarios)

Single File Import

  • Single File Yes - Clicking Yes on a single file copies it to resources and creates the asset.
  • Single File No - Clicking No on a single file skips it without copying, but still creates an asset.
  • Single File In Resources - File already in resources skips the copy dialog and creates the asset directly.

Multiple Files - Basic Flow

  • Multiple Yes to All - Clicking "Yes to all" on the first file copies all remaining files to the same directory without additional prompts.
  • Multiple No to All - Clicking "No to all" on the first file aborts the entire import process immediately.
  • Multiple Yes Each - Clicking Yes individually for each file prompts for directory selection for each file separately.
  • Multiple Mixed Yes/No - Mixing Yes and No responses copies only the files where Yes was selected, skipping others.
  • Multiple Yes Then Yes to All - Clicking "Yes to all" after some individual Yes responses copies remaining files to the same directory without further prompts.
  • Multiple Dialog Close - Closing the dialog with X button skips the current file and continues prompting for remaining files.

Mixed File Locations

  • Mixed Yes to All - Files already in resources are imported directly while outside files prompt once with "Yes to all" copying all to same directory.
  • Mixed Sequential - Only files outside resources prompt for copy dialog while in-resource files import silently.
    Overwrite Scenarios
  • Single Overwrite Yes - Overwriting a single existing file shows both copy and overwrite dialogs with Yes/No only.
  • Multiple Overwrite Yes to All - "Yes to all" on copy and overwrite dialogs overwrites all files with two total prompts.
  • Multiple Overwrite No - Clicking No on any overwrite dialog aborts the entire import and returns gracefully.
  • Multiple Overwrite Mixed - Clicking "Yes to all" on overwrite after individual confirmations overwrites remaining files automatically.

Edge Cases

  • Directory Picker Cancel - Canceling the directory picker uses the default resource folder location.
  • Large File Count - Importing 10+ files with "Yes to all" completes efficiently in a single prompt.

Button Index Verification

  • Button Mapping Validation - All buttons (0=Close, 1=Yes, 2=No, 3=Yes to all, 4=No to all) trigger their corresponding actions correctly.

@Acissathar
Copy link
Contributor Author

Ran through all my test cases and everything seems to work as expected and consistent with previous behavior where applicable, should be ready!

@Acissathar Acissathar marked this pull request as ready for review February 6, 2026 15:25
}
else
{
// If "Yes to all" we're going to assume they want to use the same directory as the initial file.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a valid assumption? It sounds like it would flatten any hierarchy during the copy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I might be misunderstanding, but I believe this assumption is valid as this is consistent with the current behavior. If you select No to the default location, and specify a directory in the window that pops up, it puts it right where you tell it to without sub folder generation vs saying Yes to the default, which puts it in Resources/subfolder

Comment on lines +592 to +615
IReadOnlyList<DialogButtonInfo> copyPromptButtons = DialogHelper.CreateButtons(files is not null && files.Count > 1 ?
[
Tr._p("Button", "Yes"),
Tr._p("Button", "No"),
Tr._p("Button", "Yes to all"),
Tr._p("Button", "No to all")
]
:
[
Tr._p("Button", "Yes"),
Tr._p("Button", "No")
], 1, 2);

IReadOnlyList<DialogButtonInfo> overwritePromptButtons = DialogHelper.CreateButtons(files is not null && files.Count > 1 ?
[
Tr._p("Button", "Yes"),
Tr._p("Button", "No"),
Tr._p("Button", "Yes to all")
]
:
[
Tr._p("Button", "Yes"),
Tr._p("Button", "No")
], 1, 2);
Copy link
Contributor

Choose a reason for hiding this comment

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

This would produce mildly undesirable behavior when the user reaches the last file, by including the "to all" buttons.

…collection

Also some minor grammar/formatting
var message = Tr._p("Message", "Source file '{0}' is not inside of your project's resource folders, do you want to copy it?").ToFormat(file.FullPath);

var message = Tr._p("Message", "Source file '{0}' is not inside of your project's resource folders, do you want to copy it?").ToFormat(file.FullPath);
var copyResult = await Dialogs.MessageBoxAsync(message, files.Count > 1 && i != files.Count - 1 ? copyPromptWithToAllButtons : dialogDefaultButtons, MessageBoxImage.Warning);
Copy link
Contributor

Choose a reason for hiding this comment

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

Checking i != files.Count - 1 makes checking files.Count > 1 unnecessary.

var message = Tr._p("Message", "The file '{0}' already exists, it will get overwritten if you continue, do you really want to proceed?").ToFormat(finalPath);

copyResult = await Dialogs.MessageBoxAsync(message, MessageBoxButton.YesNo, MessageBoxImage.Warning);
var copyResult = await Dialogs.MessageBoxAsync(message, files.Count > 1 && i != files.Count - 1 ? overwritePromptWithToAllButtons : dialogDefaultButtons, MessageBoxImage.Warning);
Copy link
Contributor

Choose a reason for hiding this comment

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

Checking i != files.Count - 1 makes checking files.Count > 1 unnecessary.

else
{
// If "Yes to all" we're going to assume they want to use the same directory as the initial file.
finalPath = Path.Combine(Path.GetDirectoryName(finalPath), file.GetFileName());
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
finalPath = Path.Combine(Path.GetDirectoryName(finalPath), file.GetFileName());
finalPath = Path.Join(Path.GetDirectoryName(finalPath), file.GetFileName());

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not opposed to the change personally, my only hang up is that the rest of Stride uses Path.Combine. I could not find any uses of Path.Join in the code base, so I'm hesitant to deviate from that consistency.

Copy link
Contributor

Choose a reason for hiding this comment

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

Path.Join is newer, faster, and likely exhibits behavior closer to coder intentions. The primary difference between the two is:

  • Path.Join is essentially concatenation.
  • Path.Combine checks if later parameters are rooted and excludes earlier parameters if they are.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants