Add Photino project
This commit is contained in:
8
DotNetSolutionTools.Core/Models/Project.cs
Normal file
8
DotNetSolutionTools.Core/Models/Project.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace DotNetSolutionTools.Core.Models;
|
||||
|
||||
public class Project
|
||||
{
|
||||
public required string FullPath { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public List<Project> DependsOn { get; set; } = [];
|
||||
}
|
||||
52
DotNetSolutionTools.Core/SolutionBuildOrder.cs
Normal file
52
DotNetSolutionTools.Core/SolutionBuildOrder.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using DotNetSolutionTools.Core.Common;
|
||||
using DotNetSolutionTools.Core.Models;
|
||||
using Microsoft.Build.Construction;
|
||||
|
||||
namespace DotNetSolutionTools.Core;
|
||||
|
||||
public static class SolutionBuildOrder
|
||||
{
|
||||
public static List<ProjectRootElement> Projects { get; set; } = [];
|
||||
|
||||
public static List<Project> GetBuildOrder(string solutionFilePath)
|
||||
{
|
||||
var solutionFile = SlnHelper.ParseSolutionFileFromPath(solutionFilePath);
|
||||
ArgumentNullException.ThrowIfNull(solutionFile);
|
||||
var projects = SlnHelper.GetCSharpProjectObjectsFromSolutionFile(solutionFile);
|
||||
Projects = projects;
|
||||
|
||||
List<Project> projects2 = [];
|
||||
foreach (var project in projects)
|
||||
{
|
||||
var projectName = Path.GetFileNameWithoutExtension(project.FullPath);
|
||||
var project2 = new Project { FullPath = project.FullPath, Name = projectName };
|
||||
project2.DependsOn = GetDependencies(project2);
|
||||
projects2.Add(project2);
|
||||
}
|
||||
|
||||
return projects2;
|
||||
}
|
||||
|
||||
public static List<Project> GetDependencies(Project project)
|
||||
{
|
||||
var projectReferences = Projects
|
||||
.Single(s => s.FullPath == project.FullPath)
|
||||
.AllChildren.OfType<ProjectItemElement>()
|
||||
.Where(x => x.ElementName == "ProjectReference")
|
||||
.ToList();
|
||||
|
||||
List<Project> dependencies = [];
|
||||
foreach (var projectReference in projectReferences)
|
||||
{
|
||||
var fullPath = Path.Combine(Path.GetDirectoryName(project.FullPath)!, projectReference.Include);
|
||||
fullPath = Path.GetFullPath(fullPath);
|
||||
var dependency = Projects.Single(s => s.FullPath == fullPath);
|
||||
var projectName = Path.GetFileNameWithoutExtension(dependency.FullPath);
|
||||
var subProject = new Project { FullPath = dependency.FullPath, Name = projectName };
|
||||
subProject.DependsOn = GetDependencies(subProject);
|
||||
dependencies.Add(subProject);
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
}
|
||||
17
DotNetSolutionTools.Photino/App.razor
Normal file
17
DotNetSolutionTools.Photino/App.razor
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
<Router AppAssembly="@typeof(Program).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
||||
</Found>
|
||||
<NotFound>
|
||||
<PageTitle>Not found</PageTitle>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<p role="alert">Sorry, there's nothing at this address.</p>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
|
||||
@code
|
||||
{
|
||||
|
||||
}
|
||||
15
DotNetSolutionTools.Photino/AppThemeProvider.cs
Normal file
15
DotNetSolutionTools.Photino/AppThemeProvider.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using MudBlazor;
|
||||
|
||||
namespace DotNetSolutionTools.Photino;
|
||||
|
||||
public static class AppThemeProvider
|
||||
{
|
||||
public static MudTheme GetTheme()
|
||||
{
|
||||
var theme = new MudTheme();
|
||||
theme.Typography.H5.FontSize = "1.4rem";
|
||||
theme.Typography.H5.FontWeight = 500;
|
||||
theme.Typography.H6.FontSize = "1.1rem";
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
@using Blazor.Diagrams
|
||||
@using Blazor.Diagrams.Core.Anchors
|
||||
@using Blazor.Diagrams.Core.Geometry
|
||||
@using Blazor.Diagrams.Core.Models
|
||||
@using DotNetSolutionTools.Core.Models
|
||||
|
||||
<h3>BuildOrderDiagram</h3>
|
||||
<div style="width: 100%; height: 400px; border: black">
|
||||
<CascadingValue Value="Diagram" IsFixed="true">
|
||||
<DiagramCanvas />
|
||||
</CascadingValue>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter, EditorRequired]
|
||||
public List<Project> Projects { get; set; }
|
||||
|
||||
private BlazorDiagram Diagram { get; set; } = null!;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Diagram = new BlazorDiagram();
|
||||
foreach (var project in Projects)
|
||||
{
|
||||
var node = Diagram.Nodes.Add(new NodeModel()
|
||||
{
|
||||
Title = project.Name,
|
||||
|
||||
});
|
||||
foreach (var dependency in project.DependsOn)
|
||||
{
|
||||
var dependencyNode = Diagram.Nodes.Add(new NodeModel()
|
||||
{
|
||||
Title = dependency.Name
|
||||
});
|
||||
Diagram.Links.Add(new LinkModel(node, dependencyNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void Example()
|
||||
{
|
||||
Diagram = new BlazorDiagram();
|
||||
var firstNode = Diagram.Nodes.Add(new NodeModel(position: new Point(50, 50))
|
||||
{
|
||||
Title = "Node 1"
|
||||
});
|
||||
var secondNode = Diagram.Nodes.Add(new NodeModel(position: new Point(200, 100))
|
||||
{
|
||||
Title = "Node 2"
|
||||
});
|
||||
var leftPort = secondNode.AddPort(PortAlignment.Left);
|
||||
var rightPort = secondNode.AddPort(PortAlignment.Right);
|
||||
// The connection point will be the intersection of
|
||||
// a line going from the target to the center of the source
|
||||
var sourceAnchor = new ShapeIntersectionAnchor(firstNode);
|
||||
// The connection point will be the port's position
|
||||
var targetAnchor = new SinglePortAnchor(leftPort);
|
||||
var link = Diagram.Links.Add(new LinkModel(sourceAnchor, targetAnchor));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType> <!-- Doesn't actually mean Windows Exe, 'Exe' = console entrypoint, 'WinExe' = application entry point -->
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ApplicationIcon>favicon.ico</ApplicationIcon>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>false</SelfContained>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MudBlazor" Version="7.15.0" />
|
||||
<PackageReference Include="Photino.Blazor" Version="3.2.0" />
|
||||
<PackageReference Include="Z.Blazor.Diagrams" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="favicon.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DotNetSolutionTools.Core\DotNetSolutionTools.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="RemoveConflictingAssets" BeforeTargets="ResolveStaticWebAssetsConfiguration">
|
||||
<ItemGroup>
|
||||
<StaticWebAsset Remove="@(StaticWebAsset)" Condition="'%(Extension)' == '.gz'" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
34
DotNetSolutionTools.Photino/Layout/MainLayout.razor
Normal file
34
DotNetSolutionTools.Photino/Layout/MainLayout.razor
Normal file
@@ -0,0 +1,34 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<MudThemeProvider Theme="@AppThemeProvider.GetTheme()" />
|
||||
<MudPopoverProvider/>
|
||||
<MudDialogProvider/>
|
||||
<MudSnackbarProvider/>
|
||||
|
||||
<MudLayout>
|
||||
<MudAppBar Dense="true">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
|
||||
</MudAppBar>
|
||||
<MudDrawer @bind-Open="@_drawerOpen">
|
||||
<MudDrawerHeader>
|
||||
<MudStack Row="false" Justify="Justify.Center">
|
||||
<MudText Typo="Typo.h5">DotNetSolutionTools.Photino</MudText>
|
||||
</MudStack>
|
||||
</MudDrawerHeader>
|
||||
<NavMenu/>
|
||||
</MudDrawer>
|
||||
<MudMainContent>
|
||||
<MudContainer Class="px-8 py-6">
|
||||
@Body
|
||||
</MudContainer>
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
|
||||
@code {
|
||||
bool _drawerOpen = true;
|
||||
|
||||
void DrawerToggle()
|
||||
{
|
||||
_drawerOpen = !_drawerOpen;
|
||||
}
|
||||
}
|
||||
3
DotNetSolutionTools.Photino/Layout/NavMenu.razor
Normal file
3
DotNetSolutionTools.Photino/Layout/NavMenu.razor
Normal file
@@ -0,0 +1,3 @@
|
||||
<MudNavMenu>
|
||||
<MudNavLink Href="/" Icon="@Icons.Material.Filled.Home" Match="NavLinkMatch.All">Home</MudNavLink>
|
||||
</MudNavMenu>
|
||||
8
DotNetSolutionTools.Photino/Models/AppState.cs
Normal file
8
DotNetSolutionTools.Photino/Models/AppState.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace DotNetSolutionTools.Photino.Models;
|
||||
|
||||
public class AppState
|
||||
{
|
||||
public required string SolutionFolderPath { get; set; }
|
||||
public required string SolutionFilePath { get; set; }
|
||||
public required string CsprojFilePath { get; set; }
|
||||
}
|
||||
41
DotNetSolutionTools.Photino/Pages/Home.razor
Normal file
41
DotNetSolutionTools.Photino/Pages/Home.razor
Normal file
@@ -0,0 +1,41 @@
|
||||
@page "/"
|
||||
@using DotNetSolutionTools.Core
|
||||
@using DotNetSolutionTools.Core.Models
|
||||
@using DotNetSolutionTools.Photino.Models
|
||||
@inject AppState AppState
|
||||
|
||||
<MudStack>
|
||||
<MudInput T="string" Label="Solution File Path" @bind-Value="_solutionFilePath" @bind-Value:after="SetToAppState" />
|
||||
<MudButton OnClick="@Populate">Populate project dependencies</MudButton>
|
||||
</MudStack>
|
||||
|
||||
@if (_projects.Count > 0)
|
||||
{
|
||||
<BuildOrderDiagram Projects="_projects"/>
|
||||
}
|
||||
@foreach(var project in _projects)
|
||||
{
|
||||
<MudText>@project.Name</MudText>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string? _solutionFilePath;
|
||||
private List<Project> _projects = [];
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_solutionFilePath = AppState.SolutionFilePath;
|
||||
}
|
||||
|
||||
private void Populate()
|
||||
{
|
||||
var result = SolutionBuildOrder.GetBuildOrder(_solutionFilePath);
|
||||
_projects = result;
|
||||
}
|
||||
|
||||
private void SetToAppState()
|
||||
{
|
||||
AppState.SolutionFilePath = _solutionFilePath;
|
||||
}
|
||||
|
||||
}
|
||||
91
DotNetSolutionTools.Photino/Program.cs
Normal file
91
DotNetSolutionTools.Photino/Program.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System.Text.Json;
|
||||
using DotNetSolutionTools.Photino.Models;
|
||||
using Microsoft.Build.Locator;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MudBlazor.Services;
|
||||
using Photino.Blazor;
|
||||
|
||||
namespace DotNetSolutionTools.Photino;
|
||||
|
||||
public class Program
|
||||
{
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var appBuilder = PhotinoBlazorAppBuilder.CreateDefault(args);
|
||||
|
||||
appBuilder.Services.AddLogging();
|
||||
appBuilder.Services.AddMudServices();
|
||||
appBuilder.Services.AddSingleton<AppState>();
|
||||
|
||||
appBuilder.RootComponents.Add<App>("app");
|
||||
|
||||
var app = appBuilder.Build();
|
||||
|
||||
app.MainWindow.SetSize(1400, 800)
|
||||
.SetDevToolsEnabled(true)
|
||||
.SetLogVerbosity(0)
|
||||
//.SetIconFile("favicon.ico")
|
||||
.SetTitle("DotNetSolutionTools.Photino");
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, error) =>
|
||||
{
|
||||
app.MainWindow.ShowMessage("Fatal exception", error.ExceptionObject.ToString());
|
||||
};
|
||||
|
||||
var instance = MSBuildLocator
|
||||
.QueryVisualStudioInstances()
|
||||
.OrderByDescending(instance => instance.Version)
|
||||
.First();
|
||||
MSBuildLocator.RegisterInstance(instance);
|
||||
|
||||
var configFilePath = GetConfigFilePath();
|
||||
|
||||
using var scope = app.Services.CreateScope();
|
||||
var appState = scope.ServiceProvider.GetRequiredService<AppState>();
|
||||
|
||||
LoadAppStateFromConfigFile(appState, configFilePath);
|
||||
|
||||
app.MainWindow.RegisterWindowClosingHandler(
|
||||
(sender, eventArgs) =>
|
||||
{
|
||||
using var stream = File.Create(configFilePath);
|
||||
JsonSerializer.Serialize(stream, appState);
|
||||
stream.Flush();
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
app.Run();
|
||||
}
|
||||
|
||||
private static string GetConfigFilePath()
|
||||
{
|
||||
var folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
var configFolder = Path.Combine(folder, "DotNetSolutionTools.Photino");
|
||||
Directory.CreateDirectory(configFolder);
|
||||
var configFilePath = Path.Combine(configFolder, "config.json");
|
||||
return configFilePath;
|
||||
}
|
||||
|
||||
private static void LoadAppStateFromConfigFile(AppState appState, string configFilePath)
|
||||
{
|
||||
if (File.Exists(configFilePath) is false)
|
||||
{
|
||||
File.WriteAllText(configFilePath, string.Empty);
|
||||
}
|
||||
|
||||
using var stream = File.OpenRead(configFilePath);
|
||||
if (stream.Length is 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var deserializedAppState = JsonSerializer.Deserialize<AppState>(stream);
|
||||
if (deserializedAppState is not null)
|
||||
{
|
||||
appState.SolutionFolderPath = deserializedAppState.SolutionFolderPath;
|
||||
appState.SolutionFilePath = deserializedAppState.SolutionFilePath;
|
||||
appState.CsprojFilePath = deserializedAppState.CsprojFilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
DotNetSolutionTools.Photino/Properties/launchSettings.json
Normal file
22
DotNetSolutionTools.Photino/Properties/launchSettings.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"Run": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"environmentVariables": {
|
||||
"DOTNET_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"(Watch)": {
|
||||
"commandName": "Executable",
|
||||
"executablePath": "dotnet",
|
||||
"workingDirectory": "$(ProjectDir)",
|
||||
"commandLineArgs": "watch run",
|
||||
"environmentVariables": {
|
||||
"DOTNET_ENVIRONMENT": "Development",
|
||||
"DOTNET_WATCH_RESTART_ON_RUDE_EDIT": "true"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
DotNetSolutionTools.Photino/_Imports.razor
Normal file
15
DotNetSolutionTools.Photino/_Imports.razor
Normal file
@@ -0,0 +1,15 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using Microsoft.Extensions.Logging
|
||||
@using MudBlazor
|
||||
@using DotNetSolutionTools.Photino.Layout
|
||||
@using DotNetSolutionTools.Photino
|
||||
@using DotNetSolutionTools.Photino.Models
|
||||
@using DotNetSolutionTools.Photino.Components
|
||||
@using Blazor.Diagrams.Components
|
||||
BIN
DotNetSolutionTools.Photino/favicon.ico
Normal file
BIN
DotNetSolutionTools.Photino/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 179 KiB |
1
DotNetSolutionTools.Photino/wwwroot/css/app.css
Normal file
1
DotNetSolutionTools.Photino/wwwroot/css/app.css
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
28
DotNetSolutionTools.Photino/wwwroot/index.html
Normal file
28
DotNetSolutionTools.Photino/wwwroot/index.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<base href="/" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
||||
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||
<link href="css/app.css" rel="stylesheet" />
|
||||
<link href="DotNetSolutionTools.Photino.styles.css" rel="stylesheet" />
|
||||
|
||||
<link href="_content/Z.Blazor.Diagrams/style.min.css" rel="stylesheet" />
|
||||
<link href="_content/Z.Blazor.Diagrams/default.styles.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<app>Loading...</app>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
|
||||
<script src="_framework/blazor.webview.js"></script>
|
||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||
<script src="_content/Z.Blazor.Diagrams/script.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{B38F
|
||||
.github\dependabot.yaml = .github\dependabot.yaml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetSolutionTools.Photino", "DotNetSolutionTools.Photino\DotNetSolutionTools.Photino.csproj", "{6030845C-0B67-4F55-ABC2-47ACD18AE216}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -37,5 +39,9 @@ Global
|
||||
{A7F46873-C8EC-4C2E-86F5-B9F2472C8036}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A7F46873-C8EC-4C2E-86F5-B9F2472C8036}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A7F46873-C8EC-4C2E-86F5-B9F2472C8036}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6030845C-0B67-4F55-ABC2-47ACD18AE216}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6030845C-0B67-4F55-ABC2-47ACD18AE216}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6030845C-0B67-4F55-ABC2-47ACD18AE216}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6030845C-0B67-4F55-ABC2-47ACD18AE216}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Reference in New Issue
Block a user