WIP file manager

dhcp-server
Pat Hartl 2023-09-09 17:36:20 -05:00
parent 329c147419
commit 235d50a73a
6 changed files with 317 additions and 0 deletions

View File

@ -0,0 +1,224 @@
@using AntDesign.TableModels;
<GridRow>
<Space>
<SpaceItem>
<Button Type="@ButtonType.Text" Icon="@IconType.Outline.ArrowLeft" OnClick="NavigateBack" />
</SpaceItem>
<SpaceItem>
<Button Type="@ButtonType.Text" Icon="@IconType.Outline.ArrowRight" OnClick="NavigateForward" />
</SpaceItem>
<SpaceItem>
<Button Type="@ButtonType.Text" Icon="@IconType.Outline.ArrowUp" OnClick="NavigateUp" Disabled="@(Path.Parent == null)" />
</SpaceItem>
<SpaceItem>
<Button Type="@ButtonType.Text" Icon="@IconType.Outline.Reload" OnClick="() => ChangeDirectory(Path, false)" />
</SpaceItem>
<SpaceItem>
<Breadcrumb>
@foreach (var breadcrumb in Breadcrumbs)
{
<BreadcrumbItem OnClick="() => ChangeDirectory(breadcrumb, false)">@breadcrumb.Name</BreadcrumbItem>
}
</Breadcrumb>
</SpaceItem>
</Space>
</GridRow>
<GridRow>
<GridCol Span="6" Class="file-manager-tree">
<Tree TItem="FileManagerDirectory"
DataSource="Directories"
TitleExpression="x => x.DataItem.Name"
ChildrenExpression="x => x.DataItem.Children"
IsLeafExpression="x => !x.DataItem.HasChildren"
OnClick="(args) => ChangeDirectory(args.Node.DataItem, false)"
OnNodeLoadDelayAsync="ExpandTree" />
</GridCol>
<GridCol Span="18" Class="file-manager-list">
<Table
TItem="IFileManagerEntry"
DataSource="Entries"
HidePagination="true"
Loading="Entries == null"
OnRow="OnRow">
<Column TData="string" Width="32">
<Text></Text>
</Column>
<PropertyColumn Property="e => e.Path" Sortable Title="Name">
@GetEntryName(context)
</PropertyColumn>
<PropertyColumn Property="e => e.Length" Sortable Title="Size">
@ByteSizeLib.ByteSize.FromBytes(context.Length)
</PropertyColumn>
<PropertyColumn Property="e => e.ModifiedOn" Format="MM/dd/yyyy hh:mm tt" Sortable Title="Modified" />
</Table>
</GridCol>
</GridRow>
@code {
[Parameter] public Guid ArchiveId { get; set; }
[Parameter] public string WorkingDirectory { get; set; }
FileManagerDirectory Path { get; set; }
List<FileManagerDirectory> Past { get; set; } = new List<FileManagerDirectory>();
List<FileManagerDirectory> Future { get; set; } = new List<FileManagerDirectory>();
List<FileManagerDirectory> Breadcrumbs = new List<FileManagerDirectory>();
List<IFileManagerEntry> Entries { get; set; } = new List<IFileManagerEntry>();
HashSet<FileManagerDirectory> Directories { get; set; } = new HashSet<FileManagerDirectory>();
Dictionary<string, object> OnRow(RowData<IFileManagerEntry> row) => new()
{
["data-path"] = row.Data.Path,
["ondblclick"] = ((System.Action)delegate
{
if (row.Data is FileManagerDirectory)
ChangeDirectory((FileManagerDirectory)row.Data, true);
})
};
protected override async Task OnParametersSetAsync()
{
if (!String.IsNullOrWhiteSpace(WorkingDirectory))
{
Directories = GetDirectories(WorkingDirectory);
}
}
HashSet<FileManagerDirectory> GetDirectories(string path)
{
var paths = Directory.EnumerateDirectories(path, "*", new EnumerationOptions
{
IgnoreInaccessible = true,
RecurseSubdirectories = true,
MaxRecursionDepth = 1
});
var root = new FileManagerDirectory()
{
Name = path,
Path = path,
IsExpanded = true
};
root.PopulateChildren(paths);
ChangeDirectory(root, true);
return new HashSet<FileManagerDirectory>
{
root
};
}
string GetEntryName(IFileManagerEntry entry)
{
if (String.IsNullOrWhiteSpace(entry.Name) && entry.Length == 0)
{
return entry.Path.TrimEnd('/').Split('/').Last();
}
else
return entry.Name;
}
void ChangeDirectory(FileManagerDirectory directory, bool clearFuture)
{
Past.Add(Path);
Path = directory;
UpdateEntries();
UpdateBreadcrumbs();
if (clearFuture)
Future.Clear();
}
async Task ExpandTree(TreeEventArgs<FileManagerDirectory> args)
{
var directory = (FileManagerDirectory)args.Node.DataItem;
foreach (var child in directory.Children)
{
var paths = Directory.EnumerateDirectories(child.Path, "*", new EnumerationOptions
{
IgnoreInaccessible = true,
RecurseSubdirectories = true,
MaxRecursionDepth = 1
});
child.PopulateChildren(paths);
}
}
void UpdateEntries()
{
Entries.Clear();
var entries = Directory.EnumerateFileSystemEntries(Path.Path);
var separator = System.IO.Path.DirectorySeparatorChar;
foreach (var entry in Directory.EnumerateFileSystemEntries(Path.Path))
{
if (Directory.Exists(entry))
{
Entries.Add(new FileManagerDirectory
{
Path = entry,
Name = entry.Substring(Path.Path.Length).TrimStart(separator),
});
}
else
{
Entries.Add(new FileManagerFile
{
Path = entry,
Name = System.IO.Path.GetFileNameWithoutExtension(entry)
});
}
}
}
void UpdateBreadcrumbs()
{
Breadcrumbs.Clear();
var currentPath = Path;
while (currentPath != null)
{
Breadcrumbs.Add(currentPath);
currentPath = currentPath.Parent;
}
Breadcrumbs.Reverse();
}
void NavigateBack()
{
if (Past.Count > 0)
{
Future.Add(Path);
Path = Past.Last();
Past = Past.Take(Past.Count - 1).ToList();
}
}
void NavigateForward()
{
if (Future.Count > 0)
{
Past.Add(Path);
Path = Future.First();
Future = Future.Skip(1).ToList();
}
}
void NavigateUp()
{
if (Path.Parent != null)
ChangeDirectory(Path.Parent, true);
}
}

