Skip to content

Commit 0714919

Browse files
committed
Improved file uploader, added attributes to Input component
1 parent 166ed67 commit 0714919

File tree

9 files changed

+157
-65
lines changed

9 files changed

+157
-65
lines changed

src/Blazor.AdminLte.Site/FilesController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public FilesController()
1616

1717

1818
[HttpPost("UploadFileChunk")]
19-
public Task<bool> UploadFileChunk([FromBody] ChunkedDataRequestDto chunkedDataRequestDto)
19+
public Task<bool> UploadFileChunkAsync([FromBody] ChunkedDataRequestDto chunkedDataRequestDto)
2020
{
2121
try
2222
{
@@ -46,7 +46,7 @@ public Task<bool> UploadFileChunk([FromBody] ChunkedDataRequestDto chunkedDataRe
4646

4747

4848
[HttpGet("GetFiles")]
49-
public Task<List<string>> GetFileNames()
49+
public Task<List<string>> GetFileNamesAsync()
5050
{
5151
var result = new List<string>();
5252
var files = Directory.GetFiles(Environment.CurrentDirectory + "\\StaticFiles", "*.*");

src/Blazor.AdminLte.Wasm/WasmFilesManager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public WasmFilesManager(HttpClient http)
1616
} //FilesManager
1717

1818

19-
public async Task<bool> UploadFileChunk(ChunkedDataRequestDto fileChunkDto)
19+
public async Task<bool> UploadFileChunkAsync(ChunkedDataRequestDto fileChunkDto)
2020
{
2121
try
2222
{
@@ -32,7 +32,7 @@ public async Task<bool> UploadFileChunk(ChunkedDataRequestDto fileChunkDto)
3232
} //UploadFileChunk
3333

3434

35-
public async Task<List<string>> GetFileNames()
35+
public async Task<List<string>> GetFileNamesAsync()
3636
{
3737
try
3838
{
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
namespace Blazor.AdminLte
1+
using System;
2+
3+
namespace Blazor.AdminLte
24
{
35
public class ChunkedDataRequestDto
46
{
57
public string FileName { get; set; } = "";
68
public long Offset { get; set; }
7-
public byte[]? Data { get; set; }
9+
public byte[] Data { get; set; }
810
public bool FirstChunk = false;
11+
public Guid Uid { get; set; }
912
}
1013
}

src/Blazor.AdminLte/Files/FileUploader.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</div>
2424
</div>
2525

26-
@if (filesQueue.Count > 0) {
26+
@if (_filesQueue.Count > 0) {
2727
<div class="card mb-4">
2828
<div class="card-header">Upload queue</div>
2929
<div class="card-body">
@@ -39,7 +39,7 @@
3939
</tr>
4040
</thead>
4141
<tbody>
42-
@foreach (var file in filesQueue.OrderByDescending(x => x.FileId))
42+
@foreach (var file in _filesQueue.OrderByDescending(x => x.FileId))
4343
{
4444
var size = Math.Round((file.Size / 1024.00));
4545
var percentage = Math.Round(file.UploadedPercentage);

src/Blazor.AdminLte/Files/FileUploader.razor.cs

Lines changed: 106 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,62 +10,120 @@ namespace Blazor.AdminLte
1010
{
1111
public partial class FileUploader
1212
{
13-
[Inject] IFilesManager? FilesManager { get; set; }
13+
[Inject]
14+
private IFilesManager FilesManager { get; set; }
15+
1416
private bool isUploading = false;
1517
private string ErrorMessage = string.Empty;
1618
private string dropClass = string.Empty;
17-
private int maxAllowedFiles = 25;
18-
List<FileUploadProgress> filesQueue = new();
19-
19+
private List<FileUploadProgress> _filesQueue = new();
20+
21+
[Parameter]
22+
public EventCallback<UploadResultDto> OnUploadFinished { get; set; }
23+
24+
[Parameter]
25+
public int MaxAllowedFiles { get; set; } = 25;
26+
27+
[Parameter]
28+
public long? MaximumFileSizeInBytes { get; set; }
29+
30+
/// <summary>
31+
/// Allowed extensions to upload. Must be specified with dot
32+
/// </summary>
33+
/// <example>
34+
/// .json
35+
/// </example>
36+
[Parameter]
37+
public string[] AllowedExtensions { get; set; }
2038

2139
private void AddFilesToQueue(InputFileChangeEventArgs e)
2240
{
2341
dropClass = string.Empty;
2442
ErrorMessage = string.Empty;
2543

26-
if (e.FileCount > maxAllowedFiles)
44+
if (e.FileCount > MaxAllowedFiles)
45+
{
46+
ErrorMessage = $"A maximum of {MaxAllowedFiles} is allowed, you have selected {e.FileCount} files!";
47+
return;
48+
}
49+
50+
if (_filesQueue.Count > MaxAllowedFiles)
2751
{
28-
ErrorMessage = $"A maximum of {maxAllowedFiles} is allowed, you have selected {e.FileCount} files!";
52+
ErrorMessage = $"Queue already contains maximum number of items ({MaxAllowedFiles})! Clear the queue to continue.";
53+
return;
2954
}
30-
else
55+
56+
var files = e.GetMultipleFiles(MaxAllowedFiles);
57+
var fileCount = _filesQueue.Count;
58+
59+
// Validate allowed extensions
60+
if (AllowedExtensions?.Any() == true)
3161
{
32-
var files = e.GetMultipleFiles(maxAllowedFiles);
33-
var fileCount = filesQueue.Count;
62+
var filesValid =
63+
files.All(x => AllowedExtensions.Any(
64+
ext => string.Equals(ext, Path.GetExtension(x.Name), StringComparison.InvariantCultureIgnoreCase)));
3465

35-
foreach (var file in files)
66+
if (!filesValid)
3667
{
37-
var progress = new FileUploadProgress(file, file.Name, file.Size, fileCount);
38-
filesQueue.Add(progress);
39-
fileCount++;
68+
ErrorMessage = $"Uploaded file(s) has invalid extension. Allowed extensions: {string.Join(", ", AllowedExtensions)}.";
69+
return;
4070
}
4171
}
42-
} //PlaceFilesInQue
4372

73+
if (MaximumFileSizeInBytes.HasValue &&
74+
files.Any(x => x.Size > MaximumFileSizeInBytes))
75+
{
76+
ErrorMessage = $"Reached maximum file size! Please select file(s) smaller than {ToReadableUnits()}";
77+
return;
78+
}
79+
80+
foreach (var file in files)
81+
{
82+
var progress = new FileUploadProgress(file, file.Name, file.Size, fileCount);
83+
_filesQueue.Add(progress);
84+
fileCount++;
85+
}
86+
}
87+
88+
private string ToReadableUnits()
89+
{
90+
var kb = Math.Round(MaximumFileSizeInBytes.Value / 1024.00);
91+
92+
// TODO: Convert to MB if too big
93+
return $"{kb} kB";
94+
}
4495

4596
private async Task UploadFileQueue()
4697
{
4798
isUploading = true;
4899
await InvokeAsync(StateHasChanged);
49100

50-
foreach (var file in filesQueue.OrderByDescending(x => x.FileId))
101+
foreach (var file in _filesQueue.OrderByDescending(x => x.FileId))
51102
{
52103
if (!file.HasBeenUploaded)
53104
{
54105
await UploadChunks(file);
55106
file.HasBeenUploaded = true;
107+
if (OnUploadFinished.HasDelegate)
108+
{
109+
await OnUploadFinished.InvokeAsync(new UploadResultDto
110+
{
111+
FileName = file.FileName,
112+
Uid = file.Uid
113+
});
114+
}
56115
}
57116
}
58117

59118
isUploading = false;
60-
} //UploadFileQueue
61-
119+
}
62120

63121
private async Task UploadChunks(FileUploadProgress file)
64122
{
65-
var TotalBytes = file.Size;
123+
var totalBytes = file.Size;
66124
long chunkSize = 400000;
67-
long numChunks = TotalBytes / chunkSize;
68-
long remainder = TotalBytes % chunkSize;
125+
long numChunks = totalBytes / chunkSize;
126+
long remainder = totalBytes % chunkSize;
69127

70128
string nameOnly = Path.GetFileNameWithoutExtension(file.FileName);
71129
var extension = Path.GetExtension(file.FileName);
@@ -83,15 +141,16 @@ private async Task UploadChunks(FileUploadProgress file)
83141
{
84142
Data = buffer,
85143
FileName = newFileNameWithoutPath,
86-
Offset = filesQueue[file.FileId].UploadedBytes,
87-
FirstChunk = firstChunk
144+
Offset = _filesQueue[file.FileId].UploadedBytes,
145+
FirstChunk = firstChunk,
146+
Uid = file.Uid
88147
};
89148

90-
await FilesManager.UploadFileChunk(chunk);
149+
await FilesManager.UploadFileChunkAsync(chunk);
91150
firstChunk = false;
92151

93152
// Update our progress data and UI
94-
filesQueue[file.FileId].UploadedBytes += chunkSize;
153+
_filesQueue[file.FileId].UploadedBytes += chunkSize;
95154
await InvokeAsync(StateHasChanged);
96155
}
97156

@@ -104,53 +163,53 @@ private async Task UploadChunks(FileUploadProgress file)
104163
{
105164
Data = buffer,
106165
FileName = newFileNameWithoutPath,
107-
Offset = filesQueue[file.FileId].UploadedBytes,
108-
FirstChunk = firstChunk
166+
Offset = _filesQueue[file.FileId].UploadedBytes,
167+
FirstChunk = firstChunk,
168+
Uid = file.Uid
109169
};
110-
await FilesManager.UploadFileChunk(chunk);
170+
171+
await FilesManager.UploadFileChunkAsync(chunk);
111172

112173
// Update our progress data and UI
113-
filesQueue[file.FileId].UploadedBytes += remainder;
114-
//await ListFiles();
174+
_filesQueue[file.FileId].UploadedBytes += remainder;
115175
await InvokeAsync(StateHasChanged);
116176
}
117177
}
118-
} //UploadChunks
119-
178+
}
120179

121180
private void RemoveFromQueue(int fileId)
122181
{
123-
var itemToRemove = filesQueue.SingleOrDefault(x => x.FileId == fileId);
182+
var itemToRemove = _filesQueue.SingleOrDefault(x => x.FileId == fileId);
124183
if (itemToRemove != null)
125-
filesQueue.Remove(itemToRemove);
126-
} //RemoveFromQueue
127-
184+
{
185+
_filesQueue.Remove(itemToRemove);
186+
}
187+
}
128188

129-
private void ClearFileQueue()
189+
public void ClearFileQueue()
130190
{
131-
filesQueue.Clear();
132-
} //ClearFileQueue
133-
191+
_filesQueue.Clear();
192+
}
134193

135-
record FileUploadProgress(IBrowserFile File, string FileName, long Size, int FileId)
194+
public record FileUploadProgress(IBrowserFile File, string FileName, long Size, int FileId)
136195
{
137196
public IBrowserFile FileData { get; set; } = File;
138197
public int FileId { get; set; } = FileId;
139198
public long UploadedBytes { get; set; }
140199
public double UploadedPercentage => (double)UploadedBytes / (double)Size * 100d;
141200
public bool HasBeenUploaded { get; set; } = false;
142-
} //FileUploadProgress
143-
201+
public Guid Uid { get; set; } = Guid.NewGuid();
202+
}
144203

145-
void HandleDragEnter()
204+
private void HandleDragEnter()
146205
{
147206
dropClass = "dropzone-active";
148-
} //HandleDragEnter
149-
void HandleDragLeave()
207+
}
208+
209+
private void HandleDragLeave()
150210
{
151211
dropClass = string.Empty;
152-
} //HandleDragLeave
153-
212+
}
154213

