mirror of
https://github.com/unclshura/BlazorOpenApi.git
synced 2025-12-21 09:51:53 +00:00
Add project files.
This commit is contained in:
commit
1744a7829d
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
###############################################################################
|
||||||
|
# Set default behavior to automatically normalize line endings.
|
||||||
|
###############################################################################
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior for command prompt diff.
|
||||||
|
#
|
||||||
|
# This is need for earlier builds of msysgit that does not have it on by
|
||||||
|
# default for csharp files.
|
||||||
|
# Note: This is only used by command line
|
||||||
|
###############################################################################
|
||||||
|
#*.cs diff=csharp
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set the merge driver for project and solution files
|
||||||
|
#
|
||||||
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
|
# these files as binary and thus will always conflict and require user
|
||||||
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
|
###############################################################################
|
||||||
|
#*.sln merge=binary
|
||||||
|
#*.csproj merge=binary
|
||||||
|
#*.vbproj merge=binary
|
||||||
|
#*.vcxproj merge=binary
|
||||||
|
#*.vcproj merge=binary
|
||||||
|
#*.dbproj merge=binary
|
||||||
|
#*.fsproj merge=binary
|
||||||
|
#*.lsproj merge=binary
|
||||||
|
#*.wixproj merge=binary
|
||||||
|
#*.modelproj merge=binary
|
||||||
|
#*.sqlproj merge=binary
|
||||||
|
#*.wwaproj merge=binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# behavior for image files
|
||||||
|
#
|
||||||
|
# image files are treated as binary by default.
|
||||||
|
###############################################################################
|
||||||
|
#*.jpg binary
|
||||||
|
#*.png binary
|
||||||
|
#*.gif binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# diff behavior for common document formats
|
||||||
|
#
|
||||||
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
|
# entries below.
|
||||||
|
###############################################################################
|
||||||
|
#*.doc diff=astextplain
|
||||||
|
#*.DOC diff=astextplain
|
||||||
|
#*.docx diff=astextplain
|
||||||
|
#*.DOCX diff=astextplain
|
||||||
|
#*.dot diff=astextplain
|
||||||
|
#*.DOT diff=astextplain
|
||||||
|
#*.pdf diff=astextplain
|
||||||
|
#*.PDF diff=astextplain
|
||||||
|
#*.rtf diff=astextplain
|
||||||
|
#*.RTF diff=astextplain
|
||||||
365
.gitignore
vendored
Normal file
365
.gitignore
vendored
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
*.patch
|
||||||
31
BlazorOpenApi.sln
Normal file
31
BlazorOpenApi.sln
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.8.34511.84
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorOpenApi.Demo", "Demo\BlazorOpenApi.Demo.csproj", "{23C0112B-477D-40F2-8088-0C086D5E7A7A}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorOpenApi", "BlazorOpenApi\BlazorOpenApi.csproj", "{57AD9505-4132-4D79-BF67-03E9F5FC0483}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{23C0112B-477D-40F2-8088-0C086D5E7A7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{23C0112B-477D-40F2-8088-0C086D5E7A7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{23C0112B-477D-40F2-8088-0C086D5E7A7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{23C0112B-477D-40F2-8088-0C086D5E7A7A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{57AD9505-4132-4D79-BF67-03E9F5FC0483}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{57AD9505-4132-4D79-BF67-03E9F5FC0483}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{57AD9505-4132-4D79-BF67-03E9F5FC0483}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{57AD9505-4132-4D79-BF67-03E9F5FC0483}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {3E7BCFDA-CFF3-4DA3-9E81-1BA3F79B0247}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
19
BlazorOpenApi/ApiUtils.cs
Normal file
19
BlazorOpenApi/ApiUtils.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Markdig;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace BlazorOpenApi;
|
||||||
|
|
||||||
|
internal static class ApiUtils
|
||||||
|
{
|
||||||
|
public static MarkupString MarkdownToHtml(string? md)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(md))
|
||||||
|
return new();
|
||||||
|
|
||||||
|
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
|
||||||
|
var html = Markdown.ToHtml(md, pipeline).ToString() ?? "";
|
||||||
|
|
||||||
|
return new (html);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
10
BlazorOpenApi/BlazorOpenApi.csproj
Normal file
10
BlazorOpenApi/BlazorOpenApi.csproj
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
|
<PackageReference Include="Markdig" />
|
||||||
|
<PackageReference Include="Microsoft.OpenApi.Readers" />
|
||||||
|
<PackageReference Include="System.Text.Json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
46
BlazorOpenApi/Controls/AnyControl.razor
Normal file
46
BlazorOpenApi/Controls/AnyControl.razor
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
@using Microsoft.OpenApi.Any
|
||||||
|
|
||||||
|
@if (Value != null)
|
||||||
|
{
|
||||||
|
<div class="e-item">
|
||||||
|
@switch (Value.AnyType)
|
||||||
|
{
|
||||||
|
case AnyType.Null:
|
||||||
|
break;
|
||||||
|
case AnyType.Primitive:
|
||||||
|
{
|
||||||
|
<span>@AsPrimitive?.PrimitiveType</span>
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AnyType.Array:
|
||||||
|
{
|
||||||
|
<span>[</span>
|
||||||
|
@foreach (var element in AsArray!)
|
||||||
|
{
|
||||||
|
<AnyControl Value="@element" />
|
||||||
|
}
|
||||||
|
<span>]</span>
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AnyType.Object:
|
||||||
|
{
|
||||||
|
@foreach (var element in AsObject!)
|
||||||
|
{
|
||||||
|
<div class="e-name">@element.Key</div>
|
||||||
|
<AnyControl Value="@element.Value" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public IOpenApiAny? Value { get; set; }
|
||||||
|
|
||||||
|
private IOpenApiPrimitive? AsPrimitive => Value as IOpenApiPrimitive;
|
||||||
|
private OpenApiArray? AsArray => Value as OpenApiArray;
|
||||||
|
private OpenApiObject? AsObject => Value as OpenApiObject;
|
||||||
|
|
||||||
|
}
|
||||||
42
BlazorOpenApi/Controls/ComponentsControl.razor
Normal file
42
BlazorOpenApi/Controls/ComponentsControl.razor
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
@if ( Value != null )
|
||||||
|
{
|
||||||
|
@if (Value.Schemas?.Count > 0)
|
||||||
|
{
|
||||||
|
<h3>Schemas</h3>
|
||||||
|
@foreach (var (name, val) in Value.Schemas)
|
||||||
|
{
|
||||||
|
<h4>@name</h4>
|
||||||
|
<SchemaControl Value="@val"/>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<ResponsesControl Value="@Value.Responses"/>
|
||||||
|
|
||||||
|
@if (Value.Parameters?.Count > 0)
|
||||||
|
{
|
||||||
|
<h3>Parameters</h3>
|
||||||
|
@foreach (var (name, val) in Value.Parameters)
|
||||||
|
{
|
||||||
|
<h4>@name</h4>
|
||||||
|
<ParametersControl Value="@ToList(val)" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (Value.Examples?.Count > 0)
|
||||||
|
{
|
||||||
|
<h3>Examples</h3>
|
||||||
|
@foreach (var (name, val) in Value.Examples)
|
||||||
|
{
|
||||||
|
<ExampleControl Example="@val" Name="@name"/>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiComponents? Value { get; set; }
|
||||||
|
|
||||||
|
private IList<OpenApiParameter> ToList(OpenApiParameter val)
|
||||||
|
=> new List<OpenApiParameter>() { val };
|
||||||
|
}
|
||||||
30
BlazorOpenApi/Controls/DiscriminatorControl.razor
Normal file
30
BlazorOpenApi/Controls/DiscriminatorControl.razor
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
|
||||||
|
@if (Value != null)
|
||||||
|
{
|
||||||
|
<div class="descriminator">
|
||||||
|
<Text Value="@Value.PropertyName" />
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>From</th>
|
||||||
|
<th>To</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var item in Value.Mapping)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@item.Key</td>
|
||||||
|
<td>@item.Value</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiDiscriminator? Value { get; set; }
|
||||||
|
}
|
||||||
46
BlazorOpenApi/Controls/ExampleControl.razor
Normal file
46
BlazorOpenApi/Controls/ExampleControl.razor
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
@using Microsoft.OpenApi.Any
|
||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
|
||||||
|
@if (Value != null || Example != null )
|
||||||
|
{
|
||||||
|
<div class="e-title">
|
||||||
|
@if (!string.IsNullOrWhiteSpace(Name))
|
||||||
|
{
|
||||||
|
<span class="e-name">@Name</span>
|
||||||
|
@if (!string.IsNullOrWhiteSpace(Example?.Summary))
|
||||||
|
{
|
||||||
|
<span class="spacer">-</span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if ( !string.IsNullOrWhiteSpace(Example?.Summary) )
|
||||||
|
{
|
||||||
|
<span>@Example.Summary </span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
if (Example != null)
|
||||||
|
{
|
||||||
|
<MarkdownControl Value="@Example.Description"/>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public IOpenApiAny? Value { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiExample? Example { get; set; }
|
||||||
|
|
||||||
|
public IOpenApiAny? Ex => Example != null ? Example.Value : Value;
|
||||||
|
/*
|
||||||
|
@if (Ex != null)
|
||||||
|
{
|
||||||
|
<div class="example">
|
||||||
|
<AnyControl Value="@Ex"/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
43
BlazorOpenApi/Controls/Expander.razor
Normal file
43
BlazorOpenApi/Controls/Expander.razor
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<div class="expander @Class">
|
||||||
|
<div class="ex-header @HeaderClass">
|
||||||
|
@Title
|
||||||
|
<div onclick="@(() => Toggle())">
|
||||||
|
@if (Collapsed)
|
||||||
|
{
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18 9L12 15L6 9" stroke="var(--oa-fg-lighter)" stroke-width="2" />
|
||||||
|
</svg>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18 15L12 9L6 15" stroke="var(--oa-fg-lighter)" stroke-width="2" />
|
||||||
|
</svg>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (!Collapsed && ChildContent != null)
|
||||||
|
{
|
||||||
|
@ChildContent
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public RenderFragment? ChildContent { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public bool Collapsed { get; set; } = true;
|
||||||
|
[Parameter]
|
||||||
|
public string Title { get; set; } = "";
|
||||||
|
[Parameter]
|
||||||
|
public string HeaderClass { get; set; } = "";
|
||||||
|
[Parameter]
|
||||||
|
public string Class { get; set; } = "";
|
||||||
|
|
||||||
|
void Toggle()
|
||||||
|
{
|
||||||
|
Collapsed = !Collapsed;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
49
BlazorOpenApi/Controls/HeaderControl.razor
Normal file
49
BlazorOpenApi/Controls/HeaderControl.razor
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
@using System.Text.Json
|
||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
@using Microsoft.OpenApi.Readers
|
||||||
|
|
||||||
|
@if (Value != null)
|
||||||
|
{
|
||||||
|
<div class="header">
|
||||||
|
<h1 class="h-title">@Value.Title <span class="h-version">@Value.Version</span></h1>
|
||||||
|
<div class="h-contact">
|
||||||
|
@if (!string.IsNullOrWhiteSpace(Value.Contact?.Name))
|
||||||
|
{
|
||||||
|
<div class="h-name">
|
||||||
|
@Value.Contact.Name
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (Value.Contact?.Url != null)
|
||||||
|
{
|
||||||
|
<div class="h-url">
|
||||||
|
@Value.Contact.Url
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (Value.Contact?.Email != null)
|
||||||
|
{
|
||||||
|
<div class="h-email">
|
||||||
|
@Value.Contact.Email
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if (!string.IsNullOrWhiteSpace(DownloadUrl))
|
||||||
|
{
|
||||||
|
<a class="h-source-url" href="@DownloadUrl">@DownloadUrl</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (!string.IsNullOrWhiteSpace(Value.Description))
|
||||||
|
{
|
||||||
|
<h2>Description</h2>
|
||||||
|
<MarkdownControl Value="@Value.Description"/>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiInfo? Value { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string DownloadUrl { get; set; } = "";
|
||||||
|
|
||||||
|
}
|
||||||
64
BlazorOpenApi/Controls/IndicatorControl.razor
Normal file
64
BlazorOpenApi/Controls/IndicatorControl.razor
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
@if (Value)
|
||||||
|
{
|
||||||
|
<Tooltip Class="@RealClass" TooltipText="@TtText">
|
||||||
|
@Name
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
[Parameter]
|
||||||
|
public string TooltipText { get; set; } = "";
|
||||||
|
[Parameter]
|
||||||
|
public bool Value { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string Class { get; set; } = "";
|
||||||
|
|
||||||
|
private string RealClass => $"indicator {Class}";
|
||||||
|
|
||||||
|
private string? TtText => !string.IsNullOrWhiteSpace(TooltipText) ? "" : Name.ToLower() switch
|
||||||
|
{
|
||||||
|
"explode" => ExplodeTooltip,
|
||||||
|
"deprecated" => DeprecatedTooltip,
|
||||||
|
"required" => RequiredTooltip,
|
||||||
|
"allowemptyvalue" => AllowEmptyValueTooltip,
|
||||||
|
"allowreserved" => AllowReservedTooltip,
|
||||||
|
_ => ""
|
||||||
|
};
|
||||||
|
|
||||||
|
internal const string ExplodeTooltip =
|
||||||
|
@"
|
||||||
|
When this is true, parameter values of type array or object generate separate parameters
|
||||||
|
for each value of the array or key-value pair of the map.
|
||||||
|
For other types of parameters this property has no effect.
|
||||||
|
When style is form, the default value is true.
|
||||||
|
For all other styles, the default value is false.
|
||||||
|
";
|
||||||
|
internal const string DeprecatedTooltip =
|
||||||
|
@"
|
||||||
|
Specifies that a parameter is deprecated and SHOULD be transitioned out of usage.
|
||||||
|
";
|
||||||
|
internal const string RequiredTooltip =
|
||||||
|
@"
|
||||||
|
Determines whether this parameter is mandatory.
|
||||||
|
If the parameter location is ""path"", this property is REQUIRED and its value MUST be true.
|
||||||
|
Otherwise, the property MAY be included and its default value is false.
|
||||||
|
";
|
||||||
|
internal const string AllowEmptyValueTooltip =
|
||||||
|
@"
|
||||||
|
Sets the ability to pass empty-valued parameters.
|
||||||
|
This is valid only for query parameters and allows sending a parameter with an empty value.
|
||||||
|
Default value is false.
|
||||||
|
If style is used, and if behavior is n/a (cannot be serialized),
|
||||||
|
the value of allowEmptyValue SHALL be ignored.
|
||||||
|
";
|
||||||
|
internal const string AllowReservedTooltip =
|
||||||
|
@"
|
||||||
|
Determines whether the parameter value SHOULD allow reserved characters,
|
||||||
|
as defined by RFC3986 :/?#[]@!$&'()*+,;= to be included without percent-encoding.
|
||||||
|
This property only applies to parameters with an in value of query.
|
||||||
|
The default value is false.
|
||||||
|
";
|
||||||
|
|
||||||
|
}
|
||||||
9
BlazorOpenApi/Controls/MarkdownControl.razor
Normal file
9
BlazorOpenApi/Controls/MarkdownControl.razor
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@if (!string.IsNullOrWhiteSpace(Value))
|
||||||
|
{
|
||||||
|
<div class="markdown">@ApiUtils.MarkdownToHtml(Value)</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public string? Value { get; set; }
|
||||||
|
}
|
||||||
75
BlazorOpenApi/Controls/OperationControl.razor
Normal file
75
BlazorOpenApi/Controls/OperationControl.razor
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
@using System.Text.Json
|
||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
@using Microsoft.OpenApi.Readers
|
||||||
|
|
||||||
|
@if (Value != null)
|
||||||
|
{
|
||||||
|
<div class="op-header @OperationClass" @onclick="Expand">
|
||||||
|
<div class="op-type">@Operation</div>
|
||||||
|
<div class="spacer op-header-text">-</div>
|
||||||
|
<div class="op-header-text" id="@Value.OperationId">@Endpoint</div>
|
||||||
|
<div class="spacer op-header-text">-</div>
|
||||||
|
<div class="op-summary op-header-text">@Value.Summary</div>
|
||||||
|
@if (Value.Tags.Count > 0)
|
||||||
|
{
|
||||||
|
<div class="op-tags">
|
||||||
|
@foreach (var tag in Value.Tags)
|
||||||
|
{
|
||||||
|
<Tooltip class="op-tag" TooltipText="@tag.Description">
|
||||||
|
<Text Class="op-tag-name" Value="@tag.Name" />
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (_expanded)
|
||||||
|
{
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18 15L12 9L6 15" stroke="var(--oa-fg-lighter)" stroke-width="2" />
|
||||||
|
</svg>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18 9L12 15L6 9" stroke="var(--oa-fg-lighter)" stroke-width="2" />
|
||||||
|
</svg>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
@if ( _expanded )
|
||||||
|
{
|
||||||
|
<div class="operation">
|
||||||
|
|
||||||
|
@if (Value != null)
|
||||||
|
{
|
||||||
|
<MarkdownControl Value="@Value.Description" />
|
||||||
|
|
||||||
|
if (Value.Servers?.Count > 0)
|
||||||
|
{
|
||||||
|
<ServersControl Value="@Value.Servers" />
|
||||||
|
}
|
||||||
|
|
||||||
|
<ParametersControl Value="@Value.Parameters"/>
|
||||||
|
<ResponsesControl Value="@Value.Responses" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public OperationType Operation { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiOperation? Value { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string Endpoint { get; set; } = "";
|
||||||
|
|
||||||
|
private string OperationClass => $"op-{Operation.ToString().ToLower()}";
|
||||||
|
|
||||||
|
private bool _expanded = true;
|
||||||
|
|
||||||
|
private void Expand()
|
||||||
|
{
|
||||||
|
_expanded = !_expanded;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
59
BlazorOpenApi/Controls/ParameterControl.razor
Normal file
59
BlazorOpenApi/Controls/ParameterControl.razor
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
@using System.Text.Json
|
||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
@using Microsoft.OpenApi.Readers
|
||||||
|
|
||||||
|
@if (Value != null)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<SchemaControl Value="@Value.Schema" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="p-attrs">
|
||||||
|
<div class="p-name">@Value.Name</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="p-attrs">
|
||||||
|
<div class="p-in @InClass(Value)">@Value.In</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="p-attrs">
|
||||||
|
<ParameterStyleControl Value="@Value.Style" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="p-attrs">
|
||||||
|
<div class="p-indicators">
|
||||||
|
<IndicatorControl Name="Deprecated" Value="@Value.Deprecated" Class="i-deprecated" />
|
||||||
|
<IndicatorControl Name="Required" Value="@Value.Required" Class="i-required"/>
|
||||||
|
<IndicatorControl Name="AllowEmptyValue" Value="@Value.AllowEmptyValue" />
|
||||||
|
<IndicatorControl Name="AllowReserved" Value="@Value.AllowReserved" />
|
||||||
|
<IndicatorControl Name="Explode" Value="@Value.Explode" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="p-body">
|
||||||
|
<MarkdownControl Value="@Value.Description" />
|
||||||
|
<ExampleControl Value="@Value.Example" />
|
||||||
|
@if (Value.Examples.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var (n, v) in Value.Examples)
|
||||||
|
{
|
||||||
|
<ExampleControl Example="@v" Name="@n" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiParameter? Value { get; set; }
|
||||||
|
|
||||||
|
private string InClass(OpenApiParameter p) => Value == null ? "" : $"p-in-{p?.In?.ToString()?.ToLower()}";
|
||||||
|
|
||||||
|
}
|
||||||
13
BlazorOpenApi/Controls/ParameterStyleControl.razor
Normal file
13
BlazorOpenApi/Controls/ParameterStyleControl.razor
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
|
||||||
|
@if ( Value != null )
|
||||||
|
{
|
||||||
|
<div class="p-style @StyleClass">@Value</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public ParameterStyle? Value { get; set; }
|
||||||
|
|
||||||
|
private string StyleClass => Value == null ? "" : $"p-style-{Value.ToString()?.ToLower()}";
|
||||||
|
}
|
||||||
34
BlazorOpenApi/Controls/ParametersControl.razor
Normal file
34
BlazorOpenApi/Controls/ParametersControl.razor
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
@using System.Text.Json
|
||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
@using Microsoft.OpenApi.Readers
|
||||||
|
|
||||||
|
@if (Value?.Count > 0)
|
||||||
|
{
|
||||||
|
<table class="op-params parameter">
|
||||||
|
@foreach (var p in Value)
|
||||||
|
{
|
||||||
|
<ParameterControl Value="@GetResolvedReference(p)"/>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public IList<OpenApiParameter>? Value { get; set; }
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
public OpenApiDocument? Api { get; set; }
|
||||||
|
|
||||||
|
private OpenApiParameter? GetResolvedReference(OpenApiParameter p)
|
||||||
|
{
|
||||||
|
if (p == null)
|
||||||
|
return null;
|
||||||
|
if (!p.UnresolvedReference || p.Reference == null || Api == null)
|
||||||
|
return p;
|
||||||
|
|
||||||
|
if (!Api.Components.Parameters.TryGetValue(p.Reference.Id, out var resolved))
|
||||||
|
return p;
|
||||||
|
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
44
BlazorOpenApi/Controls/PathControl.razor
Normal file
44
BlazorOpenApi/Controls/PathControl.razor
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
@using System.Text.Json
|
||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
@using Microsoft.OpenApi.Readers
|
||||||
|
|
||||||
|
@if (!string.IsNullOrWhiteSpace(Key) || Value != null)
|
||||||
|
{
|
||||||
|
@if (!string.IsNullOrWhiteSpace(@Value?.Summary) || !string.IsNullOrWhiteSpace(Value?.Description))
|
||||||
|
{
|
||||||
|
<div class="pa-header">
|
||||||
|
<h3>@Key</h3>
|
||||||
|
<div class="spacer">-</div>
|
||||||
|
<div class="pa-summary">@Value?.Summary</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="path">
|
||||||
|
@if (Value != null)
|
||||||
|
{
|
||||||
|
<MarkdownControl Value="@Value.Description" />
|
||||||
|
|
||||||
|
if (Value.Servers?.Count > 0)
|
||||||
|
{
|
||||||
|
<ServersControl Value="@Value.Servers" />
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (Value.Operations?.Count > 0)
|
||||||
|
{
|
||||||
|
<div class="operations">
|
||||||
|
@foreach (var (key, op) in @Value.Operations.Where(x => x.Value != null))
|
||||||
|
{
|
||||||
|
<OperationControl Endpoint="@Key" Operation="@key" Value="@op" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public string? Key { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiPathItem? Value { get; set; }
|
||||||
|
}
|
||||||
121
BlazorOpenApi/Controls/ResponseControl.razor
Normal file
121
BlazorOpenApi/Controls/ResponseControl.razor
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
|
||||||
|
@if (ResolvedValue != null)
|
||||||
|
{
|
||||||
|
<div class="response">
|
||||||
|
<MarkdownControl Value="@ResolvedValue.Description" />
|
||||||
|
|
||||||
|
@if (ResolvedValue.Headers.Count > 0)
|
||||||
|
{
|
||||||
|
<table>
|
||||||
|
@foreach (var (key, val) in ResolvedValue.Headers)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td class="p-name">@key</td>
|
||||||
|
<td>
|
||||||
|
<div class="parameter">
|
||||||
|
<div class="p-attrs">
|
||||||
|
<ParameterStyleControl Value="@val.Style" />
|
||||||
|
<div class="p-indicators">
|
||||||
|
<IndicatorControl Name="Deprecated" Value="@val.Deprecated" Class="i-deprecated" />
|
||||||
|
<IndicatorControl Name="Required" Value="@val.Required" Class="i-required" />
|
||||||
|
<IndicatorControl Name="AllowEmptyResolvedValue" Value="@val.AllowEmptyValue" />
|
||||||
|
<IndicatorControl Name="AllowReserved" Value="@val.AllowReserved" />
|
||||||
|
<IndicatorControl Name="Explode" Value="@val.Explode" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-body">
|
||||||
|
<SchemaControl Value="@val.Schema" />
|
||||||
|
|
||||||
|
@if (val.Content.Count > 0)
|
||||||
|
{
|
||||||
|
<table>
|
||||||
|
@foreach (var (k, v) in val.Content)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@k</td>
|
||||||
|
<td>
|
||||||
|
<SchemaControl Value="@v.Schema" />
|
||||||
|
@if (v.Encoding.Count > 0)
|
||||||
|
{
|
||||||
|
<table class="r-encoding">
|
||||||
|
@foreach (var (ename, eval) in v.Encoding)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div class="e-name">@ename</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="e-name">@eval.ContentType</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ParameterStyleControl Value="@eval.Style" />
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
<ExampleControl Value="@v.Example" />
|
||||||
|
@foreach (var (ename, eval) in val.Examples)
|
||||||
|
{
|
||||||
|
<ExampleControl Example="@eval" Name="@ename" />
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
|
||||||
|
<ExampleControl Value="@val.Example" />
|
||||||
|
@if (val.Examples.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var (n, v) in val.Examples)
|
||||||
|
{
|
||||||
|
<ExampleControl Example="@v" Name="@n" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<MarkdownControl Value="@val.Description" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
@if ( ResolvedValue.Content.Count > 0 )
|
||||||
|
{
|
||||||
|
@foreach (var (key, val) in ResolvedValue.Content)
|
||||||
|
{
|
||||||
|
<div class="p-name">@key</div>
|
||||||
|
<div class="p-body">
|
||||||
|
<SchemaControl Value="@val.Schema"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiResponse? Value { get; set; }
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
public OpenApiDocument? Api { get; set; }
|
||||||
|
|
||||||
|
private OpenApiResponse? ResolvedValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Value?.Reference == null || Api == null || Value?.UnresolvedReference != true)
|
||||||
|
return Value;
|
||||||
|
|
||||||
|
if (!Api.Components.Responses.TryGetValue(Value.Reference.Id, out var resolved))
|
||||||
|
return Value;
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
BlazorOpenApi/Controls/ResponsesControl.razor
Normal file
35
BlazorOpenApi/Controls/ResponsesControl.razor
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
|
||||||
|
@if (Value?.Count > 0)
|
||||||
|
{
|
||||||
|
<div class="responses">
|
||||||
|
<div class="r-title">Responces</div>
|
||||||
|
<table>
|
||||||
|
@foreach (var (name, val) in Value)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td><div class="r-name @GetClass(name)">@name</div></td>
|
||||||
|
<td>
|
||||||
|
<ResponseControl Value="@val"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public IDictionary<string, OpenApiResponse>? Value { get; set; }
|
||||||
|
|
||||||
|
private static string GetClass(string name)
|
||||||
|
{
|
||||||
|
if (name.StartsWith("2"))
|
||||||
|
return "r-success";
|
||||||
|
if (name.StartsWith("4"))
|
||||||
|
return "r-auth";
|
||||||
|
if (name.StartsWith("5"))
|
||||||
|
return "r-error";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
108
BlazorOpenApi/Controls/SchemaChildControl.razor
Normal file
108
BlazorOpenApi/Controls/SchemaChildControl.razor
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
|
||||||
|
@if ( Value != null )
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
@if (Value.Type == "array")
|
||||||
|
{
|
||||||
|
<Expander HeaderClass="s-type" Class="s-bg-odd" Title="@ArrayText">
|
||||||
|
<div class="s-nested">
|
||||||
|
<SchemaControl Value="@Value.Items" />
|
||||||
|
</div>
|
||||||
|
</Expander>
|
||||||
|
}
|
||||||
|
else if (Value.Type == "object")
|
||||||
|
{
|
||||||
|
<Expander HeaderClass="s-type" Class="s-bg-odd" Title="@ObjectText">
|
||||||
|
<div class="s-props s-nested">
|
||||||
|
<table class="schema">
|
||||||
|
@foreach (var p in Value.Properties)
|
||||||
|
{
|
||||||
|
<SchemaChildControl Value="@p.Value" Title="@p.Key" Required="@IsRequired(p.Key)" />
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</Expander>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
<Text Value="@TypeText" Class="s-type" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<Text Class="s-title" Value="@TitleText" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<IndicatorControl Name="Required" Value="@Required" Class="i-required" />
|
||||||
|
<IndicatorControl Name="Deprecated" Value="@Value.Deprecated" Class="i-deprecated" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<MarkdownControl Value="@Value.Description" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
@if (Value.AdditionalPropertiesAllowed && Value.AdditionalProperties != null)
|
||||||
|
{
|
||||||
|
<div class="s-additional-props">
|
||||||
|
<SchemaControl Value="@Value.AdditionalProperties" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<DiscriminatorControl Value="@Value.Discriminator" />
|
||||||
|
<ExampleControl Value="@Value.Example" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiSchema? Value { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string? Title { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public bool Required { get; set; }
|
||||||
|
|
||||||
|
private string TitleText => (string.IsNullOrWhiteSpace(Title) ? Value?.Title : Title) ?? "";
|
||||||
|
|
||||||
|
private string ArrayText
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Value?.Type != "array")
|
||||||
|
return "";
|
||||||
|
|
||||||
|
var nullable = Value.Nullable ? "?" : "";
|
||||||
|
var itemsType = $"{Value.Items?.Type ?? "-string-"}{nullable}";
|
||||||
|
|
||||||
|
if (Value.MinItems != null || Value.MaxItems != null)
|
||||||
|
return $"{itemsType} [{(Value.MinItems == null ? "" : Value.MinItems.Value)}..{(Value.MaxItems == null ? "" : Value.MaxItems.Value)}]";
|
||||||
|
return $"{itemsType} []";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ObjectText
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Value?.Type != "object")
|
||||||
|
return "";
|
||||||
|
var nullable = Value.Nullable ? "?" : "";
|
||||||
|
if (Value.MinProperties != null || Value.MaxProperties != null)
|
||||||
|
return $"object{nullable} {{{(Value.MinProperties == null ? "" : Value.MinProperties.Value)}..{(Value.MaxProperties == null ? "" : Value.MaxProperties.Value)}}}";
|
||||||
|
return $"object{nullable}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string TypeText
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var nullable = (Value?.Nullable ?? false) ? "?" : "";
|
||||||
|
return $"{Value?.Format ?? "string"}{nullable}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsRequired(string name) => Value?.Required.Contains(name) ?? false;
|
||||||
|
}
|
||||||
33
BlazorOpenApi/Controls/SchemaControl.razor
Normal file
33
BlazorOpenApi/Controls/SchemaControl.razor
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
|
||||||
|
@if ( ResolvedValue != null )
|
||||||
|
{
|
||||||
|
<table class="schema">
|
||||||
|
<SchemaChildControl Value="@ResolvedValue" Title="@Title" Required="@Required" />
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public OpenApiSchema? Value { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string? Title { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public bool Required { get; set; }
|
||||||
|
|
||||||
|
[CascadingParameter]
|
||||||
|
public OpenApiDocument? Api { get; set; }
|
||||||
|
|
||||||
|
private OpenApiSchema? ResolvedValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Api == null || Value?.Reference == null )
|
||||||
|
return Value;
|
||||||
|
if (!Api.Components.Schemas.TryGetValue(Value.Reference.Id, out var resolved))
|
||||||
|
return Value;
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
BlazorOpenApi/Controls/ServersControl.razor
Normal file
69
BlazorOpenApi/Controls/ServersControl.razor
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
@using System.Text.Json
|
||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
@using Microsoft.OpenApi.Readers
|
||||||
|
|
||||||
|
@if (Value != null && Value.Count > 0)
|
||||||
|
{
|
||||||
|
<h2>Servers</h2>
|
||||||
|
<table class="servers">
|
||||||
|
@foreach (var server in Value)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td><MarkdownControl Value="@server.Description" /></td>
|
||||||
|
<td><a class="sr-url" href="@server.Url">@server.Url</a></td>
|
||||||
|
</tr>
|
||||||
|
@if (server.Variables?.Count > 0)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div class="sr-vars">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var (key, val) in server.Variables.OrderBy(x => x.Key))
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td class="sr-var-name">@key</td>
|
||||||
|
<MarkdownControl Value="@val.Description" />
|
||||||
|
<td class="sr-var-val">
|
||||||
|
<Text Class="sr-default" Value="@val.Default" />
|
||||||
|
@if (val.Enum?.Count > 0)
|
||||||
|
{
|
||||||
|
<ul class="sr-enum">
|
||||||
|
@foreach (var v in val.Enum)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(v))
|
||||||
|
{
|
||||||
|
<li>< empty string ></li>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<li>@v</li>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public IList<OpenApiServer>? Value { get; set; }
|
||||||
|
}
|
||||||
11
BlazorOpenApi/Controls/Text.razor
Normal file
11
BlazorOpenApi/Controls/Text.razor
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@if (!string.IsNullOrWhiteSpace(Value))
|
||||||
|
{
|
||||||
|
<div class="@Class">@Value</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public string? Value { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string? Class { get; set; }
|
||||||
|
}
|
||||||
24
BlazorOpenApi/Controls/Tooltip.razor
Normal file
24
BlazorOpenApi/Controls/Tooltip.razor
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
@if (string.IsNullOrWhiteSpace(TooltipText))
|
||||||
|
{
|
||||||
|
<div class="@Class">
|
||||||
|
@ChildContent
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="tooltip">
|
||||||
|
<div class="@Class">
|
||||||
|
@ChildContent
|
||||||
|
</div>
|
||||||
|
<div class="tooltiptext">@TooltipText</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public RenderFragment? ChildContent { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string? TooltipText { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string Class { get; set; } = "";
|
||||||
|
}
|
||||||
101
BlazorOpenApi/OpenAPIUIControl.razor
Normal file
101
BlazorOpenApi/OpenAPIUIControl.razor
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
@using System.Text.Json
|
||||||
|
@using Microsoft.OpenApi.Models
|
||||||
|
@using Microsoft.OpenApi.Readers
|
||||||
|
|
||||||
|
@if (Palette != null )
|
||||||
|
{
|
||||||
|
@PaletteStr
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="openapi-ui">
|
||||||
|
<CascadingValue Value="@_api">
|
||||||
|
<HeaderControl Value="@_api.Info" DownloadUrl="@Url"/>
|
||||||
|
<ServersControl Value="@_api.Servers" />
|
||||||
|
@if (_api.Paths?.Count > 0)
|
||||||
|
{
|
||||||
|
<h2>Endpoints</h2>
|
||||||
|
foreach (var path in _api.Paths)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(path.Key) || path.Value != null)
|
||||||
|
{
|
||||||
|
<PathControl Key="@path.Key" Value="@path.Value" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (_api.Components != null)
|
||||||
|
{
|
||||||
|
<h2>Components</h2>
|
||||||
|
<ComponentsControl Value="@_api.Components"/>
|
||||||
|
}
|
||||||
|
</CascadingValue>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter] public string Url { get; set; } = "";
|
||||||
|
[Parameter] public string Json { get; set; } = "";
|
||||||
|
[Parameter] public OpenApiUiPalette? Palette { get; set; }
|
||||||
|
|
||||||
|
private string _loadedFor = "";
|
||||||
|
private OpenApiDocument _api = new();
|
||||||
|
|
||||||
|
private MarkupString PaletteStr => Palette?.AsMarkupString ?? new();
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync()
|
||||||
|
{
|
||||||
|
var loadedFromUrl = _loadedFor == Url && !string.IsNullOrWhiteSpace(Url);
|
||||||
|
var loadedFromJson = _loadedFor == Json && !string.IsNullOrWhiteSpace(Json);
|
||||||
|
if (loadedFromUrl || loadedFromJson)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Json))
|
||||||
|
LoadFromJson();
|
||||||
|
else if (!string.IsNullOrWhiteSpace(Url))
|
||||||
|
await LoadFromUrl();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadFromUrl()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var client = new HttpClient();
|
||||||
|
|
||||||
|
var jsonStream = await client.GetStreamAsync(Url);
|
||||||
|
var reader = new OpenApiStreamReader();
|
||||||
|
var res = await reader.ReadAsync(jsonStream);
|
||||||
|
|
||||||
|
|
||||||
|
if (res?.OpenApiDocument == null)
|
||||||
|
throw new InvalidOperationException($"Can't parse {Url}");
|
||||||
|
|
||||||
|
_api = res.OpenApiDocument;
|
||||||
|
_loadedFor = Url;
|
||||||
|
Json = "";
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_loadedFor = "";
|
||||||
|
_api = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadFromJson()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var reader = new OpenApiStringReader();
|
||||||
|
var res = reader.Read(Json, out var _)
|
||||||
|
?? throw new InvalidOperationException($"Can't parse Json/Yaml");
|
||||||
|
|
||||||
|
_api = res;
|
||||||
|
|
||||||
|
_loadedFor = Url;
|
||||||
|
// Url = ""; <-- do not set URL to ""
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_loadedFor = "";
|
||||||
|
_api = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
BlazorOpenApi/OpenApiUiPalette.cs
Normal file
79
BlazorOpenApi/OpenApiUiPalette.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace BlazorOpenApi;
|
||||||
|
|
||||||
|
public class OpenApiUiPalette : ICloneable
|
||||||
|
{
|
||||||
|
public string BackgroundLighter { get; set; } = "#0000001f";
|
||||||
|
public string BackgroundDarker { get; set; } = "#00000055";
|
||||||
|
public string BackgroundDarkest { get; set; } = "#000000AA";
|
||||||
|
|
||||||
|
public string ForegroundNormal { get; set; } = "#e4e4e4";
|
||||||
|
public string ForegroundLighter { get; set; } = "#ffffff";
|
||||||
|
public string ForegroundDarker { get; set; } = "#A0A0A0";
|
||||||
|
public string ForegroundDarkest { get; set; } = "#808080";
|
||||||
|
|
||||||
|
public string[/*8*/] Background { get; set; } = [
|
||||||
|
"#3655a3",
|
||||||
|
"#7a7620",
|
||||||
|
"#9f4b1e",
|
||||||
|
"#7e1b29",
|
||||||
|
"#52628b",
|
||||||
|
"#851192",
|
||||||
|
"#266b67",
|
||||||
|
"#456f2b"
|
||||||
|
];
|
||||||
|
|
||||||
|
public string[/*8*/] Foreground { get; set; } = [
|
||||||
|
"#7d98de",
|
||||||
|
"#ded971",
|
||||||
|
"#eda279",
|
||||||
|
"#e97d8d",
|
||||||
|
"#b1c0e6",
|
||||||
|
"#e571f2",
|
||||||
|
"#98e6e1",
|
||||||
|
"#54b319"
|
||||||
|
];
|
||||||
|
|
||||||
|
public MarkupString AsMarkupString => new MarkupString(
|
||||||
|
$@"
|
||||||
|
<style>
|
||||||
|
.openapi-ui {{
|
||||||
|
--oa-bg-lighter: {BackgroundLighter};
|
||||||
|
--oa-bg-darker: {BackgroundDarker };
|
||||||
|
--oa-bg-darkest: {BackgroundDarkest};
|
||||||
|
|
||||||
|
--oa-fg-normal: {ForegroundNormal };
|
||||||
|
--oa-fg-lighter: {ForegroundLighter};
|
||||||
|
--oa-fg-darker: {ForegroundDarker };
|
||||||
|
--oa-fg-darkest: {ForegroundDarkest};
|
||||||
|
|
||||||
|
{string.Join("\n ", Background.Select((x,i) => $"--oa-bg-{i+1}: {x};"))}
|
||||||
|
|
||||||
|
{string.Join("\n ", Foreground.Select((x, i) => $"--oa-fg-{i+1}: {x};"))}
|
||||||
|
}}
|
||||||
|
</style>
|
||||||
|
");
|
||||||
|
|
||||||
|
public OpenApiUiPalette Clone()
|
||||||
|
{
|
||||||
|
var other = new OpenApiUiPalette
|
||||||
|
{
|
||||||
|
BackgroundLighter = BackgroundLighter,
|
||||||
|
BackgroundDarker = BackgroundDarker,
|
||||||
|
BackgroundDarkest = BackgroundDarkest,
|
||||||
|
|
||||||
|
ForegroundNormal = ForegroundNormal,
|
||||||
|
ForegroundLighter = ForegroundLighter,
|
||||||
|
ForegroundDarker = ForegroundDarker,
|
||||||
|
ForegroundDarkest = ForegroundDarkest,
|
||||||
|
|
||||||
|
Background = (string[])Background.Clone(),
|
||||||
|
Foreground = (string[])Foreground.Clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
|
||||||
|
object ICloneable.Clone() => Clone();
|
||||||
|
}
|
||||||
26
BlazorOpenApi/Properties/launchSettings.json
Normal file
26
BlazorOpenApi/Properties/launchSettings.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:57161",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "http://localhost:5026",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
BlazorOpenApi/README.md
Normal file
3
BlazorOpenApi/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Blazor OpenAPI UI
|
||||||
|
|
||||||
|
Blazor implementation of SwaggerUI-like interface.
|
||||||
10
BlazorOpenApi/_Imports.razor
Normal file
10
BlazorOpenApi/_Imports.razor
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@using System.Net.Http
|
||||||
|
@using Microsoft.AspNetCore.Authorization
|
||||||
|
@using Microsoft.AspNetCore.Components.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 BlazorOpenApi
|
||||||
|
@using BlazorOpenApi.Controls
|
||||||
392
BlazorOpenApi/wwwroot/css/openapi-ui.css
Normal file
392
BlazorOpenApi/wwwroot/css/openapi-ui.css
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
.descriminator {}
|
||||||
|
|
||||||
|
.example {}
|
||||||
|
.e-item {}
|
||||||
|
.e-name {}
|
||||||
|
.e-title {}
|
||||||
|
|
||||||
|
.expander {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ex-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {}
|
||||||
|
.h-contact {}
|
||||||
|
.h-email {}
|
||||||
|
.h-name {}
|
||||||
|
.h-source-url {}
|
||||||
|
.h-title {}
|
||||||
|
.h-url {}
|
||||||
|
.h-version {
|
||||||
|
font-size: var(--oa-font-large);
|
||||||
|
width: fit-content;
|
||||||
|
color: var(--oa-fg-lighter);
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: var(--oa-bg-tag);
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h1 {}
|
||||||
|
.h2 {}
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
color: var(--oa-fg-lighter);
|
||||||
|
background-color: var(--oa-bg-lighter);
|
||||||
|
font-size: var(--oa-font-smaller);
|
||||||
|
height: fit-content;
|
||||||
|
width: fit-content;
|
||||||
|
margin-right: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-top: 3px;
|
||||||
|
padding-left: 3px;
|
||||||
|
padding-right: 3px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.i-required {
|
||||||
|
background-color: var(--oa-bg-3);
|
||||||
|
}
|
||||||
|
.i-deprecated {
|
||||||
|
background-color: var(--oa-bg-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown {}
|
||||||
|
|
||||||
|
.operation {}
|
||||||
|
.operations {}
|
||||||
|
.op-params {}
|
||||||
|
.op-header {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: var(--oa-fg-lighter);
|
||||||
|
}
|
||||||
|
.op-summary {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.op-tags {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.op-tag {
|
||||||
|
background-color: var(--oa-bg-tag);
|
||||||
|
color: var(--oa-fg-tag);
|
||||||
|
border: solid 1px;
|
||||||
|
margin: 1px;
|
||||||
|
display: block;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
.op-tag-name {
|
||||||
|
font-size: var(--oa-font-small);
|
||||||
|
white-space: nowrap;
|
||||||
|
text-transform: lowercase;
|
||||||
|
}
|
||||||
|
.op-type {
|
||||||
|
border: solid 1px;
|
||||||
|
margin: 1px;
|
||||||
|
display: block;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 2px;
|
||||||
|
padding-top: 3px;
|
||||||
|
font-size: var(--oa-font-small);
|
||||||
|
text-transform: uppercase;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
.op-get {
|
||||||
|
background-color: var(--oa-bg-op-get);
|
||||||
|
}
|
||||||
|
.op-put {
|
||||||
|
background-color: var(--oa-bg-op-put);
|
||||||
|
}
|
||||||
|
.op-post {
|
||||||
|
background-color: var(--oa-bg-op-post);
|
||||||
|
}
|
||||||
|
.op-delete {
|
||||||
|
background-color: var(--oa-bg-op-delete);
|
||||||
|
}
|
||||||
|
.op-options {
|
||||||
|
background-color: var(--oa-bg-op-options);
|
||||||
|
}
|
||||||
|
.op-head {
|
||||||
|
background-color: var(--oa-bg-op-head);
|
||||||
|
}
|
||||||
|
.op-patch {
|
||||||
|
background-color: var(--oa-bg-op-patch);
|
||||||
|
}
|
||||||
|
.op-trace {
|
||||||
|
background-color: var(--oa-bg-op-trace);
|
||||||
|
}
|
||||||
|
.parameter {
|
||||||
|
margin-left: 24px;
|
||||||
|
}
|
||||||
|
.p-attrs {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.p-body {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
.p-in {
|
||||||
|
color: var(--oa-fg-lighter);
|
||||||
|
font-size: var(--oa-font-smaller);
|
||||||
|
height: fit-content;
|
||||||
|
width: fit-content;
|
||||||
|
margin-right: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-top: 3px;
|
||||||
|
padding-left: 3px;
|
||||||
|
padding-right: 3px;
|
||||||
|
}
|
||||||
|
.p-in-query {
|
||||||
|
background-color: var(--oa-bg-query);
|
||||||
|
}
|
||||||
|
.p-in-header {
|
||||||
|
background-color: var(--oa-bg-header);
|
||||||
|
}
|
||||||
|
.p-in-path {
|
||||||
|
background-color: var(--oa-bg-path);
|
||||||
|
}
|
||||||
|
.p-in-cookie {
|
||||||
|
background-color: var(--oa-bg-cookie);
|
||||||
|
}
|
||||||
|
.p-indicators {
|
||||||
|
display: flex;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.p-name {
|
||||||
|
color: var(--oa-fg-1);
|
||||||
|
margin-right: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.p-style {
|
||||||
|
color: var(--oa-fg-lighter);
|
||||||
|
font-size: var(--oa-font-smaller);
|
||||||
|
height: fit-content;
|
||||||
|
width: fit-content;
|
||||||
|
margin-right: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-top: 3px;
|
||||||
|
padding-left: 3px;
|
||||||
|
padding-right: 3px;
|
||||||
|
}
|
||||||
|
.p-style-matrix {
|
||||||
|
background-color: var(--oa-bg-matrix);
|
||||||
|
}
|
||||||
|
.p-style-label {
|
||||||
|
background-color: var(--oa-bg-label);
|
||||||
|
}
|
||||||
|
.p-style-form {
|
||||||
|
background-color: var(--oa-bg-form);
|
||||||
|
}
|
||||||
|
.p-style-simple {
|
||||||
|
background-color: var(--oa-bg-simple);
|
||||||
|
}
|
||||||
|
.p-style-spacedelimited {
|
||||||
|
background-color: var(--oa-bg-spacedelimited);
|
||||||
|
}
|
||||||
|
.p-style-pipedelimited {
|
||||||
|
background-color: var(--oa-bg-pipedelimited);
|
||||||
|
}
|
||||||
|
.p-style-deepobject {
|
||||||
|
background-color: var(--oa-bg-deepobject);
|
||||||
|
}
|
||||||
|
|
||||||
|
.path {}
|
||||||
|
.pa-header {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.pa-summary {
|
||||||
|
}
|
||||||
|
|
||||||
|
.responses {}
|
||||||
|
.response {}
|
||||||
|
.r-name {
|
||||||
|
border: solid 1px;
|
||||||
|
padding-left: 3px;
|
||||||
|
padding-right: 3px;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
.r-success {
|
||||||
|
color: var(--oa-fg-8);
|
||||||
|
}
|
||||||
|
.r-auth {
|
||||||
|
color: var(--oa-fg-3);
|
||||||
|
}
|
||||||
|
.r-error {
|
||||||
|
color: var(--oa-fg-4);
|
||||||
|
}
|
||||||
|
.r-encoding{}
|
||||||
|
|
||||||
|
.schema {}
|
||||||
|
.s-additional-props {}
|
||||||
|
.s-props {}
|
||||||
|
.s-title {
|
||||||
|
color: var(--oa-fg-1);
|
||||||
|
margin-right: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.s-nested {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
.s-type {
|
||||||
|
color: var(--oa-fg-8);
|
||||||
|
}
|
||||||
|
.s-bg-odd {
|
||||||
|
background-color: var(--oa-bg-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
.s-bg-even {
|
||||||
|
background-color: var(--oa-bg-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
.servers {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.sr-server {
|
||||||
|
display: flex;
|
||||||
|
flex-direction:row;
|
||||||
|
}
|
||||||
|
.sr-default {}
|
||||||
|
.sr-enum {}
|
||||||
|
.sr-url {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
.sr-var-name {}
|
||||||
|
.sr-var-val {}
|
||||||
|
.sr-vars {}
|
||||||
|
.spacer {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.op-header-text {
|
||||||
|
padding-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-ui h1 {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-ui h2 {
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
.openapi-ui h3 {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
.openapi-ui h4 {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-ui .tooltip {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
border-bottom: 1px dotted black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-ui .tooltip .tooltiptext {
|
||||||
|
visibility: hidden;
|
||||||
|
width: fit-content;
|
||||||
|
width: 201px;
|
||||||
|
font-size: var(--oa-font-smaller);
|
||||||
|
background-color: var(--oa-bg-darkest);
|
||||||
|
color: var(--oa-fg-darker);
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 5px 0;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
bottom: 125%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -60px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-ui .tooltip .tooltiptext::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-width: 5px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #555 transparent transparent transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-ui .tooltip:hover .tooltiptext {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-ui span {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-ui td {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-ui {
|
||||||
|
--oa-bg-lighter: #0000001f;
|
||||||
|
--oa-bg-darker: #00000055;
|
||||||
|
--oa-bg-darkest: #000000AA;
|
||||||
|
|
||||||
|
--oa-fg-normal: #e4e4e4;
|
||||||
|
--oa-fg-lighter: #ffffff;
|
||||||
|
--oa-fg-darker: #A0A0A0;
|
||||||
|
--oa-fg-darkest: #808080;
|
||||||
|
|
||||||
|
--oa-bg-1: #3655a3;
|
||||||
|
--oa-bg-2: #7a7620;
|
||||||
|
--oa-bg-3: #9f4b1e;
|
||||||
|
--oa-bg-4: #7e1b29;
|
||||||
|
--oa-bg-5: #52628b;
|
||||||
|
--oa-bg-6: #851192;
|
||||||
|
--oa-bg-7: #266b67;
|
||||||
|
--oa-bg-8: #456f2b;
|
||||||
|
|
||||||
|
--oa-fg-1: #7d98de;
|
||||||
|
--oa-fg-2: #ded971;
|
||||||
|
--oa-fg-3: #eda279;
|
||||||
|
--oa-fg-4: #e97d8d;
|
||||||
|
--oa-fg-5: #b1c0e6;
|
||||||
|
--oa-fg-6: #e571f2;
|
||||||
|
--oa-fg-7: #98e6e1;
|
||||||
|
--oa-fg-8: #54b319;
|
||||||
|
|
||||||
|
--oa-bg-tag: var(--oa-bg-1);
|
||||||
|
--oa-fg-tag: var(--oa-fg-lighter);
|
||||||
|
|
||||||
|
--oa-bg-op-get: var(--oa-bg-1);
|
||||||
|
--oa-bg-op-put: var(--oa-bg-2);
|
||||||
|
--oa-bg-op-post: var(--oa-bg-3);
|
||||||
|
--oa-bg-op-delete: var(--oa-bg-4);
|
||||||
|
--oa-bg-op-options: var(--oa-bg-5);
|
||||||
|
--oa-bg-op-head: var(--oa-bg-6);
|
||||||
|
--oa-bg-op-patch: var(--oa-bg-7);
|
||||||
|
--oa-bg-op-trace: var(--oa-bg-8);
|
||||||
|
|
||||||
|
--oa-bg-header: var(--oa-bg-6);
|
||||||
|
--oa-bg-form: var(--oa-bg-7);
|
||||||
|
--oa-bg-path: var(--oa-bg-8);
|
||||||
|
--oa-bg-cookie: var(--oa-bg-1);
|
||||||
|
--oa-bg-query: var(--oa-bg-2);
|
||||||
|
|
||||||
|
--oa-bg-matrix: var(--oa-bg-6);
|
||||||
|
--oa-bg-label: var(--oa-bg-7);
|
||||||
|
--oa-bg-simple: var(--oa-bg-8);
|
||||||
|
--oa-bg-spacedelimited: var(--oa-bg-1);
|
||||||
|
--oa-bg-pipedelimited: var(--oa-bg-2);
|
||||||
|
--oa-bg-deepobject: var(--oa-bg-3);
|
||||||
|
|
||||||
|
--oa-font-small: 12px;
|
||||||
|
--oa-font-smaller: 10px;
|
||||||
|
--oa-font-large: 16px;
|
||||||
|
}
|
||||||
11
Demo/App.razor
Normal file
11
Demo/App.razor
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Router AppAssembly="@typeof(App).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>
|
||||||
16
Demo/BlazorOpenApi.Demo.csproj
Normal file
16
Demo/BlazorOpenApi.Demo.csproj
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MudBlazor" />
|
||||||
|
<PackageReference Include="System.Text.Json" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Examples\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\BlazorOpenApi\BlazorOpenApi.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
42
Demo/Controllers/TestController.cs
Normal file
42
Demo/Controllers/TestController.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
||||||
|
|
||||||
|
namespace BlazorOpenApi.Controllers;
|
||||||
|
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class TestController : ControllerBase
|
||||||
|
{
|
||||||
|
// GET: api/<TestController>
|
||||||
|
[HttpGet]
|
||||||
|
public IEnumerable<string> Get()
|
||||||
|
{
|
||||||
|
return new string[] { "value1", "value2" };
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET api/<TestController>/5
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public string Get(int id)
|
||||||
|
{
|
||||||
|
return "value";
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST api/<TestController>
|
||||||
|
[HttpPost]
|
||||||
|
public void Post([FromBody] string value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT api/<TestController>/5
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
public void Put(int id, [FromBody] string value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE api/<TestController>/5
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
public void Delete(int id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
1228
Demo/Examples/petstore.yaml
Normal file
1228
Demo/Examples/petstore.yaml
Normal file
File diff suppressed because it is too large
Load Diff
42
Demo/Pages/Error.cshtml
Normal file
42
Demo/Pages/Error.cshtml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
@page
|
||||||
|
@model BlazorOpenApi.Pages.ErrorModel
|
||||||
|
|
||||||
|
<!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" />
|
||||||
|
<title>Error</title>
|
||||||
|
<link href="~/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
|
||||||
|
<link href="~/css/app.css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="main">
|
||||||
|
<div class="content px-4">
|
||||||
|
<h1 class="text-danger">Error.</h1>
|
||||||
|
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||||
|
|
||||||
|
@if (Model.ShowRequestId)
|
||||||
|
{
|
||||||
|
<p>
|
||||||
|
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
<h3>Development Mode</h3>
|
||||||
|
<p>
|
||||||
|
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||||
|
It can result in displaying sensitive information from exceptions to end users.
|
||||||
|
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||||
|
and restarting the app.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
26
Demo/Pages/Error.cshtml.cs
Normal file
26
Demo/Pages/Error.cshtml.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace BlazorOpenApi.Pages;
|
||||||
|
|
||||||
|
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||||
|
[IgnoreAntiforgeryToken]
|
||||||
|
public class ErrorModel : PageModel
|
||||||
|
{
|
||||||
|
public string? RequestId { get; set; }
|
||||||
|
|
||||||
|
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||||
|
|
||||||
|
private readonly ILogger<ErrorModel> _logger;
|
||||||
|
|
||||||
|
public ErrorModel(ILogger<ErrorModel> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGet()
|
||||||
|
{
|
||||||
|
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Demo/Pages/Index.razor
Normal file
58
Demo/Pages/Index.razor
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
@page "/"
|
||||||
|
@inject NavigationManager Navigation
|
||||||
|
|
||||||
|
<PageTitle>Index</PageTitle>
|
||||||
|
@*
|
||||||
|
<MudText Typo="Typo.h3" GutterBottom="true">Hello, world!</MudText>
|
||||||
|
<MudText Class="mb-8">Welcome to your new app, powered by MudBlazor!</MudText>
|
||||||
|
<MudAlert Severity="Severity.Normal">You can find documentation and examples on our website here: <MudLink Href="https://mudblazor.com" Typo="Typo.body2" Color="Color.Inherit"><b>www.mudblazor.com</b></MudLink></MudAlert>
|
||||||
|
|
||||||
|
<MudLink Href="/api-docs/index.html" Typo="Typo.body2" Color="Color.Inherit">/api-docs/index.html</MudLink>
|
||||||
|
*@
|
||||||
|
|
||||||
|
@*
|
||||||
|
<iframe src="/api-docs/index.html" style="width:100%;height:93vh;border:none;" />
|
||||||
|
*@
|
||||||
|
|
||||||
|
<MudList>
|
||||||
|
<MudListItem>
|
||||||
|
<MudLink Href="@(GetUrl("https://redocly.github.io/redoc/openapi.yaml"))">ReDoc version</MudLink>
|
||||||
|
</MudListItem>
|
||||||
|
<MudListItem>
|
||||||
|
<MudLink Href="@(GetUrl("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json"))">GitHub version</MudLink>
|
||||||
|
</MudListItem>
|
||||||
|
</MudList>
|
||||||
|
|
||||||
|
<MudCard>
|
||||||
|
<MudForm Model="@model">
|
||||||
|
<MudCardContent>
|
||||||
|
<MudTextField @bind-Value="model.Url"
|
||||||
|
For="@(() => model.Url)"
|
||||||
|
Immediate="true"
|
||||||
|
Label="Url" />
|
||||||
|
|
||||||
|
</MudCardContent>
|
||||||
|
</MudForm>
|
||||||
|
<MudCardActions>
|
||||||
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" Class="ml-auto" OnClick="@Submit">Display</MudButton>
|
||||||
|
</MudCardActions>
|
||||||
|
</MudCard>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
private static string GetUrl(string url) => "openapi-ui?url=" + Uri.UnescapeDataString(url);
|
||||||
|
|
||||||
|
UrlModel model = new UrlModel();
|
||||||
|
|
||||||
|
public class UrlModel
|
||||||
|
{
|
||||||
|
public string Url { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Submit()
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo(GetUrl(model.Url));
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
25
Demo/Pages/OpenApiUI.razor
Normal file
25
Demo/Pages/OpenApiUI.razor
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
@page "/openapi-ui"
|
||||||
|
|
||||||
|
@using BlazorOpenApi;
|
||||||
|
|
||||||
|
<PageTitle>OpenApiUI</PageTitle>
|
||||||
|
|
||||||
|
@* <OpenAPIUIControl Url="@Url" Palette="@TestPalette"/> *@
|
||||||
|
<OpenAPIUIControl Url="@Url" />
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
[SupplyParameterFromQuery(Name = "url")]
|
||||||
|
public string Url { get; set; } = "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json";
|
||||||
|
|
||||||
|
// private OpenApiUiPalette TestPalette
|
||||||
|
// {
|
||||||
|
// get
|
||||||
|
// {
|
||||||
|
// var p = new OpenApiUiPalette().Clone();
|
||||||
|
// p.Foreground[7] = "blue";
|
||||||
|
|
||||||
|
// return p;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
8
Demo/Pages/_Host.cshtml
Normal file
8
Demo/Pages/_Host.cshtml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
@page "/"
|
||||||
|
@namespace BlazorOpenApi.Demo.Pages
|
||||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
@{
|
||||||
|
Layout = "_Layout";
|
||||||
|
}
|
||||||
|
|
||||||
|
<component type="typeof(App)" render-mode="ServerPrerendered" />
|
||||||
32
Demo/Pages/_Layout.cshtml
Normal file
32
Demo/Pages/_Layout.cshtml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
|
@namespace BlazorOpenApi.Pages
|
||||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<base href="~/" />
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
||||||
|
<link href="_content/BlazorOpenApi/css/openapi-ui.css" rel="stylesheet" />
|
||||||
|
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||||
|
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
@RenderBody()
|
||||||
|
|
||||||
|
<div id="blazor-error-ui">
|
||||||
|
<environment include="Staging,Production">
|
||||||
|
An error has occurred. This application may no longer respond until reloaded.
|
||||||
|
</environment>
|
||||||
|
<environment include="Development">
|
||||||
|
An unhandled exception has occurred. See browser dev tools for details.
|
||||||
|
</environment>
|
||||||
|
<a href="" class="reload">Reload</a>
|
||||||
|
<a class="dismiss">🗙</a>
|
||||||
|
</div>
|
||||||
|
<script src="_framework/blazor.server.js"></script>
|
||||||
|
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
45
Demo/Program.cs
Normal file
45
Demo/Program.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
|
||||||
|
using MudBlazor.Services;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
StaticWebAssetsLoader.UseStaticWebAssets(builder.Environment, builder.Configuration);
|
||||||
|
|
||||||
|
// Add services to the container.
|
||||||
|
builder.Services.AddRazorPages();
|
||||||
|
builder.Services.AddServerSideBlazor();
|
||||||
|
builder.Services.AddMudServices();
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
//builder.Services.AddSwaggerGen(c =>
|
||||||
|
//{
|
||||||
|
// c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
|
||||||
|
//});
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (!app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseExceptionHandler("/Error");
|
||||||
|
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||||
|
app.UseHsts();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseStaticFiles();
|
||||||
|
|
||||||
|
app.UseRouting();
|
||||||
|
//app.UseSwagger();
|
||||||
|
|
||||||
|
//app.UseReDoc(c =>
|
||||||
|
//{
|
||||||
|
// c.DocumentTitle = "REDOC API Documentation";
|
||||||
|
// c.SpecUrl = "/swagger/v1/swagger.json";
|
||||||
|
//});
|
||||||
|
|
||||||
|
app.MapBlazorHub();
|
||||||
|
app.MapFallbackToPage("/_Host");
|
||||||
|
|
||||||
|
app.Run();
|
||||||
22
Demo/Properties/launchSettings.json
Normal file
22
Demo/Properties/launchSettings.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"BlazorOpenApi": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "http://localhost:5000/openapi-ui?url=https://redocly.github.io/redoc/openapi.yaml",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"applicationUrl": "http://localhost:5000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:61949",
|
||||||
|
"sslPort": 44393
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
Demo/README.md
Normal file
6
Demo/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Blazor OpenAPI UI Demo
|
||||||
|
|
||||||
|
Shows capabilities of `BlazorOpenApi`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
55
Demo/Shared/MainLayout.razor
Normal file
55
Demo/Shared/MainLayout.razor
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
|
<MudThemeProvider @ref="@_mudThemeProvider" @bind-IsDarkMode="@IsDarkMode" />
|
||||||
|
<MudDialogProvider />
|
||||||
|
<MudSnackbarProvider />
|
||||||
|
|
||||||
|
<MudLayout>
|
||||||
|
<MudAppBar Elevation="0">
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
|
||||||
|
<MudSpacer />
|
||||||
|
<MudIconButton Icon="@Icons.Custom.Brands.MudBlazor" Color="Color.Inherit" Href="https://mudblazor.com/" Target="_blank" />
|
||||||
|
<MudIconButton Icon="@Icons.Custom.Brands.GitHub" Color="Color.Inherit" Href="https://github.com/MudBlazor/MudBlazor/" Target="_blank" />
|
||||||
|
</MudAppBar>
|
||||||
|
<MudDrawer @bind-Open="_drawerOpen" Elevation="1">
|
||||||
|
<MudDrawerHeader>
|
||||||
|
<MudText Typo="Typo.h6">OpenApiUI Demo</MudText>
|
||||||
|
</MudDrawerHeader>
|
||||||
|
<NavMenu />
|
||||||
|
<div class="d-flex justify-left align-end mud-height-full">
|
||||||
|
<MudSwitch @bind-Value="@IsDarkMode" Color="MudBlazor.Color.Primary" Class="ma-4" T="bool" Label="Dark Mode" />
|
||||||
|
</div>
|
||||||
|
</MudDrawer>
|
||||||
|
<MudMainContent>
|
||||||
|
<CascadingValue Value="@IsDarkMode">
|
||||||
|
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge" Class="pt-2">
|
||||||
|
@Body
|
||||||
|
</MudContainer>
|
||||||
|
</CascadingValue>
|
||||||
|
</MudMainContent>
|
||||||
|
</MudLayout>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
bool _drawerOpen = true;
|
||||||
|
private bool IsDarkMode;
|
||||||
|
private MudThemeProvider? _mudThemeProvider;
|
||||||
|
|
||||||
|
void DrawerToggle() => _drawerOpen = !_drawerOpen;
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
IsDarkMode = await _mudThemeProvider!.GetSystemPreference();
|
||||||
|
await _mudThemeProvider.WatchSystemPreference(OnSystemPreferenceChanged);
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnSystemPreferenceChanged(bool newValue)
|
||||||
|
{
|
||||||
|
IsDarkMode = newValue;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
28
Demo/Shared/NavMenu.razor
Normal file
28
Demo/Shared/NavMenu.razor
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<MudNavMenu>
|
||||||
|
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
|
||||||
|
|
||||||
|
<MudNavLink Href="@(GetUrl("https://redocly.github.io/redoc/openapi.yaml"))"
|
||||||
|
Match="NavLinkMatch.All"
|
||||||
|
Icon="@Icons.Material.Filled.Abc">
|
||||||
|
ReDoc version
|
||||||
|
</MudNavLink>
|
||||||
|
<MudNavLink Href="@(GetUrl("https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json"))"
|
||||||
|
Match="NavLinkMatch.All"
|
||||||
|
Icon="@Icons.Material.Filled.AccountBox">
|
||||||
|
GitHub version
|
||||||
|
</MudNavLink>
|
||||||
|
<MudNavLink Href="@(GetUrl("https://dtrnk0o2zy01c.cloudfront.net/openapi/en-us/dest/BrandMetrics_prod_3p.json"))"
|
||||||
|
Match="NavLinkMatch.All"
|
||||||
|
Icon="@Icons.Material.Filled.Cloud">
|
||||||
|
Amazon Brand Metrics
|
||||||
|
</MudNavLink>
|
||||||
|
<MudNavLink Href="@(GetUrl("https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/api-reference/v1.0/contracts/bcoas1.0.yaml"))"
|
||||||
|
Match="NavLinkMatch.All"
|
||||||
|
Icon="@Icons.Material.Filled.Cloud">
|
||||||
|
Dynamics 365 BC
|
||||||
|
</MudNavLink>
|
||||||
|
</MudNavMenu>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private static string GetUrl(string url) => "openapi-ui?url=" + Uri.UnescapeDataString(url);
|
||||||
|
}
|
||||||
13
Demo/_Imports.razor
Normal file
13
Demo/_Imports.razor
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
@using System.Net.Http
|
||||||
|
@using Microsoft.AspNetCore.Authorization
|
||||||
|
@using Microsoft.AspNetCore.Components.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 MudBlazor
|
||||||
|
@using BlazorOpenApi
|
||||||
|
@using BlazorOpenApi.Controls
|
||||||
|
@using BlazorOpenApi.Demo
|
||||||
|
@using BlazorOpenApi.Demo.Shared
|
||||||
10
Demo/appsettings.Development.json
Normal file
10
Demo/appsettings.Development.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"DetailedErrors": true,
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
Demo/appsettings.json
Normal file
10
Demo/appsettings.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
}
|
||||||
BIN
Demo/wwwroot/favicon.ico
Normal file
BIN
Demo/wwwroot/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
8
Directory.Build.props
Normal file
8
Directory.Build.props
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
13
Directory.Packages.props
Normal file
13
Directory.Packages.props
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageVersion Include="MudBlazor" Version="8.3.0" />
|
||||||
|
<PackageVersion Include="Markdig" Version="0.40.0" />
|
||||||
|
<PackageVersion Include="Microsoft.OpenApi.Readers" Version="2.0.0-preview9" />
|
||||||
|
<PackageVersion Include="Swashbuckle.AspNetCore.ReDoc" Version="6.5.0" />
|
||||||
|
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" />
|
||||||
|
<PackageVersion Include="System.Text.Json" Version="9.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
Loading…
x
Reference in New Issue
Block a user