198 lines
6.5 KiB
Plaintext
198 lines
6.5 KiB
Plaintext
@using Microsoft.Extensions.Options
|
|
|
|
<style>
|
|
.file-upload-input {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
z-index: 10;
|
|
opacity: 0;
|
|
}
|
|
</style>
|
|
|
|
<MudStack Style="width: 100%">
|
|
<MudFileUpload T="IReadOnlyList<IBrowserFile>"
|
|
@ref="@_fileUpload"
|
|
OnFilesChanged="OnInputFileChanged"
|
|
AppendMultipleFiles=true
|
|
MaximumFileCount="_options.Value.MaxFileCount"
|
|
Hidden="@false"
|
|
InputClass="file-upload-input"
|
|
tabindex="-1"
|
|
@ondrop="@ClearDragClass"
|
|
@ondragenter="@SetDragClass"
|
|
@ondragleave="@ClearDragClass"
|
|
@ondragend="@ClearDragClass">
|
|
<ActivatorContent>
|
|
<MudPaper Outlined="true"
|
|
Class="@_dragClass"
|
|
Style="height: 150px; display: flex; flex-direction: column; position: relative;">
|
|
|
|
<div class="d-flex align-center justify-center pa-4" style="flex-shrink: 0;">
|
|
<MudText Typo="Typo.h6">
|
|
Drag and drop files here or click
|
|
</MudText>
|
|
</div>
|
|
|
|
</MudPaper>
|
|
</ActivatorContent>
|
|
</MudFileUpload>
|
|
@if (Files.Any())
|
|
{
|
|
<MudPaper Style="max-height: 150px; overflow-y: auto;" Outlined="true" Class="pa-4">
|
|
@foreach (var file in Files)
|
|
{
|
|
var color = _fileToDiskFileName.Keys.Contains(file) ? Color.Success : Color.Warning;
|
|
<MudChip T="string"
|
|
Color="@color"
|
|
Text="@file.Name"
|
|
tabindex="-1" />
|
|
}
|
|
</MudPaper>
|
|
}
|
|
|
|
<MudToolBar Gutters="@false"
|
|
Class="relative d-flex justify-end gap-4">
|
|
<MudButton Color="Color.Primary"
|
|
OnClick="@OpenFilePickerAsync"
|
|
Variant="Variant.Filled">
|
|
Open file picker
|
|
</MudButton>
|
|
<MudButton Color="Color.Primary"
|
|
Disabled="@(!Files.Any())"
|
|
OnClick="@Upload"
|
|
Variant="Variant.Filled">
|
|
Upload
|
|
</MudButton>
|
|
<MudButton Color="Color.Error"
|
|
Disabled="@(!Files.Any())"
|
|
OnClick="@ClearAsync"
|
|
Variant="Variant.Filled">
|
|
Clear
|
|
</MudButton>
|
|
</MudToolBar>
|
|
|
|
@if (Files.Count != _fileToDiskFileName.Count)
|
|
{
|
|
<MudText Color="Color.Error" Align="Align.Right">*Files must be uploaded</MudText>
|
|
}
|
|
</MudStack>
|
|
|
|
@inject IOptions<FileUploadOptions> _options;
|
|
@inject IFilePathListingProvider PathProvider;
|
|
@inject ISnackbar Snackbar;
|
|
@inject ILogger<UploadDropBox> _logger;
|
|
|
|
@code {
|
|
private const string DefaultDragClass = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full";
|
|
|
|
private string _dragClass = DefaultDragClass;
|
|
|
|
public readonly List<IBrowserFile> Files = new();
|
|
|
|
private readonly Dictionary<IBrowserFile, string> _fileToDiskFileName = new();
|
|
|
|
private MudFileUpload<IReadOnlyList<IBrowserFile>>? _fileUpload;
|
|
|
|
public int SelectedFileCount { get => Files.Count; }
|
|
|
|
public bool UploadsComplete { get; set; } = true;
|
|
|
|
[Parameter]
|
|
public EventCallback<List<FilePathListing>> FilesUploaded {get; set; }
|
|
|
|
[Parameter]
|
|
public EventCallback ClearClicked { get; set; }
|
|
|
|
private async Task ClearAsync()
|
|
{
|
|
foreach (var pair in _fileToDiskFileName)
|
|
{
|
|
try
|
|
{
|
|
FileInfo targetFile = new(pair.Value);
|
|
if (targetFile.Exists)
|
|
{
|
|
targetFile.Delete();
|
|
}
|
|
await PathProvider.DeleteFilePathListingAsync(pair.Key.Name, pair.Value);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error deleting file {FileName}", pair.Key.Name);
|
|
Snackbar.Add($"Error cleaning up file: {pair.Key.Name}", Severity.Warning);
|
|
}
|
|
}
|
|
|
|
_fileToDiskFileName.Clear();
|
|
Files.Clear();
|
|
await (_fileUpload?.ClearAsync() ?? Task.CompletedTask);
|
|
|
|
ClearDragClass();
|
|
UploadsComplete = true;
|
|
await ClearClicked.InvokeAsync();
|
|
}
|
|
|
|
private Task OpenFilePickerAsync()
|
|
=> _fileUpload?.OpenFilePickerAsync() ?? Task.CompletedTask;
|
|
|
|
private void OnInputFileChanged(InputFileChangeEventArgs e)
|
|
{
|
|
ClearDragClass();
|
|
var files = e.GetMultipleFiles(maximumFileCount: _options.Value.MaxFileCount);
|
|
Files.AddRange(files);
|
|
|
|
UploadsComplete = false;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task Upload()
|
|
{
|
|
if (!Files.Any())
|
|
{
|
|
Snackbar.Add("No files to upload.", Severity.Warning);
|
|
return;
|
|
}
|
|
|
|
Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopCenter;
|
|
|
|
List<FilePathListing> fileListings = [];
|
|
foreach (var file in Files)
|
|
{
|
|
if (_fileToDiskFileName.ContainsKey(file)) continue;
|
|
try
|
|
{
|
|
var diskFileName = $"{Guid.NewGuid()}{Path.GetExtension(file.Name)}";
|
|
var destinationPath = Path.Combine(_options.Value.UploadFolderPath, diskFileName);
|
|
|
|
await using var browserUploadStream = file.OpenReadStream(maxAllowedSize: _options.Value.MaxUploadSizeBytes);
|
|
await using var outFileStream = new FileStream(destinationPath, FileMode.Create);
|
|
|
|
await browserUploadStream.CopyToAsync(outFileStream);
|
|
|
|
_fileToDiskFileName.Add(file, destinationPath);
|
|
|
|
var fileListing = new FilePathListing() { Path = destinationPath, OriginalName = Path.GetFileName(file.Name) };
|
|
fileListings.Add(fileListing);
|
|
await PathProvider.CreateFilePathListingAsync(fileListing);
|
|
|
|
Snackbar.Add($"Uploaded {file.Name}", Severity.Success);
|
|
|
|
UploadsComplete = true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Snackbar.Add($"Error uploading file {file.Name}: {ex.Message}", Severity.Error);
|
|
}
|
|
}
|
|
|
|
await FilesUploaded.InvokeAsync(fileListings);
|
|
}
|
|
|
|
private void SetDragClass()
|
|
=> _dragClass = $"{DefaultDragClass} mud-border-primary";
|
|
|
|
private void ClearDragClass()
|
|
=> _dragClass = DefaultDragClass;
|
|
} |