155214
/*
156215
protected override async Task OnInitializedAsync()
@@ -164,8 +223,5 @@ private async Task ListFiles()
164223
await InvokeAsync(StateHasChanged);
165224
}
166225
*/
167-
168-
169-
170226
}
171227
}
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-

2-
3-
using System.Collections.Generic;
1+
using System.Collections.Generic;
42
using System.Threading.Tasks;
53

64
namespace Blazor.AdminLte
75
{
86
public interface IFilesManager
97
{
10-
Task<bool> UploadFileChunk(ChunkedDataRequestDto fileChunkDto);
11-
Task<List<string>> GetFileNames();
8+
Task<bool> UploadFileChunkAsync(ChunkedDataRequestDto fileChunkDto);
9+
Task<List<string>> GetFileNamesAsync();
1210
}
1311
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace Blazor.AdminLte
4+
{
5+
public class UploadResultDto
6+
{
7+
public Guid Uid { get; set; }
8+
public string FileName { get; set; } = "";
9+
}
10+
}

src/Blazor.AdminLte/Forms/Input.razor

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,15 @@
33
{
44
<label for="@Value.Identifier">@((MarkupString)Value.Label)</label>
55
}
6+
67
<div class="input-group mb-3">
7-
<input class="form-control @borderColor" id="@Value.Identifier" placeholder="@Value.Placeholder" value="@Value.Value" @onchange="DoChange" type="@Value.Type">
8+
<input class="form-control @borderColor"
9+
id="@Value.Identifier"
10+
placeholder="@Value.Placeholder"
11+
value="@Value.Value"
12+
@onchange="DoChange"
13+
type="@Value.Type"
14+
@attributes="@GetAttributes()">
815

916
@if (!string.IsNullOrEmpty(Value.Icon)) {
1017
<div class="input-group-append">

0 commit comments

Comments
 (0)