View File

@ -0,0 +1,54 @@
using System.IO.Compression;
namespace LANCommander.Components.FileManagerComponents
{
public class FileManagerDirectory : FileManagerEntry
{
public bool IsExpanded { get; set; } = false;
public bool HasChildren => Children != null && Children.Count > 0;
public HashSet<FileManagerDirectory> Children { get; set; } = new HashSet<FileManagerDirectory>();
public void PopulateChildren(IEnumerable<ZipArchiveEntry> entries)
{
var childPaths = entries.Where(e => e.FullName.StartsWith("/") && e.FullName.EndsWith('/'));
var directChildren = childPaths.Where(p => p.FullName != Path && p.FullName.Substring(Path.Length + 1).TrimEnd('/').Split('/').Length == 1);
foreach (var directChild in directChildren)
{
var child = new FileManagerDirectory()
{
Path = directChild.FullName,
Name = directChild.FullName.Substring(Path.Length).TrimEnd('/')
};
child.PopulateChildren(entries);
Children.Add(child);
}
}
public void PopulateChildren(IEnumerable<string> entries)
{
var separator = System.IO.Path.DirectorySeparatorChar;
var childPaths = entries.Where(e => e.StartsWith(Path));
var directChildren = childPaths.Where(p => p != Path && p.Substring(Path.Length + 1).Split(separator).Length == 1);
foreach (var directChild in directChildren)
{
if (!Children.Any(c => c.Path == directChild))
{
var child = new FileManagerDirectory()
{
Path = directChild,
Name = directChild.Substring(Path.Length).TrimStart(separator),
Parent = this
};
child.PopulateChildren(entries);
Children.Add(child);
}
}
}
}
}

View File

@ -0,0 +1,12 @@
namespace LANCommander.Components.FileManagerComponents
{
public abstract class FileManagerEntry : IFileManagerEntry
{
public string Name { get; set; }
public string Path { get; set; }
public long Length { get; set; }
public FileManagerDirectory Parent { get; set; }
public DateTime ModifiedOn { get; set; }
public DateTime CreatedOn { get; set; }
}
}

View File

@ -0,0 +1,7 @@
namespace LANCommander.Components.FileManagerComponents
{
public class FileManagerFile : FileManagerEntry
{
public string Extension => Name.Contains('.') ? Name.Split('.').Last() : Name;
}
}

View File

@ -0,0 +1,12 @@
namespace LANCommander.Components.FileManagerComponents
{
public interface IFileManagerEntry
{
public string Name { get; set; }
public string Path { get; set; }
public long Length { get; set; }
public FileManagerDirectory Parent { get; set; }
public DateTime ModifiedOn { get; set; }
public DateTime CreatedOn { get; set; }
}
}

View File

@ -0,0 +1,8 @@
@page "/Files"
@using LANCommander.Components.FileManagerComponents
<FileManager WorkingDirectory="C:\Games" />
@code {
}